Skip to content

mrWealthid/First-MCP-Server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MCP Calculator Server

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.

Requirements

  • Python 3.10+
  • uv (recommended) or pip

Install

From the project root (MCP Server Course):

Using uv (recommended) — creates .venv and installs pyproject.toml dependencies:

uv sync

Using 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).

Verify packages exist

These checks use the same environment you will use to run calculator_server.py.

With uv

Show the installed mcp distribution and version:

uv pip show mcp

List 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 version

Confirm this repository’s server module loads (imports FastMCP and registers tools):

uv run python -c "import calculator_server; print('calculator_server import OK')"

With pip and an activated venv

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.

Test the server

1. Quick smoke test (no MCP client)

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.

2. Dev mode with bundled Inspector workflow

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.py

Watch 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.py

3. Inspector in another terminal (stdio)

If you prefer to start the Inspector yourself:

npx -y @modelcontextprotocol/inspector

In 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.

4. HTTP transport (Streamable HTTP or SSE)

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.py

Terminal 2 — Run the Inspector:

npx -y @modelcontextprotocol/inspector

In the Inspector UI:

  • Transport: StreamableHttp (or SSE)
  • URL: http://localhost:8000/mcp
  • Click Connect

5. Manual stdio process (advanced)

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.

What this server exposes

Tools

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.

Prompts

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).

Resources

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)

Start the server

For first-time verification, use Test the server (mcp dev or the Inspector) before wiring Cursor.

Stdio (default) — used by Cursor and most desktop hosts

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.py

Equivalent:

python calculator_server.py

(with your virtual environment activated and dependencies installed)

Development mode (MCP CLI + Inspector-friendly workflow)

The mcp CLI can run your server in dev mode (stdio), which is handy while iterating:

uv run mcp dev calculator_server.py

Follow the CLI output for how to attach the MCP Inspector or your client. This mode uses stdio by default.

HTTP transport (Streamable HTTP or SSE)

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.py

The 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.py

Connect your HTTP-capable client (e.g., MCP Inspector) to http://localhost:8000/mcp.

With MCP Inspector:

  1. Start the server in HTTP mode (as shown above)
  2. Run the Inspector in another terminal:
    npx -y @modelcontextprotocol/inspector
  3. In the Inspector UI, select StreamableHttp (recommended) or SSE
  4. Set the URL to http://localhost:8000/mcp
  5. Click Connect

Call tools and prompts

You never “import” the Python functions from another app. The MCP host sends JSON-RPC messages.

Tools

  1. Client sends tools/call with a name (e.g. "add") and arguments (e.g. {"a": 12, "b": 30}).
  2. Server runs the matching @mcp.tool() function and returns structured content (and optional unstructured text for older clients).

Prompts

  1. Client sends prompts/get with a name (e.g. "meeting_summary") and arguments matching the template (e.g. {"meeting_date": "2026-05-14", "meeting_title": "Q2 planning", "transcript": "..."}).
  2. Server returns the rendered prompt text (from templates/meeting_summary/template.md) for the host to pass to the model.

From Cursor

  1. 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.

  1. Reload MCP / restart Cursor if needed.
  2. 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/call under the hood. MCP prompts may only appear in clients that implement prompts/list / prompts/get for the model.

From Claude Desktop

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.

From Claude Code

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.py

B. 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.

From MCP Inspector

  1. Start the server in the mode your Inspector session expects (stdio or HTTP, depending on how you connect).
  2. Open the Inspector UI, connect to the server, open the Tools panel, pick a tool, fill arguments as JSON, and run Call.

From another Python program (conceptual)

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.

Project layout

.
├── 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)

Troubleshooting

  • ModuleNotFoundError: mcp: Run uv sync or install mcp[cli] into the same interpreter you use to run calculator_server.py.
  • Host never sees tools: Confirm the MCP config command and args point at this file and the right working directory.
  • divide / modulo errors: Those tools intentionally raise if the divisor is zero.
  • meeting_summary template missing: If prompts/get fails with FileNotFoundError, ensure templates/meeting_summary/template.md exists beside calculator_server.py (same relative layout as in this repo).

License

MIT (match your course policy; the upstream mcp SDK is MIT).

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages