Всем привет! Меня зовут Дима, некоторые меня тут уже знают, и сегодня я расскажу о том, как я создал GoMCP — production-grade альтернативу официальному MCP SDK от Anthropic. Спойлер: получилось в 10 раз быстрее, с multi-tenancy и enterprise-фичами из коробки.
100K+ tool calls/sec (vs ~10K у Python SDK)
Security hardening: input validation, audit logging, rate limiting
Multi-tenancy: изоляция namespace + квоты
3 адаптера: stdio (MCP v1), gRPC, HTTP REST
213 тестов, 430+ Full Ralph итераций
Почему не официальный SDK?
В конце 2024 года Anthropic представил Model Context Protocol — стандарт для подключения LLM к внешним инструментам. Идея отличная, но реализация... скажем так, не для production:
Проблемы официального SDK
# Типичный MCP server на Python @server.tool() async def my_tool(args: dict) -> str: # Где валидация? Где rate limiting? # Где audit logging? return do_dangerous_stuff(args) # 🔥
|
Проблема |
Python SDK |
GoMCP |
|---|---|---|
|
Input validation |
❌ |
✅ Regex patterns, depth limits |
|
Audit logging |
❌ |
✅ Structured, ring buffer |
|
Rate limiting |
❌ |
✅ Per-client, configurable |
|
Multi-tenancy |
❌ |
✅ Quotas, tool ACL |
|
Hot-reload |
❌ |
✅ Zero-downtime |
┌─────────────────────────────────────────────────────────┐ │ gomcp-server │ ├─────────────┬─────────────┬─────────────┬──────────────┤ │ Stdio │ gRPC │ HTTP │ Health │ │ Adapter │ Server │ Mode │ Endpoints │ ├─────────────┴─────────────┴─────────────┴──────────────┤ │ Supervisor │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌───────────┐ │ │ │ Security │ │ Tenant │ │ Batching │ │ HotReload │ │ │ └──────────┘ └──────────┘ └──────────┘ └───────────┘ │ └─────────────────────────────────────────────────────────┘
1. Supervisor pattern — централизованное управление workers:
sup := supervisor.New(supervisor.Config{ DefaultTimeout: 30 * time.Second, MaxWorkers: 100, HeartbeatPeriod: 5 * time.Second, }) // Graceful shutdown sup.Shutdown() // Ждёт завершения всех calls
2. Security-first — валидация на входе:
validator := security.DefaultValidator() // Проверяет: // - Max string length: 100KB // - Max array length: 10K items // - Max nesting depth: 20 // - XSS patterns: <script>, javascript: // - SQL injection: DROP, TRUNCATE // - Template injection: ${}, {{}} result := validator.ValidateJSON(userInput) if !result.Valid { return errors.New(result.Errors[0].Error()) }
3. Multi-tenancy — изоляция клиентов:
tm := tenant.NewManager() t, _ := tm.CreateTenant("company-a", "Company A", tenant.Quotas{ MaxToolCalls: 1000, MaxBatchSize: 50, MaxConcurrent: 10, }) // Ограничение доступа к инструментам t.SetAllowedTools([]string{"read_file", "list_dir"}) // company-a НЕ сможет вызвать "delete_file"
Тестировали на AMD Ryzen 9 5900X, 32GB RAM:
|
Операция |
ops/sec |
Latency p99 |
|---|---|---|
|
Supervisor.CallTool |
100,000 |
10ms |
|
Security.ValidateJSON |
500,000 |
2ms |
|
AuditLogger.Log |
1,000,000 |
1ms |
|
Tenant.CheckQuota |
2,000,000 |
0.5ms |
batch := batching.NewBuilder(). Add("r1", "tool1", args1). Add("r2", "tool2", args2). Add("r3", "tool3", args3). Parallel(5). // До 5 параллельных вызовов Build() result := processor.Process(ctx, batch) // Вместо 3 sequential calls — 1 parallel batch
gomcp-server -mode=stdio
JSON-RPC 2.0 через stdin/stdout. Полностью совместим с Claude Desktop:
{"jsonrpc":"2.0","id":"1","method":"tools/list"}
gomcp-server -mode=grpc -addr=:50051
Для микросервисной архитектуры. Поддерживает streaming, TLS.
gomcp-server -mode=http -addr=:8080
# List tools curl http://localhost:8080/v1/tools # Call tool curl -X POST http://localhost:8080/v1/tools/call \ -d '{"tool":"echo","arguments":{"msg":"hello"}}' # Batch curl -X POST http://localhost:8080/v1/tools/batch \ -d '{"requests":[...], "parallel": true}'
FROM golang:1.22-alpine AS builder WORKDIR /app COPY . . RUN CGO_ENABLED=0 go build -o /gomcp-server ./cmd/gomcp-server FROM alpine:3.19 RUN adduser -D gomcp USER gomcp COPY --from=builder /gomcp-server /app/gomcp-server HEALTHCHECK CMD wget --spider http://localhost:8080/healthz ENTRYPOINT ["/app/gomcp-server"]
# docker-compose.yml services: gomcp-server: build: . ports: ["8080:8080"] deploy: resources: limits: memory: 512M
import { GoMCPClient } from '@gomcp/sdk'; const client = new GoMCPClient({ baseUrl: 'http://localhost:8080' }); // List tools const tools = await client.listTools(); // Call tool const result = await client.callTool('echo', { msg: 'hello' }); // Batch const batch = await client.batchCall([ { tool: 't1', arguments: {} }, { tool: 't2', arguments: {} } ], { parallel: true });
Я использовал методологию Full Ralph — многократное выполнение тестов для выявления flaky tests и race conditions:
Go packages: 12 Total tests: 174 Full Ralph iterations: 430+ TypeScript SDK: 39 tests
Каждый пакет прошёл минимум 10 итераций полного тестового набора.
Источник


