Skip to main content
Glama
rubensgomes-org

calculator-mcp

Calculator MCP Server

calculator-mcp is a small MCP server that exposes 16 arithmetic operations as callable tools for an LLM. It contains no math of its own — every tool is a thin synchronous wrapper that logs its arguments and delegates to a shared Calculator instance from the external calculator-lib-rubens package.

Features

16 calculator tools available via MCP:

Two-operand operations: add, subtract, multiply, divide, power, nth_root, modulo, floor_divide

Single-operand operations: sqrt, absolute, floor, ceil, log10, ln, exp

Rounding: round_number (with configurable decimal places)

Related MCP server: Simple Calculator MCP Server

Prerequisites

  • Python 3.14+

  • Poetry for dependency management

  • Docker 23+ with the buildx and compose plugins (optional, for running the server in a container)

Installation

poetry install

Configuration

The server ships with a default config.yaml bundled inside the package. To override it, set the CALCULATOR_MCP_CONFIG environment variable to the absolute path of your custom configuration file:

export CALCULATOR_MCP_CONFIG=/path/to/your/config.yaml

When CALCULATOR_MCP_CONFIG is not set, the bundled default is used automatically.

The configuration file has two sections:

server:
    transport: "http"     # "stdio" or "http"
    host: "0.0.0.0"       # Host for HTTP transport (0.0.0.0 = all interfaces)
    port: 9000            # Port for HTTP transport
    timeout: 10           # Tool execution timeout in seconds

client:
    is_oauth: false                        # Enable OAuth authentication
    url: "http://127.0.0.1:9000/mcp"       # Server URL for HTTP transport
    token_dir: "/home/user/.fastmcp"       # OAuth token storage directory
    callback_port: 10000                   # OAuth callback server port

The logging section controls Python logging via dictConfig. The default configuration logs calculator_mcp messages at INFO level to stderr.

Running the Server

There are three ways to start the server:

Console script (installed by Poetry):

# requires poetry to be installed
poetry install # only needed once
poetry run calculator-mcp

As a Python module:

# requires poetry to be installed
poetry install # only needed once
eval $(poetry env activate)
python -m calculator_mcp
deactivate

With a custom configuration:

# requires poetry to be installed
poetry install # only needed once
export CALCULATOR_MCP_CONFIG=/path/to/your/config.yaml
poetry run calculator-mcp

Running the Server with Docker

The server can also run as a container. See DOCKER.md for the full reference.

Build the image:

# requires Docker to be installed and running
docker build --build-arg VERSION="$(poetry version -s)" \
    -t "calculator-mcp:$(poetry version -s)" -t calculator-mcp:latest .

Run the container:

docker run -d --name calculator-mcp -p 9000:9000 \
    --restart unless-stopped "calculator-mcp:$(poetry version -s)"

Verify it is up:

curl http://127.0.0.1:9000/health     # -> OK

With Docker Compose:

docker compose up --build -d
docker compose logs -f calculator-mcp
docker compose down

Notes:

  • The container listens on 0.0.0.0:9000, per the bundled config.yaml.

  • The MCP endpoint is http://127.0.0.1:9000/mcp.

  • The server runs as a non-root user (uid=1001).

  • To use a custom configuration, mount it and set CALCULATOR_MCP_CONFIG to the mounted path.

Running the Client

A sample integration test client is provided in tests/integration/client.py to demonstrate the MCP protocol with the server. It lists all available tools and calls each one with sample arguments.

Important: The server must be running before you start the client. See Running the Server above.

Run the client:

# requires poetry to be installed
poetry install # only needed once
eval $(poetry env activate)
python tests/integration/client.py
deactivate

Add MCP Server to Claude Code

  • Add the MCP server to Claude Code using project scope. The file .mcp.json is added to the project root folder:

    # It is assumed that the MCP server is running on http://127.0.0.1:9000
    cd $(git rev-parse --show-toplevel) || exit
    claude mcp add \
        --scope project \
        --transport http \
        calculator-mcp http://127.0.0.1:9000/mcp

Style Guide

This project follows the Google Python Style Guide. All docstrings use the Google format with Args:, Returns:, and Raises: sections where applicable. Compliance is enforced via pylint, black, isort, and mypy.

Development

# Run tests
poetry run pytest

# Run tests with coverage
poetry run pytest --cov

# Lint
poetry run pylint src/calculator_mcp

# Format code
poetry run black src tests
poetry run isort src tests

# Type check
poetry run mypy src/calculator_mcp

All four tools — pylint, black, isort and mypy — are declared in the dev dependency group, so poetry install is all that is needed to run them.

Project Structure

calculator-mcp/
├── pyproject.toml                 # Project metadata, dependencies, tool config
├── Dockerfile                     # Multi-stage container image build
├── .dockerignore                  # Files excluded from the build context
├── docker-compose.yml             # Compose service definition
├── DOCKER.md                      # Container build and deployment guide
├── src/calculator_mcp/
│   ├── __init__.py
│   ├── __main__.py                # python -m calculator_mcp entry point
│   ├── config.py                  # Loads config.yaml, configures logging
│   ├── config.yaml                # Bundled default runtime config
│   ├── main.py                    # CLI entry point, signal handling
│   └── server.py                  # FastMCP server with 16 @mcp.tool functions
└── tests/
    ├── __init__.py
    ├── test_config.py             # Unit tests for config module
    ├── test_main.py               # Unit tests for main module
    ├── test_server.py             # Integration tests via MCP Client
    ├── test_tools.py              # Unit tests for tool functions
    └── integration/
        ├── __init__.py
        └── client.py              # Sample MCP client with OAuth support

License

See LICENSE for details.

MCP Protocol

The MCP protocol, briefly

MCP (Model Context Protocol) is an open standard for connecting LLM applications to external context and capabilities. The shape of it:

Wire format. JSON-RPC 2.0 — requests (with id), responses, and notifications. Nothing MCP-specific about the envelope; the protocol is the vocabulary of methods on top of it.

MCP Participants

Participants. A host (Claude Code, Claude Desktop, an agent app) runs one client per connected server. The connection is 1:1 and stateful.

MCP Lifecycle

Lifecycle:

  1. client initializes request → server replies with its protocol version,capabilities, and serverInfo

  2. client sends the notifications/initialized notification → normal operation.

  3. Capabilities are negotiated at that handshake, so neither side calls methods the other never advertised.

MCP Server Primitives

Server primitives. Three things a server can offer:

  • Tools — model-controlled functions the LLM decides to invoke (tools/list, tools/call).

  • Resources — application-controlled data addressed by URI (resources/list, resources/read).

  • Prompts — user-controlled templates, typically surfaced as slash commands.

MCP Client Primitives

Client primitives. Sampling (server asks the client's model to complete something), roots (filesystem scope), and elicitation (server asks the user a question).

MCP Transport

Transports. Two standard ones:

  • stdio (server is a subprocess; JSON-RPC over newline-delimited stdin/stdout, with stderr free for logs) and

  • Streamable HTTP (a single /mcp endpoint taking POSTs, optionally upgrading to SSE for server→client streaming, with sessions tracked by an Mcp-Session-Id header). Remote HTTP servers authenticate with OAuth 2.1.

How This Project Implements the MCP Protocol

It doesn't hand-roll any of the protocol. FastMCP (fastmcp >=3.4.7) supplies the JSON-RPC layer, the initialize handshake, capability advertisement, session management, and both transports. The project's job is to declare what it serves.

Tool declaration is derived from Python

Each @mcp.tool-decorated function is turned into an MCP tool descriptor automatically:

  • The function name becomes the tool name (add, nth_root, round_number).

  • The type hints (a: float, b: float, decimals: int = 0) become the tool's JSON Schema inputSchema, including which parameters are required — that's what lets FastMCP reject bad arguments before your code runs.

  • The Google-style docstring becomes the tool description the model reads when deciding what to call. This is why src/calculator_mcp/server.py treats docstrings as a contract rather than internal commentary.

  • A raised ValueError (divide by zero, sqrt of a negative) is converted into a JSON-RPC tool error — tests/test_server.py asserts this by expecting ToolError from divide (1, 0).

Protocol-level metadata the server sets explicitly

mcp = FastMCP ("Calculator MCP Server", version=_VERSION, instructions="...", website_url=_HOMEPAGE)

instructions is part of the initialize response — server-level guidance the host can put in front of the model, summarizing the tool families so it doesn't have to infer them tool by tool.

Every tool also carries MCP behavioral annotations:

annotations={"readOnlyHint": True, "idempotentHint": True, "openWorldHint": False}

These are hints to the host, not enforcement: nothing is mutated, calling twice is safe, and the tool touches no external world. Hosts use them to decide whether a call needs a confirmation prompt — which is why a calculator can run unattended. timeout=_TIMEOUT (10s from config) bounds each call.

Transport

config.yaml selects the transport and main.py acts on it:

if transport == "http": mcp.run (transport="http", host=get_host (), port=get_port ()) else: mcp.run (transport="stdio")

The shipped default is http on 0.0.0.0:9000 — bound to all interfaces deliberately so the server is reachable from outside the container. The stdio path is what a host would use to launch it as a subprocess. Note the logging config sends handlers to ext://sys.stderr; under stdio that's mandatory, since stdout carries the JSON-RPC frames.

/health is registered via @mcp.custom_route — a plain Starlette route on the same ASGI app, outside the MCP protocol. Container orchestration needs a probe that doesn't speak JSON-RPC. tests/test_server.py::test_health_check exercises it in-process with httpx.ASGITransport over mcp.http_app (), no port required.

The client side

tests/integration/client.py is the mirror image — a real MCP client built from the same config module. It does the full round trip: client.ping (), client.list_tools (), then call_tool on each discovered tool with sample arguments. For the deployed instance at https://rubens-calculator-mcp.fastmcp.app/mcp it wraps fastmcp.client.auth.OAuth, persisting tokens in a DiskStore behind a FernetEncryptionWrapper keyed from OAUTH_STORAGE_ENCRYPTION_KEY, with a fixed callback port so the OAuth redirect URI stays stable across runs.

The unit tests use the same Client (mcp) API against the in-process server object, so tests go through genuine MCP tool dispatch rather than calling the Python functions directly.

Observability

config.yaml pre-wires loggers for the protocol internals — mcp.server.lowlevel.server, mcp.server.streamable_http, mcp.server.streamable_http_manager, mcp.client.streamable_http, plus httpx/httpcore — each at INFO with a comment saying to flip it to DEBUG to see the raw JSON-RPC messages or HTTP wire traffic. That's the debugging path when a host and this server disagree.

A
license - permissive license
Not graded
quality - not tested
A
maintenance

Maintenance

Maintainers
Response time
1wRelease cycle
18Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • -
    license
    Not graded
    quality
    Not graded
    maintenance
    A calculator server that exposes mathematical functions as tools (add, subtract, multiply, divide, square, power, square root), enabling language models to perform calculations through Model Context Protocol (MCP).
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables basic arithmetic operations (add, subtract, multiply, divide, modulo) via natural language, with a FastMCP-based server and client for exploring MCP tool calling.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    A calculator MCP server built as part of a step-by-step tutorial that demonstrates core MCP primitives—tools, resources, and prompts—and can be upgraded to a live weather server.
    MIT

View all related MCP servers

Related MCP Connectors

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rubensgomes-org/calculator-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server