Build a local TypeScript server
Keep errors useful
Design validation, not-found, backend, and unexpected failures so callers can recover without receiving sensitive internals.
8 minute lesson
MCP exposes failures at two levels.
Protocol errors mean the request cannot be dispatched, such as an unknown method or malformed request. Tool execution errors mean the tool was called but could not complete its job.
The SDK validates our Zod input before the handler runs. The handler still owns domain failures such as a missing note or unavailable database.
Return an actionable tool error:
return {
content: [{
type: 'text',
text: 'The notes backend is temporarily unavailable. Try again later.'
}],
isError: true
}
Do not return a stack trace, SQL statement, environment value, or upstream response body. Those details belong in a protected diagnostic channel.
For unexpected failures, create a request-safe incident ID. Log the ID with the internal error, then return only the ID and a generic message. The caller can report it without receiving secrets.
Build a small failure table in TESTING.md:
| Case | Handler runs? | Expected result |
|---|---|---|
| Empty query | No | Input validation error |
| Limit above ten | No | Input validation error |
| Unknown note ID | Yes | isError: true |
| Existing note ID | Yes | Structured success |
Useful errors reveal the safe next step. They do not reveal the server internals.
Lesson completed