Repository navigation
MCPServer answers an unknown prompt name or a missing required argument with code 0 / -32603; the spec uses -32602 #3669
Description
Initial Checks
- I confirm that I'm using the newest release of my line (the latest 2.x, or the latest 1.x if I'm still on v1)
- I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue
Release line
2.x (current stable)
Description
prompts/get for a prompt name that isn't registered, or without one of the prompt's required arguments, should fail with JSON-RPC -32602 (Invalid params). The spec's prompts Error Handling section says so for both cases, in 2025-11-25 and in 2026-07-28. The TypeScript SDK's McpServer throws InvalidParams for an unknown prompt (mcp.ts:657).
MCPServer raises a plain ValueError in both cases. With the script below, on mcp 2.3.0 and on main@91941ed:
| Case | 2025-11-25 | 2026-07-28 |
|---|---|---|
| unknown prompt name | code 0, Unknown prompt: does_not_exist |
-32603, Internal server error |
| missing required argument | code 0, Missing required arguments: {'name'} |
-32603, Internal server error |
| prompt function raises | code 0, Error rendering prompt boom |
-32603, Internal server error |
The first two rows should be -32602. On 2026-07-28 the client isn't even told which name was wrong. The third row is only there for contrast: it is a real internal error. docs/servers/prompts.md currently documents the missing-argument case as -32603, so fixing it changes documented behaviour.
The interaction suite already records the first two rows as divergences for 2025-11-25 (mcpserver:prompt:unknown-name and prompts:get:missing-required-args in tests/interaction/_requirements.py; the 2026-07-28 arm is excluded), but I couldn't find an issue tracking them. Draft #2999 keeps both as divergences.
#1872 (approved in March) fixes the unknown-name case, though not missing arguments, and it now conflicts with main in 11 files, including server.py. If #1872 is refreshed, it covers the first row and this issue can track the second. Otherwise I'd like to fix both myself, if you take an outside PR for it.
Related: #3659 (an unknown tool gets an isError result instead of -32602), #3342 (missing-argument errors are logged with a traceback).
Disclosure: an AI assistant helped with the investigation and this write-up.
Example Code
import anyio
from mcp import Client, MCPError
from mcp.server import MCPServer
server = MCPServer("repro")
@server.prompt()
def greet(name: str) -> str:
return f"Hello, {name}"
@server.prompt()
def boom() -> str:
raise RuntimeError("kaboom")
CASES = [
("unknown prompt", "does_not_exist", {}),
("valid call", "greet", {"name": "Ada"}),
("missing argument", "greet", {}),
("prompt raises", "boom", {}),
]
async def main() -> None:
for mode in ("legacy", "2026-07-28"):
async with Client(server, mode=mode) as c:
print(f"== mode={mode} negotiated={c.protocol_version}")
for label, name, args in CASES:
try:
r = await c.get_prompt(name, args)
print(f" {label:17} -> GetPromptResult {r.messages[0].content.text!r}")
except MCPError as e:
print(f" {label:17} -> MCPError code={e.error.code} message={e.error.message!r}")
anyio.run(main)Python & MCP Python SDK
Python 3.13.16
mcp 2.3.0 (PyPI); same result on main@91941ed
Activity
Varshith-Kali commentedon Oct 11, 2026
I'd like to take this on. Plan: map both rows (unknown prompt name and missing required argument) to JSON-RPC -32602 per the spec, keeping genuine prompt-function crashes as internal errors, and update the interaction conformance entries plus the docs that currently pin the old codes. This would supersede the prompt half of stale #1872. I'll cover both legacy and 2026-07-28 modes in the regression tests.
ajay206 commentedon Oct 12, 2026
Hi! I reproduced this: MCPServer.get_prompt (unknown name) and Prompt.render (missing required args) raise a plain ValueError, which the dispatchers map to code 0 on legacy connections and -32603 on 2026-07-28, instead of -32602 as the spec requires.
I have a fix ready that raises MCPError(INVALID_PARAMS) at both sites, matching how ResourceNotFoundError is handled for resources. It also updates the unit, end-to-end and interaction tests (both spec versions) and docs/servers/prompts.md. The full suite passes at 100% coverage, and ruff and pyright are clean. Could I be assigned to open the PR?
(I worked on this with help from Cursor and Grok Bot.)
ANcpLua commentedon Oct 13, 2026
I'm stepping back here. ajay206's fix (ajay206#3) does what I would have done, with tests on both protocol versions. I'll keep #3659 (unknown tools), which needs a different fix. (Drafted with Claude.)