MCP protocol¶
mcp-test implements the MCP 2025-06-18 spec via the official modelcontextprotocol/go-sdk.
Transport¶
Streamable HTTP only. There is no stdio transport.
The SDK's mcp.NewStreamableHTTPHandler is mounted at /. Behavior:
POST /withContent-Type: application/jsonandAccept: application/json, text/event-stream: a JSON-RPC request. Returns either a JSON body or an SSE stream depending on the method and the client's Accept preference.GET /withAccept: text/event-stream: opens a persistent SSE stream for server-initiated messages.DELETE /with the session header: terminates the session.
The session ID is round-tripped via the Mcp-Session-Id header.
Capabilities¶
The server advertises:
(prompts, resources, roots, sampling, elicitation are not
implemented; they're not relevant to a gateway test fixture.)
Methods¶
The SDK handles every standard MCP method. The relevant ones for mcp-test:
| Method | Notes |
|---|---|
initialize |
Returns serverInfo (name, version), capabilities, protocolVersion, and instructions (see Server Instructions). |
initialized (notification) |
Marks the session as ready. |
tools/list |
Returns every registered tool with its JSON schema (derived from the Go input struct). |
tools/call |
Invokes the named tool. Subject to the audit middleware. |
notifications/progress |
Server โ client. Emitted by the progress tool when the caller supplies a progressToken. |
Tool schema¶
Each tool registers with mcp.AddTool[In, Out]. The SDK derives the
JSON schema from the In type via reflection, including the
jsonschema:"..." struct tag for descriptions.
Example: the lorem tool's input is
type loremInput struct {
Words int `json:"words" jsonschema:"number of words to generate; defaults to 50 when zero"`
Seed string `json:"seed,omitempty" jsonschema:"optional seed; same seed gives the same output"`
}
So tools/list returns:
{
"name": "lorem",
"description": "Return N words of lorem-ipsum text...",
"inputSchema": {
"type": "object",
"properties": {
"words": { "type": "integer", "description": "number of words to generate; defaults to 50 when zero" },
"seed": { "type": "string", "description": "optional seed; same seed gives the same output" }
}
}
}
Middleware¶
Two pieces of MCP-side middleware sit between the transport and the tool handlers:
- Audit middleware (
pkg/mcpmw.Audit). Fortools/call:- Reads
Authorization/X-API-Keyfrom the SDK'sRequestExtra.Header. - Runs the auth chain (file โ DB API keys โ OIDC).
- Stamps the resolved Identity onto the request context.
- Sanitizes parameters via
audit.SanitizeParameters. - Times the call, measures response size, writes an audit row.
- Reads
- In-memory bypass. When
RequestExtra.Headeris nil (the in-memory transport used by the portal Try-It proxy), the audit middleware stamps an Anonymous identity, lets the call proceed, and writes no audit row. The HTTP handler is responsible for writing its own audit row in that case.
What we don't do¶
- Stdio transport. mcp-test is HTTP-only by design.
- Server-initiated requests. The SDK supports them (sampling,
elicitation,
roots/list); mcp-test doesn't use them. - Resource subscriptions. No resource implementations.
- Prompts. No prompt implementations.
- MCPB bundles. The reference project ships installable MCPB bundles; we don't, since installing mcp-test in a stdio context doesn't really make sense for a gateway test fixture.