Skip to main content

turbomcp

A zero-dependency tool registry and MCP server for LLM agents — with built-in tool search so agents don't drown in schemas.

Write plain Python functions. Get JSON Schema, OpenAI function-calling definitions, a real MCP server, and ranked tool search — without installing anything else.

from turbomcp import TurboMCP

mcp = TurboMCP()

@mcp.tool()
def greet(name: str = "World"):
    """Greet a user by name.

    Args:
        name (str): Who to greet
    """
    return f"Hello, {name}!"

That's a working tool. Schemas are generated from the signature and docstring — types from annotations, descriptions from the Args: section, required/optional from defaults.

Why turbomcp?

Most tool servers dump every tool schema into the model's context on every request. That's fine for 5 tools and a disaster for 50. turbomcp is built around progressive disclosure — an agent can work its way down this ladder and only pay for what it needs:

Call Returns Context cost
mcp.list_tools() just the names tiny
mcp.list_tools(with_summary=True) names + one-liners small
mcp.search_tools("fetch a webpage") ranked matches, full schemas only what's relevant
mcp.get_capabilities(name="read_file") one full schema on demand one tool

Search is keyword-based out of the box (name/description/parameter matching with field weighting), and optionally semantic via static embeddings — no GPU, ~1s startup, instant queries.

Install

pip install turbomcp              # core: registry + MCP server, zero dependencies
pip install turbomcp[web]         # + built-in web tools (search, scrape)
pip install turbomcp[semantic]    # + semantic tool search (model2vec)
pip install turbomcp[http]        # + Flask REST API for debugging
pip install turbomcp[all]         # everything

Use it as an MCP server

Any MCP client (Claude Code, Claude Desktop, ...) can launch your registry directly:

turbomcp serve my_tools.py          # finds the TurboMCP instance in the file
turbomcp serve my_tools.py:mcp     # or name the variable explicitly
turbomcp demo                       # try it with the built-in default tools
turbomcp init [my_tools.py]         # create a starter template
turbomcp init my_tools.py --with-web --with-semantic  # include optional features
turbomcp help                       # show all commands

Claude Code:

claude mcp add my-tools -- turbomcp serve /path/to/my_tools.py

Claude Desktop (claude_desktop_config.json):

{
  "mcpServers": {
    "my-tools": {
      "command": "turbomcp",
      "args": ["serve", "/path/to/my_tools.py"]
    }
  }
}

The server implements MCP over stdio natively (JSON-RPC 2.0): initialize, ping, tools/list, tools/call, and it emits notifications/tools/list_changed when tools are registered or removed at runtime — register a new tool while the server is live and connected clients find out immediately.

One rule when serving stdio: don't print() to stdout in your tool file — it corrupts the protocol stream. Use sys.stderr.

Lazy mode: tool search over MCP

turbomcp serve my_tools.py --lazy

In lazy mode the client doesn't see your catalog at all. It sees three meta-tools — search_tools, get_tool, call_tool — and discovers what it needs by searching. A 100-tool registry costs the model three schemas instead of a hundred.

Use it with OpenAI-compatible APIs

The same registry plugs straight into any chat-completions API (OpenAI, Gemini's OpenAI endpoint, Ollama, llama.cpp, vLLM, ...):

from openai import OpenAI

client = OpenAI(base_url="http://localhost:11434/v1", api_key="unused")

response = client.chat.completions.create(
    model="your-model",
    messages=[{"role": "user", "content": "Greet Ada"}],
    tools=mcp.to_openai_tools(),          # <- emitted in OpenAI format
)

for call in response.choices[0].message.tool_calls or []:
    import json
    result = mcp.call(call.function.name, json.loads(call.function.arguments))

Also available: mcp.to_mcp_tools() (MCP format) and mcp.get_tools_prompt() (plain text for models without native tool calling).

mcp.search_tools("fetch a webpage", top_n=3)
# {"query": ..., "semantic": False, "tools": [{"name": "webpage_scrape", "score": ..., ...}]}

Enable semantic search to close the synonym gap ("say hello" → greet):

mcp.enable_semantic_search()   # pip install turbomcp[semantic]

Keyword and semantic scores are blended (tunable alpha); without the extra installed, search falls back to pure keyword scoring automatically.

Built-in default tools

mcp.register_default(all=True)                              # everything
mcp.register_default(names=["calculate", "read_file"])      # or pick
Tool Needs [web] extra
internet_search — DuckDuckGo (default) or Google, text or images yes
webpage_scrape — fetch a page, strip boilerplate, return text yes
get_current_time — local/IANA-timezone/UTC time no
read_file — read a local text file no
calculate — math expressions via a safe AST evaluator (no eval) no
get_system_info — OS, arch, hostname, Python version no

Writing good tools

Schemas are only as good as your signatures and docstrings:

from typing import Literal, Optional

@mcp.tool()
def convert(path: str, format: Literal["mp4", "webm", "gif"], quality: Optional[int] = None):
    """Convert a video file to another format.

    Args:
        path (str): Path to the input file
        format (str): Output format
        quality (int): Output quality 1-100, default keeps source quality
    """
    ...
  • Annotations → types: str, int, float, bool, list[str], dict, Optional[X], Literal[...] (becomes an enum) all map to proper JSON Schema.
  • Defaults → optional: parameters without defaults are required.
  • Args: section → descriptions: Google-style docstrings, one line per parameter.
  • The first docstring paragraph becomes the tool description — make it say when to use the tool, not just what it does.

HTTP Transports

MCP Streamable HTTP (JSON-RPC 2.0) — for remote MCP clients

Spec-compliant 2025-06-18 transport (pip install turbomcp[http]), equivalent to mcp_stdio but over HTTP:

turbomcp serve my_tools.py --http --port 8000          # no-auth for localhost
turbomcp serve my_tools.py --http --host 0.0.0.0 --port 8000  # requires token
# or in code:
from turbomcp.mcp_http import serve_http
serve_http(mcp, host="127.0.0.1", port=8000, require_auth=False)
Endpoint Method Description
/mcp POST JSON-RPC 2.0: initialize, tools/list, tools/call, ping (single or batch) — returns application/json or text/event-stream if Accept: text/event-stream
/mcp GET SSE stream for notifications/tools/list_changed (Accept: text/event-stream required)
/health GET {"status":"ok","name":...}

Claude Desktop remote (claude_desktop_config.json via mcp-remote or native Streamable HTTP):

{
  "mcpServers": {
    "my-tools": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "http://127.0.0.1:8000/mcp"]
    }
  }
}

Streamable HTTP binds 127.0.0.1:8000 by default; use a reverse proxy + Bearer/X-API-Key (registry.security()) for internet.

Legacy REST API (non-MCP) — for curl debugging

pip install turbomcp[http]:

mcp.start_server(port=5000)   # generates an API token, printed to stderr
Endpoint Description
GET /tools?summary=true names (+ summaries)
GET /capabilities full catalog
GET /tool/<name> one tool's schema
GET /search?q=... ranked search
POST /call_tool execute — {"name": ..., "params": {...}}, token via X-API-Key header or api_key field

The REST server binds 127.0.0.1 and only /call_tool requires the token. It's a Flask dev server: fine on localhost, not meant for the open internet.

Security notes

  • Tools run with your user's permissions. A tool like "run shell command" gives the model exactly that power — register it knowingly.
  • calculate uses an AST walker, not eval — sandbox-escape expressions like (1).__class__... are rejected.
  • The HTTP token is generated per-process and printed to stderr; MCP stdio needs no token because the client launches the process itself.

License

MIT

Metadata

Release files for turbomcp 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for turbomcp 0.3.0
File Size Uploaded Provenance Actions
turbomcp-0.3.0.tar.gz 32.1 kB Without provenance Details for turbomcp-0.3.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for turbomcp 0.3.0
File Interpreter ABI Platform Actions
turbomcp-0.3.0-py3-none-any.whl Python 3 none any Details for turbomcp-0.3.0-py3-none-any.whl

Total release size: 59.1 kB

Release files / turbomcp-0.3.0.tar.gz

Download URL turbomcp-0.3.0.tar.gz
Size 32.1 kB
Tags Source
SHA-256 checksum
How to use checksums
591f52b50077e41665c6988a7a27cc8e529bff5579141d56bb3aa8aa1882fa4a
BLAKE2b-256 checksum
How to use checksums
a0641f53b3f8d4a66b2157ab6d4f3943f30143efa212292fefc18459003e2f4a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.6

Release files / turbomcp-0.3.0-py3-none-any.whl

Download URL turbomcp-0.3.0-py3-none-any.whl
Size 27.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bef03c79c571e87034db2e7d93200ff6f071032754d1640a4599269a0a9d0a16
BLAKE2b-256 checksum
How to use checksums
8f12d651dc60aa90270a8ee5ea53d962f3376e53c3fefdd05dea62feb2b86092
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.6

Security for turbomcp 0.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page