modelcontextprotocol / modelcontextprotocol/go-sdk

Index: nine findings from one audit of a large MCP server against the specification

Open
#1,257 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Go
Stars
5.1k
Forks
543
Avg merge
1d 17h
Merged PRs (30d)
37

Description

I maintain a GitLab MCP server built on this SDK: about 865 tools on its individual surface, three tool surfaces, stdio and streamable HTTP, resource subscriptions and OAuth. I audited it against the MCP specification and against the SDK, and recorded every finding that belongs upstream rather than in my own code. Nine of them concern this SDK and have no fix yet: each was reproduced against a real deployment or against the compiled binary driven over its own transport, each names the specification clause, documentation page or semantic convention it fails, and each is pinned by a test I can hand you.

I am filing them as separate issues so that each can be triaged, labelled and closed on its own. This one is the index, so you can see the set at once and see that it comes from one audit rather than from nine unrelated reports. I checked every finding against current main before filing; the individual issues give the version I first observed it on.

Specification conformance, with a fix offered

Each of these four is a conformance defect and each has a pull request open against it: a minimal change in the SDK's own style, a test that fails before it and passes after, and go test ./... green.

  • #1258 mcp: the declared protocol version, not the negotiated one, decides what a session is served. A client that asks for a newer revision and is negotiated down to an older one is still served the newer interaction. The pull request is #1266.
  • #1259 A cancelled request is still answered. A response goes out for a request the peer cancelled, which the specification says a receiver should not send. The pull request is #1267.
  • #1260 mcp: an unknown protocol version in per-request _meta is not answered with UnsupportedProtocolVersionError. An unrecognised version is misclassified instead of being refused with the error the versioning page requires. The pull request is #1268.
  • #1261 mcp: a receiving middleware cannot tell whether a request carried params. The predicate that answers the question is unexported, so middleware outside the package cannot distinguish an omitted params member from a present one. The pull request is #1269.
Found during review of the pull requests above

Two defects that the review of #1266 turned up rather than the original audit, each filed with a pull request in the same shape as the four above.

  • #1271 mcp: three methods are served on a legacy session before the initialize handshake. The gate lives in one branch of the method switch, so logging/setLevel, resources/subscribe and resources/unsubscribe skip it; subscribe is the one that reaches state. The pull request is #1273.
  • #1272 mcp: the negotiated protocol version is recorded on one path of four, so stdio accepts batches a SEP-2575 session forbids. The pull request is #1274.
Already filed
  • #1254, the cancellation reason discarded before any handler sees it. The pull request for it is open at #1255.
API the SDK does not expose, proposal only

These four cannot be closed without new exported API, so they go out as proposals rather than as pull requests: each body states the requirement, cites the SDK code that stands in the way, and offers a concrete Go signature together with the alternatives I considered. Each of them is waiting on your decision about the shape, and I will write the pull request once you say which one you want.

  • #1262 mcp: an SSE response keeps http.Server.WriteTimeout armed, so a long-lived stream dies before its first notification. A stream that stays idle is cut by the server's own write deadline before it ever sends anything.
  • #1263 mcp: a server cannot send the notifications/cancelled that 2026-07-28 requires when it tears down a subscriptions/listen stream. The protocol asks for that notification on teardown and application code has no way to send it.
  • #1264 proposal: mcp: expose the JSON-RPC request id to receiving middleware and handlers. There is no accessor for the id of the message being handled.
  • #1265 mcp: a resource update cannot be delivered to one session, and the caller's context never reaches the sending middleware. Delivery goes to every session subscribed to the URI, and nothing a caller puts on its context arrives at the middleware that sends it.

Every finding above is now filed, and each issue links back here.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Treat this as an index rather than an implementation task. Start with the individual issues listed here, their cited specification clauses and tests, and the open pull requests; run go test ./... where relevant. The index is complete as a map of the nine findings, while fixes and API decisions belong in the linked issues.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
api
Issue type
Documentation
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
15/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.