HOW_IT_WORKS.md•6.24 kB
# How the Calculator MCP Server Works
## Overview
The Calculator MCP Server is a **Model Context Protocol (MCP) server** that provides mathematical calculation tools. It communicates with MCP clients using JSON-RPC messages over standard input/output (stdio).
## Architecture
### 1. **Server Initialization** (Lines 20-21)
```python
server = Server("calculator-mcp-server")
```
- Creates an MCP Server instance named "calculator-mcp-server"
- This server handles JSON-RPC protocol communication
### 2. **Tool Registration** (Lines 24-134)
The server uses **decorators** to register handlers:
#### `@server.list_tools()` Decorator
- Registers the `list_tools()` function
- When a client requests available tools, this function returns a list of all calculator tools
- Each tool includes:
- `name`: Tool identifier (e.g., "add", "multiply")
- `description`: What the tool does
- `inputSchema`: JSON schema defining the required parameters
#### Available Tools:
1. **add** - Adds multiple numbers
2. **subtract** - Subtracts numbers sequentially
3. **multiply** - Multiplies multiple numbers
4. **divide** - Divides numbers sequentially
5. **power** - Raises a number to a power
6. **sqrt** - Calculates square root
7. **evaluate** - Safely evaluates mathematical expressions
### 3. **Tool Execution** (Lines 137-256)
#### `@server.call_tool()` Decorator
- Registers the `call_tool()` function
- This function is called when a client invokes a tool
- Parameters:
- `name`: The tool name to execute
- `arguments`: Dictionary of tool parameters
- Returns: `Sequence[TextContent]` - The result as text content
#### How Each Tool Works:
**Basic Operations (add, subtract, multiply, divide):**
```python
if name == "add":
numbers = arguments.get("numbers", [])
result = sum(float(n) for n in numbers)
return [TextContent(type="text", text=str(result))]
```
- Extracts numbers from arguments
- Performs the operation
- Returns result as TextContent
**Power Operation:**
```python
elif name == "power":
base = arguments.get("base")
exponent = arguments.get("exponent")
result = float(base) ** float(exponent)
```
**Square Root:**
```python
elif name == "sqrt":
number = arguments.get("number")
result = math.sqrt(float(number))
```
**Evaluate Expression:**
- Uses Python's `compile()` to parse the expression into AST
- Uses restricted `eval()` with only safe math functions allowed
- Prevents code injection by limiting available functions
### 4. **Main Execution Flow** (Lines 259-270)
```python
async def main():
async with stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
server.create_initialization_options()
)
```
**Step-by-step:**
1. **`stdio_server()`** - Creates stdio transport (stdin/stdout)
- Sets up bidirectional communication
- Reads JSON-RPC requests from stdin
- Writes JSON-RPC responses to stdout
2. **`server.run()`** - Starts the server event loop
- Listens for incoming JSON-RPC messages
- Routes messages to appropriate handlers
- Sends responses back to the client
3. **`create_initialization_options()`** - Provides server capabilities
- Informs client about supported features
- Part of MCP handshake protocol
## Communication Protocol
### JSON-RPC Messages
The server communicates using JSON-RPC 2.0 protocol:
**Example: Client requests tool list**
```json
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}
```
**Server response:**
```json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "add",
"description": "Add two or more numbers together",
"inputSchema": { ... }
},
...
]
}
}
```
**Example: Client calls a tool**
```json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "add",
"arguments": {
"numbers": [1, 2, 3, 4]
}
}
}
```
**Server response:**
```json
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "10.0"
}
],
"isError": false
}
}
```
## Initialization Sequence
1. **Client sends `initialize` request**
- Protocol version handshake
- Client capabilities exchange
2. **Server responds with initialization options**
- Server capabilities
- Supported protocol features
3. **Client sends `notifications/initialized`**
- Confirms ready to communicate
4. **Client can now call tools**
- `tools/list` - Get available tools
- `tools/call` - Execute a tool
## Error Handling
The server includes comprehensive error handling:
- **Missing parameters**: Returns error message
- **Division by zero**: Detected and prevented
- **Invalid operations**: Caught and returned as errors
- **Expression evaluation errors**: Safely handled
## Security Features
**Safe Expression Evaluation:**
- Uses `compile()` to parse expressions
- Restricted namespace (no dangerous functions)
- Only allows safe math operations
- Prevents code injection
## Async/Await Pattern
The server uses Python's `asyncio`:
- **Asynchronous I/O**: Non-blocking operations
- **Concurrent handling**: Can process multiple requests efficiently
- **Event loop**: Manages async operations
## Running the Server
```bash
python calculator_server.py
```
The server:
1. Starts and waits on stdin for JSON-RPC messages
2. Processes requests asynchronously
3. Returns responses on stdout
4. Runs until the connection is closed
## Integration
To use with an MCP client, configure:
```json
{
"mcpServers": {
"calculator": {
"command": "python",
"args": ["calculator_server.py"],
"transport": "stdio"
}
}
}
```
The client will:
1. Launch the server as a subprocess
2. Communicate via stdin/stdout pipes
3. Send JSON-RPC messages
4. Receive responses and display results
---
**Summary**: The server acts as a calculator service that MCP clients can query. It receives calculation requests via JSON-RPC, executes the appropriate mathematical operation, and returns the result. All communication happens through standard input/output, making it compatible with any MCP client.