Skip to content

Surface resource, prompt, and proxy errors on the modern protocol - #4579

Merged
jlowin merged 1 commit into
mainfrom
fix/protocol-version-defects
Jul 20, 2026
Merged

Surface resource, prompt, and proxy errors on the modern protocol#4579
jlowin merged 1 commit into
mainfrom
fix/protocol-version-defects

Conversation

@jlowin

@jlowin jlowin commented Jul 20, 2026

Copy link
Copy Markdown
Member

Auditing the test suite for the mode="auto" default surfaced three latent defects, all with the same root cause: on the modern protocol (2026-07-28), the SDK's error handling preserves only MCPError and ValidationError and replaces everything else with a generic "Internal server error". On the older handshake protocol the same exception reached the wire as its real message. So any code path that raised a non-MCPError toward the wire was silently protocol-version-dependent, and tests pinned to the older protocol could never see it.

Resource and prompt errors were masked. _on_call_tool caught FastMCPError broadly, but _on_read_resource and _on_get_prompt caught only (DisabledError, NotFoundError). A ResourceError or PromptError — for example from bad argument conversion on a resource template — escaped, and on the modern protocol became indistinguishable from a genuine server bug. Both handlers now translate FastMCPError to MCPError, mirroring how tools already surface these, with mask_error_details respected exactly as before.

A proxy dropped its upstream's instructions for modern clients. Instructions were copied onto the proxy's result only inside the legacy initialize handler. A modern client negotiates server/discover, which had no equivalent hook, so the upstream server's instructions silently never arrived. The proxy now registers a server/discover handler that fills in the upstream instructions, without changing when the proxy first contacts its backend — proxies still connect lazily.

Proxy list methods leaked masked errors. ProxyProvider's list methods caught only MCPError, so a backend connection failure surfaced as "Internal server error" on the modern protocol instead of the clear "Client failed to connect..." the older protocol produced. They now normalize transport errors the same way the proxy's other paths do.

Each fix has a regression test verified to fail against main and split precisely on protocol version.

Note one behavior change for reviewers: a proxy's in-process list_tools() now raises MCPError rather than RuntimeError on a backend connection failure, matching the over-the-wire contract. This is recorded in the change register as breaking.

Label: bugs

Three defects hidden by tests pinned to the handshake era, where a raw
exception reaches the wire as str(exc). At 2026-07-28 the runner masks
anything that is not an MCPError/ValidationError as "Internal server error".

- _on_read_resource / _on_get_prompt now translate FastMCPError through
  to_mcp_error, mirroring _on_call_tool. Masking is unchanged.
- FastMCPProxy registers a server/discover handler so upstream instructions
  reach modern clients; on_initialize only fires for the handshake.
- ProxyProvider's list methods normalize transport failures into MCPError.
@marvin-context-protocol marvin-context-protocol Bot added breaking change Breaks backward compatibility. Requires minor version bump. Critical for maintainer attention. bug Something isn't working. Reports of errors, unexpected behavior, or broken functionality. server Related to FastMCP server implementation or server-side functionality. labels Jul 20, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 43fe00744d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

# mirroring exists to protect; negotiate with "auto" instead, which
# probes `server/discover` and falls back to the handshake for a
# legacy-only backend.
client.mode = "auto"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve prior discovery when fetching proxy instructions

When the supplied backend is a disconnected Client pinned to a modern version with prior_discover=..., forcing mode to "auto" makes _negotiate() ignore that result even though it may already contain the upstream instructions. This introduces an unnecessary server/discover probe and can make proxy negotiation fail or fall back to the legacy handshake for a backend that was intentionally configured for direct pinned adoption. Use the pinned client's prior discovery when available rather than overriding its negotiation mode.

Useful? React with 👍 / 👎.

@jlowin
jlowin merged commit 57bbc98 into main Jul 20, 2026
23 of 24 checks passed
@jlowin
jlowin deleted the fix/protocol-version-defects branch July 20, 2026 21:52
jlowin added a commit that referenced this pull request Jul 20, 2026
Resource/prompt error detail and proxy instructions/connection-error
surfacing now work on the modern protocol era, so the tests pinned to
mode="legacy" with a TODO(defect)/TODO(mode="legacy" pin) marker run
on the default auto mode again.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking change Breaks backward compatibility. Requires minor version bump. Critical for maintainer attention. bug Something isn't working. Reports of errors, unexpected behavior, or broken functionality. server Related to FastMCP server implementation or server-side functionality.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant