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.
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:
- AI can discover your tools: Claude can see all your methods and their parameters
- AI can call your tools: Claude can execute methods with proper inputs
- 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
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.
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:
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:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-06-18",
"capabilities": {
"tools": {"listChanged": false}
},
"serverInfo": {
"name": "mizu-contract",
"version": "0.1.0"
}
}
}
The AI asks what tools are available:
curl -X POST http://localhost:8080/mcp \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list"
}'
Response:
{
"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": {}
}
}
]
}
}
The AI calls a tool:
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:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "{\"id\":\"1\",\"title\":\"Buy groceries\",\"completed\":false}"
}
],
"isError": false
}
}
Error response:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "todo not found"
}
],
"isError": true
}
}
Configuration Options
Customize your MCP server:
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:
// 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"`
}
// 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)
}
// 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
}
// 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
# 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:
- Start your server:
go run main.go
# Server running on http://localhost:8080
-
Configure Claude Desktop to connect to
http://localhost:8080/mcp
-
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
Always validate inputs - don’t trust AI-provided data:
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:
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:
func (s *Service) Get(ctx context.Context, in *GetInput) (*Todo, error) {
return nil, contract.ErrNotFound("todo not found")
}
Response:
{
"result": {
"content": [{"type": "text", "text": "todo not found"}],
"isError": true
}
}
Protocol Errors
Invalid requests return JSON-RPC errors:
{
"error": {
"code": -32601,
"message": "Method not found"
}
}
Multiple Services
Each service needs its own MCP endpoint:
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:
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.
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:
rest.Mount(app.Router, svc) // /todos
mcp.Mount(app.Router, "/mcp", svc) // /mcp
What’s Next?