Skip to main content
Glama
mtmultiservicesllc-jpg

mcp-toolkit

mcp-toolkit

Tests Python 3.10+ License: MIT

A hands-on exploration of the Model Context Protocol (MCP) — the open protocol (created by Anthropic) that standardizes how AI applications connect to external tools and data sources. This repo implements both sides of the protocol: an MCP client and an MCP server, plus a test suite and CI.

Why this project

MCP is becoming the standard way AI assistants (Claude, and increasingly others) discover and call external tools — think of it as a plugin interface for LLMs. Rather than just reading about it, I built:

  1. A client that connects to Anthropic's official filesystem MCP server

  2. A custom MCP server exposing my own tools

  3. A client that talks to that custom server

  4. Unit + integration tests, and CI to run them on every push

Related MCP server: MCP Server Basic Example

Architecture

                         MCP protocol (JSON-RPC over stdio)
┌──────────────┐        ┌──────────────────────────────┐
│  client.py    │ <────> │ @modelcontextprotocol/        │  (official,
│              │        │ server-filesystem (npx)       │   Anthropic)
└──────────────┘        └──────────────────────────────┘

┌──────────────┐        ┌──────────────────────────────┐
│client_local.py│ <────> │  server.py                    │  (custom,
│              │        │  - calculate(expression)      │   this repo)
│              │        │  - get_weather(city)          │
└──────────────┘        └──────────────────────────────┘

Both clients follow the same MCP lifecycle:

  1. Spawn the server as a subprocess (stdio transport)

  2. initialize — protocol handshake

  3. list_tools — discover what the server can do, dynamically (no hardcoded knowledge of the server's capabilities)

  4. call_tool — invoke a tool by name with typed arguments

This is exactly what Claude Desktop does under the hood when you connect an MCP server.

Repo structure

mcp-toolkit/
├── server.py                # custom MCP server (FastMCP) — calculate & get_weather
├── client.py                 # MCP client -> official filesystem server
├── client_local.py           # MCP client -> server.py
├── sandbox_files/             # sample files used by client.py's demo
├── tests/
│   ├── test_calculate.py      # unit tests: correctness + security
│   └── test_server.py         # integration tests: tool registration & schemas
├── .github/workflows/tests.yml   # CI: pytest on Python 3.10 & 3.12
├── requirements.txt
└── LICENSE

Getting started

git clone https://github.com/<your-username>/mcp-toolkit.git
cd mcp-toolkit
pip install -r requirements.txt

Run the client against Anthropic's official filesystem server:

python3 client.py

Run the client against the custom server built in this repo:

python3 client_local.py

Run the test suite:

pytest -v

Example output

$ python3 client_local.py
Connexion au serveur MCP maison (server.py)

✅ Session MCP initialisée

🔧 Outils disponibles :
  - get_weather: Donne la météo actuelle (température, vent) pour une ville donnée.
  - calculate: Évalue une expression arithmétique (+, -, *, /, %, **).

🧮 Appel de calculate(expression='12 * (3 + 4)') :
12 * (3 + 4) = 84
$ pytest -v
tests/test_calculate.py::TestCalculateNominal::test_addition PASSED
tests/test_calculate.py::TestCalculateNominal::test_power PASSED
tests/test_calculate.py::TestCalculateSecurity::test_rejects_function_calls PASSED
tests/test_calculate.py::TestCalculateSecurity::test_rejects_attribute_access PASSED
tests/test_server.py::test_registered_tools PASSED
...
21 passed in 0.49s

Engineering notes

A few things worth calling out for anyone reviewing this code:

  • Security-conscious tool design. calculate doesn't use eval(). It parses the expression into a Python AST and walks a restricted whitelist of node types (ast.BinOp, ast.UnaryOp, numeric constants), so arbitrary code execution isn't possible even though the input is a raw string. Covered by dedicated security tests in tests/test_calculate.py (rejecting function calls, attribute access, name lookups, etc.).

  • Default environment isolation. The MCP SDK does not forward the parent process's full environment to spawned servers by default — only a minimal safe subset (get_default_environment()). Servers that need network access (like get_weather, via httpx) need env passed explicitly. This tripped up the first version of this project and is documented here so it doesn't trip up the next person.

  • Tests don't require a live subprocess. tests/test_server.py exercises the server's tool registration and schemas directly through the FastMCP instance (mcp.list_tools()), not by spawning a real stdio subprocess — faster and more deterministic for CI.

Connecting to Claude Desktop

To use server.py as a real MCP server inside Claude Desktop, add it to your claude_desktop_config.json:

{
  "mcpServers": {
    "mcp-toolkit-demo": {
      "command": "python3",
      "args": ["/absolute/path/to/mcp-toolkit/server.py"]
    }
  }
}

Restart Claude Desktop and the calculate / get_weather tools become available in conversation.

License

MIT — see LICENSE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    A minimal, production-ready MCP server with a simple addition calculator tool that demonstrates integration with the Model Context Protocol.
    6 npm
    1
    MIT
  • F
    license
    Not graded
    quality
    Not graded
    maintenance
    A basic Model Context Protocol server implementation that demonstrates core MCP functionality including tools and resources. Provides weather alerts through the Weather API and serves as a learning example for MCP development.
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    This MCP server provides tools like weather lookup and follows the Model Context Protocol for tool calling, resource sharing, and prompt templates.
    205 npm
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    A proof-of-concept MCP server that enables LLMs to read local text files and fetch real-time weather data through external tools.
    -