An MCP server breaks at three seams: the SDK class name, the upstream request shape, and each CLI's server config. Treating those as one upgrade is what makes a small rename expensive.
Put a thin adapter between your tools and the vendor SDK. Keep all imports and request construction in one module, so a FastMCP to MCPServer or genai client bump touches one file. Add a startup check that lists tools, sends one tiny generation call, and prints the resolved model, endpoint, and SDK version on failure.
DIY baseline that covers the rename case: pin exact versions in the lockfile, run that smoke script in CI, and keep one config snippet per CLI pointing at the same entrypoint. For a single-maintainer server, that is usually enough.
The remaining gap is silent divergence: one CLI passes env or cwd differently, or the Interactions API returns 400 for a field shape the old SDK sent. Log the outbound payload bytes on non-2xx and diff them against the last known-good call before changing code.
What workaround have you used when the same MCP server passes in one CLI but fails in another?
Top comments (1)
The three-seams framing matches what I keep hitting: the SDK rename is the cheap one, the CLI config is the ugly one. Two clients can point at the same entrypoint and still differ in how they pass env and cwd to a stdio server — one inherits the parent environment, the other only what you declare — so the same server passes in one CLI and hangs in the other with no error to read.
The payload-byte diff on non-2xx is the part I'd steal; silent divergence almost always shows up as a field-shape drift in the request, not in the code path, and a 'last known-good call' gives you a comparator that a stack trace never does. Is the smoke check just startup, or does it run as a real CI job per CLI?