> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/cloudflare/agents/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Server Example

> Build a stateful MCP server using McpAgent backed by Durable Objects with persistent state, tools, and resources

A stateful MCP server using `McpAgent` backed by a Durable Object. State persists across requests - the built-in UI lets you call tools and read resources to see it in action.

## What it demonstrates

* **`McpAgent`** - the Agents SDK class for building MCP servers with persistent state
* **Tools** - registering an `add` tool that modifies the counter
* **Resources** - exposing the counter value as an MCP resource
* **State management** - `setState` and `onStateChanged` for durable state
* **Streamable HTTP transport** - the default transport for `McpAgent`

## Server Implementation

```typescript src/server.ts theme={null}
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { McpAgent } from "agents/mcp";
import { z } from "zod";
import icon from "./mcp-icon.svg";

type State = { counter: number };

export class MyMCP extends McpAgent<Env, State, {}> {
  server = new McpServer({
    name: "Demo",
    version: "1.0.0",
    icons: [
      {
        src: icon,
        sizes: ["any"],
        mimeType: "image/svg+xml"
      }
    ],
    websiteUrl: "https://github.com/cloudflare/agents"
  });

  initialState: State = {
    counter: 1
  };

  async init() {
    // Register a resource that exposes the counter value
    this.server.resource("counter", "mcp://resource/counter", (uri) => {
      return {
        contents: [{ text: String(this.state.counter), uri: uri.href }]
      };
    });

    // Register a tool that modifies the counter
    this.server.registerTool(
      "add",
      {
        description: "Add to the counter, stored in the MCP",
        inputSchema: { a: z.number() }
      },
      async ({ a }) => {
        this.setState({ ...this.state, counter: this.state.counter + a });

        return {
          content: [
            {
              text: String(`Added ${a}, total is now ${this.state.counter}`),
              type: "text"
            }
          ]
        };
      }
    );
  }
}

export default MyMCP.serve("/mcp", { binding: "MyMCP" });
```

## How It Works

<Steps>
  <Step title="Extend McpAgent">
    `McpAgent` extends the base `Agent` class with MCP protocol support. Each instance is backed by a Durable Object.
  </Step>

  <Step title="Define state">
    The `initialState` property sets the default state. This state persists across hibernation and restarts.
  </Step>

  <Step title="Register tools and resources">
    In the `init()` method, register MCP tools and resources. Tools can read and modify state via `this.state` and `this.setState()`.
  </Step>

  <Step title="Serve the MCP">
    `MyMCP.serve()` creates a Worker handler that routes requests to the MCP agent.
  </Step>
</Steps>

## Testing with the Built-in UI

Run the example locally:

```bash theme={null}
npm install
npm run dev
```

Open [http://localhost:5173](http://localhost:5173) to see the built-in tool tester. You can:

* Call the `add` tool with different numbers
* Read the `counter` resource to see the current value
* Watch state persist across requests

## Testing with MCP Inspector

You can also connect with the [MCP Inspector](https://github.com/modelcontextprotocol/inspector):

1. Install the inspector: `npm install -g @modelcontextprotocol/inspector`
2. Run your MCP server: `npm run dev`
3. Open the inspector
4. Set transport to **Streamable HTTP**
5. Set URL to `http://localhost:5173/mcp`

## Key Features

### Persistent State

State is stored in Durable Objects and survives:

* Worker restarts
* Hibernation (when idle)
* Redeployments

```typescript theme={null}
this.setState({ counter: this.state.counter + 1 });
// State is now persisted and available in all tools/resources
```

### Tools

MCP tools are functions that can be called by MCP clients:

```typescript theme={null}
this.server.registerTool(
  "add",
  {
    description: "Add to the counter",
    inputSchema: { a: z.number() }
  },
  async ({ a }) => {
    // Tool implementation
    this.setState({ counter: this.state.counter + a });
    return {
      content: [{ type: "text", text: `Counter is now ${this.state.counter}` }]
    };
  }
);
```

### Resources

MCP resources are read-only data exposed to clients:

```typescript theme={null}
this.server.resource("counter", "mcp://resource/counter", (uri) => {
  return {
    contents: [{ text: String(this.state.counter), uri: uri.href }]
  };
});
```

Resources can dynamically read from agent state, SQLite, KV, or any other source.

### Prompts

MCP prompts are reusable message templates:

```typescript theme={null}
this.server.registerPrompt(
  "counter-status",
  {
    name: "counter-status",
    description: "Get a formatted status message about the counter"
  },
  async () => {
    return {
      messages: [
        {
          role: "user",
          content: {
            type: "text",
            text: `The counter is currently at ${this.state.counter}.`
          }
        }
      ]
    };
  }
);
```

## Advanced: Using SQLite

```typescript theme={null}
export class MyMCP extends McpAgent<Env, State, {}> {
  async init() {
    // Create tables
    this.sql`
      CREATE TABLE IF NOT EXISTS items (
        id TEXT PRIMARY KEY,
        name TEXT,
        created_at TEXT
      )
    `;

    // Register tool that uses SQLite
    this.server.registerTool(
      "list_items",
      { description: "List all items", inputSchema: {} },
      async () => {
        const items = [...this.sql`SELECT * FROM items`];
        return {
          content: [{
            type: "text",
            text: JSON.stringify(items, null, 2)
          }]
        };
      }
    );
  }
}
```

## Deployment

Deploy to Cloudflare Workers:

```bash theme={null}
npm run deploy
```

Your MCP server will be available at:

```
https://your-worker.workers.dev/mcp
```

Clients can connect using the Streamable HTTP transport.

## Related Examples

<CardGroup cols={2}>
  <Card title="MCP Client" icon="plug" href="/examples/mcp-client">
    Connect to MCP servers as a client
  </Card>

  <Card title="MCP Worker" icon="server" href="/examples/mcp-worker">
    Simplest stateless MCP server
  </Card>

  <Card title="MCP Authenticated" icon="lock" href="/examples/mcp-worker-authenticated">
    Adding OAuth to an MCP server
  </Card>

  <Card title="MCP Guide" icon="book" href="/guides/mcp">
    In-depth guide to Model Context Protocol
  </Card>
</CardGroup>

## Further Reading

* [MCP Specification](https://spec.modelcontextprotocol.io/)
* [MCP SDK Documentation](https://github.com/modelcontextprotocol/typescript-sdk)
* [McpAgent API Reference](/api/mcp-agent)
