Skip to main content
Glama
zahrafatima9432

MCP Toolbox

MCP Toolbox — a Model Context Protocol server + client, from scratch

CI Python License: MIT

A clean, well-documented reference implementation of the Model Context Protocol (MCP): a server that exposes three real tools, and a client agent that discovers and calls them.

Demo of the client running every tool over MCP

  • Document store — add, search (keyword-ranked), fetch, and list text documents. Persists to disk.

  • Web search — real web results via DuckDuckGo with a Wikipedia fallback. No API key required.

  • Calculator — safe arithmetic (no eval; expressions are parsed and evaluated against a strict whitelist).

The client works in two modes:

Mode

Needs an API key?

What it does

Offline (default)

No

Runs a scripted demo that exercises every tool and prints the results. Proves the full MCP round-trip.

LLM

Yes (ANTHROPIC_API_KEY)

Hands the MCP tools to Claude and runs an agent loop; the model decides which tools to call.

The same client code drives both modes — only who decides which tool to call changes. That is the core idea of MCP: the tool interface is uniform, so a simple scripted caller and a smart LLM caller use it identically.


Quickstart (60 seconds, no API key)

You need Python 3.10+.

# 1. From the project folder, create a virtual environment
python -m venv .venv

# 2. Activate it
source .venv/bin/activate          # macOS / Linux
# .venv\Scripts\Activate.ps1        # Windows PowerShell
# .venv\Scripts\activate.bat        # Windows cmd.exe

# 3. Install
pip install -e .

# 4. Run the offline demo — launches the server and calls every tool
python -m mcp_toolbox.client

You'll see the client discover the server's tools and then run the calculator, the document store (search → add → fetch), and a web search, printing the structured result of each call.

Just want to see the tools the server exposes?

python -m mcp_toolbox.client --list

Related MCP server: Agent Construct

Turning on LLM mode (optional)

This lets Claude decide which tools to call to answer a question.

# Install the Anthropic SDK
pip install anthropic

# Add your key (get one at https://console.anthropic.com/ — pay-as-you-go)
cp .env.example .env
# then edit .env and set ANTHROPIC_API_KEY=sk-ant-...

# Ask a question; the agent will use the tools as needed
python -m mcp_toolbox.client --mode llm "What's stored about MCP transports, and what is 23 * 19?"

A demo run costs a fraction of a cent. Without a key, everything else still works — the client simply falls back to the offline demo.


Run it with Docker (no Python setup)

If you'd rather not install anything locally, the demo runs in a container:

docker build -t mcp-toolbox .
docker run --rm mcp-toolbox

For LLM mode, pass your key in and override the command:

docker run --rm -e ANTHROPIC_API_KEY=sk-ant-... mcp-toolbox \
  python -m mcp_toolbox.client --mode llm "What is MCP, and what is 12*9?"

Project layout

mcp-toolbox/
├── README.md
├── demo.gif                  # the animation shown above
├── Dockerfile                # run the demo in a container
├── pyproject.toml            # packaging + console scripts + pytest config
├── requirements.txt
├── .env.example              # copy to .env for LLM mode
├── run_demo.sh               # convenience script: venv + install + demo
├── claude_desktop_config.example.json   # use the server from Claude Desktop
├── .github/workflows/ci.yml  # runs the tests on every push (Linux + Windows)
├── docs/
│   └── ARCHITECTURE.md       # how MCP works and how this repo maps to it
├── src/mcp_toolbox/
│   ├── server.py             # the MCP server (FastMCP over stdio)
│   ├── client.py             # the client agent (offline + LLM modes)
│   └── tools/
│       ├── calculator.py     # safe AST-based arithmetic
│       ├── document_store.py # in-memory store + keyword search + JSON persistence
│       └── web_search.py     # keyless web search (DuckDuckGo → Wikipedia)
└── tests/
    ├── test_calculator.py
    ├── test_document_store.py
    └── test_server_integration.py   # launches the real server over stdio

The tools in tools/ are pure Python with no MCP dependency, so they're unit-testable in isolation and reusable elsewhere. server.py is a thin layer that exposes them as MCP tools; client.py is a thin layer that consumes them.


The tools in detail

Calculator — calculate(expression)

Parses the expression into Python's AST and walks it, allowing only whitelisted node types, constants (pi, e, tau) and functions (sqrt, sin, log, factorial, …). There is no path to eval, imports, or attribute access, so it's safe to expose to an autonomous agent. Division by zero and malformed input come back as structured errors.

Document store — add_document, search_documents, get_document, list_documents

An in-memory store that persists to a JSON file (~/.mcp_toolbox/documents.json by default; override with the MCP_TOOLBOX_DB env var). Search uses a transparent keyword scorer — term frequency in the body, with a ×3 boost for title matches and ×2 for tag matches — and returns ranked hits with snippets. It's deliberately simple so the ranking is easy to read; swapping in a vector store later wouldn't change the tool surface. The server seeds a few documents about MCP on first run so search has something to find.

Queries the DuckDuckGo Instant Answer API, falling back to the Wikipedia search API. Both are free and keyless. Network failures are caught and returned as an error field rather than raised, so the agent can react gracefully. (Some restricted/corporate networks block these endpoints; the tool degrades cleanly if so.)


Running the tests

pip install pytest pytest-asyncio
pytest

The suite covers the calculator, the document store, and — importantly — an end-to-end integration test that launches the real MCP server as a subprocess and calls its tools through a real MCP client session, proving tool discovery, argument passing, and structured results all work over stdio.


Using the server from Claude Desktop (or any MCP host)

Because this is a standard MCP server, any MCP-compatible host can use it — not just the bundled client. See claude_desktop_config.example.json for a ready-to-adapt config; point the command/args at your Python and the -m mcp_toolbox.server module, and the three tools show up in the host.


How it works (the short version)

MCP standardizes how an AI application talks to external tools. A host runs a client, and the client speaks MCP to one or more servers; each server advertises tools (plus resources and prompts). Here:

  • mcp_toolbox.server is the server — it advertises six tools over the stdio transport.

  • mcp_toolbox.client is the client — it launches the server as a subprocess, calls initialize, list_tools, and call_tool, and either scripts the calls or lets an LLM choose them.

For the full walkthrough, see docs/ARCHITECTURE.md.


License

MIT — see LICENSE.

Available Tools

6 tools
add_documentA

Store a new text document and return its generated id and metadata.

Args: content: The document body text (required, non-empty). title: An optional short title. tags: Optional list of tag strings for filtering/boosting search.

ParametersJSON Schema
NameRequiredDescriptionDefault
tagsNo
titleNo
contentYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the transparency burden; it discloses that the call creates ('stores') a new document and returns generated id and metadata, and that content must be non-empty. It does not mention failure modes, indexing behavior, or storage side effects beyond creation, but the core create-and-return behavior is covered.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is compact: a one-sentence summary followed by a concise Args list, with no filler. It front-loads the core purpose before the parameter details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple 3-parameter create tool with no output schema, the description covers inputs, the non-empty constraint, and the return value. Gaps are limited to explicit when-to-use guidance and failure/edge-case behavior, which are not critical for basic invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it does: content is described as body text with a non-empty requirement, title as an optional short title, tags as optional strings for filtering/boosting search. This adds meaning beyond the bare types/defaults in the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb ('Store') and resource ('new text document'), and the sibling tools (search/get/list) are clearly retrieval operations, so the tool's purpose is distinct. It also states the return value, which further clarifies the operation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies this tool is for adding a new document, in contrast to the retrieval siblings, but it never explicitly says when to use it or when to prefer search_documents/get_document/list_documents. No exclusions or alternative routing are given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

calculateA

Safely evaluate an arithmetic expression and return the numeric result.

Supports + - * / // % ** parentheses, the constants pi/e/tau, and common math functions (sqrt, sin, cos, log, factorial, etc.). It does NOT use eval; expressions are parsed and evaluated against a strict whitelist.

Args: expression: e.g. "2 + 2", "sqrt(144)", "(3.5 * 4) ** 2", "log(e)".

ParametersJSON Schema
NameRequiredDescriptionDefault
expressionYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It explicitly states safety guarantees: 'does NOT use eval', 'parsed and evaluated against a strict whitelist', and lists supported operators, constants, and functions. This goes far beyond a bare definition and adequately discloses behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and well-structured: purpose in the first sentence, then capabilities and safety note, then parameter examples. Every sentence adds value, and the most important information is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter tool with no output schema, the description is nearly complete: it covers syntax, supported functions, constants, and safety. The only gap is error behavior (e.g., how invalid expressions are handled), which is a minor omission for a calculator tool but would help an agent anticipate failures.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate. It does so effectively by documenting the 'expression' parameter with concrete examples ('2 + 2', 'sqrt(144)', 'log(e)') and a list of supported syntax. This gives an agent far more semantic understanding than the bare schema field.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear verb and resource: 'Safely evaluate an arithmetic expression and return the numeric result.' It explicitly states what the tool does and its scope, and it is easily distinguished from the document/search siblings. No ambiguity remains about purpose.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly defines the domain of use (arithmetic expressions with a specific feature set), and the sibling tools are unrelated to calculation, so confusion is unlikely. However, it does not explicitly state when not to use the tool or mention any alternative, making the guidance contextually clear but not explicitly comparative.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_documentA

Fetch a single document's full content by its id.

Args: document_id: The id returned by add_document or search_documents.

ParametersJSON Schema
NameRequiredDescriptionDefault
document_idYes

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the behavioral disclosure burden. It makes clear that this is a read-only retrieval operation returning full content, but it does not describe what happens for a missing/invalid document_id, any error behavior, or whether 'full content' includes metadata. This is acceptable but not richly transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise: one purpose sentence and one parameter clarification. It is front-loaded with the core behavior and contains no filler or redundant restatements of the tool name.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a one-parameter read operation with no output schema, the description covers purpose, input origin, and return nature. The main gap is the lack of edge-case behavior (e.g., not found), but given the simplicity of the tool, the description is near-complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema only defines document_id as a required string, while the description adds meaningful provenance: the id is returned by add_document or search_documents. This tells the agent exactly where to get a valid value and helps avoid guessing, compensating for the schema's 0% description coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Fetch'), resource ('a single document'), and scope ('full content by its id'), which makes the tool's main purpose immediately clear. It does not explicitly distinguish itself from sibling tools like list_documents or search_documents, but the wording is specific enough to infer the difference.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context: use this tool when you have a document_id and want the full content, and it notes that the id comes from add_document or search_documents. It stops short of listing explicit exclusions or when not to use this tool in favor of a sibling, but the intended usage is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_documentsA

List all stored documents (newest first) with their ids and titles.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of disclosing behavior. It adds meaningful details beyond the name: the result is ordered newest-first and includes only ids and titles. It does not mention pagination, potential size limits, or that it is read-only, but for a parameterless list operation the disclosed behavior is sufficiently transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, front-loaded sentence that states the operation, the scope, the ordering rule, and the returned fields. Every word contributes value, with no repetition of the tool name or generic filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given that there are no parameters, no annotations, and no output schema, the description fully covers what the tool does and what it returns (ids and titles, newest first). An agent has all the information needed to decide to call it and to understand the result shape. No critical behavioral context is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so there are no parameter semantics to explain. The baseline of 4 applies because the description does not need to compensate for any parameter documentation gaps.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('List') and a clear resource ('all stored documents'), and it adds distinguishing details: ordering ('newest first') and return fields ('ids and titles'). This clearly differentiates it from siblings like search_documents (search vs list), get_document (single vs all), and add_document (write vs read).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes the intended use case clear: when an agent needs an unfiltered, chronological overview of all stored documents. It does not explicitly name alternatives or exclusions, but the contrast with search_documents (filtered retrieval) is strongly implied by 'all stored documents'. Slight deduction for not explicitly stating when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_documentsA

Keyword-search the stored documents and return ranked matches.

Each result includes an id, title, relevance score, tags, and a snippet. Use get_document with a returned id to read the full text.

Args: query: Words to search for. limit: Maximum number of results (default 5).

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
queryYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden and discloses the result shape (id, title, relevance score, tags, snippet), the ranked nature, and that full text is read separately via get_document. It does not discuss edge cases such as empty results or limit enforcement, but the core behavior is transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core action and result shape are front-loaded, the follow-up get_document hint is earned, and the Args block is compact. No unnecessary detail.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-parameter search tool, the description covers trigger, result records, follow-up, and parameters. It lacks only edge-case behavior like empty matches or pagination, which are not essential given the tool's simplicity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Since the schema has no descriptions, the description compensates by defining query as 'Words to search for' and limit as 'Maximum number of results (default 5).' It adds meaning beyond type and default, although it omits query syntax and any range constraints.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses 'Keyword-search the stored documents and return ranked matches,' which names a specific verb, resource, and output. It also tells the agent to use get_document on a returned id for full text, distinguishing this search tool from the read-by-id sibling.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It clearly frames the tool for finding stored documents by keyword, and explicitly routes the follow-up from results to get_document. It does not spell out when to prefer list_documents or web_search, but the 'stored documents' scope makes the context clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 6 tool updatesv0.1.0
    • First observedadd_document
    • First observedcalculate
    • First observedget_document
    • First observedlist_documents
    • First observedsearch_documents
    • First observedweb_search

TDQS

A4.2/5.0

Scored across 6 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: document search, document creation, document retrieval, document listing, web search, and calculation. Even search_documents and list_documents are well differentiated by query-driven search versus full listing.

Naming Consistency4/5

Most tools follow a clear verb_noun pattern (add_document, get_document, list_documents, search_documents). web_search inverts that order and calculate uses only a verb, but the overall naming is still readable and predictable.

Tool Count5/5

Six tools is a reasonable, focused size for a document management helper with optional web search and calculation utilities. Each tool contributes a distinct capability without redundancy or bloat.

Completeness3/5

The document lifecycle is incomplete: add, get, list, and search are covered, but there is no update or delete operation for stored documents, which is a notable gap for a document store. web_search and calculate are one-shot utilities and don't need additional operations.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers