An MCP server can connect successfully and still fail the workflow it was meant to support.
The endpoint responds. The client lists tools. OAuth opens in a browser. Someone takes a screenshot and the integration gets called MCP-compatible.
Then a different client negotiates an older protocol revision. A desktop redirect fails. A tool returns an error as ordinary text. A schema changes after an SDK upgrade. The connection is technically alive, but the product is not ready.
“MCP-compatible” should describe a tested contract, not a successful handshake.
The short version
Before shipping an MCP integration, be able to name:
- the protocol revisions you support
- the transports and authentication flows you tested
- the client versions in your test matrix
- the tools, schemas, and error paths the workflow depends on
- the owner and procedure for upgrades
If those facts are missing, “MCP-compatible” is too broad a claim.
Compatibility starts with a declared target
MCP now has two materially different protocol eras.
Revisions through 2025-11-25 use an initialize handshake and may use an Mcp-Session-Id. The 2026-07-28 revision removed both from the modern protocol path. Each request carries the information needed to process it, and server/discover is available when a client wants the server’s capabilities in advance (MCP 2026-07-28 release).
That is not a small implementation detail. It changes connection setup, request metadata, server-to-client interaction, long-running work, and some failure modes.
A useful compatibility statement looks like this:
Tested over Streamable HTTP with MCP
2026-07-28and fallback to2025-11-25, using client versions X, Y, and Z. The integration supports the listed tools and OAuth flows described below.
An unhelpful statement looks like this:
Works with MCP.
Pin the SDK versions used in the test. Record the negotiated protocol revision in logs. If the client can automatically fall back between protocol eras, test both paths deliberately. An automatic fallback is useful behavior, but it can also hide the fact that the modern path never worked.
Test the workflow across real clients
MCP standardizes the messages. It does not make every host behave identically.
Clients differ in how they present authorization, request approval for tools, render structured content, support extensions, retry failed calls, and expose errors to the model or user. They can also ship different MCP revisions on different release schedules.
Build a small client matrix around the clients you actually support.
| Check | What to record |
|---|---|
| Connection | Client name and version, transport, endpoint, negotiated protocol revision |
| Discovery | Expected tools present, unexpected tools absent, schemas parsed correctly |
| Authentication | Authorization metadata, redirect path, requested scopes, refresh or reauthorization behavior |
| Read operation | Valid input, structured result, empty result, upstream timeout |
| Write operation | Approval boundary, exact arguments, duplicate protection, verified outcome |
| Error handling | What the model sees, what the user sees, what the application logs |
| Reconnection | Token expiry, client restart, server restart, interrupted request |
Do not reduce the matrix to “client connected.” Run the smallest complete workflow that matters to the product.
For a support integration, that may be: find a ticket, add an internal note, and confirm the updated ticket. For a deployment tool, it may be: inspect an environment, request approval, start a deployment, and retrieve the result. For a registrar, it may be: check availability, obtain a current quote, submit an approved registration, and verify the domain state.
The write path needs its own test. A read-only success does not prove that permissions, approvals, idempotency, and result reconciliation are correct.
Treat login as a full compatibility surface
Authentication is where a large share of remote MCP integration work happens.
The 2026-07-28 MCP release hardened authorization around issuer validation, client registration metadata, credential isolation, and scope handling. It also deprecated Dynamic Client Registration in favor of Client ID Metadata Documents while retaining DCR for backward compatibility (MCP authorization changes).
That means “OAuth supported” is not a sufficient test result.
Check at least these cases:
- a first-time user authorizes successfully
- desktop, web, and CLI redirect URIs work where those clients are supported
- the client discovers the correct protected resource and authorization server
- scopes match the tools the client is meant to call
- insufficient scope produces a specific reauthorization path
- an expired access token does not become a generic connection failure
- revoked access stops new tool calls
- credentials are not reused across authorization-server issuers
- a user can reconnect without accumulating stale registrations or grants
Keep identity separate from authority. A valid token identifies a principal and grants scopes. It does not prove that a particular purchase, deletion, transfer, or deployment was approved. That decision belongs in application policy at the action boundary.
Validate tool contracts, not just tool names
Tool discovery is a beginning, not a guarantee.
A client needs to parse the tool’s input schema, construct valid arguments, receive a result it understands, and distinguish success from failure. The server needs to reject invalid input without turning a recoverable business problem into an opaque transport error.
For every tool your workflow depends on, test:
- The expected schema is discoverable.
- Required and optional fields behave as documented.
- Unknown or malformed arguments produce a useful failure.
- Empty and partial results remain valid.
- Structured output matches the declared output schema.
- A result can be correlated with the attempted action.
Protocol versions matter here too. In the modern revision, tool output schemas can use full JSON Schema 2020-12 and structuredContent can be any conforming JSON value. Older revisions expected structured content to be an object. A bare array that works with a modern client may fail or be omitted on an older path (MCP PHP SDK tool compatibility notes).
If you serve both eras, choose response shapes both can consume or branch intentionally. Do not discover this difference through a production client.
Make errors useful to the right audience
Not every failure belongs in the same channel.
The MCP TypeScript SDK documentation makes a useful distinction: a tool error is returned as a normal tool result with isError: true, so the model can read it and recover. A protocol error is a JSON-RPC error intended for the calling application (MCP error handling).
That distinction should show up in your tests.
If a requested record does not exist, tell the model what was missing and what valid next step is available. If the client sent malformed JSON or used an unsupported protocol version, return the appropriate protocol-level failure. Do not convert every upstream exception into “Something went wrong.” Do not return a failed purchase as successful text that merely contains the word “error.”
A useful tool failure answers three questions:
- What failed?
- Did anything change?
- What can safely happen next?
For state-changing tools, add a fourth: is a retry safe?
That last question matters after timeouts. The client may not know whether the server completed the operation. The correct next step is often to inspect current state with an idempotency key or operation handle, not to repeat the write.
Test upgrades as a product event
An SDK update is not only a dependency update. It can change protocol behavior, default negotiation, authentication handling, schema validation, or extension support.
Maintain a small compatibility record for each integration:
server_release: 2.4.0
sdk: example-mcp-sdk@2.1.3
protocol_paths:
- 2026-07-28
- 2025-11-25
tested_clients:
- name: client-a
version: 6.2.1
- name: client-b
version: 1.18.0
critical_tools:
- search_records
- create_record
- get_operation_status
last_verified: 2026-11-10
owner: integrations-team
The values are illustrative. The record is the point.
When the server, SDK, authentication service, or supported client changes, compare the discovered schemas and rerun the relevant paths. Keep a previous version available long enough to diagnose a regression. Define how you will announce breaking tool changes and how long consumers have to migrate.
Protocol conformance and SDK tiering are useful signals, but they do not replace this work. The official release lists TypeScript, Python, Go, and C# as Tier 1 SDKs for 2026-07-28 (MCP 2026-07-28 SDK support). That tells you about the SDK’s implementation target. It does not prove that your authentication setup, tool contract, client UI, and business workflow work together.
The pre-ship checklist
Do not ship the compatibility label until the team can check these boxes.
Protocol and transport
- Supported protocol revisions are named explicitly.
- Modern and fallback negotiation paths are tested where both are claimed.
- The production transport and endpoint configuration are tested.
- Negotiated revision, client version, request ID, and tool name are observable.
- Reconnection and interrupted-request behavior are understood.
Clients
- Every supported client has a pinned test version.
- Tool discovery and schema parsing work in each client.
- Approval and confirmation UX is checked for state-changing tools.
- Structured output and errors are visible in a useful form.
- Unsupported capabilities fail clearly.
Authentication and authority
- First login, refresh or reauthorization, revocation, and logout are tested.
- Redirect URIs work for each supported client type.
- Resource and authorization-server metadata resolve correctly.
- Scope failures identify the missing permission.
- Business approval is enforced separately from authentication.
Tools and failures
- Critical tool inputs and outputs are contract-tested.
- Invalid arguments, empty results, timeouts, and upstream failures are covered.
- Tool errors and protocol errors use the correct channel.
- Write operations have idempotency or reconciliation behavior.
- The final business state is verified before success is reported.
Upgrades
- SDK and client versions are recorded.
- Schema changes are diffed before release.
- A regression suite covers the critical workflow.
- Deprecation and migration expectations are documented.
- An owner is responsible for retesting and incident response.
Compatibility is a maintained promise
MCP removes a great deal of custom integration work. It does not remove the need to define what your integration supports.
The strongest compatibility claim is narrow enough to test and useful enough to act on. It names the versions, clients, authentication path, tools, and operational expectations behind the label.
That may sound less impressive than “works everywhere.”
It is also the statement a team can keep true.
Frequently asked questions
Does using an official SDK make an integration MCP-compatible?
It is a strong starting point, not complete evidence. You still need to test your server behavior, authentication setup, tool schemas, errors, and target clients.
Should a server support both MCP protocol eras?
Only if its users need both. If you claim both, test both. A clearly documented modern-only integration is better than an untested fallback path.
Is a successful tools/list call enough for a smoke test?
It proves discovery on that connection. Add a representative read, a controlled failure, and the critical write workflow before calling the integration production-ready.
How often should compatibility be retested?
Retest when the server, MCP SDK, authentication service, tool schema, or supported client changes. Also run the critical path on a schedule so an external client update does not remain invisible.