Всем привет! Меня зовут Дима, некоторые меня тут уже знают, и сегодня я расскажу о том, как я создал GoMCP — production-grade альтернативу официальному MCP SDK Всем привет! Меня зовут Дима, некоторые меня тут уже знают, и сегодня я расскажу о том, как я создал GoMCP — production-grade альтернативу официальному MCP SDK

Как я переписал Model Context Protocol на Go и получили 100K ops/sec (может и больше)))

Всем привет! Меня зовут Дима, некоторые меня тут уже знают, и сегодня я расскажу о том, как я создал 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

Batching

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

Три адаптера — один интерфейс

1. Stdio (MCP v1 compatible)

gomcp-server -mode=stdio

JSON-RPC 2.0 через stdin/stdout. Полностью совместим с Claude Desktop:

{"jsonrpc":"2.0","id":"1","method":"tools/list"}

2. gRPC (native)

gomcp-server -mode=grpc -addr=:50051

Для микросервисной архитектуры. Поддерживает streaming, TLS.

3. HTTP REST (Docker-native)

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}'

Docker

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

TypeScript SDK

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 итераций полного тестового набора.

Источник

Отказ от ответственности: Статьи, размещенные на этом веб-сайте, взяты из общедоступных источников и предоставляются исключительно в информационных целях. Они не обязательно отражают точку зрения MEXC. Все права принадлежат первоисточникам. Если вы считаете, что какой-либо контент нарушает права третьих лиц, пожалуйста, обратитесь по адресу service@support.mexc.com для его удаления. MEXC не дает никаких гарантий в отношении точности, полноты или своевременности контента и не несет ответственности за любые действия, предпринятые на основе предоставленной информации. Контент не является финансовой, юридической или иной профессиональной консультацией и не должен рассматриваться как рекомендация или одобрение со стороны MEXC.

Вам также может быть интересно