> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/anthropics/claude-agent-sdk-python/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Calculator Example

> Build an in-process MCP server with calculator tools

This example demonstrates how to create an in-process MCP (Model Context Protocol) server with calculator tools using the Claude Agent SDK.

<Note>
  Unlike external MCP servers that require separate processes, this server runs directly within your Python application, providing better performance and simpler deployment.
</Note>

## Overview

We'll create a calculator server with the following tools:

* `add` - Add two numbers
* `subtract` - Subtract one number from another
* `multiply` - Multiply two numbers
* `divide` - Divide one number by another
* `sqrt` - Calculate square root
* `power` - Raise a number to a power

## Defining Tools

Use the `@tool` decorator to create MCP tools:

```python theme={null}
from typing import Any
from claude_agent_sdk import tool

@tool("add", "Add two numbers", {"a": float, "b": float})
async def add_numbers(args: dict[str, Any]) -> dict[str, Any]:
    """Add two numbers together."""
    result = args["a"] + args["b"]
    return {
        "content": [{"type": "text", "text": f"{args['a']} + {args['b']} = {result}"}]
    }


@tool("subtract", "Subtract one number from another", {"a": float, "b": float})
async def subtract_numbers(args: dict[str, Any]) -> dict[str, Any]:
    """Subtract b from a."""
    result = args["a"] - args["b"]
    return {
        "content": [{"type": "text", "text": f"{args['a']} - {args['b']} = {result}"}]
    }


@tool("multiply", "Multiply two numbers", {"a": float, "b": float})
async def multiply_numbers(args: dict[str, Any]) -> dict[str, Any]:
    """Multiply two numbers."""
    result = args["a"] * args["b"]
    return {
        "content": [{"type": "text", "text": f"{args['a']} × {args['b']} = {result}"}]
    }


@tool("divide", "Divide one number by another", {"a": float, "b": float})
async def divide_numbers(args: dict[str, Any]) -> dict[str, Any]:
    """Divide a by b."""
    if args["b"] == 0:
        return {
            "content": [
                {"type": "text", "text": "Error: Division by zero is not allowed"}
            ],
            "is_error": True,
        }

    result = args["a"] / args["b"]
    return {
        "content": [{"type": "text", "text": f"{args['a']} ÷ {args['b']} = {result}"}]
    }
```

## Advanced Tools

Tools can include error handling and validation:

```python theme={null}
import math
from typing import Any
from claude_agent_sdk import tool

@tool("sqrt", "Calculate square root", {"n": float})
async def square_root(args: dict[str, Any]) -> dict[str, Any]:
    """Calculate the square root of a number."""
    n = args["n"]
    if n < 0:
        return {
            "content": [
                {
                    "type": "text",
                    "text": f"Error: Cannot calculate square root of negative number {n}",
                }
            ],
            "is_error": True,
        }

    result = math.sqrt(n)
    return {"content": [{"type": "text", "text": f"√{n} = {result}"}]}


@tool("power", "Raise a number to a power", {"base": float, "exponent": float})
async def power(args: dict[str, Any]) -> dict[str, Any]:
    """Raise base to the exponent power."""
    result = args["base"] ** args["exponent"]
    return {
        "content": [
            {"type": "text", "text": f"{args['base']}^{args['exponent']} = {result}"}
        ]
    }
```

## Creating the MCP Server

Use `create_sdk_mcp_server` to create your calculator server:

```python theme={null}
import asyncio
from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    create_sdk_mcp_server,
)

async def main():
    # Create the calculator server with all tools
    calculator = create_sdk_mcp_server(
        name="calculator",
        version="2.0.0",
        tools=[
            add_numbers,
            subtract_numbers,
            multiply_numbers,
            divide_numbers,
            square_root,
            power,
        ],
    )

    # Configure Claude to use the calculator server
    # Pre-approve all calculator MCP tools
    options = ClaudeAgentOptions(
        mcp_servers={"calc": calculator},
        allowed_tools=[
            "mcp__calc__add",
            "mcp__calc__subtract",
            "mcp__calc__multiply",
            "mcp__calc__divide",
            "mcp__calc__sqrt",
            "mcp__calc__power",
        ],
    )

    # Use the calculator
    async with ClaudeSDKClient(options=options) as client:
        await client.query("Calculate 15 + 27")
        
        async for message in client.receive_response():
            # Handle messages...
            pass

if __name__ == "__main__":
    asyncio.run(main())
```

<Note>
  MCP tool names follow the pattern `mcp__{server_name}__{tool_name}`. In this example, the `add` tool becomes `mcp__calc__add`.
</Note>

## Running Multiple Calculations

Here's a complete example with multiple prompts:

<Accordion title="Complete calculator example">
  ```python theme={null}
  #!/usr/bin/env python3
  """Example: Calculator MCP Server.

  This example demonstrates how to create an in-process MCP server with
  calculator tools using the Claude Code Python SDK.
  """

  import asyncio
  from typing import Any

  from claude_agent_sdk import (
      ClaudeAgentOptions,
      ClaudeSDKClient,
      create_sdk_mcp_server,
      tool,
      AssistantMessage,
      ResultMessage,
      TextBlock,
      ToolUseBlock,
  )

  # Define calculator tools using the @tool decorator

  @tool("add", "Add two numbers", {"a": float, "b": float})
  async def add_numbers(args: dict[str, Any]) -> dict[str, Any]:
      """Add two numbers together."""
      result = args["a"] + args["b"]
      return {
          "content": [{"type": "text", "text": f"{args['a']} + {args['b']} = {result}"}]
      }


  @tool("subtract", "Subtract one number from another", {"a": float, "b": float})
  async def subtract_numbers(args: dict[str, Any]) -> dict[str, Any]:
      """Subtract b from a."""
      result = args["a"] - args["b"]
      return {
          "content": [{"type": "text", "text": f"{args['a']} - {args['b']} = {result}"}]
      }


  @tool("multiply", "Multiply two numbers", {"a": float, "b": float})
  async def multiply_numbers(args: dict[str, Any]) -> dict[str, Any]:
      """Multiply two numbers."""
      result = args["a"] * args["b"]
      return {
          "content": [{"type": "text", "text": f"{args['a']} × {args['b']} = {result}"}]
      }


  @tool("divide", "Divide one number by another", {"a": float, "b": float})
  async def divide_numbers(args: dict[str, Any]) -> dict[str, Any]:
      """Divide a by b."""
      if args["b"] == 0:
          return {
              "content": [
                  {"type": "text", "text": "Error: Division by zero is not allowed"}
              ],
              "is_error": True,
          }

      result = args["a"] / args["b"]
      return {
          "content": [{"type": "text", "text": f"{args['a']} ÷ {args['b']} = {result}"}]
      }


  @tool("sqrt", "Calculate square root", {"n": float})
  async def square_root(args: dict[str, Any]) -> dict[str, Any]:
      """Calculate the square root of a number."""
      n = args["n"]
      if n < 0:
          return {
              "content": [
                  {
                      "type": "text",
                      "text": f"Error: Cannot calculate square root of negative number {n}",
                  }
              ],
              "is_error": True,
          }

      import math

      result = math.sqrt(n)
      return {"content": [{"type": "text", "text": f"√{n} = {result}"}]}


  @tool("power", "Raise a number to a power", {"base": float, "exponent": float})
  async def power(args: dict[str, Any]) -> dict[str, Any]:
      """Raise base to the exponent power."""
      result = args["base"] ** args["exponent"]
      return {
          "content": [
              {"type": "text", "text": f"{args['base']}^{args['exponent']} = {result}"}
          ]
      }


  def display_message(msg):
      """Display message content in a clean format."""
      if isinstance(msg, AssistantMessage):
          for block in msg.content:
              if isinstance(block, TextBlock):
                  print(f"Claude: {block.text}")
              elif isinstance(block, ToolUseBlock):
                  print(f"Using tool: {block.name}")
                  # Show tool inputs for calculator
                  if block.input:
                      print(f"  Input: {block.input}")
      elif isinstance(msg, ResultMessage):
          print("Result ended")
          if msg.total_cost_usd:
              print(f"Cost: ${msg.total_cost_usd:.6f}")


  async def main():
      """Run example calculations using the SDK MCP server with streaming client."""
      # Create the calculator server with all tools
      calculator = create_sdk_mcp_server(
          name="calculator",
          version="2.0.0",
          tools=[
              add_numbers,
              subtract_numbers,
              multiply_numbers,
              divide_numbers,
              square_root,
              power,
          ],
      )

      # Configure Claude to use the calculator server with allowed tools
      # Pre-approve all calculator MCP tools so they can be used without permission prompts
      options = ClaudeAgentOptions(
          mcp_servers={"calc": calculator},
          allowed_tools=[
              "mcp__calc__add",
              "mcp__calc__subtract",
              "mcp__calc__multiply",
              "mcp__calc__divide",
              "mcp__calc__sqrt",
              "mcp__calc__power",
          ],
      )

      # Example prompts to demonstrate calculator usage
      prompts = [
          "List your tools",
          "Calculate 15 + 27",
          "What is 100 divided by 7?",
          "Calculate the square root of 144",
          "What is 2 raised to the power of 8?",
          "Calculate (12 + 8) * 3 - 10",  # Complex calculation
      ]

      for prompt in prompts:
          print(f"\n{'=' * 50}")
          print(f"Prompt: {prompt}")
          print(f"{'=' * 50}")

          async with ClaudeSDKClient(options=options) as client:
              await client.query(prompt)

              async for message in client.receive_response():
                  display_message(message)


  if __name__ == "__main__":
      asyncio.run(main())
  ```
</Accordion>

## Tool Response Format

Tools must return a dictionary with:

* `content`: List of content blocks (typically text)
* `is_error` (optional): Boolean indicating if an error occurred

```python theme={null}
# Success response
return {
    "content": [{"type": "text", "text": "Result: 42"}]
}

# Error response
return {
    "content": [{"type": "text", "text": "Error: Division by zero"}],
    "is_error": True,
}
```

## Key Takeaways

* Use `@tool` decorator to define MCP tools
* MCP tools are async functions that accept a dict and return a dict
* Use `create_sdk_mcp_server()` to create the server
* Add server to `mcp_servers` in `ClaudeAgentOptions`
* Pre-approve tools using the `mcp__{server}__{tool}` naming pattern
* Include error handling in your tools

## Next Steps

<CardGroup cols={2}>
  <Card title="Tool Permissions" icon="shield-check" href="/examples/tool-permissions">
    Control tool access with callbacks
  </Card>

  <Card title="Hooks" icon="hook" href="/examples/hooks-example">
    Customize behavior with hooks
  </Card>
</CardGroup>
