|
| 1 | +# MCP Server with Auth Middleware |
| 2 | + |
| 3 | +This example demonstrates how to integrate the Go MCP SDK's `auth.RequireBearerToken` middleware with an MCP server to provide authenticated access to MCP tools and resources. |
| 4 | + |
| 5 | +## Features |
| 6 | + |
| 7 | +The server provides authentication and authorization capabilities for MCP tools: |
| 8 | + |
| 9 | +### 1. Authentication Methods |
| 10 | + |
| 11 | +- **JWT Token Authentication**: JSON Web Token-based authentication |
| 12 | +- **API Key Authentication**: API key-based authentication |
| 13 | +- **Scope-based Access Control**: Permission-based access to MCP tools |
| 14 | + |
| 15 | +### 2. MCP Integration |
| 16 | + |
| 17 | +- **Authenticated MCP Tools**: Tools that require authentication and check permissions |
| 18 | +- **Token Generation**: Utility endpoints for generating test tokens |
| 19 | +- **Middleware Integration**: Seamless integration with MCP server handlers |
| 20 | + |
| 21 | +## Setup |
| 22 | + |
| 23 | +```bash |
| 24 | +cd examples/server/auth-middleware |
| 25 | +go mod tidy |
| 26 | +go run main.go |
| 27 | +``` |
| 28 | + |
| 29 | +## Testing |
| 30 | + |
| 31 | +```bash |
| 32 | +# Run all tests |
| 33 | +go test -v |
| 34 | + |
| 35 | +# Run benchmark tests |
| 36 | +go test -bench=. |
| 37 | + |
| 38 | +# Generate coverage report |
| 39 | +go test -cover |
| 40 | +``` |
| 41 | + |
| 42 | +## Endpoints |
| 43 | + |
| 44 | +### Public Endpoints (No Authentication Required) |
| 45 | + |
| 46 | +- `GET /health` - Health check |
| 47 | + |
| 48 | +### MCP Endpoints (Authentication Required) |
| 49 | + |
| 50 | +- `POST /mcp/jwt` - MCP server with JWT authentication |
| 51 | +- `POST /mcp/apikey` - MCP server with API key authentication |
| 52 | + |
| 53 | +### Utility Endpoints |
| 54 | + |
| 55 | +- `GET /generate-token` - Generate JWT token |
| 56 | +- `POST /generate-api-key` - Generate API key |
| 57 | + |
| 58 | +## Available MCP Tools |
| 59 | + |
| 60 | +The server provides three authenticated MCP tools: |
| 61 | + |
| 62 | +### 1. Say Hi (`say_hi`) |
| 63 | + |
| 64 | +A simple greeting tool that requires authentication. |
| 65 | + |
| 66 | +**Parameters:** |
| 67 | +- None required |
| 68 | + |
| 69 | +**Required Scopes:** |
| 70 | +- Any authenticated user |
| 71 | + |
| 72 | +### 2. Get User Info (`get_user_info`) |
| 73 | + |
| 74 | +Retrieves user information based on the provided user ID. |
| 75 | + |
| 76 | +**Parameters:** |
| 77 | +- `user_id` (string): The user ID to get information for |
| 78 | + |
| 79 | +**Required Scopes:** |
| 80 | +- `read` permission |
| 81 | + |
| 82 | +### 3. Create Resource (`create_resource`) |
| 83 | + |
| 84 | +Creates a new resource with the provided details. |
| 85 | + |
| 86 | +**Parameters:** |
| 87 | +- `name` (string): The name of the resource |
| 88 | +- `description` (string): The description of the resource |
| 89 | +- `content` (string): The content of the resource |
| 90 | + |
| 91 | +**Required Scopes:** |
| 92 | +- `write` permission |
| 93 | + |
| 94 | +## Example Usage |
| 95 | + |
| 96 | +### 1. Generating JWT Token and Using MCP Tools |
| 97 | + |
| 98 | +```bash |
| 99 | +# Generate a token |
| 100 | +curl 'http://localhost:8080/generate-token?user_id=alice&scopes=read,write' |
| 101 | + |
| 102 | +# Use MCP tool with JWT authentication |
| 103 | +curl -H 'Authorization: Bearer <generated_token>' \ |
| 104 | + -H 'Content-Type: application/json' \ |
| 105 | + -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"say_hi","arguments":{}}}' \ |
| 106 | + http://localhost:8080/mcp/jwt |
| 107 | +``` |
| 108 | + |
| 109 | +### 2. Generating API Key and Using MCP Tools |
| 110 | + |
| 111 | +```bash |
| 112 | +# Generate an API key |
| 113 | +curl -X POST 'http://localhost:8080/generate-api-key?user_id=bob&scopes=read' |
| 114 | + |
| 115 | +# Use MCP tool with API key authentication |
| 116 | +curl -H 'Authorization: Bearer <generated_api_key>' \ |
| 117 | + -H 'Content-Type: application/json' \ |
| 118 | + -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_user_info","arguments":{"user_id":"test"}}}' \ |
| 119 | + http://localhost:8080/mcp/apikey |
| 120 | +``` |
| 121 | + |
| 122 | +### 3. Testing Scope Restrictions |
| 123 | + |
| 124 | +```bash |
| 125 | +# Access MCP tool requiring write scope |
| 126 | +curl -H 'Authorization: Bearer <token_with_write_scope>' \ |
| 127 | + -H 'Content-Type: application/json' \ |
| 128 | + -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"create_resource","arguments":{"name":"test","description":"test resource","content":"test content"}}}' \ |
| 129 | + http://localhost:8080/mcp/jwt |
| 130 | +``` |
| 131 | + |
| 132 | +## Core Concepts |
| 133 | + |
| 134 | +### Authentication Integration |
| 135 | + |
| 136 | +This example demonstrates how to integrate `auth.RequireBearerToken` middleware with an MCP server to provide authenticated access. The MCP server operates as an HTTP handler protected by authentication middleware. |
| 137 | + |
| 138 | +### Key Features |
| 139 | + |
| 140 | +1. **MCP Server Integration**: Create MCP server using `mcp.NewServer` |
| 141 | +2. **Authentication Middleware**: Protect MCP handlers with `auth.RequireBearerToken` |
| 142 | +3. **Token Verification**: Validate tokens using provided `TokenVerifier` functions |
| 143 | +4. **Scope Checking**: Verify required permissions (scopes) are present |
| 144 | +5. **Expiration Validation**: Check that tokens haven't expired |
| 145 | +6. **Context Injection**: Add verified token information to request context |
| 146 | +7. **Authenticated MCP Tools**: Tools that operate based on authentication information |
| 147 | +8. **Error Handling**: Return appropriate HTTP status codes and error messages on authentication failure |
| 148 | + |
| 149 | +### Implementation |
| 150 | + |
| 151 | +```go |
| 152 | +// Create MCP server |
| 153 | +server := mcp.NewServer(&mcp.Implementation{Name: "authenticated-mcp-server"}, nil) |
| 154 | + |
| 155 | +// Create authentication middleware |
| 156 | +authMiddleware := auth.RequireBearerToken(verifier, &auth.RequireBearerTokenOptions{ |
| 157 | + Scopes: []string{"read", "write"}, |
| 158 | +}) |
| 159 | + |
| 160 | +// Create MCP handler |
| 161 | +handler := mcp.NewStreamableHTTPHandler(func(r *http.Request) *mcp.Server { |
| 162 | + return server |
| 163 | +}, nil) |
| 164 | + |
| 165 | +// Apply authentication middleware to MCP handler |
| 166 | +authenticatedHandler := authMiddleware(customMiddleware(handler)) |
| 167 | +``` |
| 168 | + |
| 169 | +### Parameters |
| 170 | + |
| 171 | +- **verifier**: Function to verify tokens (`TokenVerifier` type) |
| 172 | +- **opts**: Authentication options |
| 173 | + - `Scopes`: List of required permissions |
| 174 | + - `ResourceMetadataURL`: OAuth 2.0 resource metadata URL |
| 175 | + |
| 176 | +### Error Responses |
| 177 | + |
| 178 | +- **401 Unauthorized**: Token is invalid, expired, or missing |
| 179 | +- **403 Forbidden**: Required scopes are insufficient |
| 180 | +- **WWW-Authenticate Header**: Included when resource metadata URL is configured |
| 181 | + |
| 182 | +## Implementation Details |
| 183 | + |
| 184 | +### 1. TokenVerifier Implementation |
| 185 | + |
| 186 | +```go |
| 187 | +func jwtVerifier(ctx context.Context, tokenString string) (*auth.TokenInfo, error) { |
| 188 | + // JWT token verification logic |
| 189 | + // On success: Return TokenInfo |
| 190 | + // On failure: Return auth.ErrInvalidToken |
| 191 | +} |
| 192 | +``` |
| 193 | + |
| 194 | +### 2. Using Authentication Information in MCP Tools |
| 195 | + |
| 196 | +```go |
| 197 | +// Get authentication information in MCP tool |
| 198 | +func MyTool(ctx context.Context, req *mcp.CallToolRequest, args MyArgs) (*mcp.CallToolResult, any, error) { |
| 199 | + // Extract authentication info from request |
| 200 | + userInfo := req.Extra.TokenInfo |
| 201 | + |
| 202 | + // Check scopes |
| 203 | + if !slices.Contains(userInfo.Scopes, "read") { |
| 204 | + return nil, nil, fmt.Errorf("insufficient permissions: read scope required") |
| 205 | + } |
| 206 | + |
| 207 | + // Execute tool logic |
| 208 | + return &mcp.CallToolResult{ |
| 209 | + Content: []mcp.Content{ |
| 210 | + &mcp.TextContent{Text: "Tool executed successfully"}, |
| 211 | + }, |
| 212 | + }, nil, nil |
| 213 | +} |
| 214 | +``` |
| 215 | + |
| 216 | +### 3. Middleware Composition |
| 217 | + |
| 218 | +```go |
| 219 | +// Combine authentication middleware with custom middleware |
| 220 | +authenticatedHandler := authMiddleware(customMiddleware(mcpHandler)) |
| 221 | +``` |
| 222 | + |
| 223 | +## Security Best Practices |
| 224 | + |
| 225 | +1. **Environment Variables**: Use environment variables for JWT secrets in production |
| 226 | +2. **Database Storage**: Store API keys in a database |
| 227 | +3. **HTTPS Usage**: Always use HTTPS in production environments |
| 228 | +4. **Token Expiration**: Set appropriate token expiration times |
| 229 | +5. **Principle of Least Privilege**: Grant only the minimum required scopes |
| 230 | + |
| 231 | +## Use Cases |
| 232 | + |
| 233 | +**Ideal for:** |
| 234 | + |
| 235 | +- MCP servers requiring authentication and authorization |
| 236 | +- Applications needing scope-based access control |
| 237 | +- Systems requiring both JWT and API key authentication |
| 238 | +- Projects needing secure MCP tool access |
| 239 | +- Scenarios requiring audit trails and permission management |
| 240 | + |
| 241 | +**Examples:** |
| 242 | + |
| 243 | +- Enterprise MCP servers with user management |
| 244 | +- Multi-tenant MCP applications |
| 245 | +- Secure API gateways with MCP integration |
| 246 | +- Development environments with authentication requirements |
| 247 | +- Production systems requiring fine-grained access control |
0 commit comments