> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP

> Connect your API to AI assistants like Claude using the Model Context Protocol

## What is MCP?

MCP (Model Context Protocol) is a protocol developed by Anthropic that lets AI assistants interact with external tools and services. When you expose your service via MCP:

1. **AI can discover your tools**: Claude can see all your methods and their parameters
2. **AI can call your tools**: Claude can execute methods with proper inputs
3. **AI understands the results**: Responses are formatted for AI interpretation

Think of it like giving an AI a "toolbox" - each method in your service becomes a tool the AI can use.

## Quick Start

```go theme={null}
import (
    "github.com/go-mizu/mizu"
    contract "github.com/go-mizu/mizu/contract/v2"
    "github.com/go-mizu/mizu/contract/v2/transport/mcp"

    "yourapp/todo"
)

// Your interface is defined in the todo package as todo.API:
// type API interface {
//     Create(ctx context.Context, in *CreateInput) (*Todo, error)
//     List(ctx context.Context) (*ListOutput, error)
//     Get(ctx context.Context, in *GetInput) (*Todo, error)
// }

// Create your service implementation
impl := todo.NewService()

// Register your service
svc := contract.Register[todo.API](impl,
    contract.WithDefaultResource("todos"),
)

// Create mizu app
app := mizu.New()

// Mount MCP endpoint
mcp.Mount(app.Router, "/mcp", svc)

// Start server
app.Listen(":8080")
```

Your service methods are now available as AI tools.

## How Methods Become Tools

Each method becomes an MCP tool:

| Interface Method | MCP Tool Name  |
| ---------------- | -------------- |
| `Create`         | `todos.create` |
| `List`           | `todos.list`   |
| `Get`            | `todos.get`    |
| `Delete`         | `todos.delete` |

Tool names follow the pattern `resource.method`.

## The MCP Protocol

MCP uses JSON-RPC 2.0 as its transport. Here's how an AI interacts with your server:

### Step 1: Initialize

The AI establishes a connection:

```bash theme={null}
curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-06-18"
    }
  }'
```

Response:

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-06-18",
    "capabilities": {
      "tools": {"listChanged": false}
    },
    "serverInfo": {
      "name": "mizu-contract",
      "version": "0.1.0"
    }
  }
}
```

### Step 2: Discover Tools

The AI asks what tools are available:

```bash theme={null}
curl -X POST http://localhost:8080/mcp \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/list"
  }'
```

Response:

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      {
        "name": "todos.create",
        "description": "Create a new todo",
        "inputSchema": {
          "type": "object",
          "properties": {
            "title": {"type": "string"}
          },
          "required": ["title"]
        }
      },
      {
        "name": "todos.list",
        "description": "List all todos",
        "inputSchema": {
          "type": "object",
          "properties": {}
        }
      }
    ]
  }
}
```

### Step 3: Call a Tool

The AI calls a tool:

```bash theme={null}
curl -X POST http://localhost:8080/mcp \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
      "name": "todos.create",
      "arguments": {
        "title": "Buy groceries"
      }
    }
  }'
```

Success response:

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"id\":\"1\",\"title\":\"Buy groceries\",\"completed\":false}"
      }
    ],
    "isError": false
  }
}
```

Error response:

```json theme={null}
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "todo not found"
      }
    ],
    "isError": true
  }
}
```

## Configuration Options

Customize your MCP server:

```go theme={null}
mcp.Mount(app.Router, "/mcp", svc,
    // Server information
    mcp.WithServerInfo(mcp.ServerInfo{
        Name:    "my-todo-api",
        Version: "1.0.0",
    }),

    // Instructions for the AI
    mcp.WithInstructions("Use these tools to manage todos. Be careful with delete operations."),
)
```

### Available Options

| Option             | Description                      |
| ------------------ | -------------------------------- |
| `WithServerInfo`   | Set server name and version      |
| `WithInstructions` | Provide usage guidance to the AI |

## Complete Example

This example shows a complete MCP service using the recommended package-based organization:

```go theme={null}
// todo/types.go
package todo

type Todo struct {
    ID        string `json:"id"`
    Title     string `json:"title"`
    Completed bool   `json:"completed"`
}

type CreateInput struct {
    Title string `json:"title"`
}

type GetInput struct {
    ID string `json:"id"`
}

type CompleteInput struct {
    ID string `json:"id"`
}

type ListOutput struct {
    Items []*Todo `json:"items"`
}
```

```go theme={null}
// todo/api.go
package todo

import "context"

// API defines the contract for todo operations
type API interface {
    Create(ctx context.Context, in *CreateInput) (*Todo, error)
    List(ctx context.Context) (*ListOutput, error)
    Get(ctx context.Context, in *GetInput) (*Todo, error)
    Complete(ctx context.Context, in *CompleteInput) (*Todo, error)
}
```

```go theme={null}
// todo/service.go
package todo

import (
    "context"
    "fmt"
    "sync"

    contract "github.com/go-mizu/mizu/contract/v2"
)

// Service implements todo.API
type Service struct {
    mu     sync.RWMutex
    todos  map[string]*Todo
    nextID int
}

// Compile-time check
var _ API = (*Service)(nil)

func NewService() *Service {
    return &Service{todos: make(map[string]*Todo)}
}

func (s *Service) Create(ctx context.Context, in *CreateInput) (*Todo, error) {
    if in.Title == "" {
        return nil, contract.ErrInvalidArgument("title is required")
    }

    s.mu.Lock()
    defer s.mu.Unlock()

    s.nextID++
    todo := &Todo{
        ID:    fmt.Sprintf("%d", s.nextID),
        Title: in.Title,
    }
    s.todos[todo.ID] = todo
    return todo, nil
}

func (s *Service) List(ctx context.Context) (*ListOutput, error) {
    s.mu.RLock()
    defer s.mu.RUnlock()

    items := make([]*Todo, 0, len(s.todos))
    for _, t := range s.todos {
        items = append(items, t)
    }
    return &ListOutput{Items: items}, nil
}

func (s *Service) Get(ctx context.Context, in *GetInput) (*Todo, error) {
    s.mu.RLock()
    defer s.mu.RUnlock()

    todo, ok := s.todos[in.ID]
    if !ok {
        return nil, contract.ErrNotFound("todo not found")
    }
    return todo, nil
}

func (s *Service) Complete(ctx context.Context, in *CompleteInput) (*Todo, error) {
    s.mu.Lock()
    defer s.mu.Unlock()

    todo, ok := s.todos[in.ID]
    if !ok {
        return nil, contract.ErrNotFound("todo not found")
    }
    todo.Completed = true
    return todo, nil
}
```

```go theme={null}
// main.go
package main

import (
    "fmt"

    "github.com/go-mizu/mizu"
    contract "github.com/go-mizu/mizu/contract/v2"
    "github.com/go-mizu/mizu/contract/v2/transport/mcp"
    "github.com/go-mizu/mizu/contract/v2/transport/rest"

    "yourapp/todo"
)

func main() {
    impl := todo.NewService()

    svc := contract.Register[todo.API](impl,
        contract.WithName("Todo"),
        contract.WithDefaultResource("todos"),
    )

    app := mizu.New()

    // Mount MCP for AI assistants
    mcp.Mount(app.Router, "/mcp", svc,
        mcp.WithInstructions("Use these tools to manage a todo list. Available operations: create todos, list all todos, get a specific todo, and mark todos as complete."),
    )

    // Also mount REST for testing
    rest.Mount(app.Router, svc)

    fmt.Println("Server running on http://localhost:8080")
    fmt.Println("MCP endpoint: /mcp (for AI assistants)")
    fmt.Println("REST endpoint: /todos (for testing)")
    app.Listen(":8080")
}
```

### Test with curl

```bash theme={null}
# Initialize connection
curl -X POST http://localhost:8080/mcp \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}'

# List available tools
curl -X POST http://localhost:8080/mcp \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

# Create a todo
curl -X POST http://localhost:8080/mcp \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"todos.create","arguments":{"title":"Buy milk"}}}'

# List todos
curl -X POST http://localhost:8080/mcp \
  -d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"todos.list","arguments":{}}}'

# Complete a todo
curl -X POST http://localhost:8080/mcp \
  -d '{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"todos.complete","arguments":{"id":"1"}}}'
```

## Using with Claude Desktop

Claude Desktop can connect to MCP servers:

1. Start your server:

```bash theme={null}
go run main.go
# Server running on http://localhost:8080
```

2. Configure Claude Desktop to connect to `http://localhost:8080/mcp`

3. Ask Claude:
   * "Create a todo to buy groceries"
   * "Show me all my todos"
   * "Mark the first todo as complete"

Claude will use your MCP tools to fulfill these requests.

## Security

### Input Validation

Always validate inputs - don't trust AI-provided data:

```go theme={null}
func (s *Service) Create(ctx context.Context, in *CreateInput) (*Todo, error) {
    if in.Title == "" {
        return nil, contract.ErrInvalidArgument("title is required")
    }
    if len(in.Title) > 500 {
        return nil, contract.ErrInvalidArgument("title too long")
    }
    // Proceed with validated input
}
```

### Authentication

Add authentication with middleware:

```go theme={null}
func authMiddleware(next mizu.Handler) mizu.Handler {
    return func(c *mizu.Ctx) error {
        token := c.Get("Authorization")
        if !isValidToken(token) {
            return c.Status(401).SendString("unauthorized")
        }
        return next(c)
    }
}

app := mizu.New()
app.Use(authMiddleware)
mcp.Mount(app.Router, "/mcp", svc)
```

## Error Handling

### Method Errors

When your method returns an error, MCP wraps it with `isError: true`:

```go theme={null}
func (s *Service) Get(ctx context.Context, in *GetInput) (*Todo, error) {
    return nil, contract.ErrNotFound("todo not found")
}
```

Response:

```json theme={null}
{
  "result": {
    "content": [{"type": "text", "text": "todo not found"}],
    "isError": true
  }
}
```

### Protocol Errors

Invalid requests return JSON-RPC errors:

```json theme={null}
{
  "error": {
    "code": -32601,
    "message": "Method not found"
  }
}
```

## Multiple Services

Each service needs its own MCP endpoint:

```go theme={null}
todoSvc := contract.Register[todo.API](todoImpl, contract.WithDefaultResource("todos"))
userSvc := contract.Register[user.API](userImpl, contract.WithDefaultResource("users"))

mcp.Mount(app.Router, "/mcp/todos", todoSvc)
mcp.Mount(app.Router, "/mcp/users", userSvc)
```

## Combining Transports

Use MCP alongside REST and JSON-RPC:

```go theme={null}
import (
    "github.com/go-mizu/mizu/contract/v2/transport/rest"
    "github.com/go-mizu/mizu/contract/v2/transport/jsonrpc"
    "github.com/go-mizu/mizu/contract/v2/transport/mcp"
)

app := mizu.New()

// REST for browsers and testing
rest.Mount(app.Router, svc)

// JSON-RPC for service-to-service
jsonrpc.Mount(app.Router, "/rpc", svc)

// MCP for AI assistants
mcp.Mount(app.Router, "/mcp", svc)

app.Listen(":8080")
```

Same business logic, multiple access methods.

## Common Questions

### How does the AI know what parameters to use?

The `tools/list` response includes `inputSchema` for each tool. This JSON Schema tells the AI what parameters are expected, their types, and which are required.

### Can I add descriptions to tools?

Tool descriptions come from your method organization. Use clear method names and the `WithInstructions` option to guide the AI.

### What if the AI sends invalid data?

Your method receives the data and should validate it. Return `contract.ErrInvalidArgument` for validation failures - this shows as an error to the AI.

### Can I use MCP and REST together?

Yes, and it's recommended. REST is great for testing and debugging while MCP serves AI assistants:

```go theme={null}
rest.Mount(app.Router, svc)     // /todos
mcp.Mount(app.Router, "/mcp", svc)  // /mcp
```

## What's Next?

* **[REST Transport](/contract/rest)** - For browser-friendly APIs
* **[JSON-RPC Transport](/contract/jsonrpc)** - Similar protocol with batching
* **[Error Handling](/contract/errors)** - Proper error responses
* **[Transports Overview](/contract/transports-overview)** - Compare all transports
