|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +This is a **Streamable HTTP Stateless MCP Server** - a reference implementation demonstrating true stateless Model Context Protocol (MCP) architecture. Unlike traditional MCP servers that maintain sessions, this server creates fresh instances for every request, enabling infinite horizontal scaling and serverless deployment. |
| 8 | + |
| 9 | +### Core Architecture |
| 10 | + |
| 11 | +- **Stateless Pattern**: Every request spawns a new `McpServer` instance via `createMCPServer()` factory |
| 12 | +- **Transport**: Uses `StreamableHTTPServerTransport` for HTTP+SSE communication |
| 13 | +- **No Sessions**: No `Mcp-Session-Id` headers, no server-side state |
| 14 | +- **Request Isolation**: Each HTTP request gets its own logger context with unique `requestId` |
| 15 | +- **Express Wrapper**: Single endpoint `/mcp` handles both POST commands and GET SSE streams |
| 16 | + |
| 17 | +### Key Components |
| 18 | + |
| 19 | +- `src/stateless-production-server.ts`: Main server implementation with Express app, MCP factory, and all tools/prompts/resources |
| 20 | +- Server runs on port **1071** (not the typical 3000 mentioned in some scripts) |
| 21 | +- Fresh server instance per request pattern at `handleMCPRequest()` function |
| 22 | +- Built-in monitoring endpoints: `/health`, `/health/detailed`, `/metrics` |
| 23 | + |
| 24 | +## Common Commands |
| 25 | + |
| 26 | +### Development Workflow |
| 27 | +```bash |
| 28 | +# Install dependencies |
| 29 | +npm install |
| 30 | + |
| 31 | +# Build (critical: requires ES modules with "bundler" moduleResolution) |
| 32 | +npm run build |
| 33 | + |
| 34 | +# Development with auto-reload |
| 35 | +npm run dev |
| 36 | + |
| 37 | +# Start stateless server (port 1071) |
| 38 | +npm run start:stateless |
| 39 | + |
| 40 | +# Background server with nohup (recommended for testing) |
| 41 | +nohup npm run start:stateless > /tmp/stateless-server.log 2>&1 & |
| 42 | +``` |
| 43 | + |
| 44 | +### Testing & Validation |
| 45 | +```bash |
| 46 | +# Run all tests |
| 47 | +npm run test |
| 48 | + |
| 49 | +# Integration tests only |
| 50 | +npm run test:integration |
| 51 | + |
| 52 | +# Test with coverage |
| 53 | +npm run test:coverage |
| 54 | + |
| 55 | +# Test single file/pattern |
| 56 | +npm run test -- --testPathPattern=stateless-server |
| 57 | + |
| 58 | +# Health check (server on 1071, not 3000) |
| 59 | +curl -s http://localhost:1071/health |
| 60 | + |
| 61 | +# MCP Calculator test (requires proper Accept headers) |
| 62 | +curl -s -X POST -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \ |
| 63 | + -d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"calculate","arguments":{"a":15,"b":7,"op":"add"}},"id":1}' \ |
| 64 | + http://localhost:1071/mcp |
| 65 | +``` |
| 66 | + |
| 67 | +### Quality & CI |
| 68 | +```bash |
| 69 | +# Lint code |
| 70 | +npm run lint |
| 71 | +npm run lint:fix |
| 72 | + |
| 73 | +# Type checking only (no emit) |
| 74 | +npm run typecheck |
| 75 | + |
| 76 | +# Format code |
| 77 | +npm run format |
| 78 | + |
| 79 | +# Full CI pipeline |
| 80 | +npm run ci |
| 81 | +``` |
| 82 | + |
| 83 | +### MCP Inspector Testing |
| 84 | +```bash |
| 85 | +# Build first, then test with Inspector |
| 86 | +npm run build |
| 87 | +npx @modelcontextprotocol/inspector --cli http://localhost:1071/mcp |
| 88 | +``` |
| 89 | + |
| 90 | +## Critical Configuration Notes |
| 91 | + |
| 92 | +### TypeScript Configuration |
| 93 | +- **CRITICAL**: `tsconfig.json` uses `"moduleResolution": "bundler"` (not "node") to generate proper ES modules |
| 94 | +- Package.json specifies `"type": "module"` requiring ES module output |
| 95 | +- Build outputs to `dist/` directory with source maps and declarations |
| 96 | + |
| 97 | +### MCP Transport Requirements |
| 98 | +- Clients must send `Accept: application/json, text/event-stream` header |
| 99 | +- Server responds with SSE streams for real-time communication |
| 100 | +- No session handshake - each request is independent |
| 101 | + |
| 102 | +### Server Behavior |
| 103 | +- **Port**: Always 1071 (despite some scripts mentioning 3000) |
| 104 | +- **Logging**: Structured JSON logs with request correlation via `requestId` |
| 105 | +- **Cleanup**: Transport and server instances are disposed after each request |
| 106 | +- **Rate Limiting**: 1000 requests per 15-minute window on `/mcp` endpoint |
| 107 | + |
| 108 | +## Development Patterns |
| 109 | + |
| 110 | +### Adding New Tools |
| 111 | +Tools are defined in `createMCPServer()` factory. Each tool gets a fresh server instance per call: |
| 112 | +- Use `z.` schemas for parameter validation |
| 113 | +- Generate unique `requestId` for request correlation |
| 114 | +- Implement progress notifications via `sendNotification` for streaming tools |
| 115 | +- Follow stateless principle - no cross-request state |
| 116 | + |
| 117 | +### Testing Stateless Behavior |
| 118 | +- Tests should verify fresh server instances are created |
| 119 | +- Mock `createMCPServer()` to verify isolation |
| 120 | +- Test concurrent requests don't interfere |
| 121 | +- Validate no shared state between requests |
| 122 | + |
| 123 | +### Monitoring Production |
| 124 | +- Use `/health/detailed` for comprehensive system status |
| 125 | +- Monitor logs for request correlation and performance |
| 126 | +- `/metrics` endpoint provides Prometheus-style metrics |
| 127 | +- Server uptime in `/stats` resource reflects process uptime only |
| 128 | + |
| 129 | +This server is designed for serverless environments where each request may hit a different instance, making traditional session-based patterns impossible. |
0 commit comments