A tool schema is a promise to the model. The registry is what actually keeps it.
1A Registry Is Just a Dict of Functions
There's no special MCP machinery required to route a tool call — a plain dictionary mapping each tool's name (a string) to the function that implements it is enough. When a tools/call request names "read_file", dispatch looks that string up in the dict and calls whatever function it finds.
2Unknown Tools Must Fail Gracefully
A model can send a tool name your server doesn't recognize — from a stale schema on the client side, a typo, or a bug. dispatch has to treat that as an expected case, not a crash: checking for a missing handler and returning a clear error result keeps one bad call from taking down the whole server process.
3Step-by-Step Breakdown
From Schema to Real Code. A schema tells a model a tool exists — it doesn't run anything. When a tools/call request arrives with a tool name, your server needs a real lookup table mapping that name to the actual Python function that does the work. That lookup table is the tool registry, and it's the core of every MCP server.
Build the Real Dispatch Function. The registry lookup and the unknown-tool guard are already written. Finish dispatch so a recognized tool name actually calls its handler with the given arguments and returns the result.
Why does dispatch check if handler is None and return an error string, instead of just calling TOOL_REGISTRY[tool_name] directly?
- →So an unrecognized tool name — which a model can absolutely send, whether from a bug or a stale schema — fails gracefully with a clear message instead of crashing the server with a KeyError.
- →It makes the dispatch function run faster.
A Real Dispatcher, Two Toy Handlers. Your dispatch function now really works — but the handlers behind it are still stubs with one hardcoded file. Next: giving list_files and read_file a real, slightly bigger simulated project to operate on, closer to what a real server would manage.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Return Consistent Error Shapes From Every Handler
If some errors are strings and others raise exceptions, any UI or client rendering tool results has to handle both — pick one consistent shape across your whole registry.
return {"error": "unknown tool"}SEO Implications
- 1
Target 'MCP server dispatch function' and 'tool registry pattern Python' separately
Developers implementing their first server search for the MCP-specific routing step and the general dict-of-functions pattern independently.
Best Practices
Keep the Registry as the Single Source of Truth for Available Tools
Generate the schemas you send to the client from the same registry, rather than maintaining a separate hardcoded list — otherwise the two can silently drift apart.
Frequent Bugs
Calling `TOOL_REGISTRY[tool_name]` directly without a guard.
An unrecognized name raises an unhandled KeyError and can crash the request-handling loop — always look up with `.get()` and check for `None` first.
Real-World Examples
Plugin Systems
Many plugin architectures — not just MCP servers — use this same name-to-function registry pattern so new capabilities can be added by registering a new entry, without touching the dispatch logic itself.
REGISTRY["new_tool"] = new_tool_handler