A small Model Context Protocol server written in Python with the official mcp package. It exposes calculator tools so MCP hosts (Cursor, Claude Desktop, Claude Code, the MCP Inspector, etc.) can perform basic arithmetic through the protocol instead of ad-hoc code execution.
- Python 3.10+
- uv (recommended) or
pip
From the project root (MCP Server Course):
Using uv (recommended) — creates .venv and installs pyproject.toml dependencies:
uv syncUsing pip only — use a virtual environment so you do not pollute your system Python:
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -U pip
pip install "mcp[cli]>=1.0.0,<2"After either path, keep using the same interpreter for all commands below (uv run … picks .venv automatically; with pip, stay in the activated shell or call .venv/bin/python explicitly).
These checks use the same environment you will use to run calculator_server.py.
Show the installed mcp distribution and version:
uv pip show mcpList packages in the project environment and confirm mcp appears:
uv pip list | grep -i '^mcp 'Confirm Python can import the SDK and read its version:
uv run python -c "import importlib.metadata as m; print('mcp', m.version('mcp'))"Confirm the MCP CLI is on the path for that environment:
uv run mcp versionConfirm this repository’s server module loads (imports FastMCP and registers tools):
uv run python -c "import calculator_server; print('calculator_server import OK')"Replace uv run with python (or python3) in the import commands above, and use:
pip show mcp
pip list | grep -i '^mcp '
python -c "import importlib.metadata as m; print('mcp', m.version('mcp'))"
mcp version
python -c "import calculator_server; print('calculator_server import OK')"If any command fails with ModuleNotFoundError or command not found: mcp, dependencies are not installed in that interpreter — go back to Install.
Already covered: import calculator_server should print calculator_server import OK. That only proves the file and dependencies load; it does not exercise the protocol.
The SDK’s mcp dev command runs your server and is intended for interactive testing with the MCP Inspector:
uv run mcp dev calculator_server.pyWatch the terminal: it prints how to open or attach the Inspector. From there you can list tools, send a tools/call (for example add with {"a": 2, "b": 3}), and confirm the JSON response.
With pip, activate .venv first, then:
mcp dev calculator_server.pyIf you prefer to start the Inspector yourself:
npx -y @modelcontextprotocol/inspectorIn the Inspector UI, choose stdio, then set the server command to match how you run Python, for example:
- Command:
uv - Arguments:
run,python,calculator_server.py - Working directory: your project root (
MCP Server Course)
Or Command: full path to .venv/bin/python (or python on Windows) with Arguments: calculator_server.py. Connect, then use the Tools and Prompts tabs to exercise the server.
Run the server in HTTP mode and test with the Inspector in a separate terminal:
Terminal 1 — Start the server:
TRANSPORT=streamable-http uv run python calculator_server.pyTerminal 2 — Run the Inspector:
npx -y @modelcontextprotocol/inspectorIn the Inspector UI:
- Transport: StreamableHttp (or SSE)
- URL:
http://localhost:8000/mcp - Click Connect
Running uv run python calculator_server.py starts the server and waits on stdin for MCP messages. A normal terminal will look “hung” — that is expected. Use Ctrl+C to stop. For interactive testing, prefer mcp dev or the Inspector in step 2, 3, or 4.
| Tool | Description |
|---|---|
add |
Sum of two numbers |
subtract |
(a - b) |
multiply |
Product of two numbers |
divide |
(a / b) (error if (b = 0)) |
modulo |
Floating-point remainder of (a \div b) (error if (b = 0)) |
power |
base raised to exponent |
square_root |
(\sqrt{x}) for (x \geq 0) |
absolute |
(\lvert x \rvert) |
get_meeting_summary_prompt |
Same filled Markdown as the meeting_summary prompt (meeting_date, meeting_title, transcript). Use this in Claude Desktop and other hosts that only surface tools to the model. Put the full transcript in the transcript argument (plain text). This server does not accept a separate file upload for the transcript—if the user pasted the transcript in chat, pass that text into transcript. |
If the model asks you to “re-upload” or “paste the file”: ignore that pattern for this integration. Either paste the transcript in your message and ask it to call get_meeting_summary_prompt with that text in transcript, or ask the model explicitly: “Call get_meeting_summary_prompt with my transcript in the transcript field.”
All numeric parameters are floats in the JSON-RPC layer; integers are fine to send from clients.
Many clients (notably Claude Desktop) connect to MCP servers but only attach tools/list results to the model. They may never call prompts/list or prompts/get, so the model acts as if your prompt does not exist. There is nothing wrong with your @mcp.prompt() registration; the host simply does not expose that capability to the model. Use the get_meeting_summary_prompt tool above for the same rendered text, or test prompts in the MCP Inspector (see Test the server). For broader discussion of hosts surfacing tools vs prompts/resources, see for example anthropics/claude-ai-mcp#23.
| Prompt | Arguments | Description |
|---|---|---|
meeting_summary |
meeting_date, meeting_title, transcript |
Reads templates/meeting_summary/template.md in this repo and substitutes {{ meeting_date }}, {{ meeting_title }}, and {{ transcript }}. Edit that file to change wording without touching Python. |
Hosts that implement prompts call prompts/get with the prompt name and argument object (same keys as the table).
| URI | Description |
|---|---|
downloads://typescript.md |
Full text of typescript.md in your user Downloads folder (~/Downloads/typescript.md). UTF-8 Markdown. Missing file → clear error. |
calculator://help |
Plain-text summary of tools and resources (useful for debugging or for clients that list resources) |
For first-time verification, use Test the server (mcp dev or the Inspector) before wiring Cursor.
The server speaks MCP over stdin/stdout. Hosts spawn your process and connect automatically; you normally do not run this manually unless you are debugging.
uv run python calculator_server.pyEquivalent:
python calculator_server.py(with your virtual environment activated and dependencies installed)
The mcp CLI can run your server in dev mode (stdio), which is handy while iterating:
uv run mcp dev calculator_server.pyFollow the CLI output for how to attach the MCP Inspector or your client. This mode uses stdio by default.
This server supports Streamable HTTP and SSE transports in addition to the default stdio. Configure via the TRANSPORT environment variable:
# Streamable HTTP (recommended for HTTP clients)
TRANSPORT=streamable-http python calculator_server.py# SSE (Server-Sent Events)
TRANSPORT=sse python calculator_server.pyThe server listens on localhost:8000/mcp by default. Customize with environment variables:
HOST=0.0.0.0 PORT=9000 TRANSPORT=streamable-http python calculator_server.pyConnect your HTTP-capable client (e.g., MCP Inspector) to http://localhost:8000/mcp.
With MCP Inspector:
- Start the server in HTTP mode (as shown above)
- Run the Inspector in another terminal:
npx -y @modelcontextprotocol/inspector
- In the Inspector UI, select StreamableHttp (recommended) or SSE
- Set the URL to
http://localhost:8000/mcp - Click Connect
You never “import” the Python functions from another app. The MCP host sends JSON-RPC messages.
Tools
- Client sends
tools/callwith a name (e.g."add") and arguments (e.g.{"a": 12, "b": 30}). - Server runs the matching
@mcp.tool()function and returns structured content (and optional unstructured text for older clients).
Prompts
- Client sends
prompts/getwith a name (e.g."meeting_summary") and arguments matching the template (e.g.{"meeting_date": "2026-05-14", "meeting_title": "Q2 planning", "transcript": "..."}). - Server returns the rendered prompt text (from
templates/meeting_summary/template.md) for the host to pass to the model.
- Add an MCP server entry that runs this project (stdio), for example in your Cursor MCP settings:
{
"mcpServers": {
"calculator": {
"command": "uv",
"args": [
"run",
"--directory",
"/absolute/path/to/MCP Server Course",
"python",
"calculator_server.py"
]
}
}
}Replace /absolute/path/to/MCP Server Course with your real project path.
- Reload MCP / restart Cursor if needed.
- In chat, ask the model to use tools (e.g. “Use multiply for 7 and 8”, or “Call get_meeting_summary_prompt with …”). The agent issues
tools/callunder the hood. MCP prompts may only appear in clients that implementprompts/list/prompts/getfor the model.
Claude Desktop reads mcpServers from a JSON file on disk. Edit the file for your OS, then fully quit and reopen Claude Desktop (changes are not reliably hot-reloaded).
| OS | Config path |
|---|---|
| macOS | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Windows | %APPDATA%\Claude\claude_desktop_config.json |
| Linux | ~/.config/Claude/claude_desktop_config.json |
If the file does not exist yet, create it with valid JSON (no trailing commas). Merge new keys into any existing mcpServers object rather than overwriting unrelated servers.
Calculator entry (stdio, same pattern as Cursor):
{
"mcpServers": {
"calculator": {
"command": "uv",
"args": [
"run",
"--directory",
"/absolute/path/to/MCP Server Course",
"python",
"calculator_server.py"
]
}
}
}Replace the --directory value with your real project path. If uv is not on the PATH that Claude Desktop inherits, use the full path to the uv binary (from which uv), or point command at your virtualenv’s Python and set args to ["calculator_server.py"] with cwd unset (run from project root via a small wrapper script if needed).
Optional installer from the MCP Python CLI (writes into Claude Desktop’s config for you — run from the project root after uv sync):
uv run mcp install calculator_server.py --name "Calculator"See uv run mcp install --help for flags such as -v / -f for environment variables and .env files.
Meeting summary in Claude Desktop: ask Claude to call the get_meeting_summary_prompt tool with meeting_date, meeting_title, and transcript. The tool returns Markdown text in the result—there is no separate file upload step for this server.
Claude Code stores MCP servers via the claude mcp CLI or project .mcp.json. For a local stdio server, options must come before the server name; a -- separates the name from the command you want spawned.
From your machine, pick one style:
A. uv with an explicit project directory (works no matter which folder you run claude from):
claude mcp add --transport stdio calculator -- \
uv run --directory "/absolute/path/to/MCP Server Course" python calculator_server.pyB. Same thing using claude mcp add-json:
claude mcp add-json calculator \
'{"type":"stdio","command":"uv","args":["run","--directory","/absolute/path/to/MCP Server Course","python","calculator_server.py"]}'C. Project-scoped file — add a .mcp.json at the repo root (often committed so the team shares it) with the same command / args shape as in the Cursor snippet under mcpServers.
Use claude mcp list to confirm the server is registered, and /mcp inside a session to inspect connection status. Remove with claude mcp remove calculator if you need to re-register after changing paths.
- Start the server in the mode your Inspector session expects (stdio or HTTP, depending on how you connect).
- Open the Inspector UI, connect to the server, open the Tools panel, pick a tool, fill arguments as JSON, and run Call.
Use the MCP client APIs from the same mcp package (stdio_client, etc.) to connect and call session.call_tool("add", {"a": 2, "b": 3}). See the SDK client examples on the v1.x branch.
.
├── calculator_server.py # FastMCP server + tool definitions
├── pyproject.toml # Dependencies (mcp[cli])
├── uv.lock # Locked dependency versions (uv)
├── README.md # This file
├── templates/
│ └── meeting_summary/
│ └── template.md # meeting_summary prompt ({{ placeholders }})
└── docs/ # Extra course notes (optional reading)
ModuleNotFoundError: mcp: Runuv syncor installmcp[cli]into the same interpreter you use to runcalculator_server.py.- Host never sees tools: Confirm the MCP config command and args point at this file and the right working directory.
divide/moduloerrors: Those tools intentionally raise if the divisor is zero.meeting_summarytemplate missing: Ifprompts/getfails withFileNotFoundError, ensuretemplates/meeting_summary/template.mdexists besidecalculator_server.py(same relative layout as in this repo).
MIT (match your course policy; the upstream mcp SDK is MIT).