You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- Log rejected tool arguments with %r: pydantic's error locations can
include caller-supplied dict keys, which must not break onto new log
lines.
- Build CompleteResult inside the completion adapter's try, so a handler
returning the wrong type is logged as a crash and answered with the
generic -32603 rather than "Invalid request parameters".
- On the legacy resolver path, a malformed ElicitResult from a
non-conformant client no longer has its pydantic text repeated back.
- Add FuncMetadata.call_fn() for calling with already-validated
arguments and use it from Tool.run; call_fn_with_arg_validation()
becomes a deprecated wrapper (MCPDeprecationWarning, removal in 3.0).
- Docstring and docs wording: MCPError carve-outs, nested crash message,
ResourceError in the imports and resource paragraph, the exact
MCPDeprecationWarning path a traceback prints.
Copy file name to clipboardExpand all lines: docs/servers/handling-errors.md
+4-4Lines changed: 4 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -125,7 +125,7 @@ When it can't, raise `ResourceNotFoundError`. The SDK turns it into the protocol
125
125
}
126
126
```
127
127
128
-
Notice there is no `is_error=True` half-result here. A resource read either returns contents or fails: resources have only the protocol path. `ResourceError` is the same thing for a failure that isn't "not found" (`-32603`, your message). Any other exception is a crash: the client gets `-32603` naming only the URI, and the traceback goes to your log at `ERROR`. Templates and everything else about resources live in **[Resources](resources.md)**.
128
+
Notice there is no `is_error=True` half-result here. A resource read either returns contents or fails: resources have only the protocol path. `ResourceError` is the same thing for a failure that isn't "not found" (`-32603`, your message), and both are one `INFO` line in your log. Any other exception bar `MCPError` is a crash: the client gets `-32603` naming only the URI, and the traceback goes to your log at `ERROR`. Templates and everything else about resources live in **[Resources](resources.md)**.
129
129
130
130
## Errors you never raise
131
131
@@ -136,8 +136,8 @@ Send `get_author` a `title` that isn't a string and the SDK rejects it against t
136
136
It means a whole class of `raise` statements you don't write: don't re-validate your own type hints.
137
137
138
138
!!! info
139
-
Everything on this page is what a **client** sees, and the in-memory `Client` you'll write
140
-
tests with sees exactly the same thing. Even `raise_exceptions=True` doesn't hand a failing
139
+
Everything a **client** sees on this page, the in-memory `Client` you'll write tests with
140
+
sees too. Even `raise_exceptions=True` doesn't hand a failing
141
141
tool's exception back to the caller: by the time that flag could act, your exception is already
142
142
the `is_error=True` result. Assert on the result. If you need the traceback of a crash, it is in
143
143
the server's log, and pytest's `caplog` captures it. **[Testing](../get-started/testing.md)** covers the pattern.
@@ -150,7 +150,7 @@ It means a whole class of `raise` statements you don't write: don't re-validate
150
150
* Any **other exception** is a crash -> `is_error=True` with only `Error executing tool <name>` for the model, and an `ERROR` record with the traceback for you.
151
151
*`ResourceNotFoundError` from a resource handler -> the protocol's `-32602`, with the URI in `data`.
152
152
* Bad arguments are rejected against the schema before your function runs; you don't `raise` for those.
153
-
* Imports: `from mcp import MCPError`, `from mcp.server.mcpserver.exceptions import ToolError, ResourceNotFoundError`, and the error-code constants from `mcp.types`.
153
+
* Imports: `from mcp import MCPError`, `from mcp.server.mcpserver.exceptions import ToolError, ResourceError, ResourceNotFoundError`, and the error-code constants from `mcp.types`.
154
154
155
155
Errors handled. That is everything a server *exposes*. What every handler can read, and do back to the client while it runs, is the next section: **[Inside your handler](../handlers/index.md)**.
The fix is in your client: **check `result.is_error`**. A `try/except` around `call_tool` catches none of these, because there is nothing to catch. This is deliberate, and it is the single most useful thing on this page to internalise: the *model* chose the call, so the model gets the message and a chance to try again. **[Handling errors](servers/handling-errors.md)** is the whole story, including the `MCPError` path that *does* raise.
94
94
95
-
The bare form, `Error executing tool <name>` with no message, means the tool **crashed**: it raised something other than `ToolError`, and the exception's text is kept off the wire. The traceback is in the **server's log** at `ERROR`, as `Tool '<name>' raised an unexpected exception`.
95
+
The bare form, `Error executing tool <name>` with no message, means the tool **crashed**: something other than `ToolError` was raised while running it (or its return value failed the output schema), and that exception's text is kept off the wire. The traceback is in the **server's log** at `ERROR`, as `Tool '<name>' raised an unexpected exception`.
96
96
97
97
## `TypeError: The @tool decorator was used incorrectly. Did you forget to call it? Use @tool() instead of @tool`
0 commit comments