Test an MCP integration as a contract, not as a demo: prove discovery, authentication, permission denial, tool invocation, failure reporting and client configuration before you give it to a team. The minimum rollout gate is a repeatable harness that sends real JSON-RPC tools/list and tools/call traffic, plus client smoke tests in the agents people will actually use. A server is ready when normal, denied and broken paths are predictable enough that support can explain them from logs.
Define the rollout boundary
Start by naming the exact endpoint, credentials, clients and sources that are in scope. MCP supports different transports, but Streamable HTTP is the rollout shape most teams want for shared remote integrations: each protocol message is sent as an HTTP POST to one MCP endpoint, and the response is either a JSON object or a request-scoped SSE stream. Your test plan should exercise the same remote URL, authorization path and network boundary that Claude Code, Cursor, VS Code or another client will use.
The first artifact should be a small matrix. Put clients on one axis and permissions on the other: read-only key, write-enabled key if one exists, expired credential, source-limited credential and unauthenticated request. For each cell, write the expected behavior before running it. For example, the read-only key should discover read tools, be denied on a write tool, and still return a clear failure when an upstream system is unreachable. This keeps the exercise focused on least-privilege agent keys, not on whether one happy-path prompt worked.
Also freeze the candidate tool list. MCP tool definitions include a name, description and input schema, and clients can cache or summarize those definitions for the model. Compare discovery against an approved manifest, flag accidental new tools and flag changed argument schemas. If the integration is a gateway, include namespacing so two upstream servers cannot both publish an ambiguous search tool by accident.
Probe the protocol directly
Before testing through an agent UI, send protocol requests directly. This catches problems that a model can hide with retries or vague prose. The discovery request is tools/list; the invocation request is tools/call. The MCP specification notes that request examples omit required protocol metadata for brevity, so your harness should add the required _meta fields while asserting the method, params and result shape shown here.
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "github.search_issues",
"arguments": {
"query": "repo:example/api label:bug",
"limit": 5
}
}
}Assert more than a 200 response. For tools/list, check deterministic ordering, stable names, valid JSON Schema input definitions and whether the list changes when the bearer token changes. The specification allows availability to vary by authorization, so a narrower key may correctly see fewer tools. For tools/call, check MCP content blocks or structured content, that isError is reserved for tool-level failures, and that bad arguments produce a useful error instead of an upstream stack trace.
Keep one boring call in the suite. A low-risk read, such as listing a tiny fixture issue or querying a test table, becomes your canary for latency, auth refresh and regression checks. Then add one denied call and one malformed call so the harness proves refusal as well as completion.
Install it like users will
Client-specific behavior belongs in the test plan because configuration shape affects what users experience. Claude Code can add a remote HTTPS MCP endpoint with claude mcp add --transport http, and it can pass an authentication header for token-based servers. A rollout smoke test should run the real command in a disposable project, then verify claude mcp list or /mcp shows the expected server state.
claude mcp add --transport http company-tools https://api.example.com/agent/mcp \
--header "Authorization: Bearer $AGENT_MCP_KEY"Cursor uses mcp.json with an mcpServers object; project-specific configuration lives at .cursor/mcp.json, while user-wide configuration lives at ~/.cursor/mcp.json. Test the checked-in project file and the local secret path engineers will use. Do not hardcode real tokens in the file.
{
"mcpServers": {
"company-tools": {
"url": "https://api.example.com/agent/mcp",
"headers": {
"Authorization": "Bearer ${env:AGENT_MCP_KEY}"
}
}
}
}VS Code supports workspace MCP configuration in .vscode/mcp.json with a top-level servers object, and it also supports the portable .mcp.json format with mcpServers. If VS Code is part of the rollout, check the exact file you will document and whether the editor prompts for trust, logs connection errors and exposes only expected tools.
{
"servers": {
"company-tools": {
"type": "http",
"url": "https://api.example.com/agent/mcp"
}
}
}
Test auth and permission denial
Authentication success is only one branch. For HTTP MCP servers using OAuth, the authorization specification relies on OAuth metadata discovery, including protected resource metadata, so test the unauthenticated path as deliberately as the signed-in path. A client that receives a challenge should know where to send the user; a bad static bearer token should fail clearly rather than silently falling back to a broader credential.
| Case | Expected result | Why it matters |
|---|---|---|
| No credential | Authentication challenge or explicit unauthenticated error | Users can start the right sign-in flow |
| Expired token | Refresh, reauth prompt or clear failure | Support can distinguish stale auth from server outage |
| Read-only key calls write tool | Denied before upstream mutation | Policy holds even if the model selects the wrong tool |
| Source-limited key calls another source | Denied with source and tool in logs | One integration cannot become all integrations |
| Malformed arguments | Schema or validation error | The caller gets a fixable problem, not leaked internals |
Run these cases through direct protocol tests and at least one real client. The direct test proves the server contract. The client test proves the denial is visible to the human and to the model in a way that will not invite unsafe retries. This is especially important for write tools, where a vague failure can lead an agent to try a neighboring tool with broader side effects.
Log the authorization decision separately from the tool result. The audit record should include actor, client, source, tool, grant checked, denial reason, upstream status and latency. That evidence turns a rollout incident from guesswork into a traceable event, which is why it pairs naturally with tool-call audit logging.
Break dependencies on purpose
A rollout test should make upstream systems fail before users do. Stop one upstream MCP server, revoke one upstream OAuth grant, force one REST API timeout and make one database fixture reject a query. The correct result is not always a fallback. Often it is a precise failure that keeps the source visible, marks the tool unavailable or reports a bounded timeout without losing the rest of the workspace.
Measure latency at the same time. Direct calls should record server time, upstream time and total client-observed time. Agent calls should record the number of tool attempts and whether the model chose the expected tool. A slow tools/list can delay every session start; a slow tools/call is easier to isolate if the response identifies which upstream system was waiting.
Rollout gate
Do not ship until the broken path is as documented as the happy path: what the user sees, what the agent sees, what support sees in logs, and whether retrying is safe.
Include tool-list changes in the failure plan. Some clients keep an initial tool list for a whole session, while others can react to list-change notifications or reloads. If a server goes unreachable after the session starts, calls against its tools should fail in a bounded, explainable way. Do not depend on every client immediately removing tools from context.
How SPYN3 tests this
A useful rollout test in SPYN3 needs two keys: the real one, and a read-only key limited to one source. Run your discovery and call checks with both. The real key should succeed, and the restricted one should be refused, while its list_toolsets still reports how many tools it withholds. Then check the Logs page: every call should appear with the key that made it. A source whose server is down should show as unreachable, not as an empty result.
Make the checklist shippable
Turn the tests into a release checklist with owners, not a notebook. The server owner owns protocol probes and fixture data. The security owner owns credential scope, OAuth behavior and denial cases. The client owner owns Claude Code, Cursor, VS Code or any other supported surface. The support owner owns error copy and log queries. If nobody owns a row, it is not a requirement yet.
- Confirm the endpoint and transport match production.
- Run
tools/listwith every credential class and compare the result with the approved manifest. - Run one successful
tools/call, one denied call and one malformed call per source. - Install the endpoint in every supported client with the documented config.
- Break one upstream dependency and verify the visible error, timeout and audit record.
- Review the final tool list for naming collisions, risky descriptions and write tools exposed to read-only keys.
Keep the checklist close to the integration code and run it before widening access. MCP makes it easy to connect tools to agents; the rollout discipline is proving that the connection behaves predictably when the model, the credential, the client or the upstream system is wrong.
Built for the next step
Test denials, not only demos
Validate source scopes, write grants and upstream failures before rollout.
Failure guideSPYN3 is a consolidated MCP layer: one hosted endpoint in front of every system you connect — MCP servers, Postgres, REST APIs, Google Drive — with tools foldered by source and read/write permissions per key. Switching agents means moving one URL. Free plan available; current capabilities are documented on the product facts page.
Sources
- MCP specification: tools — tool discovery, invocation and security considerations. Verified 14 Oct 2026
- MCP specification: transports — stdio and Streamable HTTP transport boundaries. Verified 14 Oct 2026
- MCP specification: authorization — OAuth-based authorization for HTTP MCP servers. Verified 14 Oct 2026
- Anthropic docs: Claude Code MCP setup — Claude Code MCP commands, scopes, transports and JSON configuration. Verified 14 Oct 2026
- VS Code documentation: add and manage MCP servers — VS Code MCP configuration, trust and logging behavior. Verified 14 Oct 2026
- Cursor documentation: MCP integrations — Cursor MCP configuration locations, remote URL entries, headers and approval behavior. Verified 14 Oct 2026
