③ Answers
Tools & Agent Overview
How agents, runtime-discovered Python tools, skills, and the MCP endpoint fit together
Four moving parts do the work in a chat turn, and this page is the map between them.
Two runtimes — DeepAgent and BaseAgent — differing in who runs the tool loop.
Plain Python functions, found by scanning directories when the server starts.
Directories of instructions an agent reads on demand — prose, not code it calls.
/mcp — the same tools, over JSON-RPC 2.0, for outside clients.
Two agents
Section titled “Two agents”Mirobody ships two agent runtimes and picks one per chat turn. Both read from the same tool registry; what differs is who runs the tool loop.
| Agent | Shape of a turn |
|---|---|
| DeepAgent | LangChain create_agent plus the deepagents middleware stack, over a PostgreSQL-backed virtual filesystem, with an in-process JavaScript REPL. The loop runs here. |
| BaseAgent | No LangChain. It hands /mcp to the provider and streams the result — the loop runs in the provider. |
Which one answers, which providers each can use, and how their prompts are configured is the subject of Agent Types.
Runtime discovery
Section titled “Runtime discovery”There is no registration macro and no build step. When the server starts, the engine walks
every directory named in MCP_TOOL_DIRS, imports each module it finds, and turns the
eligible callables into MCP tools.
- Scan the directories in
MCP_TOOL_DIRSsubdirectories, non-.pyfiles and files whose name starts with_are skipped - Import each module an import error is logged and that module is skipped — the server still starts
- Register top-level functions and methods of classes whose name ends in
Service - Build the JSON schema from the type hints
strintfloatboollist[...]dict[...] - Build the description from the docstring first block → tool description; the
Args:block → per-parameter descriptions
The rules, in full:
- Directories come from the
MCP_TOOL_DIRSconfig key. The shipped default is the single packaged directorymirobody/agent/tools; add your own and list it first. - Files must end in
.py. A leading underscore means “not a tool module” — which is how__init__.pyand private helpers stay out of the registry. - Functions at module level are registered as tools. A leading underscore excludes them.
- Classes are only considered when the class name ends in
Service. Inside such a class, public methods become tools;_-prefixed methods, inherited methods and methods imported from another module are ignored. - A class may opt out by defining a static
_enabled() -> bool. ReturnFalseand the whole class is skipped, so none of its tools exist. This is how optional integrations disappear cleanly when their API key is not configured.
Identity injection
Section titled “Identity injection”A tool that needs to know who is asking declares a user_info parameter. It is stripped
from the schema the model sees, and filled in by the server from the authenticated
caller before the function runs:
{"success": True, "user_id": "...", "session_id": "..."}So the model never supplies — and cannot forge — an identity; a tool reads it with
user_info.get("user_id") and scopes its query to that user.
Skills
Section titled “Skills”Skills are the other half of “what an agent knows how to do”, and they are not tools.
A skill is a directory containing one SKILL.md: its frontmatter says when to reach for it
and is injected into every prompt, its body is read only when a task calls for it. The
content becomes context, not a function call. See Agent Skills.
The MCP endpoint
Section titled “The MCP endpoint”The same registry is served at /mcp over JSON-RPC 2.0,
so Claude Desktop, Cursor and any custom client can call exactly the tools your own
agents call. tools/list is unauthenticated — and honest per account: the two tools bound
to user data are listed only when that account actually holds that kind of data.
curl -X POST http://localhost:18080/mcp \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'The endpoint faces both ways: it serves tools outward, and Mirobody also keeps a per-user registry of external MCP servers. Mirobody MCP Server covers client setup, remote HTTPS access and OAuth.
Tool visibility
Section titled “Tool visibility”Two config keys per agent narrow the registry, using the agent name in upper case as the
suffix — DEEP and BASE for the two shipped agents:
| Key | Effect |
|---|---|
ALLOWED_TOOLS_{NAME} | Whitelist. When set, only these tools are offered. |
DISALLOWED_TOOLS_{NAME} | Blacklist. Applied after the whitelist, so it always wins. |
Leave both empty — as the shipped config.yaml does — and every discovered tool is
available to that agent.
Next steps
Section titled “Next steps”What ships in the box, parameter by parameter
Drop a .py file in and restart
Connect Claude, Cursor, and remote clients
MCP_TOOL_DIRS, provider keys, and everything else