create_tool
Generates and verifies a new Python MCP tool server when no existing tool can perform a task, then mounts it so its tools become callable.
Instructions
Create a new tool when none of your current tools can do what the task needs (a web API, live data, a computation). Write a complete Python MCP tool server script (MCPServer); AutoTool verifies it in a guarded subprocess, injects only the credentials it declares, and mounts it: its tools appear in your tool list (or call them through run_tool). If verification fails you get the error; fix the code and call create_tool again with the same name.
The script MUST follow this contract:
It is one self-contained file that runs as
python <file>.pyand serves MCP over stdio.It uses
from mcp.server.mcpserver import MCPServerand createsmcp = MCPServer("<tool_name>").Every tool is a function decorated with
@mcp.tool()with full type annotations and a docstring that explains what it does and each parameter. Prefer simple parameter types (str, int, float, bool) with sensible defaults. Return astr(plain text orjson.dumps(...)of the result).The file ends with: if name == "main": mcp.run()
Only import the standard library,
httpx2,pydanticandmcp.Use
httpx2with an explicit timeout of at most 10 seconds for network calls. Use public APIs, or APIs whose credentials the prompt lists as available environment variables. Never hard-code credentials.Credentials: read each one with
os.environ["NAME"]and declare every name you read at module level, e.g.REQUIRED_ENV = ["NAME"]. Only declared names are injected into the process. Send keys in headers when the API allows it; never return, log or put key values in error messages.Make every external API base URL overridable through an environment variable named
<SERVICE>_API_BASE(e.g.HN_API_BASE), defaulting to the real public URL.Report failures the caller should see (an HTTP error status, nothing found) by raising
ToolError("...")frommcp.server.mcpserver.exceptions, with a clear message that names the service and status. Let unexpected errors raise: they fail the call, and the traceback reaches the verification harness. Never return an error as a normal string, and never swallow exceptions.No subprocesses, no filesystem writes, no
eval/exec.Keep the tool fast: bound fan-out (e.g. concurrent requests for at most ~30 items).
No credentials are available: only use public, keyless APIs and do not declare REQUIRED_ENV.
Structural reference:
import os
import httpx2
from mcp.server.mcpserver import MCPServer
from mcp.server.mcpserver.exceptions import ToolError
mcp = MCPServer("example_tool")
API_BASE = os.environ.get("EXAMPLE_API_BASE", "https://api.example.com")
@mcp.tool()
def get_thing(thing_id: int, verbose: bool = False) -> str:
"""Fetch a thing by id.
Args:
thing_id: Numeric id of the thing.
verbose: Include extra fields.
"""
with httpx2.Client(timeout=10) as client:
resp = client.get(f"{API_BASE}/things/{thing_id}")
if resp.status_code != 200:
raise ToolError(f"Example API returned HTTP {resp.status_code} for thing {thing_id}")
return resp.text
if __name__ == "__main__":
mcp.run()Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | Complete Python source of the MCPServer tool script. | |
| name | Yes | snake_case module name ending in _tool, e.g. 'weather_tool'. | |
| test_tool | No | Tool to smoke-test (default: the first one). | |
| test_arguments | No | Safe, realistic arguments for the smoke test. |