This is the full developer documentation for MCP Doc
# Model Context Protocol
> Первая русскоязычная документация по созданию MCP серверов на Python, TypeScript, Java, Kotlin, C#, Go, PHP, Ruby, Rust и Swift
## Быстрая навигация
[Заголовок раздела «Быстрая навигация»](#быстрая-навигация)
### [Быстрый старт](/guides/getting-started/)
[Создайте свой первый MCP сервер за 5 минут](/guides/getting-started/)
### [SDK](#sdk-по-языкам-программирования)
[Выберите SDK для вашего языка программирования](#sdk-по-языкам-программирования)
### [Серверы](/servers/overview/)
[Готовые MCP серверы для интеграции](/servers/overview/)
### [Развёртывание](#развёртывание)
[Docker, Linux, Windows и удалённые транспорты](#развёртывание)
### [Безопасность](/security/best-practices/)
[Лучшие практики защиты MCP серверов](/security/best-practices/)
### [Справочник](/reference/protocol/)
[Протокол, клиенты и спецификация](/reference/protocol/)
## Что такое MCP?
[Заголовок раздела «Что такое MCP?»](#что-такое-mcp)
**Model Context Protocol (MCP)** — это открытый стандарт от Anthropic, который позволяет AI-ассистентам (Claude, ChatGPT, Copilot) безопасно подключаться к внешним источникам данных и инструментам.
MCP решает фундаментальную проблему: как дать языковым моделям доступ к актуальной информации и возможность выполнять действия во внешних системах.
Инструменты (Tools)
Функции, которые AI может вызывать: запросы к API, работа с файлами, выполнение команд
Ресурсы (Resources)
Данные, которые AI может читать: файлы, базы данных, документация
Промпты (Prompts)
Шаблоны для структурированных запросов и инструкций
Безопасность
Изоляция, контроль доступа, аудит всех операций
## Популярные MCP серверы
[Заголовок раздела «Популярные MCP серверы»](#популярные-mcp-серверы)
### [Context7](/servers/context7/)
[Хит](/servers/context7/)
[Актуальная документация библиотек в реальном времени. Больше никаких устаревших знаний!](/servers/context7/)
### [Filesystem](/servers/filesystem/)
[Безопасное чтение и запись файлов с поддержкой разрешённых директорий](/servers/filesystem/)
### [Git](/servers/git/)
[Работа с Git-репозиториями: коммиты, история, диффы, ветки](/servers/git/)
### [Memory](/servers/memory/)
[Персистентная память для AI через граф знаний](/servers/memory/)
[Смотреть все серверы →](/servers/overview/)
## SDK по языкам программирования
[Заголовок раздела «SDK по языкам программирования»](#sdk-по-языкам-программирования)
### [Python SDK](/sdk/python/)
[Рекомендуется](/sdk/python/)
[FastMCP — самый простой способ создать MCP сервер. Декораторы, type hints, async.](/sdk/python/)
### [TypeScript SDK](/sdk/typescript/)
[Официальный SDK для Node.js с поддержкой SSE и StreamableHTTP транспортов.](/sdk/typescript/)
### [Java SDK](/sdk/java/)
[Reactive Streams API, Spring Boot интеграция, Jakarta Servlet транспорт.](/sdk/java/)
### [Kotlin SDK](/sdk/kotlin/)
[Multiplatform SDK для JVM, WebAssembly и Native (iOS). Ktor интеграция.](/sdk/kotlin/)
### [C# SDK](/sdk/csharp/)
[Атрибуты \[McpServerTool\] и полная интеграция с .NET DI.](/sdk/csharp/)
### [Go SDK](/sdk/go/)
[Рекомендуется](/sdk/go/)
[mark3labs/mcp-go — production-ready SDK с SSE поддержкой.](/sdk/go/)
### [PHP SDK](/sdk/php/)
[Рекомендуется](/sdk/php/)
[php-mcp/server — SDK с PHP атрибутами и PSR-11 dependency injection.](/sdk/php/)
### [Ruby SDK](/sdk/ruby/)
[Rails и Rack интеграция. Streamable HTTP и stdio транспорты.](/sdk/ruby/)
### [Rust SDK](/sdk/rust/)
[RMCP — proc-макросы #\[tool\], #\[resource\] для минимального бойлерплейта.](/sdk/rust/)
### [Swift SDK](/sdk/swift/)
[Apple платформы и Linux. Service Lifecycle для graceful shutdown.](/sdk/swift/)
## Развёртывание
[Заголовок раздела «Развёртывание»](#развёртывание)
### [Docker](/deployment/docker/)
[Контейнеризация MCP серверов с volume mounting и network configuration.](/deployment/docker/)
### [Windows](/deployment/windows/)
[Специфика установки на Windows: полные пути, node.exe, двойные слэши.](/deployment/windows/)
### [Ubuntu/Linux](/deployment/ubuntu/)
[Развёртывание через uvx, local repository, Docker и systemd.](/deployment/ubuntu/)
### [NPM Registry](/deployment/npm/)
[Публикация серверов в официальный MCP Registry через NPM.](/deployment/npm/)
### [HTTP/SSE](/deployment/http-sse/)
[Удалённый транспорт для веб-интеграций и масштабируемых развёртываний.](/deployment/http-sse/)
## Архитектура MCP
[Заголовок раздела «Архитектура MCP»](#архитектура-mcp)
**Клиент** (Claude Desktop, Cursor, VS Code) подключается к **серверу** через транспорт (stdio или HTTP/SSE). Сервер предоставляет инструменты, ресурсы и промпты, которые клиент может использовать.
## Быстрый старт
[Заголовок раздела «Быстрый старт»](#быстрый-старт)
* Python
server.py
```python
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("My Server")
@mcp.tool()
def add(a: int, b: int) -> int:
"""Сложение двух чисел"""
return a + b
@mcp.resource("config://app")
def get_config() -> str:
"""Конфигурация приложения"""
return "debug=true"
```
* TypeScript
server.ts
```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new McpServer({
name: "my-server",
version: "1.0.0",
});
server.tool("add", { a: "number", b: "number" }, async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }],
}));
const transport = new StdioServerTransport();
await server.connect(transport);
```
## Официальные ресурсы
[Заголовок раздела «Официальные ресурсы»](#официальные-ресурсы)
* [modelcontextprotocol.io](https://modelcontextprotocol.io) — официальная документация Anthropic
* [GitHub: modelcontextprotocol](https://github.com/modelcontextprotocol) — все официальные SDK
* [MCP Registry](https://registry.modelcontextprotocol.io) — реестр готовых серверов
# Docker развёртывание
> Полное руководство по контейнеризации MCP серверов с Docker
Docker обеспечивает изоляцию, воспроизводимость и простоту развёртывания MCP серверов в любой среде.
## Базовый Dockerfile
[Заголовок раздела «Базовый Dockerfile»](#базовый-dockerfile)
### Python (Multi-stage)
[Заголовок раздела «Python (Multi-stage)»](#python-multi-stage)
Dockerfile
```dockerfile
# Build stage для зависимостей
FROM python:3.12-slim AS builder
WORKDIR /app
# Установка build-зависимостей
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc libpq-dev && rm -rf /var/lib/apt/lists/*
# Виртуальное окружение
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Production stage
FROM python:3.12-slim
# Non-root пользователь
RUN useradd --create-home --shell /bin/bash mcp
WORKDIR /home/mcp/app
# Копирование venv из builder
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# Копирование кода
COPY --chown=mcp:mcp src/ ./src/
USER mcp
CMD ["python", "-m", "src.server"]
```
### Python (простой вариант)
[Заголовок раздела «Python (простой вариант)»](#python-простой-вариант)
Dockerfile
```dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY src/ ./src/
CMD ["python", "-m", "src.server"]
```
### TypeScript
[Заголовок раздела «TypeScript»](#typescript)
Dockerfile
```dockerfile
# Multi-stage build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
CMD ["node", "dist/index.js"]
```
### Rust
[Заголовок раздела «Rust»](#rust)
Dockerfile
```dockerfile
FROM rust:1.75 AS builder
WORKDIR /app
COPY . .
RUN cargo build --release
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/mcp-server /usr/local/bin/
CMD ["mcp-server"]
```
### Go
[Заголовок раздела «Go»](#go)
Dockerfile
```dockerfile
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o mcp-server ./cmd/server
FROM alpine:latest
RUN apk --no-cache add ca-certificates
COPY --from=builder /app/mcp-server /usr/local/bin/
CMD ["mcp-server"]
```
## docker-compose.yml
[Заголовок раздела «docker-compose.yml»](#docker-composeyml)
Для комплексных сервисов с зависимостями:
docker-compose.yml
```yaml
version: '3.8'
services:
mcp-server:
build: .
container_name: mcp-server
restart: unless-stopped
volumes:
- ./data:/app/data:ro
- ./config:/app/config:ro
environment:
- DATABASE_URL=postgresql://postgres:password@db:5432/mcp
- LOG_LEVEL=info
depends_on:
- db
networks:
- mcp-network
db:
image: postgres:16-alpine
container_name: mcp-db
restart: unless-stopped
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
- POSTGRES_DB=mcp
networks:
- mcp-network
volumes:
postgres_data:
networks:
mcp-network:
driver: bridge
```
## Volume Mounting
[Заголовок раздела «Volume Mounting»](#volume-mounting)
Для доступа к данным на хосте:
docker-compose.yml
```yaml
services:
mcp-server:
volumes:
# Только чтение для безопасности
- /home/user/documents:/app/documents:ro
# Запись для кэша
- mcp-cache:/app/cache
# Конфигурация
- ./config.json:/app/config.json:ro
```
## Environment Variables
[Заголовок раздела «Environment Variables»](#environment-variables)
Dockerfile
```dockerfile
ENV MCP_SERVER_NAME=my-server
ENV MCP_LOG_LEVEL=info
ENV MCP_MAX_CONNECTIONS=100
```
docker-compose.yml
```yaml
services:
mcp-server:
environment:
- MCP_SERVER_NAME=${SERVER_NAME:-default}
- MCP_LOG_LEVEL=${LOG_LEVEL:-info}
- DATABASE_URL
env_file:
- .env
```
.env
```bash
SERVER_NAME=production-server
LOG_LEVEL=warn
DATABASE_URL=postgresql://user:pass@host:5432/db
```
## Networking
[Заголовок раздела «Networking»](#networking)
### HTTP/SSE транспорт
[Заголовок раздела «HTTP/SSE транспорт»](#httpsse-транспорт)
docker-compose.yml
```yaml
services:
mcp-server:
ports:
- "3000:3000"
environment:
- MCP_TRANSPORT=http
- MCP_PORT=3000
```
### Internal network
[Заголовок раздела «Internal network»](#internal-network)
docker-compose.yml
```yaml
services:
mcp-server:
networks:
- internal
app:
networks:
- internal
environment:
- MCP_SERVER_URL=http://mcp-server:3000
networks:
internal:
internal: true
```
## Health Checks
[Заголовок раздела «Health Checks»](#health-checks)
Dockerfile
```dockerfile
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
```
docker-compose.yml
```yaml
services:
mcp-server:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 5s
```
## Security Best Practices
[Заголовок раздела «Security Best Practices»](#security-best-practices)
### Non-root user
[Заголовок раздела «Non-root user»](#non-root-user)
Dockerfile
```dockerfile
FROM python:3.12-slim
# Создание non-root пользователя
RUN useradd --create-home --shell /bin/bash mcp
USER mcp
WORKDIR /home/mcp/app
COPY --chown=mcp:mcp . .
CMD ["python", "-m", "src.server"]
```
### Read-only filesystem
[Заголовок раздела «Read-only filesystem»](#read-only-filesystem)
docker-compose.yml
```yaml
services:
mcp-server:
read_only: true
tmpfs:
- /tmp
volumes:
- ./data:/app/data:ro
```
### Capabilities
[Заголовок раздела «Capabilities»](#capabilities)
docker-compose.yml
```yaml
services:
mcp-server:
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
```
## Logging
[Заголовок раздела «Logging»](#logging)
docker-compose.yml
```yaml
services:
mcp-server:
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
```
### Централизованное логирование
[Заголовок раздела «Централизованное логирование»](#централизованное-логирование)
docker-compose.yml
```yaml
services:
mcp-server:
logging:
driver: syslog
options:
syslog-address: "tcp://logs.example.com:514"
tag: "mcp-server"
```
## Production Deployment
[Заголовок раздела «Production Deployment»](#production-deployment)
### Kubernetes-ready
[Заголовок раздела «Kubernetes-ready»](#kubernetes-ready)
Dockerfile
```dockerfile
FROM python:3.12-slim
# Labels для Kubernetes
LABEL org.opencontainers.image.source="https://github.com/user/mcp-server"
LABEL org.opencontainers.image.version="1.0.0"
WORKDIR /app
# Сигнал для graceful shutdown
STOPSIGNAL SIGTERM
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY src/ ./src/
# Health check endpoint
EXPOSE 8080
USER 1000
CMD ["python", "-m", "src.server"]
```
### Kubernetes deployment
[Заголовок раздела «Kubernetes deployment»](#kubernetes-deployment)
deployment.yaml
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcp-server
spec:
replicas: 3
selector:
matchLabels:
app: mcp-server
template:
metadata:
labels:
app: mcp-server
spec:
containers:
- name: mcp-server
image: registry.example.com/mcp-server:1.0.0
ports:
- containerPort: 3000
resources:
limits:
memory: "256Mi"
cpu: "500m"
requests:
memory: "128Mi"
cpu: "250m"
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
```
## Claude Desktop с Docker
[Заголовок раздела «Claude Desktop с Docker»](#claude-desktop-с-docker)
### Настройка через wrapper script
[Заголовок раздела «Настройка через wrapper script»](#настройка-через-wrapper-script)
Создайте `run-mcp-docker.sh`:
run-mcp-docker.sh
```bash
#!/bin/bash
docker run --rm -i \
-v /home/user/data:/app/data:ro \
-e LOG_LEVEL=info \
my-mcp-server:latest
```
### Claude Desktop config
[Заголовок раздела «Claude Desktop config»](#claude-desktop-config)
claude\_desktop\_config.json
```json
{
"mcpServers": {
"docker-server": {
"command": "/path/to/run-mcp-docker.sh"
}
}
}
```
### Альтернативный метод
[Заголовок раздела «Альтернативный метод»](#альтернативный-метод)
claude\_desktop\_config.json
```json
{
"mcpServers": {
"docker-server": {
"command": "docker",
"args": [
"run", "--rm", "-i",
"-v", "/home/user/data:/app/data:ro",
"my-mcp-server:latest"
]
}
}
}
```
## Сборка и публикация
[Заголовок раздела «Сборка и публикация»](#сборка-и-публикация)
Terminal
```bash
# Сборка
docker build -t my-mcp-server:1.0.0 .
# Тегирование для registry
docker tag my-mcp-server:1.0.0 registry.example.com/my-mcp-server:1.0.0
# Push
docker push registry.example.com/my-mcp-server:1.0.0
```
## Multi-platform builds
[Заголовок раздела «Multi-platform builds»](#multi-platform-builds)
Terminal
```bash
# Сборка для нескольких архитектур
docker buildx build \
--platform linux/amd64,linux/arm64 \
-t my-mcp-server:1.0.0 \
--push .
```
## Полезные ссылки
[Заголовок раздела «Полезные ссылки»](#полезные-ссылки)
* [Docker Best Practices](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)
* [Azure MCP Container Sample](https://github.com/Azure-Samples/mcp-container-ts)
* [Docker Compose Documentation](https://docs.docker.com/compose/)
# HTTP/SSE транспорт
> Развёртывание MCP серверов с HTTP и Server-Sent Events для веб-приложений
HTTP/SSE транспорт позволяет развёртывать MCP серверы как веб-сервисы, доступные через HTTP API.
## Архитектура
[Заголовок раздела «Архитектура»](#архитектура)
**Два канала связи:**
* **HTTP POST** — запросы от клиента к серверу (JSON-RPC)
* **SSE** — события от сервера к клиенту (Server-Sent Events)
## TypeScript реализация
[Заголовок раздела «TypeScript реализация»](#typescript-реализация)
### Базовый сервер
[Заголовок раздела «Базовый сервер»](#базовый-сервер)
server.ts
```typescript
import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
const app = express();
app.use(express.json());
const server = new McpServer({
name: "http-server",
version: "1.0.0",
});
// Регистрация инструментов
server.tool("hello", {}, async () => ({
content: [{ type: "text", text: "Hello from HTTP!" }],
}));
// Хранение сессий
const sessions = new Map();
// SSE endpoint
app.get("/sse", async (req, res) => {
const sessionId = req.query.sessionId as string || crypto.randomUUID();
// Настройка SSE
res.setHeader("Content-Type", "text/event-stream");
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Connection", "keep-alive");
res.setHeader("Access-Control-Allow-Origin", "*");
const transport = new StreamableHTTPServerTransport("/message", res);
sessions.set(sessionId, transport);
// Подключение сервера
await server.connect(transport);
// Отправка session ID клиенту
res.write(`data: ${JSON.stringify({ sessionId })}\n\n`);
// Cleanup при отключении
req.on("close", () => {
sessions.delete(sessionId);
});
});
// POST endpoint для запросов
app.post("/message", async (req, res) => {
const sessionId = req.query.sessionId as string;
const transport = sessions.get(sessionId);
if (!transport) {
res.status(404).json({ error: "Session not found" });
return;
}
try {
await transport.handleRequest(req.body, res);
} catch (error) {
res.status(500).json({ error: "Internal server error" });
}
});
// Health check
app.get("/health", (req, res) => {
res.json({ status: "ok", sessions: sessions.size });
});
app.listen(3000, () => {
console.log("MCP HTTP server on http://localhost:3000");
});
```
### Клиент
[Заголовок раздела «Клиент»](#клиент)
client.ts
```typescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
const transport = new StreamableHTTPClientTransport(
"http://localhost:3000/sse",
"http://localhost:3000/message"
);
const client = new Client({
name: "http-client",
version: "1.0.0",
});
await client.connect(transport);
// Вызов инструмента
const result = await client.callTool("hello", {});
console.log(result);
```
## Python реализация
[Заголовок раздела «Python реализация»](#python-реализация)
### FastAPI сервер
[Заголовок раздела «FastAPI сервер»](#fastapi-сервер)
server.py
```python
from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse
from sse_starlette.sse import EventSourceResponse
import asyncio
import uuid
import json
from mcp.server.fastmcp import FastMCP
from mcp.server.sse import SseServerTransport
app = FastAPI()
mcp = FastMCP("http-server")
# Хранение сессий
sessions: dict[str, SseServerTransport] = {}
@mcp.tool()
def hello() -> str:
"""Приветствие"""
return "Hello from HTTP!"
@app.get("/sse")
async def sse_endpoint(request: Request):
session_id = str(uuid.uuid4())
async def event_generator():
transport = SseServerTransport()
sessions[session_id] = transport
# Отправляем session ID
yield {
"event": "session",
"data": json.dumps({"sessionId": session_id})
}
try:
async for message in transport.receive():
yield {
"event": "message",
"data": json.dumps(message)
}
finally:
del sessions[session_id]
return EventSourceResponse(event_generator())
@app.post("/message")
async def message_endpoint(request: Request, sessionId: str):
transport = sessions.get(sessionId)
if not transport:
return {"error": "Session not found"}, 404
body = await request.json()
response = await transport.handle_request(body)
return response
@app.get("/health")
async def health():
return {"status": "ok", "sessions": len(sessions)}
```
### Запуск
[Заголовок раздела «Запуск»](#запуск)
Terminal
```bash
uvicorn server:app --host 0.0.0.0 --port 3000
```
## Nginx конфигурация
[Заголовок раздела «Nginx конфигурация»](#nginx-конфигурация)
/etc/nginx/sites-available/mcp-server
```nginx
upstream mcp_server {
server 127.0.0.1:3000;
keepalive 32;
}
server {
listen 443 ssl http2;
server_name mcp.example.com;
ssl_certificate /etc/letsencrypt/live/mcp.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mcp.example.com/privkey.pem;
# SSE endpoint
location /sse {
proxy_pass http://mcp_server;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# SSE настройки
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
# Chunked transfer
chunked_transfer_encoding on;
}
# Message endpoint
location /message {
proxy_pass http://mcp_server;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header Host $host;
proxy_set_header Content-Type application/json;
}
# Health check
location /health {
proxy_pass http://mcp_server;
}
}
```
## CORS настройка
[Заголовок раздела «CORS настройка»](#cors-настройка)
server.ts
```typescript
import cors from "cors";
app.use(cors({
origin: ["https://allowed-origin.com"],
methods: ["GET", "POST"],
allowedHeaders: ["Content-Type", "Authorization"],
credentials: true,
}));
```
## Аутентификация
[Заголовок раздела «Аутентификация»](#аутентификация)
### Bearer token
[Заголовок раздела «Bearer token»](#bearer-token)
middleware/auth.ts
```typescript
const authenticate = (req: Request, res: Response, next: NextFunction) => {
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith("Bearer ")) {
res.status(401).json({ error: "Unauthorized" });
return;
}
const token = authHeader.substring(7);
try {
const payload = verifyToken(token);
req.user = payload;
next();
} catch {
res.status(401).json({ error: "Invalid token" });
}
};
app.use("/sse", authenticate);
app.use("/message", authenticate);
```
### API Key
[Заголовок раздела «API Key»](#api-key)
middleware/apiKey.ts
```typescript
const apiKeyAuth = (req: Request, res: Response, next: NextFunction) => {
const apiKey = req.headers["x-api-key"];
if (!apiKey || !isValidApiKey(apiKey as string)) {
res.status(401).json({ error: "Invalid API key" });
return;
}
next();
};
```
## Rate Limiting
[Заголовок раздела «Rate Limiting»](#rate-limiting)
middleware/rateLimit.ts
```typescript
import rateLimit from "express-rate-limit";
const limiter = rateLimit({
windowMs: 60 * 1000, // 1 минута
max: 100, // 100 запросов
message: { error: "Too many requests" },
});
app.use("/message", limiter);
```
## Мониторинг
[Заголовок раздела «Мониторинг»](#мониторинг)
### Prometheus metrics
[Заголовок раздела «Prometheus metrics»](#prometheus-metrics)
metrics.ts
```typescript
import { Counter, Histogram, Gauge, register } from "prom-client";
const requestCounter = new Counter({
name: "mcp_requests_total",
help: "Total MCP requests",
labelNames: ["method", "status"],
});
const requestDuration = new Histogram({
name: "mcp_request_duration_seconds",
help: "MCP request duration",
labelNames: ["method"],
});
const activeSessions = new Gauge({
name: "mcp_active_sessions",
help: "Number of active sessions",
});
// Middleware
app.use((req, res, next) => {
const start = Date.now();
res.on("finish", () => {
const duration = (Date.now() - start) / 1000;
requestCounter.inc({ method: req.method, status: res.statusCode });
requestDuration.observe({ method: req.method }, duration);
});
next();
});
// Metrics endpoint
app.get("/metrics", async (req, res) => {
activeSessions.set(sessions.size);
res.set("Content-Type", register.contentType);
res.end(await register.metrics());
});
```
## Load Balancing
[Заголовок раздела «Load Balancing»](#load-balancing)
### С sticky sessions
[Заголовок раздела «С sticky sessions»](#с-sticky-sessions)
/etc/nginx/nginx.conf
```nginx
upstream mcp_servers {
ip_hash; # Sticky sessions по IP
server 127.0.0.1:3001;
server 127.0.0.1:3002;
server 127.0.0.1:3003;
}
```
### Redis для сессий
[Заголовок раздела «Redis для сессий»](#redis-для-сессий)
redis.ts
```typescript
import Redis from "ioredis";
const redis = new Redis();
// Сохранение сессии
await redis.set(`session:${sessionId}`, JSON.stringify(sessionData), "EX", 3600);
// Получение сессии
const data = await redis.get(`session:${sessionId}`);
```
## Docker Compose
[Заголовок раздела «Docker Compose»](#docker-compose)
docker-compose.yml
```yaml
version: '3.8'
services:
mcp-http:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- REDIS_URL=redis://redis:6379
depends_on:
- redis
deploy:
replicas: 3
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
nginx:
image: nginx:alpine
ports:
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- /etc/letsencrypt:/etc/letsencrypt:ro
depends_on:
- mcp-http
volumes:
redis_data:
```
## Полезные ссылки
[Заголовок раздела «Полезные ссылки»](#полезные-ссылки)
* [TypeScript SDK - HTTP Transport](https://github.com/modelcontextprotocol/typescript-sdk)
* [SSE Specification](https://html.spec.whatwg.org/multipage/server-sent-events.html)
* [JSON-RPC 2.0](https://www.jsonrpc.org/specification)
# NPM Registry и публикация
> Руководство по публикации MCP серверов в NPM Registry и официальный MCP Registry
Публикация MCP серверов в NPM Registry позволяет легко распространять и устанавливать серверы через npm/npx.
## Подготовка пакета
[Заголовок раздела «Подготовка пакета»](#подготовка-пакета)
### package.json
[Заголовок раздела «package.json»](#packagejson)
package.json
```json
{
"name": "@myorg/mcp-server-example",
"version": "1.0.0",
"description": "MCP сервер для примера",
"type": "module",
"main": "dist/index.js",
"bin": {
"mcp-server-example": "./dist/index.js"
},
"files": [
"dist",
"README.md"
],
"scripts": {
"build": "tsc",
"prepare": "npm run build"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0"
},
"devDependencies": {
"typescript": "^5.0.0",
"@types/node": "^20.0.0"
},
"keywords": [
"mcp",
"model-context-protocol",
"ai",
"claude"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/myorg/mcp-server-example.git"
},
"mcpName": "example"
}
```
### Важные поля
[Заголовок раздела «Важные поля»](#важные-поля)
| Поле | Описание |
| --------- | ----------------------------------------------------- |
| `name` | Уникальное имя пакета (рекомендуется с scope `@org/`) |
| `bin` | Путь к исполняемому файлу |
| `files` | Файлы для включения в пакет |
| `mcpName` | Имя для MCP Registry (опционально) |
## Структура проекта
[Заголовок раздела «Структура проекта»](#структура-проекта)
```plaintext
mcp-server-example/
├── src/
│ ├── index.ts
│ └── tools/
├── dist/ # Скомпилированный код
├── package.json
├── tsconfig.json
├── README.md
└── LICENSE
```
### src/index.ts
[Заголовок раздела «src/index.ts»](#srcindexts)
src/index.ts
```typescript
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new McpServer({
name: "example",
version: "1.0.0",
});
// Регистрация инструментов
server.tool("hello", {}, async () => ({
content: [{ type: "text", text: "Hello from MCP!" }],
}));
// Запуск
const transport = new StdioServerTransport();
await server.connect(transport);
```
## Публикация в NPM
[Заголовок раздела «Публикация в NPM»](#публикация-в-npm)
### Регистрация на npmjs.com
[Заголовок раздела «Регистрация на npmjs.com»](#регистрация-на-npmjscom)
Terminal
```bash
npm adduser
```
### Проверка перед публикацией
[Заголовок раздела «Проверка перед публикацией»](#проверка-перед-публикацией)
Terminal
```bash
# Что будет опубликовано
npm pack --dry-run
# Линтинг
npm run lint
# Тесты
npm test
# Сборка
npm run build
```
### Публикация
[Заголовок раздела «Публикация»](#публикация)
Terminal
```bash
# Первая публикация
npm publish --access public
# Обновление версии
npm version patch # 1.0.0 -> 1.0.1
npm version minor # 1.0.0 -> 1.1.0
npm version major # 1.0.0 -> 2.0.0
# Публикация обновления
npm publish
```
### Scoped packages
[Заголовок раздела «Scoped packages»](#scoped-packages)
Terminal
```bash
# Публичный scoped пакет
npm publish --access public
# Приватный (требует платную подписку)
npm publish
```
## MCP Registry
[Заголовок раздела «MCP Registry»](#mcp-registry)
MCP Registry — официальный реестр MCP серверов, который агрегирует метаданные из NPM, PyPI и других источников.
### Добавление в MCP Registry
[Заголовок раздела «Добавление в MCP Registry»](#добавление-в-mcp-registry)
1. Убедитесь, что `mcpName` указан в package.json:
package.json
```json
{
"mcpName": "example"
}
```
2. Пакет должен быть опубликован в NPM
3. Регистрация в MCP Registry:
Terminal
```bash
# Установка CLI
npm install -g @modelcontextprotocol/registry-cli
# Аутентификация
mcp-registry login
# Публикация
mcp-registry publish
```
### server.json
[Заголовок раздела «server.json»](#serverjson)
Альтернативный способ — создать `server.json`:
server.json
```json
{
"name": "example",
"description": "Пример MCP сервера",
"version": "1.0.0",
"homepage": "https://github.com/myorg/mcp-server-example",
"license": "MIT",
"author": {
"name": "My Organization"
},
"categories": ["tools", "utilities"],
"runtime": {
"type": "npm",
"package": "@myorg/mcp-server-example"
}
}
```
## Использование опубликованного сервера
[Заголовок раздела «Использование опубликованного сервера»](#использование-опубликованного-сервера)
### Через npx
[Заголовок раздела «Через npx»](#через-npx)
Terminal
```bash
npx -y @myorg/mcp-server-example
```
### Claude Desktop конфигурация
[Заголовок раздела «Claude Desktop конфигурация»](#claude-desktop-конфигурация)
claude\_desktop\_config.json
```json
{
"mcpServers": {
"example": {
"command": "npx",
"args": ["-y", "@myorg/mcp-server-example"]
}
}
}
```
### Глобальная установка
[Заголовок раздела «Глобальная установка»](#глобальная-установка)
Terminal
```bash
npm install -g @myorg/mcp-server-example
```
claude\_desktop\_config.json
```json
{
"mcpServers": {
"example": {
"command": "mcp-server-example"
}
}
}
```
## Private NPM Registry
[Заголовок раздела «Private NPM Registry»](#private-npm-registry)
### Конфигурация .npmrc
[Заголовок раздела «Конфигурация .npmrc»](#конфигурация-npmrc)
.npmrc
```ini
# .npmrc
@myorg:registry=https://npm.mycompany.com
//npm.mycompany.com/:_authToken=${NPM_TOKEN}
```
### Публикация в приватный registry
[Заголовок раздела «Публикация в приватный registry»](#публикация-в-приватный-registry)
Terminal
```bash
npm publish --registry https://npm.mycompany.com
```
### Использование
[Заголовок раздела «Использование»](#использование)
claude\_desktop\_config.json
```json
{
"mcpServers": {
"private-server": {
"command": "npx",
"args": [
"--registry", "https://npm.mycompany.com",
"-y", "@myorg/private-mcp-server"
]
}
}
}
```
## Версионирование
[Заголовок раздела «Версионирование»](#версионирование)
### Semantic Versioning
[Заголовок раздела «Semantic Versioning»](#semantic-versioning)
* **MAJOR** (1.0.0 → 2.0.0): Несовместимые изменения API
* **MINOR** (1.0.0 → 1.1.0): Новые функции, обратная совместимость
* **PATCH** (1.0.0 → 1.0.1): Исправления багов
### Pre-release версии
[Заголовок раздела «Pre-release версии»](#pre-release-версии)
Terminal
```bash
npm version prerelease --preid=beta # 1.0.0 -> 1.0.1-beta.0
npm publish --tag beta
```
### Использование beta версий
[Заголовок раздела «Использование beta версий»](#использование-beta-версий)
Terminal
```bash
npx -y @myorg/mcp-server-example@beta
```
## CI/CD публикация
[Заголовок раздела «CI/CD публикация»](#cicd-публикация)
### GitHub Actions
[Заголовок раздела «GitHub Actions»](#github-actions)
.github/workflows/publish.yml
```yaml
# .github/workflows/publish.yml
name: Publish to NPM
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- run: npm ci
- run: npm run build
- run: npm test
- run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
```
### Получение NPM\_TOKEN
[Заголовок раздела «Получение NPM\_TOKEN»](#получение-npm_token)
1. Зайдите на [npmjs.com](https://www.npmjs.com/)
2. Settings → Access Tokens → Generate New Token
3. Выберите “Automation” тип
4. Добавьте в GitHub Secrets
## README для NPM
[Заголовок раздела «README для NPM»](#readme-для-npm)
```markdown
# @myorg/mcp-server-example
MCP сервер для примера.
## Установка
\`\`\`bash
npx -y @myorg/mcp-server-example
\`\`\`
## Конфигурация Claude Desktop
\`\`\`json
{
"mcpServers": {
"example": {
"command": "npx",
"args": ["-y", "@myorg/mcp-server-example"]
}
}
}
\`\`\`
## Инструменты
- `hello` - Приветственное сообщение
- `add` - Сложение чисел
## Лицензия
MIT
```
## Полезные ссылки
[Заголовок раздела «Полезные ссылки»](#полезные-ссылки)
* [NPM Documentation](https://docs.npmjs.com/)
* [MCP Registry](https://registry.modelcontextprotocol.io)
* [MCP Registry Publishing](https://modelcontextprotocol.info/tools/registry/publishing/)
* [@modelcontextprotocol/sdk](https://www.npmjs.com/package/@modelcontextprotocol/sdk)
# Развёртывание на Ubuntu/Linux
> Руководство по установке и настройке MCP серверов на Ubuntu и других Linux дистрибутивах
Linux — рекомендуемая платформа для production развёртывания MCP серверов благодаря стабильности, безопасности и удобству автоматизации.
## Подготовка системы
[Заголовок раздела «Подготовка системы»](#подготовка-системы)
### Обновление пакетов
[Заголовок раздела «Обновление пакетов»](#обновление-пакетов)
Terminal
```bash
sudo apt update && sudo apt upgrade -y
```
### Установка зависимостей
[Заголовок раздела «Установка зависимостей»](#установка-зависимостей)
Terminal
```bash
# Базовые инструменты
sudo apt install -y curl git build-essential
# Node.js (через NodeSource)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
# Python 3.12
sudo add-apt-repository -y ppa:deadsnakes/ppa
sudo apt install -y python3.12 python3.12-venv python3-pip
# uv (менеджер пакетов Python)
curl -LsSf https://astral.sh/uv/install.sh | sh
```
## Установка MCP серверов
[Заголовок раздела «Установка MCP серверов»](#установка-mcp-серверов)
### Через uvx (рекомендуется для Python)
[Заголовок раздела «Через uvx (рекомендуется для Python)»](#через-uvx-рекомендуется-для-python)
Terminal
```bash
# Одноразовый запуск
uvx mcp-server-fetch
# Или установка для постоянного использования
uv pip install mcp-server-fetch
```
### Через npm (для Node.js)
[Заголовок раздела «Через npm (для Node.js)»](#через-npm-для-nodejs)
Terminal
```bash
# Глобальная установка
npm install -g @modelcontextprotocol/server-filesystem
# Или через npx
npx -y @modelcontextprotocol/server-filesystem
```
### Из исходников
[Заголовок раздела «Из исходников»](#из-исходников)
Terminal
```bash
# Клонирование
git clone https://github.com/user/mcp-server.git
cd mcp-server
# Python
python3.12 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
# Node.js
npm install
npm run build
```
## Systemd сервис
[Заголовок раздела «Systemd сервис»](#systemd-сервис)
### Создание unit файла
[Заголовок раздела «Создание unit файла»](#создание-unit-файла)
Terminal
```bash
sudo nano /etc/systemd/system/mcp-server.service
```
/etc/systemd/system/mcp-server.service
```ini
[Unit]
Description=MCP Server
After=network.target
[Service]
Type=simple
User=mcp
Group=mcp
WorkingDirectory=/opt/mcp-server
Environment=PATH=/opt/mcp-server/.venv/bin:/usr/local/bin:/usr/bin
ExecStart=/opt/mcp-server/.venv/bin/python -m src.server
Restart=always
RestartSec=5
# Безопасность
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
ReadWritePaths=/opt/mcp-server/data
PrivateTmp=yes
[Install]
WantedBy=multi-user.target
```
### Управление сервисом
[Заголовок раздела «Управление сервисом»](#управление-сервисом)
Terminal
```bash
# Перезагрузка systemd
sudo systemctl daemon-reload
# Запуск
sudo systemctl start mcp-server
# Автозапуск при загрузке
sudo systemctl enable mcp-server
# Статус
sudo systemctl status mcp-server
# Логи
journalctl -u mcp-server -f
```
## Создание пользователя
[Заголовок раздела «Создание пользователя»](#создание-пользователя)
Terminal
```bash
# Создание системного пользователя
sudo useradd --system --home-dir /opt/mcp-server --shell /bin/false mcp
# Права на директорию
sudo mkdir -p /opt/mcp-server
sudo chown -R mcp:mcp /opt/mcp-server
```
## Конфигурация Claude Desktop
[Заголовок раздела «Конфигурация Claude Desktop»](#конфигурация-claude-desktop)
Файл конфигурации:
```plaintext
~/.config/claude/claude_desktop_config.json
```
### Примеры конфигурации
[Заголовок раздела «Примеры конфигурации»](#примеры-конфигурации)
#### Python сервер
[Заголовок раздела «Python сервер»](#python-сервер)
claude\_desktop\_config.json
```json
{
"mcpServers": {
"my-server": {
"command": "/opt/mcp-server/.venv/bin/python",
"args": ["-m", "src.server"],
"cwd": "/opt/mcp-server",
"env": {
"DATABASE_URL": "postgresql://localhost/mydb"
}
}
}
}
```
#### Node.js сервер
[Заголовок раздела «Node.js сервер»](#nodejs-сервер)
claude\_desktop\_config.json
```json
{
"mcpServers": {
"node-server": {
"command": "node",
"args": ["/opt/mcp-server/dist/index.js"]
}
}
}
```
#### С uvx
[Заголовок раздела «С uvx»](#с-uvx)
claude\_desktop\_config.json
```json
{
"mcpServers": {
"uvx-server": {
"command": "uvx",
"args": ["mcp-server-fetch"]
}
}
}
```
## Firewall (ufw)
[Заголовок раздела «Firewall (ufw)»](#firewall-ufw)
Terminal
```bash
# Для HTTP/SSE транспорта
sudo ufw allow 3000/tcp comment 'MCP Server'
# Проверка
sudo ufw status
```
## Nginx reverse proxy
[Заголовок раздела «Nginx reverse proxy»](#nginx-reverse-proxy)
Для HTTP/SSE транспорта:
/etc/nginx/sites-available/mcp-server
```nginx
server {
listen 443 ssl http2;
server_name mcp.example.com;
ssl_certificate /etc/letsencrypt/live/mcp.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mcp.example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
# SSE настройки
proxy_buffering off;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
}
# Health check
location /health {
proxy_pass http://127.0.0.1:3000/health;
}
}
```
Terminal
```bash
# Активация
sudo ln -s /etc/nginx/sites-available/mcp-server /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```
## Мониторинг
[Заголовок раздела «Мониторинг»](#мониторинг)
### Prometheus metrics
[Заголовок раздела «Prometheus metrics»](#prometheus-metrics)
Terminal
```bash
# Установка node_exporter
sudo apt install prometheus-node-exporter
```
### Логирование
[Заголовок раздела «Логирование»](#логирование)
Terminal
```bash
# Настройка rsyslog
sudo nano /etc/rsyslog.d/mcp-server.conf
```
```title="/etc/rsyslog.d/mcp-server.conf"
if $programname == 'mcp-server' then /var/log/mcp-server.log
& stop
```
### Logrotate
[Заголовок раздела «Logrotate»](#logrotate)
Terminal
```bash
sudo nano /etc/logrotate.d/mcp-server
```
```title="/etc/logrotate.d/mcp-server"
/var/log/mcp-server.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 640 mcp mcp
postrotate
systemctl reload rsyslog > /dev/null 2>&1 || true
endscript
}
```
## Автоматизация с Ansible
[Заголовок раздела «Автоматизация с Ansible»](#автоматизация-с-ansible)
playbook.yml
```yaml
---
- hosts: mcp_servers
become: yes
tasks:
- name: Create mcp user
user:
name: mcp
system: yes
home: /opt/mcp-server
shell: /bin/false
- name: Clone repository
git:
repo: https://github.com/user/mcp-server.git
dest: /opt/mcp-server
version: main
- name: Install Python dependencies
pip:
requirements: /opt/mcp-server/requirements.txt
virtualenv: /opt/mcp-server/.venv
virtualenv_python: python3.12
- name: Copy systemd service
template:
src: mcp-server.service.j2
dest: /etc/systemd/system/mcp-server.service
notify: restart mcp-server
- name: Enable and start service
systemd:
name: mcp-server
enabled: yes
state: started
handlers:
- name: restart mcp-server
systemd:
name: mcp-server
state: restarted
daemon_reload: yes
```
## Security Hardening
[Заголовок раздела «Security Hardening»](#security-hardening)
### Эшелонированная защита (Defense in Depth)
[Заголовок раздела «Эшелонированная защита (Defense in Depth)»](#эшелонированная-защита-defense-in-depth)
Применяйте несколько уровней защиты:
1. **Пользователь**: Отдельный системный пользователь без shell
2. **Файловая система**: Минимальные права, read-only где возможно
3. **Сеть**: Firewall, только необходимые порты
4. **Процесс**: systemd ограничения, AppArmor/SELinux
5. **Мониторинг**: Fail2ban, логирование, алерты
mcp-server.service
```ini
# Расширенные ограничения systemd
[Service]
# Изоляция сети
PrivateNetwork=no
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
# Изоляция файловой системы
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
# Ограничение capabilities
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
AmbientCapabilities=
# Memory и процессы
MemoryDenyWriteExecute=yes
LockPersonality=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
```
### AppArmor профиль
[Заголовок раздела «AppArmor профиль»](#apparmor-профиль)
Terminal
```bash
sudo nano /etc/apparmor.d/opt.mcp-server
```
```title="/etc/apparmor.d/opt.mcp-server"
#include
/opt/mcp-server/.venv/bin/python {
#include
#include
/opt/mcp-server/** r,
/opt/mcp-server/data/** rw,
/tmp/** rw,
deny /etc/passwd r,
deny /etc/shadow r,
}
```
### Fail2ban
[Заголовок раздела «Fail2ban»](#fail2ban)
Terminal
```bash
sudo nano /etc/fail2ban/jail.d/mcp-server.conf
```
/etc/fail2ban/jail.d/mcp-server.conf
```ini
[mcp-server]
enabled = true
port = 3000
filter = mcp-server
logpath = /var/log/mcp-server.log
maxretry = 5
bantime = 3600
```
## Полезные ссылки
[Заголовок раздела «Полезные ссылки»](#полезные-ссылки)
* [Serena MCP on Ubuntu](https://itecsonline.com/post/how-to-install-serena-mcp-linux)
* [Ubuntu MCP Server](https://lobehub.com/mcp/pazuzu1w-ubuntu_mcp_server)
* [Systemd Documentation](https://www.freedesktop.org/software/systemd/man/systemd.service.html)
# Развёртывание на Windows
> Специфика установки и настройки MCP серверов на Windows
Развёртывание MCP серверов на Windows имеет ряд важных отличий от macOS и Linux. Эта документация поможет избежать типичных ошибок.
Критически важно
На Windows **всегда используйте абсолютные пути** к исполняемым файлам. Команды `npx`, `uvx` и относительные пути **не работают** в конфигурации Claude Desktop.
## Ключевые отличия
[Заголовок раздела «Ключевые отличия»](#ключевые-отличия)
| Аспект | macOS/Linux | Windows |
| ---------- | ----------------- | ------------------------ |
| Пути | `/path/to/server` | `C:\\path\\to\\server` |
| Команды | `npx`, `uvx` | Полный путь к `node.exe` |
| Слэши | `/` | `\\` (двойные в JSON) |
| Переменные | `$HOME` | `%USERPROFILE%` |
## Установка зависимостей
[Заголовок раздела «Установка зависимостей»](#установка-зависимостей)
### Node.js
[Заголовок раздела «Node.js»](#nodejs)
1. Скачайте LTS версию с [nodejs.org](https://nodejs.org/)
2. Установите с опцией “Add to PATH”
3. Проверьте установку:
PowerShell
```powershell
node --version
npm --version
```
### Python
[Заголовок раздела «Python»](#python)
1. Скачайте с [python.org](https://www.python.org/downloads/windows/)
2. **Важно:** Отметьте “Add Python to PATH”
3. Проверьте:
PowerShell
```powershell
python --version
pip --version
```
### uv (рекомендуется для Python)
[Заголовок раздела «uv (рекомендуется для Python)»](#uv-рекомендуется-для-python)
PowerShell
```powershell
# Через pip
pip install uv
# Или через PowerShell
irm https://astral.sh/uv/install.ps1 | iex
```
## Claude Desktop конфигурация
[Заголовок раздела «Claude Desktop конфигурация»](#claude-desktop-конфигурация)
Файл конфигурации находится:
```plaintext
%APPDATA%\Claude\claude_desktop_config.json
```
Или полный путь:
```plaintext
C:\Users\\AppData\Roaming\Claude\claude_desktop_config.json
```
### Правильный формат
[Заголовок раздела «Правильный формат»](#правильный-формат)
claude\_desktop\_config.json
```json
{
"mcpServers": {
"my-server": {
"command": "C:\\Program Files\\nodejs\\node.exe",
"args": ["C:\\Users\\username\\mcp-servers\\my-server\\dist\\index.js"]
}
}
}
```
### Типичные ошибки
[Заголовок раздела «Типичные ошибки»](#типичные-ошибки)
❌ **Неправильно:**
claude\_desktop\_config.json
```json
{
"mcpServers": {
"my-server": {
"command": "npx",
"args": ["-y", "@myorg/mcp-server"]
}
}
}
```
✅ **Правильно:**
claude\_desktop\_config.json
```json
{
"mcpServers": {
"my-server": {
"command": "C:\\Program Files\\nodejs\\node.exe",
"args": [
"C:\\Users\\username\\AppData\\Roaming\\npm\\node_modules\\@myorg\\mcp-server\\dist\\index.js"
]
}
}
}
```
## Пути на Windows
[Заголовок раздела «Пути на Windows»](#пути-на-windows)
### Нахождение путей
[Заголовок раздела «Нахождение путей»](#нахождение-путей)
PowerShell
```powershell
# Путь к node.exe
where node
# Путь к npm packages
npm root -g
# Путь к Python
where python
# Путь к pip packages
pip show mcp
```
### Примеры путей
[Заголовок раздела «Примеры путей»](#примеры-путей)
| Программа | Типичный путь |
| ------------ | --------------------------------------------------------------------------- |
| node.exe | `C:\Program Files\nodejs\node.exe` |
| npm modules | `C:\Users\\AppData\Roaming\npm\node_modules` |
| python.exe | `C:\Users\\AppData\Local\Programs\Python\Python312\python.exe` |
| pip packages | `C:\Users\\AppData\Local\Programs\Python\Python312\Lib\site-packages` |
## Конфигурация для Python
[Заголовок раздела «Конфигурация для Python»](#конфигурация-для-python)
### С обычным Python
[Заголовок раздела «С обычным Python»](#с-обычным-python)
claude\_desktop\_config.json
```json
{
"mcpServers": {
"python-server": {
"command": "C:\\Users\\username\\AppData\\Local\\Programs\\Python\\Python312\\python.exe",
"args": [
"-m",
"src.server"
],
"cwd": "C:\\Users\\username\\mcp-servers\\my-server"
}
}
}
```
### С uv
[Заголовок раздела «С uv»](#с-uv)
claude\_desktop\_config.json
```json
{
"mcpServers": {
"uv-server": {
"command": "C:\\Users\\username\\.local\\bin\\uv.exe",
"args": [
"run",
"python",
"-m",
"src.server"
],
"cwd": "C:\\Users\\username\\mcp-servers\\my-server"
}
}
}
```
### С виртуальным окружением
[Заголовок раздела «С виртуальным окружением»](#с-виртуальным-окружением)
claude\_desktop\_config.json
```json
{
"mcpServers": {
"venv-server": {
"command": "C:\\Users\\username\\mcp-servers\\my-server\\.venv\\Scripts\\python.exe",
"args": [
"-m",
"src.server"
],
"cwd": "C:\\Users\\username\\mcp-servers\\my-server"
}
}
}
```
## Конфигурация для Node.js
[Заголовок раздела «Конфигурация для Node.js»](#конфигурация-для-nodejs)
### Локальный проект
[Заголовок раздела «Локальный проект»](#локальный-проект)
claude\_desktop\_config.json
```json
{
"mcpServers": {
"node-server": {
"command": "C:\\Program Files\\nodejs\\node.exe",
"args": [
"C:\\Users\\username\\mcp-servers\\my-server\\dist\\index.js"
]
}
}
}
```
### Глобально установленный пакет
[Заголовок раздела «Глобально установленный пакет»](#глобально-установленный-пакет)
claude\_desktop\_config.json
```json
{
"mcpServers": {
"global-server": {
"command": "C:\\Program Files\\nodejs\\node.exe",
"args": [
"C:\\Users\\username\\AppData\\Roaming\\npm\\node_modules\\@myorg\\mcp-server\\dist\\index.js"
]
}
}
}
```
## PowerShell скрипты
[Заголовок раздела «PowerShell скрипты»](#powershell-скрипты)
### Wrapper скрипт
[Заголовок раздела «Wrapper скрипт»](#wrapper-скрипт)
Создайте `run-mcp.ps1`:
run-mcp.ps1
```powershell
#!/usr/bin/env pwsh
$ErrorActionPreference = "Stop"
# Путь к проекту
$projectPath = "C:\Users\username\mcp-servers\my-server"
# Активация venv
& "$projectPath\.venv\Scripts\Activate.ps1"
# Запуск сервера
python -m src.server
```
### Использование в конфигурации
[Заголовок раздела «Использование в конфигурации»](#использование-в-конфигурации)
claude\_desktop\_config.json
```json
{
"mcpServers": {
"ps-server": {
"command": "powershell.exe",
"args": [
"-ExecutionPolicy", "Bypass",
"-File", "C:\\Users\\username\\mcp-servers\\run-mcp.ps1"
]
}
}
}
```
## Environment Variables
[Заголовок раздела «Environment Variables»](#environment-variables)
claude\_desktop\_config.json
```json
{
"mcpServers": {
"my-server": {
"command": "C:\\Program Files\\nodejs\\node.exe",
"args": ["C:\\path\\to\\server.js"],
"env": {
"DATABASE_URL": "postgresql://localhost/mydb",
"LOG_LEVEL": "debug"
}
}
}
}
```
## Troubleshooting
[Заголовок раздела «Troubleshooting»](#troubleshooting)
### Проверка работоспособности
[Заголовок раздела «Проверка работоспособности»](#проверка-работоспособности)
PowerShell
```powershell
# Тест Node.js сервера
& "C:\Program Files\nodejs\node.exe" "C:\path\to\server\dist\index.js"
# Тест Python сервера
& "C:\path\to\.venv\Scripts\python.exe" -m src.server
```
### Логирование
[Заголовок раздела «Логирование»](#логирование)
Для отладки включите логирование:
claude\_desktop\_config.json
```json
{
"mcpServers": {
"my-server": {
"command": "...",
"args": ["..."],
"env": {
"DEBUG": "mcp:*",
"LOG_LEVEL": "debug"
}
}
}
}
```
### Типичные проблемы
[Заголовок раздела «Типичные проблемы»](#типичные-проблемы)
#### Сервер не запускается
[Заголовок раздела «Сервер не запускается»](#сервер-не-запускается)
1. Проверьте пути — используйте полные абсолютные пути
2. Проверьте двойные слэши в JSON
3. Убедитесь, что все зависимости установлены
#### Permission denied
[Заголовок раздела «Permission denied»](#permission-denied)
PowerShell
```powershell
# Проверка прав на выполнение
Get-ExecutionPolicy
# Разрешение выполнения скриптов
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
```
#### Модуль не найден
[Заголовок раздела «Модуль не найден»](#модуль-не-найден)
PowerShell
```powershell
# Проверка установки npm пакета
npm list -g @myorg/mcp-server
# Переустановка
npm install -g @myorg/mcp-server
```
## WSL (Windows Subsystem for Linux)
[Заголовок раздела «WSL (Windows Subsystem for Linux)»](#wsl-windows-subsystem-for-linux)
Альтернативный подход — использование WSL:
claude\_desktop\_config.json
```json
{
"mcpServers": {
"wsl-server": {
"command": "wsl.exe",
"args": [
"--",
"python3",
"-m",
"src.server"
],
"cwd": "\\\\wsl$\\Ubuntu\\home\\user\\mcp-servers\\my-server"
}
}
}
```
## Полезные ссылки
[Заголовок раздела «Полезные ссылки»](#полезные-ссылки)
* [Windows MCP Installation Guide](https://github.com/trevorwilkerson/Windows-MCP-Server-Installation-Verification-Guide)
* [MCP Market Windows Guide](https://mcpmarket.com/server/windows-installation-guide)
* [Reddit: Installing MCP on Windows](https://www.reddit.com/r/ClaudeAI/comments/1hciaxk/solved_installing_mcp_servers_on_windows_with/)
# Пример калькулятора
> Базовый MCP сервер с математическими инструментами
## Python реализация
[Заголовок раздела «Python реализация»](#python-реализация)
server.py
```python
from mcp.server.fastmcp import FastMCP
from enum import Enum
mcp = FastMCP("calculator")
class Operation(Enum):
ADD = "add"
SUBTRACT = "subtract"
MULTIPLY = "multiply"
DIVIDE = "divide"
@mcp.tool()
def calculate(operation: Operation, a: float, b: float) -> float:
"""Выполняет математическую операцию"""
match operation:
case Operation.ADD:
return a + b
case Operation.SUBTRACT:
return a - b
case Operation.MULTIPLY:
return a * b
case Operation.DIVIDE:
if b == 0:
raise ValueError("Деление на ноль")
return a / b
@mcp.tool()
def sqrt(n: float) -> float:
"""Квадратный корень"""
if n < 0:
raise ValueError("Отрицательное число")
return n ** 0.5
@mcp.tool()
def power(base: float, exp: float) -> float:
"""Возведение в степень"""
return base ** exp
if __name__ == "__main__":
mcp.run()
```
## Конфигурация
[Заголовок раздела «Конфигурация»](#конфигурация)
claude\_desktop\_config.json
```json
{
"mcpServers": {
"calculator": {
"command": "python",
"args": ["server.py"]
}
}
}
```
# Начало работы с MCP
> Пошаговое руководство по созданию первого MCP сервера — от установки до тестирования
Model Context Protocol (MCP) позволяет создавать серверы, которые расширяют возможности AI-ассистентов. В этом руководстве мы создадим первый MCP сервер с нуля.
## Требования
[Заголовок раздела «Требования»](#требования)
* **Python 3.10+** или **Node.js 18+**
* **pip** или **npm/pnpm**
* **Claude Desktop** или другой MCP клиент для тестирования
## Выбор языка
[Заголовок раздела «Выбор языка»](#выбор-языка)
| Язык | Рекомендуется для | SDK |
| ---------- | -------------------------------------- | ------------------------- |
| Python | Новичков, ML/Data Science | FastMCP |
| TypeScript | Web-разработчиков | @modelcontextprotocol/sdk |
| PHP | Legacy систем, Laravel | php-mcp/server |
| Rust | Production, высокой производительности | rust-sdk |
| Go | Микросервисов | mcp-go |
| C# | .NET экосистемы | modelcontextprotocol |
## Быстрый старт с Python
[Заголовок раздела «Быстрый старт с Python»](#быстрый-старт-с-python)
### 1. Установка
[Заголовок раздела «1. Установка»](#1-установка)
Terminal
```bash
# Создание виртуального окружения
python -m venv .venv
source .venv/bin/activate # Linux/macOS
# .venv\Scripts\activate # Windows
# Установка MCP SDK
pip install mcp
```
### 2. Создание сервера
[Заголовок раздела «2. Создание сервера»](#2-создание-сервера)
Создайте файл `server.py`:
server.py
```python
from mcp.server.fastmcp import FastMCP
# Инициализация сервера
mcp = FastMCP("Мой первый сервер")
# Инструмент: функция, которую AI может вызвать
@mcp.tool()
def calculate(operation: str, a: float, b: float) -> float:
"""
Выполняет математическую операцию.
Args:
operation: Операция (add, subtract, multiply, divide)
a: Первое число
b: Второе число
Returns:
Результат вычисления
"""
match operation:
case "add":
return a + b
case "subtract":
return a - b
case "multiply":
return a * b
case "divide":
if b == 0:
raise ValueError("Деление на ноль")
return a / b
case _:
raise ValueError(f"Неизвестная операция: {operation}")
# Ресурс: данные, которые AI может прочитать
@mcp.resource("info://server")
def get_server_info() -> str:
"""Информация о сервере"""
return """
Сервер: Мой первый MCP сервер
Версия: 1.0.0
Автор: kaktak.net
"""
# Промпт: шаблон для структурированных запросов
@mcp.prompt()
def math_prompt(problem: str) -> str:
"""Промпт для математических задач"""
return f"""
Реши следующую математическую задачу, используя инструмент calculate:
{problem}
Покажи пошаговое решение.
"""
if __name__ == "__main__":
mcp.run()
```
### 3. Тестирование с MCP Inspector
[Заголовок раздела «3. Тестирование с MCP Inspector»](#3-тестирование-с-mcp-inspector)
MCP Inspector — официальный инструмент для тестирования серверов:
Terminal
```bash
# Установка
npm install -g @anthropic-ai/mcp-inspector
# Запуск
npx @modelcontextprotocol/inspector python server.py
```
Откройте в браузере и протестируйте:
* Вкладка **Tools** — вызовите `calculate`
* Вкладка **Resources** — прочитайте `info://server`
* Вкладка **Prompts** — используйте `math_prompt`
### 4. Подключение к Claude Desktop
[Заголовок раздела «4. Подключение к Claude Desktop»](#4-подключение-к-claude-desktop)
Отредактируйте конфигурацию Claude Desktop:
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
claude\_desktop\_config.json
```json
{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["/полный/путь/к/server.py"]
}
}
}
```
Перезапустите Claude Desktop. Сервер появится в списке доступных.
## Быстрый старт с TypeScript
[Заголовок раздела «Быстрый старт с TypeScript»](#быстрый-старт-с-typescript)
### 1. Инициализация проекта
[Заголовок раздела «1. Инициализация проекта»](#1-инициализация-проекта)
Terminal
```bash
mkdir my-mcp-server
cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk
npm install -D typescript @types/node
npx tsc --init
```
### 2. Создание сервера
[Заголовок раздела «2. Создание сервера»](#2-создание-сервера-1)
Создайте файл `src/index.ts`:
src/index.ts
```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new McpServer({
name: "my-server",
version: "1.0.0",
});
// Регистрация инструмента
server.tool(
"calculate",
{
operation: { type: "string", enum: ["add", "subtract", "multiply", "divide"] },
a: { type: "number" },
b: { type: "number" },
},
async ({ operation, a, b }) => {
let result: number;
switch (operation) {
case "add":
result = a + b;
break;
case "subtract":
result = a - b;
break;
case "multiply":
result = a * b;
break;
case "divide":
if (b === 0) throw new Error("Деление на ноль");
result = a / b;
break;
default:
throw new Error(`Неизвестная операция: ${operation}`);
}
return {
content: [{ type: "text", text: `Результат: ${result}` }],
};
}
);
// Запуск сервера
const transport = new StdioServerTransport();
await server.connect(transport);
```
### 3. Сборка и запуск
[Заголовок раздела «3. Сборка и запуск»](#3-сборка-и-запуск)
Terminal
```bash
npx tsc
node dist/index.js
```
### 4. Конфигурация Claude Desktop
[Заголовок раздела «4. Конфигурация Claude Desktop»](#4-конфигурация-claude-desktop)
claude\_desktop\_config.json
```json
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["/полный/путь/к/dist/index.js"]
}
}
}
```
## Структура проекта
[Заголовок раздела «Структура проекта»](#структура-проекта)
Рекомендуемая структура для MCP сервера:
```plaintext
my-mcp-server/
├── src/
│ ├── index.ts # Entry point
│ ├── tools/ # Инструменты
│ │ ├── calculator.ts
│ │ └── filesystem.ts
│ ├── resources/ # Ресурсы
│ │ └── config.ts
│ └── prompts/ # Промпты
│ └── templates.ts
├── tests/
│ └── server.test.ts
├── package.json
├── tsconfig.json
├── Dockerfile # Для Docker развёртывания
└── README.md
```
## Ключевые концепции
[Заголовок раздела «Ключевые концепции»](#ключевые-концепции)
### Инструменты (Tools)
[Заголовок раздела «Инструменты (Tools)»](#инструменты-tools)
Инструменты — это функции, которые AI может вызывать. Каждый инструмент имеет:
* **Имя** — уникальный идентификатор
* **Описание** — что делает инструмент (важно для AI)
* **Схему параметров** — типы входных данных
* **Обработчик** — логика выполнения
tools.py
```python
@mcp.tool()
def search_database(query: str, limit: int = 10) -> list[dict]:
"""
Поиск в базе данных.
Args:
query: Поисковый запрос
limit: Максимальное количество результатов
"""
# Логика поиска
return results
```
### Ресурсы (Resources)
[Заголовок раздела «Ресурсы (Resources)»](#ресурсы-resources)
Ресурсы — это данные, которые AI может прочитать:
* **URI** — уникальный идентификатор (`file://`, `db://`, `api://`)
* **MIME-тип** — формат данных
* **Содержимое** — сами данные
resources.py
```python
@mcp.resource("config://database")
def get_db_config() -> str:
"""Конфигурация базы данных"""
return json.dumps({
"host": "localhost",
"port": 5432,
"database": "myapp"
})
```
### Промпты (Prompts)
[Заголовок раздела «Промпты (Prompts)»](#промпты-prompts)
Промпты — шаблоны для структурированных запросов:
prompts.py
````python
@mcp.prompt()
def code_review(language: str, code: str) -> str:
"""Промпт для ревью кода"""
return f"""
Проведи код-ревью следующего {language} кода:
```{language}
{code}
```
Обрати внимание на:
1. Потенциальные баги
2. Производительность
3. Читаемость
4. Best practices
"""
````
## Следующие шаги
[Заголовок раздела «Следующие шаги»](#следующие-шаги)
* [Python SDK](/sdk/python/) — подробная документация FastMCP
* [TypeScript SDK](/sdk/typescript/) — работа с Node.js
* [Docker развёртывание](/deployment/docker/) — контейнеризация
* [Безопасность](/security/best-practices/) — защита сервера
## Полезные ссылки
[Заголовок раздела «Полезные ссылки»](#полезные-ссылки)
* [Официальная документация](https://modelcontextprotocol.io/docs/develop/build-server)
* [MCP Inspector](https://github.com/modelcontextprotocol/inspector)
* [Примеры серверов](https://github.com/modelcontextprotocol/servers)
# Оптимизация производительности
> Руководство по оптимизации MCP серверов для высокой производительности
Оптимизация MCP серверов критична для production развёртываний с высокой нагрузкой.
## Системный уровень
[Заголовок раздела «Системный уровень»](#системный-уровень)
### CPU Isolation (Linux)
[Заголовок раздела «CPU Isolation (Linux)»](#cpu-isolation-linux)
Terminal
```bash
# Выделение CPU cores для MCP сервера
sudo cset shield --cpu 2-3 --kthread on
# Запуск в изолированных CPU
sudo cset shield --exec -- python -m src.server
```
### cgroups v2
[Заголовок раздела «cgroups v2»](#cgroups-v2)
Terminal
```bash
# Создание cgroup
sudo mkdir /sys/fs/cgroup/mcp-server
# Лимит CPU (50%)
echo "50000 100000" | sudo tee /sys/fs/cgroup/mcp-server/cpu.max
# Лимит памяти (512MB)
echo "536870912" | sudo tee /sys/fs/cgroup/mcp-server/memory.max
```
### HugePages для ML workloads
[Заголовок раздела «HugePages для ML workloads»](#hugepages-для-ml-workloads)
Terminal
```bash
# Включение HugePages
echo 512 | sudo tee /proc/sys/vm/nr_hugepages
# Проверка
cat /proc/meminfo | grep Huge
```
### Kernel tuning
[Заголовок раздела «Kernel tuning»](#kernel-tuning)
/etc/sysctl.d/99-mcp.conf
```bash
# /etc/sysctl.d/99-mcp.conf
# Network buffers
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# Connections
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
# File descriptors
fs.file-max = 2097152
```
## Кэширование
[Заголовок раздела «Кэширование»](#кэширование)
### Уровни кэширования
[Заголовок раздела «Уровни кэширования»](#уровни-кэширования)
### Redis кэширование
[Заголовок раздела «Redis кэширование»](#redis-кэширование)
cache.py
```python
import redis
import json
import hashlib
redis_client = redis.Redis(host='localhost', port=6379, db=0)
def cache_key(tool_name: str, params: dict) -> str:
"""Генерация ключа кэша"""
param_hash = hashlib.md5(json.dumps(params, sort_keys=True).encode()).hexdigest()
return f"mcp:tool:{tool_name}:{param_hash}"
@mcp.tool()
async def expensive_operation(query: str) -> dict:
"""Ресурсоёмкая операция с кэшированием"""
key = cache_key("expensive_operation", {"query": query})
# Проверка кэша
cached = redis_client.get(key)
if cached:
return json.loads(cached)
# Выполнение операции
result = await perform_expensive_query(query)
# Сохранение в кэш (TTL 5 минут)
redis_client.setex(key, 300, json.dumps(result))
return result
```
### In-memory кэширование
[Заголовок раздела «In-memory кэширование»](#in-memory-кэширование)
memory\_cache.py
```python
from functools import lru_cache
from cachetools import TTLCache
import asyncio
# LRU кэш для синхронных функций
@lru_cache(maxsize=1000)
def get_config(key: str) -> str:
return load_config(key)
# TTL кэш для асинхронных
cache = TTLCache(maxsize=1000, ttl=300)
async def cached_fetch(url: str) -> str:
if url in cache:
return cache[url]
result = await fetch_url(url)
cache[url] = result
return result
```
## Connection Pooling
[Заголовок раздела «Connection Pooling»](#connection-pooling)
### Database pool
[Заголовок раздела «Database pool»](#database-pool)
database.py
```python
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
engine = create_async_engine(
"postgresql+asyncpg://user:pass@localhost/db",
pool_size=20,
max_overflow=10,
pool_pre_ping=True,
pool_recycle=3600,
)
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
@mcp.tool()
async def query_db(sql: str) -> list:
async with async_session() as session:
result = await session.execute(text(sql))
return [dict(row) for row in result.fetchall()]
```
### HTTP connection pool
[Заголовок раздела «HTTP connection pool»](#http-connection-pool)
http\_client.py
```python
import aiohttp
# Глобальный session
connector = aiohttp.TCPConnector(
limit=100, # Общий лимит соединений
limit_per_host=30, # Лимит на хост
keepalive_timeout=30,
)
session = aiohttp.ClientSession(connector=connector)
@mcp.tool()
async def fetch_api(url: str) -> dict:
async with session.get(url) as response:
return await response.json()
```
## Async/Await оптимизация
[Заголовок раздела «Async/Await оптимизация»](#asyncawait-оптимизация)
### Параллельное выполнение
[Заголовок раздела «Параллельное выполнение»](#параллельное-выполнение)
parallel.py
```python
import asyncio
@mcp.tool()
async def parallel_fetch(urls: list[str]) -> list[dict]:
"""Параллельная загрузка нескольких URL"""
tasks = [fetch_url(url) for url in urls]
results = await asyncio.gather(*tasks, return_exceptions=True)
return [
{"url": url, "result": r if not isinstance(r, Exception) else str(r)}
for url, r in zip(urls, results)
]
```
### Batch processing
[Заголовок раздела «Batch processing»](#batch-processing)
batch.py
```python
@mcp.tool()
async def batch_process(items: list[dict]) -> list[dict]:
"""Пакетная обработка"""
BATCH_SIZE = 100
results = []
for i in range(0, len(items), BATCH_SIZE):
batch = items[i:i + BATCH_SIZE]
batch_results = await asyncio.gather(*[
process_item(item) for item in batch
])
results.extend(batch_results)
return results
```
### Semaphore для ограничения concurrency
[Заголовок раздела «Semaphore для ограничения concurrency»](#semaphore-для-ограничения-concurrency)
semaphore.py
```python
semaphore = asyncio.Semaphore(10) # Максимум 10 параллельных операций
async def limited_fetch(url: str) -> str:
async with semaphore:
return await fetch_url(url)
```
## Load Balancing
[Заголовок раздела «Load Balancing»](#load-balancing)
### Nginx upstream
[Заголовок раздела «Nginx upstream»](#nginx-upstream)
/etc/nginx/nginx.conf
```nginx
upstream mcp_servers {
least_conn; # Выбор наименее загруженного
server 127.0.0.1:3001 weight=5;
server 127.0.0.1:3002 weight=3;
server 127.0.0.1:3003 weight=2;
keepalive 32;
}
```
### Kubernetes HPA
[Заголовок раздела «Kubernetes HPA»](#kubernetes-hpa)
hpa.yaml
```yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: mcp-server-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: mcp-server
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
```
## Мониторинг
[Заголовок раздела «Мониторинг»](#мониторинг)
### Prometheus метрики
[Заголовок раздела «Prometheus метрики»](#prometheus-метрики)
metrics.py
```python
from prometheus_client import Counter, Histogram, Gauge, start_http_server
# Метрики
REQUESTS = Counter('mcp_requests_total', 'Total requests', ['tool'])
LATENCY = Histogram('mcp_request_latency_seconds', 'Request latency', ['tool'])
ACTIVE = Gauge('mcp_active_requests', 'Active requests')
def instrument_tool(func):
"""Декоратор для инструментации"""
@wraps(func)
async def wrapper(*args, **kwargs):
tool_name = func.__name__
REQUESTS.labels(tool=tool_name).inc()
ACTIVE.inc()
with LATENCY.labels(tool=tool_name).time():
try:
return await func(*args, **kwargs)
finally:
ACTIVE.dec()
return wrapper
# Запуск сервера метрик
start_http_server(9090)
```
### Grafana dashboard
[Заголовок раздела «Grafana dashboard»](#grafana-dashboard)
dashboard.json
```json
{
"panels": [
{
"title": "Requests per Second",
"type": "graph",
"targets": [
{
"expr": "rate(mcp_requests_total[1m])",
"legendFormat": "{{tool}}"
}
]
},
{
"title": "Latency P99",
"type": "graph",
"targets": [
{
"expr": "histogram_quantile(0.99, rate(mcp_request_latency_seconds_bucket[5m]))",
"legendFormat": "{{tool}}"
}
]
}
]
}
```
## Stress Testing
[Заголовок раздела «Stress Testing»](#stress-testing)
### Locust
[Заголовок раздела «Locust»](#locust)
locustfile.py
```python
# locustfile.py
from locust import HttpUser, task, between
class McpUser(HttpUser):
wait_time = between(0.1, 0.5)
@task(3)
def call_tool(self):
self.client.post("/message", json={
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "add",
"arguments": {"a": 1, "b": 2}
},
"id": 1
})
@task(1)
def list_tools(self):
self.client.post("/message", json={
"jsonrpc": "2.0",
"method": "tools/list",
"id": 1
})
```
Terminal
```bash
locust -f locustfile.py --host=http://localhost:3000 -u 100 -r 10
```
## Полезные ссылки
[Заголовок раздела «Полезные ссылки»](#полезные-ссылки)
* [Performance Optimization Guide](https://dev.to/nishantbijani/a-guide-to-optimizing-performance-and-security-for-mcp-servers-1pm9)
* [Redis Documentation](https://redis.io/documentation)
* [Prometheus Best Practices](https://prometheus.io/docs/practices/)
# Production Checklist
> 14 пунктов для подготовки MCP сервера к production — безопасность, производительность, мониторинг
## Чеклист перед деплоем
[Заголовок раздела «Чеклист перед деплоем»](#чеклист-перед-деплоем)
Проверьте каждый пункт перед выкладкой в production.
### Безопасность (Security)
[Заголовок раздела «Безопасность (Security)»](#безопасность-security)
#### 1. Валидация входных данных
[Заголовок раздела «1. Валидация входных данных»](#1-валидация-входных-данных)
```python
from pydantic import BaseModel, Field, validator
from typing import Annotated
class FileReadInput(BaseModel):
path: Annotated[str, Field(max_length=255)]
@validator('path')
def validate_path(cls, v):
# Запрещаем выход за пределы директории
if '..' in v or v.startswith('/'):
raise ValueError('Invalid path')
return v
@mcp.tool()
def read_file(input: FileReadInput) -> str:
"""Безопасное чтение файла"""
safe_path = ALLOWED_DIR / input.path
return safe_path.read_text()
```
#### 2. Ограничение доступа к файловой системе
[Заголовок раздела «2. Ограничение доступа к файловой системе»](#2-ограничение-доступа-к-файловой-системе)
```python
from pathlib import Path
ALLOWED_DIR = Path("/app/data").resolve()
def safe_path(user_path: str) -> Path:
"""Проверяет, что путь в разрешённой директории"""
requested = (ALLOWED_DIR / user_path).resolve()
if not str(requested).startswith(str(ALLOWED_DIR)):
raise PermissionError(f"Access denied: {user_path}")
return requested
```
#### 3. Защита от инъекций
[Заголовок раздела «3. Защита от инъекций»](#3-защита-от-инъекций)
```python
# ❌ ОПАСНО: SQL инъекция
@mcp.tool()
def search_users(query: str) -> str:
cursor.execute(f"SELECT * FROM users WHERE name LIKE '%{query}%'")
# ✅ БЕЗОПАСНО: параметризованные запросы
@mcp.tool()
def search_users(query: str) -> str:
cursor.execute(
"SELECT * FROM users WHERE name LIKE ?",
(f"%{query}%",)
)
```
#### 4. Секреты через переменные окружения
[Заголовок раздела «4. Секреты через переменные окружения»](#4-секреты-через-переменные-окружения)
```python
import os
# ❌ ОПАСНО
API_KEY = "sk-1234567890abcdef"
# ✅ БЕЗОПАСНО
API_KEY = os.environ.get("API_KEY")
if not API_KEY:
raise ValueError("API_KEY not set")
```
```dockerfile
# Docker
ENV API_KEY=${API_KEY}
```
***
### Производительность (Performance)
[Заголовок раздела «Производительность (Performance)»](#производительность-performance)
#### 5. Connection pooling для БД
[Заголовок раздела «5. Connection pooling для БД»](#5-connection-pooling-для-бд)
```python
import asyncpg
# Глобальный пул соединений
pool: asyncpg.Pool | None = None
async def get_pool() -> asyncpg.Pool:
global pool
if pool is None:
pool = await asyncpg.create_pool(
DATABASE_URL,
min_size=5,
max_size=20,
command_timeout=60
)
return pool
@mcp.tool()
async def query(sql: str) -> str:
pool = await get_pool()
async with pool.acquire() as conn:
result = await conn.fetch(sql)
return str(result)
```
#### 6. Кэширование
[Заголовок раздела «6. Кэширование»](#6-кэширование)
```python
from functools import lru_cache
from datetime import datetime, timedelta
# Простой кэш в памяти
cache = {}
CACHE_TTL = timedelta(minutes=5)
def cached(key: str):
def decorator(func):
async def wrapper(*args, **kwargs):
now = datetime.now()
if key in cache:
value, expires = cache[key]
if now < expires:
return value
result = await func(*args, **kwargs)
cache[key] = (result, now + CACHE_TTL)
return result
return wrapper
return decorator
@mcp.tool()
@cached("weather")
async def get_weather(city: str) -> str:
"""Погода с кэшированием на 5 минут"""
# Запрос к API...
return weather_data
```
#### 7. Таймауты для внешних вызовов
[Заголовок раздела «7. Таймауты для внешних вызовов»](#7-таймауты-для-внешних-вызовов)
```python
import asyncio
import aiohttp
@mcp.tool()
async def fetch_url(url: str) -> str:
"""Загрузка URL с таймаутом"""
timeout = aiohttp.ClientTimeout(total=30)
async with aiohttp.ClientSession(timeout=timeout) as session:
try:
async with session.get(url) as response:
return await response.text()
except asyncio.TimeoutError:
return "Error: Request timeout (30s)"
```
#### 8. Ограничение размера ответа
[Заголовок раздела «8. Ограничение размера ответа»](#8-ограничение-размера-ответа)
```python
MAX_RESPONSE_SIZE = 100 * 1024 # 100 KB
@mcp.tool()
def read_file(path: str) -> str:
"""Чтение файла с ограничением размера"""
with open(path, 'r') as f:
content = f.read(MAX_RESPONSE_SIZE)
if len(content) == MAX_RESPONSE_SIZE:
content += "\n\n[... truncated, file too large ...]"
return content
```
***
### Надёжность (Reliability)
[Заголовок раздела «Надёжность (Reliability)»](#надёжность-reliability)
#### 9. Graceful error handling
[Заголовок раздела «9. Graceful error handling»](#9-graceful-error-handling)
```python
from mcp.server.fastmcp import FastMCP
import logging
logger = logging.getLogger(__name__)
@mcp.tool()
async def risky_operation(data: str) -> str:
"""Операция с обработкой ошибок"""
try:
result = await process(data)
return result
except ConnectionError as e:
logger.error(f"Connection failed: {e}")
return "Error: Service temporarily unavailable"
except ValueError as e:
logger.warning(f"Invalid input: {e}")
return f"Error: Invalid input - {e}"
except Exception as e:
logger.exception("Unexpected error")
return "Error: Internal server error"
```
#### 10. Идемпотентные операции
[Заголовок раздела «10. Идемпотентные операции»](#10-идемпотентные-операции)
```python
import hashlib
@mcp.tool()
def create_file(name: str, content: str) -> str:
"""Идемпотентное создание файла"""
# Используем хэш контента для уникальности
content_hash = hashlib.sha256(content.encode()).hexdigest()[:8]
filename = f"{name}_{content_hash}.txt"
path = ALLOWED_DIR / filename
# Если файл с таким содержимым уже есть — не перезаписываем
if path.exists():
return f"File already exists: {filename}"
path.write_text(content)
return f"Created: {filename}"
```
#### 11. Health check endpoint
[Заголовок раздела «11. Health check endpoint»](#11-health-check-endpoint)
```python
from datetime import datetime
start_time = datetime.now()
@mcp.tool()
def health_check() -> str:
"""Проверка здоровья сервера"""
uptime = datetime.now() - start_time
return f"""
Status: OK
Uptime: {uptime}
Version: 1.0.0
Database: {"connected" if db_connected() else "disconnected"}
"""
```
***
### Мониторинг (Monitoring)
[Заголовок раздела «Мониторинг (Monitoring)»](#мониторинг-monitoring)
#### 12. Структурированные логи
[Заголовок раздела «12. Структурированные логи»](#12-структурированные-логи)
```python
import json
import sys
from datetime import datetime
def log(level: str, message: str, **kwargs):
"""Структурированный лог в JSON"""
entry = {
"timestamp": datetime.utcnow().isoformat(),
"level": level,
"message": message,
**kwargs
}
print(json.dumps(entry), file=sys.stderr)
@mcp.tool()
def process_data(data: str) -> str:
log("INFO", "Processing started", data_length=len(data))
try:
result = do_processing(data)
log("INFO", "Processing completed", result_length=len(result))
return result
except Exception as e:
log("ERROR", "Processing failed", error=str(e))
raise
```
#### 13. Метрики производительности
[Заголовок раздела «13. Метрики производительности»](#13-метрики-производительности)
```python
import time
from functools import wraps
def timed(func):
"""Декоратор для измерения времени"""
@wraps(func)
async def wrapper(*args, **kwargs):
start = time.perf_counter()
try:
return await func(*args, **kwargs)
finally:
elapsed = time.perf_counter() - start
log("INFO", "Tool executed",
tool=func.__name__,
duration_ms=round(elapsed * 1000, 2))
return wrapper
@mcp.tool()
@timed
async def slow_operation(data: str) -> str:
"""Операция с замером времени"""
await asyncio.sleep(1)
return "Done"
```
#### 14. Алерты на критические ошибки
[Заголовок раздела «14. Алерты на критические ошибки»](#14-алерты-на-критические-ошибки)
```python
import aiohttp
ALERT_WEBHOOK = os.environ.get("ALERT_WEBHOOK")
async def send_alert(message: str, severity: str = "error"):
"""Отправка алерта в Slack/Discord"""
if not ALERT_WEBHOOK:
return
payload = {
"text": f"[{severity.upper()}] MCP Server: {message}"
}
async with aiohttp.ClientSession() as session:
await session.post(ALERT_WEBHOOK, json=payload)
@mcp.tool()
async def critical_operation(data: str) -> str:
try:
return await process(data)
except Exception as e:
await send_alert(f"Critical operation failed: {e}")
raise
```
***
## Docker Production Setup
[Заголовок раздела «Docker Production Setup»](#docker-production-setup)
### Dockerfile
[Заголовок раздела «Dockerfile»](#dockerfile)
```dockerfile
FROM python:3.11-slim
# Не запускать от root
RUN useradd -m -u 1000 mcpuser
WORKDIR /app
# Зависимости
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Код
COPY --chown=mcpuser:mcpuser . .
USER mcpuser
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD python -c "import sys; sys.exit(0)"
CMD ["python", "server.py"]
```
### docker-compose.yml
[Заголовок раздела «docker-compose.yml»](#docker-composeyml)
```yaml
version: '3.8'
services:
mcp-server:
build: .
restart: unless-stopped
environment:
- DATABASE_URL=${DATABASE_URL}
- API_KEY=${API_KEY}
- LOG_LEVEL=INFO
stdin_open: true
tty: true
deploy:
resources:
limits:
memory: 512M
cpus: '0.5'
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
```
***
## 7-дневный путь обучения
[Заголовок раздела «7-дневный путь обучения»](#7-дневный-путь-обучения)
### День 1: Основы
[Заголовок раздела «День 1: Основы»](#день-1-основы)
* [ ] Прочитать [Быстрый старт](/reference/quickstart/)
* [ ] Создать первый сервер с 2 tools
* [ ] Протестировать в MCP Inspector
### День 2: Примитивы MCP
[Заголовок раздела «День 2: Примитивы MCP»](#день-2-примитивы-mcp)
* [ ] Изучить [Примеры кода](/reference/examples/)
* [ ] Добавить Resources к серверу
* [ ] Добавить Prompts
### День 3: Интеграции
[Заголовок раздела «День 3: Интеграции»](#день-3-интеграции)
* [ ] Подключить базу данных (SQLite)
* [ ] Создать tool для REST API
* [ ] Обработать ошибки
### День 4: Клиенты
[Заголовок раздела «День 4: Клиенты»](#день-4-клиенты)
* [ ] Настроить [Claude Desktop](/reference/clients/)
* [ ] Протестировать tools в реальном чате
* [ ] Настроить VS Code или Cursor
### День 5: Отладка
[Заголовок раздела «День 5: Отладка»](#день-5-отладка)
* [ ] Изучить [Troubleshooting](/reference/troubleshooting/)
* [ ] Настроить логирование в stderr
* [ ] Написать unit-тесты
### День 6: Production
[Заголовок раздела «День 6: Production»](#день-6-production)
* [ ] Пройти этот чеклист (14 пунктов)
* [ ] Создать Dockerfile
* [ ] Настроить переменные окружения
### День 7: Деплой
[Заголовок раздела «День 7: Деплой»](#день-7-деплой)
* [ ] Собрать Docker image
* [ ] Протестировать в production-like окружении
* [ ] Задокументировать API своего сервера
***
## Быстрая проверка
[Заголовок раздела «Быстрая проверка»](#быстрая-проверка)
Используйте этот скрипт для проверки сервера:
```python
#!/usr/bin/env python3
"""pre_deploy_check.py - Проверка перед деплоем"""
import subprocess
import json
import sys
def check_server(command: list[str]) -> dict:
"""Проверяет MCP сервер"""
results = {
"initialize": False,
"tools_list": False,
"tool_call": False,
"errors": []
}
# 1. Initialize
init_req = json.dumps({
"jsonrpc": "2.0", "id": 1, "method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {"name": "check", "version": "1.0"}
}
}) + "\n"
try:
result = subprocess.run(
command, input=init_req, capture_output=True,
text=True, timeout=10
)
response = json.loads(result.stdout.strip())
if "result" in response:
results["initialize"] = True
print("✅ Initialize: OK")
else:
results["errors"].append(f"Initialize failed: {response}")
print("❌ Initialize: FAILED")
except Exception as e:
results["errors"].append(str(e))
print(f"❌ Initialize: {e}")
# 2. Tools list
tools_req = json.dumps({
"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {}
}) + "\n"
try:
result = subprocess.run(
command, input=init_req + tools_req, capture_output=True,
text=True, timeout=10
)
lines = result.stdout.strip().split('\n')
if len(lines) >= 2:
tools_response = json.loads(lines[1])
if "result" in tools_response and "tools" in tools_response["result"]:
tools_count = len(tools_response["result"]["tools"])
results["tools_list"] = True
print(f"✅ Tools list: OK ({tools_count} tools)")
else:
print("❌ Tools list: FAILED")
else:
print("❌ Tools list: No response")
except Exception as e:
results["errors"].append(str(e))
print(f"❌ Tools list: {e}")
return results
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python pre_deploy_check.py ")
sys.exit(1)
results = check_server(sys.argv[1:])
if results["initialize"] and results["tools_list"]:
print("\n✅ Server is ready for deployment!")
sys.exit(0)
else:
print("\n❌ Server has issues. Fix before deploying.")
for error in results["errors"]:
print(f" - {error}")
sys.exit(1)
```
***
## Ссылки
[Заголовок раздела «Ссылки»](#ссылки)
Примеры кода
[25+ примеров](/reference/examples/) — production-ready код
Troubleshooting
[Решение проблем](/reference/troubleshooting/) — ошибки и решения
MCP Specification
[Best Practices](https://modelcontextprotocol.io/specification/draft/basic/security_best_practices) — официальные рекомендации
Инструменты
[MCP Inspector](/reference/tools/) — отладка и тестирование
# Настройка клиентов
> Подключение MCP серверов к Claude Desktop, VS Code, Cursor и другим клиентам
Клиент MCP — это приложение, которое подключается к вашему серверу и использует его инструменты. Самые популярные клиенты: **Claude Desktop**, **VS Code** и **Cursor**.
## Claude Desktop
[Заголовок раздела «Claude Desktop»](#claude-desktop)
Claude Desktop — официальный клиент от Anthropic с полной поддержкой MCP.
### Расположение конфигурации
[Заголовок раздела «Расположение конфигурации»](#расположение-конфигурации)
* macOS
```plaintext
~/Library/Application Support/Claude/claude_desktop_config.json
```
* Windows
```plaintext
%APPDATA%\Claude\claude_desktop_config.json
```
* Linux
```plaintext
~/.config/Claude/claude_desktop_config.json
```
### Формат конфигурации
[Заголовок раздела «Формат конфигурации»](#формат-конфигурации)
```json
{
"mcpServers": {
"имя-сервера": {
"command": "команда",
"args": ["аргумент1", "аргумент2"],
"env": {
"ПЕРЕМЕННАЯ": "значение"
}
}
}
}
```
### Примеры конфигураций
[Заголовок раздела «Примеры конфигураций»](#примеры-конфигураций)
* Python
```json
{
"mcpServers": {
"my-python-server": {
"command": "python",
"args": ["/path/to/server.py"]
}
}
}
```
С виртуальным окружением:
```json
{
"mcpServers": {
"my-python-server": {
"command": "/path/to/venv/bin/python",
"args": ["/path/to/server.py"],
"env": {
"PYTHONPATH": "/path/to/project"
}
}
}
}
```
* Node.js
```json
{
"mcpServers": {
"my-node-server": {
"command": "node",
"args": ["/path/to/dist/server.js"]
}
}
}
```
С npx:
```json
{
"mcpServers": {
"my-server": {
"command": "npx",
"args": ["-y", "@my-org/mcp-server"]
}
}
}
```
* Docker
```json
{
"mcpServers": {
"my-docker-server": {
"command": "docker",
"args": ["run", "-i", "--rm", "my-mcp-server:latest"]
}
}
}
```
* uvx (Python)
```json
{
"mcpServers": {
"my-server": {
"command": "uvx",
"args": ["my-mcp-package"]
}
}
}
```
### Несколько серверов
[Заголовок раздела «Несколько серверов»](#несколько-серверов)
```json
{
"mcpServers": {
"calculator": {
"command": "python",
"args": ["/path/to/calculator.py"]
},
"database": {
"command": "python",
"args": ["/path/to/db_server.py"],
"env": {
"DATABASE_URL": "postgresql://localhost/mydb"
}
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "ghp_xxxxxxxxxxxx"
}
}
}
}
```
### Проверка подключения
[Заголовок раздела «Проверка подключения»](#проверка-подключения)
1. Сохраните конфигурацию
2. Перезапустите Claude Desktop
3. Откройте новый чат
4. Нажмите на иконку 🔧 (инструменты) внизу
5. Убедитесь, что ваши tools отображаются в списке
Отладка
Если tools не появляются:
1. Проверьте логи: `~/Library/Logs/Claude/mcp*.log` (macOS)
2. Убедитесь, что путь к серверу абсолютный
3. Проверьте, что сервер запускается вручную без ошибок
***
## VS Code (Copilot)
[Заголовок раздела «VS Code (Copilot)»](#vs-code-copilot)
VS Code с GitHub Copilot поддерживает MCP через файл конфигурации.
### Расположение конфигурации
[Заголовок раздела «Расположение конфигурации»](#расположение-конфигурации-1)
* .vscode/
* **mcp.json** ← конфигурация MCP
* settings.json
Или глобально: `~/.vscode/mcp.json`
### Формат конфигурации
[Заголовок раздела «Формат конфигурации»](#формат-конфигурации-1)
```json
{
"servers": {
"имя-сервера": {
"command": "команда",
"args": ["аргумент1"],
"env": {
"КЛЮЧ": "значение"
}
}
}
}
```
### Примеры
[Заголовок раздела «Примеры»](#примеры)
* Python
```json
{
"servers": {
"my-mcp-server": {
"command": "python",
"args": ["${workspaceFolder}/server.py"]
}
}
}
```
* Node.js
```json
{
"servers": {
"my-mcp-server": {
"command": "node",
"args": ["${workspaceFolder}/dist/server.js"]
}
}
}
```
* npx
```json
{
"servers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "${workspaceFolder}"]
}
}
}
```
### Переменные VS Code
[Заголовок раздела «Переменные VS Code»](#переменные-vs-code)
| Переменная | Значение |
| -------------------- | -------------------------- |
| `${workspaceFolder}` | Корень открытого workspace |
| `${file}` | Текущий открытый файл |
| `${env:NAME}` | Переменная окружения NAME |
### Включение MCP в Copilot
[Заголовок раздела «Включение MCP в Copilot»](#включение-mcp-в-copilot)
1. Откройте настройки VS Code
2. Найдите `github.copilot.chat.experimental.mcp`
3. Включите опцию
4. Перезагрузите VS Code
***
## Cursor
[Заголовок раздела «Cursor»](#cursor)
Cursor — AI-first редактор с встроенной поддержкой MCP.
### Расположение конфигурации
[Заголовок раздела «Расположение конфигурации»](#расположение-конфигурации-2)
* .cursor/
* **mcp.json** ← конфигурация MCP
Глобально: `~/.cursor/mcp.json`
### Формат конфигурации
[Заголовок раздела «Формат конфигурации»](#формат-конфигурации-2)
```json
{
"mcpServers": {
"имя-сервера": {
"command": "команда",
"args": ["аргументы"],
"env": {}
}
}
}
```
Заметка
Формат идентичен Claude Desktop — можно скопировать конфигурацию.
### Примеры
[Заголовок раздела «Примеры»](#примеры-1)
* Python
```json
{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["/Users/me/mcp/server.py"]
}
}
}
```
* Node.js
```json
{
"mcpServers": {
"my-server": {
"command": "npx",
"args": ["ts-node", "/Users/me/mcp/server.ts"]
}
}
}
```
### Активация в Cursor
[Заголовок раздела «Активация в Cursor»](#активация-в-cursor)
1. Создайте `.cursor/mcp.json` в проекте или `~/.cursor/mcp.json` глобально
2. Перезапустите Cursor
3. Откройте Composer (Cmd+I / Ctrl+I)
4. MCP tools автоматически доступны
***
## Windsurf
[Заголовок раздела «Windsurf»](#windsurf)
Windsurf (от Codeium) также поддерживает MCP.
### Конфигурация
[Заголовок раздела «Конфигурация»](#конфигурация)
\~/.windsurf/mcp.json
```json
{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["server.py"]
}
}
}
```
***
## Zed
[Заголовок раздела «Zed»](#zed)
Zed — быстрый редактор с поддержкой MCP через расширения.
### Конфигурация
[Заголовок раздела «Конфигурация»](#конфигурация-1)
\~/.config/zed/settings.json
```json
{
"assistant": {
"mcp_servers": {
"my-server": {
"command": "python",
"args": ["server.py"]
}
}
}
}
```
***
## Сравнение клиентов
[Заголовок раздела «Сравнение клиентов»](#сравнение-клиентов)
| Клиент | Файл конфигурации | Формат | Особенности |
| -------------- | ---------------------------- | ------------- | ----------------------------- |
| Claude Desktop | `claude_desktop_config.json` | `mcpServers` | Официальный, полная поддержка |
| VS Code | `.vscode/mcp.json` | `servers` | Интеграция с Copilot |
| Cursor | `.cursor/mcp.json` | `mcpServers` | AI-first редактор |
| Windsurf | `~/.windsurf/mcp.json` | `mcpServers` | Codeium |
| Zed | `settings.json` | `mcp_servers` | Быстрый редактор |
***
## Популярные MCP серверы
[Заголовок раздела «Популярные MCP серверы»](#популярные-mcp-серверы)
Готовые серверы, которые можно подключить:
### Официальные (от Anthropic)
[Заголовок раздела «Официальные (от Anthropic)»](#официальные-от-anthropic)
```json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/dir"]
},
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "ghp_xxx"
}
},
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"DATABASE_URL": "postgresql://user:pass@localhost/db"
}
},
"sqlite": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-sqlite", "/path/to/database.db"]
},
"puppeteer": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-puppeteer"]
},
"brave-search": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
"env": {
"BRAVE_API_KEY": "xxx"
}
}
}
}
```
### Сторонние популярные
[Заголовок раздела «Сторонние популярные»](#сторонние-популярные)
```json
{
"mcpServers": {
"everything": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-everything"]
},
"memory": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-memory"]
},
"fetch": {
"command": "npx",
"args": ["-y", "@tokenizin/mcp-npx-fetch"]
}
}
}
```
***
## Безопасность
[Заголовок раздела «Безопасность»](#безопасность)
Внимание!
MCP серверы имеют доступ к вашей системе. Подключайте только доверенные серверы!
### Рекомендации
[Заголовок раздела «Рекомендации»](#рекомендации)
1. **Проверяйте исходный код** сервера перед подключением
2. **Ограничивайте доступ** к файловой системе (`server-filesystem` только к нужным папкам)
3. **Не храните секреты** в конфигурации — используйте переменные окружения
4. **Обновляйте серверы** регулярно
5. **Используйте Docker** для изоляции ненадёжных серверов
### Безопасная конфигурация
[Заголовок раздела «Безопасная конфигурация»](#безопасная-конфигурация)
```json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"/Users/me/safe-folder"
]
}
}
}
```
Не делайте так:
```json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/"]
}
}
}
```
***
## Troubleshooting
[Заголовок раздела «Troubleshooting»](#troubleshooting)
### Tools не появляются
[Заголовок раздела «Tools не появляются»](#tools-не-появляются)
1. Перезапустите клиент полностью
2. Проверьте синтаксис JSON (запятые, кавычки)
3. Проверьте абсолютные пути
4. Запустите сервер вручную: `python server.py`
### Ошибка “Command not found”
[Заголовок раздела «Ошибка “Command not found”»](#ошибка-command-not-found)
```json
{
"mcpServers": {
"my-server": {
"command": "/usr/local/bin/python3",
"args": ["/full/path/to/server.py"]
}
}
}
```
### Ошибка подключения
[Заголовок раздела «Ошибка подключения»](#ошибка-подключения)
Проверьте логи:
* Claude Desktop: `~/Library/Logs/Claude/mcp*.log`
* VS Code: Output → MCP
* Cursor: Developer Tools → Console
***
## Ссылки
[Заголовок раздела «Ссылки»](#ссылки)
Официальные серверы
[MCP Servers](https://github.com/modelcontextprotocol/servers) — коллекция готовых серверов
MCP Registry
[registry.mcphub.io](https://registry.mcphub.io) — каталог MCP серверов
Claude Desktop
[claude.ai/download](https://claude.ai/download) — скачать клиент
Troubleshooting
[Решение проблем](/reference/troubleshooting/) — типичные ошибки
# Примеры кода
> 25+ готовых примеров MCP серверов — копируйте и адаптируйте под свои задачи
Коллекция готовых примеров для копирования и адаптации. Все примеры протестированы и работают с MCP Inspector.
## Базовые примеры
[Заголовок раздела «Базовые примеры»](#базовые-примеры)
### Калькулятор
[Заголовок раздела «Калькулятор»](#калькулятор)
* Python
calculator.py
```python
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("calculator")
@mcp.tool()
def add(a: float, b: float) -> float:
"""Сложение двух чисел"""
return a + b
@mcp.tool()
def subtract(a: float, b: float) -> float:
"""Вычитание: a - b"""
return a - b
@mcp.tool()
def multiply(a: float, b: float) -> float:
"""Умножение двух чисел"""
return a * b
@mcp.tool()
def divide(a: float, b: float) -> float:
"""Деление: a / b"""
if b == 0:
raise ValueError("Деление на ноль невозможно")
return a / b
@mcp.tool()
def power(base: float, exponent: float) -> float:
"""Возведение в степень: base^exponent"""
return base ** exponent
if __name__ == "__main__":
mcp.run(transport="stdio")
```
* TypeScript
calculator.ts
```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new McpServer({ name: "calculator", version: "1.0.0" });
const tools = [
{ name: "add", description: "Сложение", op: (a: number, b: number) => a + b },
{ name: "subtract", description: "Вычитание", op: (a: number, b: number) => a - b },
{ name: "multiply", description: "Умножение", op: (a: number, b: number) => a * b },
{ name: "divide", description: "Деление", op: (a: number, b: number) => {
if (b === 0) throw new Error("Деление на ноль");
return a / b;
}},
];
server.setRequestHandler("tools/list", async () => ({
tools: tools.map(t => ({
name: t.name,
description: t.description,
inputSchema: {
type: "object",
properties: {
a: { type: "number" },
b: { type: "number" }
},
required: ["a", "b"]
}
}))
}));
server.setRequestHandler("tools/call", async (req) => {
const tool = tools.find(t => t.name === req.params.name);
if (!tool) throw new Error(`Unknown tool: ${req.params.name}`);
const { a, b } = req.params.arguments as { a: number; b: number };
const result = tool.op(a, b);
return { content: [{ type: "text", text: String(result) }] };
});
await server.connect(new StdioServerTransport());
```
### Работа с файлами
[Заголовок раздела «Работа с файлами»](#работа-с-файлами)
file\_manager.py
```python
from mcp.server.fastmcp import FastMCP
from pathlib import Path
mcp = FastMCP("file-manager")
# Укажите разрешённую директорию
ALLOWED_DIR = Path("/tmp/mcp-files")
ALLOWED_DIR.mkdir(exist_ok=True)
def safe_path(filename: str) -> Path:
"""Проверка что путь внутри разрешённой директории"""
path = (ALLOWED_DIR / filename).resolve()
if not str(path).startswith(str(ALLOWED_DIR)):
raise ValueError("Доступ запрещён")
return path
@mcp.tool()
def read_file(filename: str) -> str:
"""Прочитать содержимое файла"""
path = safe_path(filename)
if not path.exists():
raise FileNotFoundError(f"Файл не найден: {filename}")
return path.read_text()
@mcp.tool()
def write_file(filename: str, content: str) -> str:
"""Записать содержимое в файл"""
path = safe_path(filename)
path.write_text(content)
return f"Записано {len(content)} символов в {filename}"
@mcp.tool()
def list_files() -> list[str]:
"""Список файлов в директории"""
return [f.name for f in ALLOWED_DIR.iterdir() if f.is_file()]
@mcp.tool()
def delete_file(filename: str) -> str:
"""Удалить файл"""
path = safe_path(filename)
if not path.exists():
raise FileNotFoundError(f"Файл не найден: {filename}")
path.unlink()
return f"Файл {filename} удалён"
if __name__ == "__main__":
mcp.run(transport="stdio")
```
Безопасность
Всегда проверяйте пути файлов! Функция `safe_path` предотвращает path traversal атаки (`../../../etc/passwd`).
## API интеграции
[Заголовок раздела «API интеграции»](#api-интеграции)
### REST API клиент
[Заголовок раздела «REST API клиент»](#rest-api-клиент)
rest\_client.py
```python
from mcp.server.fastmcp import FastMCP
import httpx
mcp = FastMCP("rest-client")
@mcp.tool()
async def http_get(url: str, headers: dict | None = None) -> dict:
"""Выполнить GET запрос к API"""
async with httpx.AsyncClient(timeout=30) as client:
response = await client.get(url, headers=headers or {})
return {
"status": response.status_code,
"headers": dict(response.headers),
"body": response.text[:5000] # Ограничение размера
}
@mcp.tool()
async def http_post(url: str, data: dict, headers: dict | None = None) -> dict:
"""Выполнить POST запрос к API"""
async with httpx.AsyncClient(timeout=30) as client:
response = await client.post(url, json=data, headers=headers or {})
return {
"status": response.status_code,
"body": response.text[:5000]
}
@mcp.tool()
async def fetch_json(url: str) -> dict:
"""Получить JSON с URL"""
async with httpx.AsyncClient(timeout=30) as client:
response = await client.get(url)
response.raise_for_status()
return response.json()
if __name__ == "__main__":
mcp.run(transport="stdio")
```
### Погода (Weather API)
[Заголовок раздела «Погода (Weather API)»](#погода-weather-api)
weather.py
```python
from mcp.server.fastmcp import FastMCP
import httpx
mcp = FastMCP("weather")
NWS_API = "https://api.weather.gov"
HEADERS = {"User-Agent": "mcp-weather/1.0"}
@mcp.tool()
async def get_weather(latitude: float, longitude: float) -> dict:
"""Получить погоду по координатам (только США)"""
async with httpx.AsyncClient() as client:
# Получаем grid point
points = await client.get(
f"{NWS_API}/points/{latitude},{longitude}",
headers=HEADERS
)
points_data = points.json()
# Получаем прогноз
forecast_url = points_data["properties"]["forecast"]
forecast = await client.get(forecast_url, headers=HEADERS)
periods = forecast.json()["properties"]["periods"][:3]
return {
"location": points_data["properties"]["relativeLocation"]["properties"],
"forecast": [
{
"name": p["name"],
"temperature": f"{p['temperature']}°{p['temperatureUnit']}",
"description": p["shortForecast"]
}
for p in periods
]
}
@mcp.tool()
async def get_alerts(state: str) -> list[dict]:
"""Получить погодные предупреждения по штату США"""
async with httpx.AsyncClient() as client:
response = await client.get(
f"{NWS_API}/alerts/active?area={state.upper()}",
headers=HEADERS
)
features = response.json().get("features", [])
return [
{
"event": f["properties"]["event"],
"headline": f["properties"]["headline"],
"severity": f["properties"]["severity"]
}
for f in features[:5]
]
if __name__ == "__main__":
mcp.run(transport="stdio")
```
## Базы данных
[Заголовок раздела «Базы данных»](#базы-данных)
### SQLite
[Заголовок раздела «SQLite»](#sqlite)
sqlite\_server.py
```python
from mcp.server.fastmcp import FastMCP
import sqlite3
from contextlib import contextmanager
mcp = FastMCP("sqlite")
DB_PATH = "data.db"
@contextmanager
def get_db():
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
try:
yield conn
finally:
conn.close()
@mcp.tool()
def init_database() -> str:
"""Инициализировать БД с примером таблицы"""
with get_db() as conn:
conn.execute("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
""")
conn.commit()
return "База данных инициализирована"
@mcp.tool()
def query(sql: str) -> list[dict]:
"""Выполнить SELECT запрос (только чтение!)"""
sql_lower = sql.lower().strip()
if not sql_lower.startswith("select"):
raise ValueError("Разрешены только SELECT запросы")
with get_db() as conn:
cursor = conn.execute(sql)
return [dict(row) for row in cursor.fetchall()]
@mcp.tool()
def insert_user(name: str, email: str) -> dict:
"""Добавить пользователя"""
with get_db() as conn:
cursor = conn.execute(
"INSERT INTO users (name, email) VALUES (?, ?)",
(name, email)
)
conn.commit()
return {"id": cursor.lastrowid, "name": name, "email": email}
@mcp.tool()
def list_users() -> list[dict]:
"""Список всех пользователей"""
return query("SELECT * FROM users ORDER BY created_at DESC")
@mcp.resource("db://schema")
def get_schema() -> str:
"""Схема базы данных"""
with get_db() as conn:
cursor = conn.execute(
"SELECT sql FROM sqlite_master WHERE type='table'"
)
return "\n\n".join(row[0] for row in cursor.fetchall() if row[0])
if __name__ == "__main__":
mcp.run(transport="stdio")
```
### PostgreSQL
[Заголовок раздела «PostgreSQL»](#postgresql)
postgres\_server.py
```python
from mcp.server.fastmcp import FastMCP
import asyncpg
import os
mcp = FastMCP("postgres")
DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://user:pass@localhost/db")
async def get_pool():
return await asyncpg.create_pool(DATABASE_URL, min_size=1, max_size=5)
@mcp.tool()
async def query(sql: str, params: list | None = None) -> list[dict]:
"""Выполнить SQL запрос"""
pool = await get_pool()
async with pool.acquire() as conn:
rows = await conn.fetch(sql, *(params or []))
return [dict(row) for row in rows]
@mcp.tool()
async def execute(sql: str, params: list | None = None) -> str:
"""Выполнить SQL команду (INSERT/UPDATE/DELETE)"""
pool = await get_pool()
async with pool.acquire() as conn:
result = await conn.execute(sql, *(params or []))
return result
@mcp.tool()
async def list_tables() -> list[str]:
"""Список таблиц в БД"""
result = await query("""
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
""")
return [row["table_name"] for row in result]
@mcp.tool()
async def describe_table(table_name: str) -> list[dict]:
"""Описание структуры таблицы"""
return await query("""
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_name = $1
ORDER BY ordinal_position
""", [table_name])
if __name__ == "__main__":
mcp.run(transport="stdio")
```
## Ресурсы и промпты
[Заголовок раздела «Ресурсы и промпты»](#ресурсы-и-промпты)
### Ресурсы (Resources)
[Заголовок раздела «Ресурсы (Resources)»](#ресурсы-resources)
resources\_example.py
```python
from mcp.server.fastmcp import FastMCP
from datetime import datetime
import json
mcp = FastMCP("resources-demo")
# Статический ресурс
@mcp.resource("config://app")
def get_config() -> str:
"""Конфигурация приложения"""
return json.dumps({
"version": "1.0.0",
"environment": "development",
"features": ["tools", "resources", "prompts"]
}, indent=2)
# Динамический ресурс с параметром
@mcp.resource("user://{user_id}")
def get_user(user_id: str) -> str:
"""Информация о пользователе"""
users = {
"1": {"name": "Алиса", "role": "admin"},
"2": {"name": "Борис", "role": "user"},
}
user = users.get(user_id, {"error": "Пользователь не найден"})
return json.dumps(user, ensure_ascii=False)
# Ресурс с текущим временем
@mcp.resource("system://time")
def get_time() -> str:
"""Текущее время сервера"""
return datetime.now().isoformat()
# Ресурс со списком
@mcp.resource("data://products")
def get_products() -> str:
"""Каталог продуктов"""
products = [
{"id": 1, "name": "Ноутбук", "price": 50000},
{"id": 2, "name": "Телефон", "price": 30000},
{"id": 3, "name": "Планшет", "price": 25000},
]
return json.dumps(products, ensure_ascii=False, indent=2)
if __name__ == "__main__":
mcp.run(transport="stdio")
```
### Промпты (Prompts)
[Заголовок раздела «Промпты (Prompts)»](#промпты-prompts)
prompts\_example.py
````python
from mcp.server.fastmcp import FastMCP
from mcp.types import PromptMessage, TextContent
mcp = FastMCP("prompts-demo")
@mcp.prompt()
def code_review(code: str, language: str = "python") -> list[PromptMessage]:
"""Промпт для code review"""
return [
PromptMessage(
role="user",
content=TextContent(
type="text",
text=f"""Проведи code review следующего кода на {language}.
Обрати внимание на:
1. Читаемость и стиль кода
2. Потенциальные баги
3. Производительность
4. Безопасность
5. Предложения по улучшению
Код:
```{language}
{code}
```"""
)
)
]
@mcp.prompt()
def explain_error(error_message: str, context: str = "") -> list[PromptMessage]:
"""Промпт для объяснения ошибки"""
return [
PromptMessage(
role="user",
content=TextContent(
type="text",
text=f"""Объясни эту ошибку простым языком и предложи решение.
Ошибка:
{error_message}
{"Контекст: " + context if context else ""}
Пожалуйста:
1. Объясни что означает эта ошибка
2. Укажи возможные причины
3. Предложи способы исправления"""
)
)
]
@mcp.prompt()
def generate_tests(function_code: str, framework: str = "pytest") -> list[PromptMessage]:
"""Промпт для генерации тестов"""
return [
PromptMessage(
role="user",
content=TextContent(
type="text",
text=f"""Напиши тесты для этой функции используя {framework}.
Функция:
```python
{function_code}
````
Требования:
1. Тесты на основные сценарии
2. Тесты на граничные случаи
3. Тесты на ошибки
4. Понятные названия тестов""" ) ) ]
if **name** == “**main**”: mcp.run(transport=“stdio”)
````plaintext
## Продвинутые примеры
### Контекст и логирование
```python title="context_logging.py"
from mcp.server.fastmcp import FastMCP, Context
from datetime import datetime
mcp = FastMCP("context-demo")
@mcp.tool()
async def long_task(steps: int, ctx: Context) -> str:
"""Задача с отчётом о прогрессе"""
for i in range(steps):
# Отчёт о прогрессе
await ctx.report_progress(i + 1, steps)
# Логирование
await ctx.info(f"Выполнен шаг {i + 1} из {steps}")
# Имитация работы
import asyncio
await asyncio.sleep(0.5)
return f"Выполнено {steps} шагов"
@mcp.tool()
async def get_request_info(ctx: Context) -> dict:
"""Информация о текущем запросе"""
return {
"request_id": ctx.request_id,
"client_id": getattr(ctx, 'client_id', 'unknown'),
"timestamp": datetime.now().isoformat()
}
if __name__ == "__main__":
mcp.run(transport="stdio")
````
### Dependency Injection (Lifespan)
[Заголовок раздела «Dependency Injection (Lifespan)»](#dependency-injection-lifespan)
lifespan\_example.py
```python
from mcp.server.fastmcp import FastMCP
from contextlib import asynccontextmanager
from dataclasses import dataclass
import asyncpg
@dataclass
class AppContext:
db_pool: asyncpg.Pool
@asynccontextmanager
async def app_lifespan(server: FastMCP):
"""Управление жизненным циклом приложения"""
# Startup
pool = await asyncpg.create_pool("postgresql://localhost/mydb")
try:
yield AppContext(db_pool=pool)
finally:
# Shutdown
await pool.close()
mcp = FastMCP("lifespan-demo", lifespan=app_lifespan)
@mcp.tool()
async def db_query(sql: str, ctx: Context) -> list[dict]:
"""Запрос к БД через пул соединений"""
app: AppContext = ctx.request_context.lifespan_context
async with app.db_pool.acquire() as conn:
rows = await conn.fetch(sql)
return [dict(row) for row in rows]
if __name__ == "__main__":
mcp.run(transport="stdio")
```
### Обработка ошибок
[Заголовок раздела «Обработка ошибок»](#обработка-ошибок)
error\_handling.py
```python
from mcp.server.fastmcp import FastMCP
from mcp.server.fastmcp.exceptions import ToolError
mcp = FastMCP("error-demo")
class ValidationError(ToolError):
"""Ошибка валидации"""
pass
class NotFoundError(ToolError):
"""Ресурс не найден"""
pass
@mcp.tool()
def validate_email(email: str) -> dict:
"""Валидация email"""
if not email:
raise ValidationError("Email не может быть пустым")
if "@" not in email:
raise ValidationError("Email должен содержать @")
parts = email.split("@")
if len(parts) != 2 or not parts[1]:
raise ValidationError("Неверный формат email")
return {"email": email, "valid": True}
@mcp.tool()
def get_user(user_id: int) -> dict:
"""Получить пользователя (с обработкой ошибок)"""
users = {1: "Алиса", 2: "Борис"}
if user_id not in users:
raise NotFoundError(f"Пользователь {user_id} не найден")
return {"id": user_id, "name": users[user_id]}
@mcp.tool()
def divide_safe(a: float, b: float) -> float:
"""Безопасное деление"""
try:
return a / b
except ZeroDivisionError:
raise ToolError("Деление на ноль невозможно")
if __name__ == "__main__":
mcp.run(transport="stdio")
```
## Полезные ссылки
[Заголовок раздела «Полезные ссылки»](#полезные-ссылки)
| Ресурс | Описание |
| ------------------------------------------------------------------------ | ---------------------------- |
| [Python SDK](https://github.com/modelcontextprotocol/python-sdk) | Официальный Python SDK |
| [TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk) | Официальный TypeScript SDK |
| [FastMCP Docs](https://gofastmcp.com) | Документация FastMCP |
| [MCP Examples](https://github.com/modelcontextprotocol/servers) | Официальные примеры серверов |
| [awesome-mcp-servers](https://github.com/punkpeye/awesome-mcp-servers) | Коллекция MCP серверов |
# Архитектура MCP
> Техническая спецификация Model Context Protocol — транспорты, примитивы, жизненный цикл
**Model Context Protocol (MCP)** — открытый протокол для интеграции AI-приложений с внешними источниками данных и инструментами. Создан Anthropic в ноябре 2024 года.
## Общая архитектура
[Заголовок раздела «Общая архитектура»](#общая-архитектура)
### Роли
[Заголовок раздела «Роли»](#роли)
| Компонент | Описание | Примеры |
| ---------- | ---------------------------------- | ------------------- |
| **Host** | Приложение, запускающее клиент | Claude Desktop, IDE |
| **Client** | Поддерживает соединение с сервером | Встроен в Host |
| **Server** | Предоставляет capabilities | Ваш MCP сервер |
***
## Транспорты
[Заголовок раздела «Транспорты»](#транспорты)
MCP поддерживает два типа транспорта для коммуникации.
### stdio (Standard I/O)
[Заголовок раздела «stdio (Standard I/O)»](#stdio-standard-io)
Клиент запускает сервер как subprocess и общается через stdin/stdout.
**Когда использовать:**
* Локальная разработка
* Интеграция с Claude Desktop
* Простые сценарии
**Пример запуска:**
```bash
# Клиент запускает сервер
python server.py
# stdin → JSON-RPC запросы
# stdout → JSON-RPC ответы
# stderr → логи (не протокол!)
```
Осторожно
**Важно:** stdout должен содержать ТОЛЬКО JSON-RPC сообщения. Все логи и отладочные сообщения — в stderr!
### Streamable HTTP
[Заголовок раздела «Streamable HTTP»](#streamable-http)
HTTP-транспорт для удалённых серверов (спецификация 2025).
**Когда использовать:**
* Удалённые серверы
* Масштабируемые решения
* Production окружения
**Требования (2025):**
* OAuth 2.1 обязателен для аутентификации
* HTTPS для production
***
## Примитивы MCP
[Заголовок раздела «Примитивы MCP»](#примитивы-mcp)
MCP определяет три основных примитива для взаимодействия.
### Tools (Инструменты)
[Заголовок раздела «Tools (Инструменты)»](#tools-инструменты)
Функции, которые AI может вызывать для выполнения действий.
```python
@mcp.tool()
def send_email(to: str, subject: str, body: str) -> str:
"""Отправить email"""
# Реализация...
return "Email отправлен"
```
**Характеристики:**
* Вызываются по инициативе AI
* Могут изменять состояние
* Возвращают результат
**JSON-RPC:**
```json
// Запрос: tools/call
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "send_email",
"arguments": {
"to": "user@example.com",
"subject": "Hello",
"body": "Message"
}
}
}
// Ответ
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{"type": "text", "text": "Email отправлен"}
]
}
}
```
### Resources (Ресурсы)
[Заголовок раздела «Resources (Ресурсы)»](#resources-ресурсы)
Данные, доступные для чтения по URI.
```python
@mcp.resource("config://settings")
def get_settings() -> str:
"""Настройки приложения"""
return json.dumps({"theme": "dark", "lang": "ru"})
```
**Характеристики:**
* Read-only доступ
* Идентифицируются по URI
* Могут обновляться (подписка)
**Схемы URI:**
| Схема | Пример | Назначение |
| ----------- | ----------------------------- | ------------ |
| `file://` | `file:///path/to/file.txt` | Файлы |
| `http://` | `http://api.example.com/data` | HTTP ресурсы |
| `db://` | `db://users/123` | База данных |
| `memory://` | `memory://cache` | Память |
| `config://` | `config://settings` | Конфигурация |
### Prompts (Промпты)
[Заголовок раздела «Prompts (Промпты)»](#prompts-промпты)
Шаблоны для типовых запросов к AI.
````python
@mcp.prompt()
def code_review(language: str, code: str) -> str:
"""Шаблон для code review"""
return f"""
Проведи code review для следующего {language} кода:
```{language}
{code}
````
Проверь:
1. Ошибки и баги
2. Стиль кода
3. Производительность
4. Безопасность """
````plaintext
**Характеристики:**
- Генерируют текст для AI
- Принимают аргументы
- Упрощают типовые задачи
---
## JSON-RPC 2.0
MCP использует JSON-RPC 2.0 для всей коммуникации.
### Формат запроса
```json
{
"jsonrpc": "2.0",
"id": 1,
"method": "method_name",
"params": { ... }
}
````
### Формат ответа
[Заголовок раздела «Формат ответа»](#формат-ответа)
```json
{
"jsonrpc": "2.0",
"id": 1,
"result": { ... }
}
```
### Формат ошибки
[Заголовок раздела «Формат ошибки»](#формат-ошибки)
```json
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32600,
"message": "Invalid Request",
"data": { ... }
}
}
```
### Уведомления (без ответа)
[Заголовок раздела «Уведомления (без ответа)»](#уведомления-без-ответа)
```json
{
"jsonrpc": "2.0",
"method": "notifications/progress",
"params": {
"progress": 50,
"total": 100
}
}
```
***
## Жизненный цикл соединения
[Заголовок раздела «Жизненный цикл соединения»](#жизненный-цикл-соединения)
### 1. Initialize
[Заголовок раздела «1. Initialize»](#1-initialize)
```json
// Запрос
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"roots": { "listChanged": true }
},
"clientInfo": {
"name": "Claude Desktop",
"version": "1.0.0"
}
}
}
// Ответ
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {},
"resources": { "subscribe": true },
"prompts": {}
},
"serverInfo": {
"name": "my-server",
"version": "1.0.0"
}
}
}
```
### 2. Initialized (уведомление)
[Заголовок раздела «2. Initialized (уведомление)»](#2-initialized-уведомление)
```json
{
"jsonrpc": "2.0",
"method": "notifications/initialized"
}
```
***
## Методы протокола
[Заголовок раздела «Методы протокола»](#методы-протокола)
### Основные методы
[Заголовок раздела «Основные методы»](#основные-методы)
| Метод | Направление | Описание |
| ------------- | --------------- | --------------------------- |
| `initialize` | Client → Server | Инициализация соединения |
| `initialized` | Client → Server | Подтверждение инициализации |
| `shutdown` | Client → Server | Завершение работы |
### Tools
[Заголовок раздела «Tools»](#tools)
| Метод | Описание |
| ------------ | ---------------------------- |
| `tools/list` | Получить список инструментов |
| `tools/call` | Вызвать инструмент |
### Resources
[Заголовок раздела «Resources»](#resources)
| Метод | Описание |
| ----------------------- | ------------------------- |
| `resources/list` | Получить список ресурсов |
| `resources/read` | Прочитать ресурс |
| `resources/subscribe` | Подписаться на обновления |
| `resources/unsubscribe` | Отписаться от обновлений |
### Prompts
[Заголовок раздела «Prompts»](#prompts)
| Метод | Описание |
| -------------- | --------------------------- |
| `prompts/list` | Получить список промптов |
| `prompts/get` | Получить содержимое промпта |
### Уведомления
[Заголовок раздела «Уведомления»](#уведомления)
| Метод | Направление | Описание |
| ---------------------------------- | --------------- | ---------------------- |
| `notifications/progress` | Server → Client | Прогресс операции |
| `notifications/resources/updated` | Server → Client | Ресурс обновился |
| `notifications/tools/list_changed` | Server → Client | Список tools изменился |
***
## Content Types
[Заголовок раздела «Content Types»](#content-types)
MCP поддерживает несколько типов контента в ответах.
### Text
[Заголовок раздела «Text»](#text)
```json
{
"type": "text",
"text": "Результат операции"
}
```
### Image
[Заголовок раздела «Image»](#image)
```json
{
"type": "image",
"data": "base64_encoded_image_data",
"mimeType": "image/png"
}
```
### Resource
[Заголовок раздела «Resource»](#resource)
```json
{
"type": "resource",
"resource": {
"uri": "file:///path/to/file.txt",
"mimeType": "text/plain",
"text": "Содержимое файла"
}
}
```
***
## Коды ошибок
[Заголовок раздела «Коды ошибок»](#коды-ошибок)
### JSON-RPC стандартные
[Заголовок раздела «JSON-RPC стандартные»](#json-rpc-стандартные)
| Код | Название | Описание |
| -------- | ---------------- | -------------------------- |
| `-32700` | Parse error | Невалидный JSON |
| `-32600` | Invalid Request | Неверная структура запроса |
| `-32601` | Method not found | Метод не существует |
| `-32602` | Invalid params | Неверные параметры |
| `-32603` | Internal error | Внутренняя ошибка сервера |
### MCP специфичные
[Заголовок раздела «MCP специфичные»](#mcp-специфичные)
| Код | Название | Описание |
| -------- | ------------------ | -------------------- |
| `-32000` | Connection closed | Соединение закрыто |
| `-32001` | Request timeout | Таймаут запроса |
| `-32002` | Resource not found | Ресурс не найден |
| `-32003` | Tool not found | Инструмент не найден |
| `-32004` | Prompt not found | Промпт не найден |
Совет
Подробнее об ошибках и их решениях см. [Troubleshooting](/reference/troubleshooting/).
***
## Capabilities
[Заголовок раздела «Capabilities»](#capabilities)
При инициализации клиент и сервер обмениваются своими capabilities.
### Server Capabilities
[Заголовок раздела «Server Capabilities»](#server-capabilities)
```json
{
"capabilities": {
"tools": {},
"resources": {
"subscribe": true,
"listChanged": true
},
"prompts": {
"listChanged": true
},
"logging": {}
}
}
```
### Client Capabilities
[Заголовок раздела «Client Capabilities»](#client-capabilities)
```json
{
"capabilities": {
"roots": {
"listChanged": true
},
"sampling": {}
}
}
```
***
## Версии протокола
[Заголовок раздела «Версии протокола»](#версии-протокола)
| Версия | Дата | Основные изменения |
| ------------ | -------- | ----------------------------- |
| `2024-11-05` | Nov 2024 | Первая публичная версия |
| `2025-03-xx` | Mar 2025 | OAuth 2.1 обязателен для HTTP |
| `2025-06-xx` | Jun 2025 | Streamable HTTP вместо SSE |
***
## Ссылки
[Заголовок раздела «Ссылки»](#ссылки)
Спецификация MCP
[modelcontextprotocol.io](https://modelcontextprotocol.io/specification) — официальная документация
JSON-RPC 2.0
[jsonrpc.org](https://www.jsonrpc.org/specification) — спецификация протокола
Быстрый старт
[5 минут](/reference/quickstart/) — создайте первый сервер
Примеры кода
[25+ примеров](/reference/examples/) — готовый код
# Быстрый старт
> Запустите первый MCP сервер за 5 минут — пошаговое руководство для начинающих
Это руководство поможет вам создать и запустить первый MCP сервер за **5 минут**. Выберите ваш язык программирования и следуйте инструкциям.
## Что вы создадите
[Заголовок раздела «Что вы создадите»](#что-вы-создадите)
Простой MCP сервер с двумя инструментами:
* `add` — сложение двух чисел
* `greet` — приветствие по имени
- Python
1. **Создайте папку проекта**
```bash
mkdir my-mcp-server && cd my-mcp-server
```
2. **Установите зависимости**
```bash
pip install mcp
```
3. **Создайте файл `server.py`**
```python
from mcp.server.fastmcp import FastMCP
# Создаём сервер
mcp = FastMCP("my-first-server")
@mcp.tool()
def add(a: int, b: int) -> int:
"""Сложить два числа"""
return a + b
@mcp.tool()
def greet(name: str) -> str:
"""Поприветствовать по имени"""
return f"Привет, {name}!"
@mcp.resource("info://about")
def get_about() -> str:
"""Информация о сервере"""
return "Мой первый MCP сервер!"
if __name__ == "__main__":
mcp.run(transport="stdio")
```
4. **Запустите сервер**
```bash
python server.py
```
5. **Протестируйте с MCP Inspector**
```bash
npx @modelcontextprotocol/inspector python server.py
```
Откройте в браузере.
- TypeScript
1. **Создайте папку проекта**
```bash
mkdir my-mcp-server && cd my-mcp-server
npm init -y
```
2. **Установите зависимости**
```bash
npm install @modelcontextprotocol/sdk
npm install -D typescript ts-node @types/node
```
3. **Создайте файл `server.ts`**
```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
ListToolsRequestSchema,
CallToolRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
const server = new McpServer({
name: "my-first-server",
version: "1.0.0",
});
// Регистрируем инструменты
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "add",
description: "Сложить два числа",
inputSchema: {
type: "object" as const,
properties: {
a: { type: "number", description: "Первое число" },
b: { type: "number", description: "Второе число" },
},
required: ["a", "b"],
},
},
{
name: "greet",
description: "Поприветствовать по имени",
inputSchema: {
type: "object" as const,
properties: {
name: { type: "string", description: "Имя" },
},
required: ["name"],
},
},
],
}));
// Обрабатываем вызовы
server.setRequestHandler(CallToolRequestSchema, async (request) => {
switch (request.params.name) {
case "add": {
const a = request.params.arguments?.a as number;
const b = request.params.arguments?.b as number;
return { content: [{ type: "text", text: String(a + b) }] };
}
case "greet": {
const name = request.params.arguments?.name as string;
return { content: [{ type: "text", text: `Привет, ${name}!` }] };
}
default:
throw new Error(`Unknown tool: ${request.params.name}`);
}
});
// Запускаем сервер
const transport = new StdioServerTransport();
await server.connect(transport);
```
4. **Добавьте скрипт в `package.json`**
```json
{
"type": "module",
"scripts": {
"start": "ts-node server.ts"
}
}
```
5. **Запустите и протестируйте**
```bash
npx @modelcontextprotocol/inspector npm start
```
- Go
1. **Создайте проект**
```bash
mkdir my-mcp-server && cd my-mcp-server
go mod init my-mcp-server
go get github.com/mark3labs/mcp-go
```
2. **Создайте файл `main.go`**
```go
package main
import (
"context"
"fmt"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)
func main() {
s := server.NewMCPServer(
"my-first-server",
"1.0.0",
)
// Инструмент сложения
addTool := mcp.NewTool("add",
mcp.WithDescription("Сложить два числа"),
mcp.WithNumber("a", mcp.Required(), mcp.Description("Первое число")),
mcp.WithNumber("b", mcp.Required(), mcp.Description("Второе число")),
)
s.AddTool(addTool, func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
a := req.Params.Arguments["a"].(float64)
b := req.Params.Arguments["b"].(float64)
return mcp.NewToolResultText(fmt.Sprintf("%.0f", a+b)), nil
})
// Инструмент приветствия
greetTool := mcp.NewTool("greet",
mcp.WithDescription("Поприветствовать по имени"),
mcp.WithString("name", mcp.Required(), mcp.Description("Имя")),
)
s.AddTool(greetTool, func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
name := req.Params.Arguments["name"].(string)
return mcp.NewToolResultText(fmt.Sprintf("Привет, %s!", name)), nil
})
// Запуск
if err := server.ServeStdio(s); err != nil {
panic(err)
}
}
```
3. **Запустите**
```bash
go run main.go
```
4. **Протестируйте**
```bash
npx @modelcontextprotocol/inspector go run main.go
```
## Что происходит при запуске
[Заголовок раздела «Что происходит при запуске»](#что-происходит-при-запуске)
## Проверка работы
[Заголовок раздела «Проверка работы»](#проверка-работы)
После запуска MCP Inspector:
1. Откройте
2. Нажмите **Connect**
3. Перейдите в раздел **Tools**
4. Выберите инструмент `add`
5. Введите параметры: `a = 5`, `b = 3`
6. Нажмите **Call Tool**
7. Результат: `8`
Совет
MCP Inspector — ваш лучший друг при разработке! Используйте его для отладки перед интеграцией с Claude.
## Следующие шаги
[Заголовок раздела «Следующие шаги»](#следующие-шаги)
Примеры кода
[25+ готовых примеров](/reference/examples/) для разных задач
Инструменты
[MCP Inspector и CLI](/reference/tools/) — полное руководство
Настройка клиентов
[Claude Desktop, VS Code, Cursor](/reference/clients/)
Production Checklist
[14 пунктов](/reference/checklist/) перед деплоем
## Частые вопросы новичков
[Заголовок раздела «Частые вопросы новичков»](#частые-вопросы-новичков)
### Что такое `stdio` транспорт?
[Заголовок раздела «Что такое stdio транспорт?»](#что-такое-stdio-транспорт)
Stdio (standard input/output) — способ коммуникации через stdin/stdout. Клиент запускает ваш сервер как subprocess и общается через потоки ввода/вывода. Это самый простой и надёжный способ для локальной разработки.
### Почему `npx` перед командой?
[Заголовок раздела «Почему npx перед командой?»](#почему-npx-перед-командой)
`npx @modelcontextprotocol/inspector` запускает MCP Inspector без установки. Inspector — это веб-интерфейс для тестирования вашего сервера.
### Как добавить свой инструмент?
[Заголовок раздела «Как добавить свой инструмент?»](#как-добавить-свой-инструмент)
В Python (FastMCP):
```python
@mcp.tool()
def my_tool(param1: str, param2: int = 10) -> str:
"""Описание инструмента (будет видно в Claude)"""
return f"Результат: {param1}, {param2}"
```
Описание в docstring автоматически становится description инструмента.
### Как подключить к Claude Desktop?
[Заголовок раздела «Как подключить к Claude Desktop?»](#как-подключить-к-claude-desktop)
См. раздел [Настройка клиентов](/reference/clients/) — там пошаговые инструкции для всех платформ.
# Инструменты разработчика
> MCP Inspector, CLI и инструменты отладки для разработки MCP серверов
## MCP Inspector
[Заголовок раздела «MCP Inspector»](#mcp-inspector)
**MCP Inspector** — официальный веб-интерфейс для тестирования и отладки MCP серверов. Позволяет интерактивно вызывать tools, читать resources и тестировать prompts.
### Быстрый запуск
[Заголовок раздела «Быстрый запуск»](#быстрый-запуск)
```bash
npx @modelcontextprotocol/inspector <команда_запуска_сервера>
```
* Python
```bash
npx @modelcontextprotocol/inspector python server.py
```
* TypeScript
```bash
npx @modelcontextprotocol/inspector npm run start
```
* Go
```bash
npx @modelcontextprotocol/inspector go run main.go
```
* Docker
```bash
npx @modelcontextprotocol/inspector docker run -i my-mcp-server
```
После запуска откройте **** в браузере.
### Порты Inspector
[Заголовок раздела «Порты Inspector»](#порты-inspector)
| Порт | Назначение |
| ------ | ------------------------ |
| `6274` | Веб-интерфейс Inspector |
| `6277` | Внутренний proxy для MCP |
Смена портов
Если порты заняты, используйте переменные окружения:
```bash
CLIENT_PORT=8080 SERVER_PORT=8081 npx @modelcontextprotocol/inspector python server.py
```
### Интерфейс Inspector
[Заголовок раздела «Интерфейс Inspector»](#интерфейс-inspector)
### Вкладки Inspector
[Заголовок раздела «Вкладки Inspector»](#вкладки-inspector)
#### Tools
[Заголовок раздела «Tools»](#tools)
* Список всех зарегистрированных инструментов
* Форма для ввода параметров
* Кнопка вызова и отображение результата
#### Resources
[Заголовок раздела «Resources»](#resources)
* Список доступных ресурсов (URI)
* Чтение содержимого ресурса
* Подписка на обновления
#### Prompts
[Заголовок раздела «Prompts»](#prompts)
* Список prompt-шаблонов
* Заполнение аргументов
* Получение сформированного промпта
#### Logs
[Заголовок раздела «Logs»](#logs)
* JSON-RPC сообщения в реальном времени
* Ошибки и предупреждения
* Debugging информация
### CLI режим Inspector
[Заголовок раздела «CLI режим Inspector»](#cli-режим-inspector)
Inspector можно использовать без веб-интерфейса:
```bash
# Только проверка подключения
npx @modelcontextprotocol/inspector --cli python server.py
# Вызов конкретного tool
echo '{"method":"tools/call","params":{"name":"add","arguments":{"a":5,"b":3}}}' | \
npx @modelcontextprotocol/inspector --cli python server.py
```
***
## mcp CLI (Python)
[Заголовок раздела «mcp CLI (Python)»](#mcp-cli-python)
Пакет `mcp` включает CLI для разработки:
### Установка
[Заголовок раздела «Установка»](#установка)
```bash
pip install mcp
```
### Команды
[Заголовок раздела «Команды»](#команды)
```bash
# Запуск сервера
mcp run server.py
# Запуск с отладкой
mcp run server.py --debug
# Информация о сервере
mcp info server.py
```
### Пример вывода `mcp info`
[Заголовок раздела «Пример вывода mcp info»](#пример-вывода-mcp-info)
```plaintext
Server: my-first-server
Version: 1.0.0
Tools (2):
- add: Сложить два числа
- greet: Поприветствовать по имени
Resources (1):
- info://about
Prompts (0):
(none)
```
***
## Отладка и логирование
[Заголовок раздела «Отладка и логирование»](#отладка-и-логирование)
### Логирование в stderr
[Заголовок раздела «Логирование в stderr»](#логирование-в-stderr)
Важно!
MCP использует stdout для JSON-RPC коммуникации. **Все логи должны идти в stderr**, иначе сервер сломается!
* Python
```python
import sys
import logging
# Настройка логгера на stderr
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
stream=sys.stderr # Важно!
)
logger = logging.getLogger(__name__)
@mcp.tool()
def my_tool(param: str) -> str:
logger.debug(f"Вызван my_tool с param={param}")
return f"Результат: {param}"
```
* TypeScript
```typescript
// Логирование в stderr
function log(message: string) {
process.stderr.write(`[DEBUG] ${new Date().toISOString()} ${message}\n`);
}
// Использование
server.setRequestHandler(CallToolRequestSchema, async (request) => {
log(`Tool called: ${request.params.name}`);
// ...
});
```
* Go
```go
import (
"log"
"os"
)
func init() {
// Логи в stderr
log.SetOutput(os.Stderr)
}
func main() {
log.Println("Server starting...")
// ...
}
```
### Уровни логирования
[Заголовок раздела «Уровни логирования»](#уровни-логирования)
```python
import logging
# Для разработки
logging.basicConfig(level=logging.DEBUG, stream=sys.stderr)
# Для production
logging.basicConfig(level=logging.WARNING, stream=sys.stderr)
```
| Уровень | Когда использовать |
| ---------- | -------------------------------------- |
| `DEBUG` | Детальная информация для отладки |
| `INFO` | Подтверждение нормальной работы |
| `WARNING` | Потенциальные проблемы |
| `ERROR` | Ошибки, сервер продолжает работать |
| `CRITICAL` | Критические ошибки, сервер остановится |
***
## Тестирование серверов
[Заголовок раздела «Тестирование серверов»](#тестирование-серверов)
### Unit-тесты (Python)
[Заголовок раздела «Unit-тесты (Python)»](#unit-тесты-python)
```python
import pytest
from mcp.server.fastmcp import FastMCP
# Создаём тестовый сервер
mcp = FastMCP("test-server")
@mcp.tool()
def add(a: int, b: int) -> int:
"""Сложить два числа"""
return a + b
@mcp.tool()
def divide(a: float, b: float) -> float:
"""Разделить a на b"""
if b == 0:
raise ValueError("Деление на ноль")
return a / b
# Тесты
class TestTools:
def test_add(self):
result = add(5, 3)
assert result == 8
def test_add_negative(self):
result = add(-5, 3)
assert result == -2
def test_divide(self):
result = divide(10, 2)
assert result == 5.0
def test_divide_by_zero(self):
with pytest.raises(ValueError, match="Деление на ноль"):
divide(10, 0)
```
### Integration-тесты (TypeScript)
[Заголовок раздела «Integration-тесты (TypeScript)»](#integration-тесты-typescript)
```typescript
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import { spawn, ChildProcess } from 'child_process';
describe('MCP Server Integration', () => {
let serverProcess: ChildProcess;
beforeAll(async () => {
serverProcess = spawn('npm', ['run', 'start'], {
stdio: ['pipe', 'pipe', 'pipe']
});
// Ждём запуска
await new Promise(resolve => setTimeout(resolve, 1000));
});
afterAll(() => {
serverProcess.kill();
});
it('should respond to initialize', async () => {
const request = JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'initialize',
params: {
protocolVersion: '2024-11-05',
capabilities: {},
clientInfo: { name: 'test', version: '1.0.0' }
}
});
serverProcess.stdin!.write(request + '\n');
const response = await new Promise(resolve => {
serverProcess.stdout!.once('data', data => resolve(data.toString()));
});
const parsed = JSON.parse(response);
expect(parsed.result).toBeDefined();
expect(parsed.result.serverInfo).toBeDefined();
});
});
```
### Запуск тестов
[Заголовок раздела «Запуск тестов»](#запуск-тестов)
```bash
# Python
pytest tests/ -v
# TypeScript
npm test
# С coverage
pytest tests/ --cov=src --cov-report=html
npm test -- --coverage
```
***
## JSON-RPC отладка
[Заголовок раздела «JSON-RPC отладка»](#json-rpc-отладка)
### Ручное тестирование через stdin
[Заголовок раздела «Ручное тестирование через stdin»](#ручное-тестирование-через-stdin)
```bash
# Запустите сервер
python server.py
# В другом терминале отправьте запрос
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | python server.py
```
### Пример JSON-RPC диалога
[Заголовок раздела «Пример JSON-RPC диалога»](#пример-json-rpc-диалога)
```json
// Запрос: initialize
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{
"protocolVersion":"2024-11-05",
"capabilities":{},
"clientInfo":{"name":"test","version":"1.0"}
}}
// Ответ
{"jsonrpc":"2.0","id":1,"result":{
"protocolVersion":"2024-11-05",
"serverInfo":{"name":"my-server","version":"1.0.0"},
"capabilities":{"tools":{}}
}}
// Запрос: tools/list
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}
// Ответ
{"jsonrpc":"2.0","id":2,"result":{"tools":[
{"name":"add","description":"Сложить два числа","inputSchema":{...}}
]}}
// Запрос: tools/call
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{
"name":"add",
"arguments":{"a":5,"b":3}
}}
// Ответ
{"jsonrpc":"2.0","id":3,"result":{
"content":[{"type":"text","text":"8"}]
}}
```
***
## Полезные скрипты
[Заголовок раздела «Полезные скрипты»](#полезные-скрипты)
### Скрипт проверки здоровья сервера
[Заголовок раздела «Скрипт проверки здоровья сервера»](#скрипт-проверки-здоровья-сервера)
```python
#!/usr/bin/env python3
"""health_check.py - Проверка работоспособности MCP сервера"""
import subprocess
import json
import sys
def check_server(command: list[str]) -> bool:
"""Проверяет, что сервер отвечает на initialize"""
init_request = json.dumps({
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {"name": "health-check", "version": "1.0"}
}
}) + "\n"
try:
result = subprocess.run(
command,
input=init_request,
capture_output=True,
text=True,
timeout=5
)
response = json.loads(result.stdout.strip())
if "result" in response and "serverInfo" in response["result"]:
print(f"✅ Server OK: {response['result']['serverInfo']}")
return True
else:
print(f"❌ Invalid response: {response}")
return False
except subprocess.TimeoutExpired:
print("❌ Server timeout")
return False
except json.JSONDecodeError as e:
print(f"❌ Invalid JSON: {e}")
return False
except Exception as e:
print(f"❌ Error: {e}")
return False
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python health_check.py ")
print("Example: python health_check.py python server.py")
sys.exit(1)
command = sys.argv[1:]
success = check_server(command)
sys.exit(0 if success else 1)
```
### Использование
[Заголовок раздела «Использование»](#использование)
```bash
# Проверка Python сервера
python health_check.py python server.py
# Проверка Docker контейнера
python health_check.py docker run -i my-mcp-server
# В CI/CD
python health_check.py python server.py && echo "Deploy OK"
```
***
## Docker для разработки
[Заголовок раздела «Docker для разработки»](#docker-для-разработки)
### docker-compose для отладки
[Заголовок раздела «docker-compose для отладки»](#docker-compose-для-отладки)
docker-compose.dev.yml
```yaml
version: '3.8'
services:
mcp-server:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- .:/app
- /app/node_modules # Для Node.js
environment:
- DEBUG=1
- LOG_LEVEL=debug
stdin_open: true
tty: true
inspector:
image: node:20
command: npx @modelcontextprotocol/inspector nc mcp-server 3000
ports:
- "6274:6274"
depends_on:
- mcp-server
```
### Dockerfile.dev (Python)
[Заголовок раздела «Dockerfile.dev (Python)»](#dockerfiledev-python)
```dockerfile
FROM python:3.11-slim
WORKDIR /app
# Установка зависимостей для hot-reload
RUN pip install watchdog
COPY requirements.txt .
RUN pip install -r requirements.txt
# Копируем код
COPY . .
# Hot-reload с watchmedo
CMD ["watchmedo", "auto-restart", "--patterns=*.py", "--recursive", "--", "python", "server.py"]
```
***
## Ссылки
[Заголовок раздела «Ссылки»](#ссылки)
MCP Inspector
[GitHub репозиторий](https://github.com/modelcontextprotocol/inspector) — исходный код и документация
Python SDK
[mcp на PyPI](https://pypi.org/project/mcp/) — включает CLI инструменты
Troubleshooting
[Решение проблем](/reference/troubleshooting/) — типичные ошибки и их решения
Production Checklist
[Чеклист](/reference/checklist/) — подготовка к production
# Решение проблем
> Типичные ошибки MCP серверов и их решения — коды ошибок, отладка, FAQ
## Коды ошибок JSON-RPC
[Заголовок раздела «Коды ошибок JSON-RPC»](#коды-ошибок-json-rpc)
MCP использует стандартные коды ошибок JSON-RPC 2.0 плюс специфичные для протокола.
### Стандартные ошибки JSON-RPC
[Заголовок раздела «Стандартные ошибки JSON-RPC»](#стандартные-ошибки-json-rpc)
| Код | Название | Описание |
| -------- | ---------------- | -------------------------------- |
| `-32700` | Parse error | Невалидный JSON |
| `-32600` | Invalid Request | Запрос не соответствует JSON-RPC |
| `-32601` | Method not found | Метод не существует |
| `-32602` | Invalid params | Неверные параметры |
| `-32603` | Internal error | Внутренняя ошибка сервера |
### Ошибки MCP
[Заголовок раздела «Ошибки MCP»](#ошибки-mcp)
| Код | Название | Описание |
| -------- | ------------------ | --------------------------------------- |
| `-32000` | Connection closed | Соединение закрыто (часто из-за stdout) |
| `-32001` | Request timeout | Таймаут запроса |
| `-32002` | Resource not found | Ресурс не найден |
| `-32003` | Tool not found | Инструмент не найден |
| `-32004` | Prompt not found | Промпт не найден |
***
## Ошибка -32000: Connection closed
[Заголовок раздела «Ошибка -32000: Connection closed»](#ошибка--32000-connection-closed)
**Симптомы:** Сервер запускается, но сразу отключается. В логах: “Connection closed unexpectedly”.
**Причина:** Вывод в stdout нарушает JSON-RPC протокол.
### Решение
[Заголовок раздела «Решение»](#решение)
* Python
```python
import sys
import logging
# ❌ НЕПРАВИЛЬНО
print("Debug message") # Ломает JSON-RPC!
# ✅ ПРАВИЛЬНО
logging.basicConfig(stream=sys.stderr, level=logging.DEBUG)
logger = logging.getLogger(__name__)
logger.debug("Debug message")
# Или напрямую
print("Debug message", file=sys.stderr)
```
* TypeScript
```typescript
// ❌ НЕПРАВИЛЬНО
console.log("Debug message"); // Идёт в stdout!
// ✅ ПРАВИЛЬНО
console.error("Debug message"); // Идёт в stderr
// Или создайте helper
function log(msg: string) {
process.stderr.write(`[DEBUG] ${msg}\n`);
}
```
* Go
```go
import (
"log"
"os"
)
// ❌ НЕПРАВИЛЬНО
fmt.Println("Debug message")
// ✅ ПРАВИЛЬНО
log.SetOutput(os.Stderr)
log.Println("Debug message")
```
Золотое правило
**stdout** = только JSON-RPC сообщения **stderr** = логи, отладка, ошибки
***
## Ошибка -32002: Resource not found
[Заголовок раздела «Ошибка -32002: Resource not found»](#ошибка--32002-resource-not-found)
**Симптомы:** `{"error": {"code": -32002, "message": "Resource not found: xxx"}}`
**Причина:** Клиент запрашивает ресурс, который не зарегистрирован на сервере.
### Решение
[Заголовок раздела «Решение»](#решение-1)
1. Проверьте, что ресурс зарегистрирован:
```python
@mcp.resource("config://settings") # Точный URI
def get_settings():
return {"theme": "dark"}
```
2. Проверьте URI — он должен точно совпадать:
```python
# ❌ Зарегистрировано
@mcp.resource("config://settings")
# ❌ Запрашивается (не совпадает)
# "config://setting" — нет 's' в конце
# "config:/settings" — одна косая черта
# "settings" — нет схемы
# ✅ Правильный запрос
# "config://settings"
```
3. Проверьте список ресурсов в MCP Inspector:
* Откройте вкладку Resources
* Убедитесь, что нужный ресурс есть в списке
***
## Ошибка -32003: Tool not found
[Заголовок раздела «Ошибка -32003: Tool not found»](#ошибка--32003-tool-not-found)
**Симптомы:** `{"error": {"code": -32003, "message": "Tool not found: xxx"}}`
### Решение
[Заголовок раздела «Решение»](#решение-2)
1. Проверьте регистрацию инструмента:
```python
@mcp.tool() # Декоратор обязателен
def my_tool(param: str) -> str:
"""Описание инструмента"""
return f"Result: {param}"
```
2. Проверьте имя инструмента:
```python
# Имя берётся из имени функции
@mcp.tool()
def calculate_sum(a: int, b: int) -> int: # Имя: "calculate_sum"
return a + b
# Или можно задать явно
@mcp.tool(name="sum") # Имя: "sum"
def calculate_sum(a: int, b: int) -> int:
return a + b
```
3. Перезапустите сервер после изменений
***
## Tools не видны в Claude Desktop
[Заголовок раздела «Tools не видны в Claude Desktop»](#tools-не-видны-в-claude-desktop)
**Симптомы:** Сервер запускается, но инструменты не появляются в списке.
### Чеклист
[Заголовок раздела «Чеклист»](#чеклист)
1. **Проверьте конфигурацию**
```bash
# macOS
cat ~/Library/Application\ Support/Claude/claude_desktop_config.json
```
JSON должен быть валидным (проверьте запятые и кавычки).
2. **Проверьте пути** Используйте абсолютные пути:
```json
{
"mcpServers": {
"my-server": {
"command": "/usr/bin/python3",
"args": ["/Users/me/project/server.py"]
}
}
}
```
3. **Проверьте запуск вручную**
```bash
python /Users/me/project/server.py
```
Если есть ошибки — исправьте их.
4. **Проверьте логи Claude**
```bash
# macOS
tail -f ~/Library/Logs/Claude/mcp*.log
```
5. **Полностью перезапустите Claude**
* Закройте все окна
* Cmd+Q (macOS) или завершите процесс
* Запустите заново
### Типичные ошибки конфигурации
[Заголовок раздела «Типичные ошибки конфигурации»](#типичные-ошибки-конфигурации)
```json
// ❌ Неправильно: относительный путь
{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["server.py"]
}
}
}
// ✅ Правильно: абсолютный путь
{
"mcpServers": {
"my-server": {
"command": "/usr/bin/python3",
"args": ["/Users/me/project/server.py"]
}
}
}
```
```json
// ❌ Неправильно: лишняя запятая
{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["server.py"], // <-- Лишняя запятая!
}
}
}
// ✅ Правильно
{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["server.py"]
}
}
}
```
***
## Ошибки подключения к базе данных
[Заголовок раздела «Ошибки подключения к базе данных»](#ошибки-подключения-к-базе-данных)
### PostgreSQL
[Заголовок раздела «PostgreSQL»](#postgresql)
```plaintext
Error: connection refused
Error: password authentication failed
Error: database "xxx" does not exist
```
**Решения:**
```python
import os
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("db-server")
# 1. Проверьте DATABASE_URL
DATABASE_URL = os.getenv("DATABASE_URL")
if not DATABASE_URL:
raise ValueError("DATABASE_URL не установлена")
# 2. Проверьте формат URL
# postgresql://user:password@host:port/database
# postgresql://postgres:secret@localhost:5432/mydb
# 3. Используйте connection pool
import asyncpg
pool = None
@mcp.tool()
async def query_db(sql: str) -> str:
global pool
if pool is None:
pool = await asyncpg.create_pool(DATABASE_URL)
async with pool.acquire() as conn:
result = await conn.fetch(sql)
return str(result)
```
### SQLite
[Заголовок раздела «SQLite»](#sqlite)
```plaintext
Error: unable to open database file
Error: database is locked
```
**Решения:**
```python
import sqlite3
import os
# 1. Проверьте путь к файлу
db_path = "/path/to/database.db"
if not os.path.exists(db_path):
raise FileNotFoundError(f"БД не найдена: {db_path}")
# 2. Используйте правильные флаги
conn = sqlite3.connect(
db_path,
check_same_thread=False, # Для многопоточности
timeout=30.0 # Таймаут блокировки
)
# 3. Для read-only доступа
conn = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
```
***
## Ошибки с виртуальным окружением Python
[Заголовок раздела «Ошибки с виртуальным окружением Python»](#ошибки-с-виртуальным-окружением-python)
**Симптомы:** `ModuleNotFoundError: No module named 'mcp'`
### Решение
[Заголовок раздела «Решение»](#решение-3)
```json
{
"mcpServers": {
"my-server": {
"command": "/path/to/venv/bin/python",
"args": ["/path/to/server.py"]
}
}
}
```
Или используйте `uvx`:
```json
{
"mcpServers": {
"my-server": {
"command": "uvx",
"args": ["--from", "mcp", "mcp", "run", "server.py"]
}
}
}
```
***
## Ошибки TypeScript
[Заголовок раздела «Ошибки TypeScript»](#ошибки-typescript)
### ”Cannot find module"
[Заголовок раздела «”Cannot find module"»](#cannot-find-module)
```bash
# Скомпилируйте TypeScript
npx tsc
# Или используйте ts-node
npm install -D ts-node typescript @types/node
```
```json
{
"mcpServers": {
"my-server": {
"command": "npx",
"args": ["ts-node", "/path/to/server.ts"]
}
}
}
```
### "Top-level await”
[Заголовок раздела «"Top-level await”»](#top-level-await)
tsconfig.json
```json
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "Node",
"target": "ES2022"
}
}
```
package.json
```json
{
"type": "module"
}
```
***
## Таймауты и производительность
[Заголовок раздела «Таймауты и производительность»](#таймауты-и-производительность)
### Симптомы
[Заголовок раздела «Симптомы»](#симптомы)
* Инструменты работают медленно
* `Request timeout` ошибки
* Claude “зависает” при вызове tool
### Решения
[Заголовок раздела «Решения»](#решения)
1. **Добавьте прогресс-уведомления:**
```python
@mcp.tool()
async def long_operation(data: str) -> str:
"""Долгая операция"""
# Уведомляем о прогрессе
await mcp.request_context.session.send_progress(
progress=0, total=100, message="Начинаю обработку..."
)
# Делаем работу
result = await process_data(data)
await mcp.request_context.session.send_progress(
progress=100, total=100, message="Готово!"
)
return result
```
2. **Используйте асинхронные операции:**
```python
import asyncio
import aiohttp
@mcp.tool()
async def fetch_data(url: str) -> str:
"""Получить данные из URL"""
async with aiohttp.ClientSession() as session:
async with session.get(url, timeout=30) as response:
return await response.text()
```
3. **Ограничьте размер ответа:**
```python
@mcp.tool()
def get_file(path: str) -> str:
"""Читает файл (макс 100KB)"""
MAX_SIZE = 100 * 1024
with open(path, 'r') as f:
content = f.read(MAX_SIZE)
if len(content) == MAX_SIZE:
content += "\n... (файл обрезан)"
return content
```
***
## Отладка с MCP Inspector
[Заголовок раздела «Отладка с MCP Inspector»](#отладка-с-mcp-inspector)
### Запуск Inspector
[Заголовок раздела «Запуск Inspector»](#запуск-inspector)
```bash
npx @modelcontextprotocol/inspector python server.py
```
### Что проверять
[Заголовок раздела «Что проверять»](#что-проверять)
1. **Вкладка Tools** — все инструменты должны быть в списке
2. **Вызовите tool** — проверьте, что возвращается результат
3. **Вкладка Logs** — смотрите JSON-RPC сообщения
### CLI режим для автоматизации
[Заголовок раздела «CLI режим для автоматизации»](#cli-режим-для-автоматизации)
```bash
# Проверка initialize
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' | python server.py
# Список tools
echo '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' | python server.py
```
***
## FAQ
[Заголовок раздела «FAQ»](#faq)
### Как узнать версию MCP SDK?
[Заголовок раздела «Как узнать версию MCP SDK?»](#как-узнать-версию-mcp-sdk)
```bash
# Python
pip show mcp
# Node.js
npm list @modelcontextprotocol/sdk
```
### Как обновить SDK?
[Заголовок раздела «Как обновить SDK?»](#как-обновить-sdk)
```bash
# Python
pip install --upgrade mcp
# Node.js
npm update @modelcontextprotocol/sdk
```
### Можно ли использовать несколько серверов одновременно?
[Заголовок раздела «Можно ли использовать несколько серверов одновременно?»](#можно-ли-использовать-несколько-серверов-одновременно)
Да, добавьте несколько записей в `mcpServers`:
```json
{
"mcpServers": {
"server1": { "command": "python", "args": ["server1.py"] },
"server2": { "command": "python", "args": ["server2.py"] }
}
}
```
### Как передать секреты?
[Заголовок раздела «Как передать секреты?»](#как-передать-секреты)
Используйте переменные окружения:
```json
{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["server.py"],
"env": {
"API_KEY": "xxx",
"DATABASE_URL": "postgresql://..."
}
}
}
}
```
### Где хранятся логи?
[Заголовок раздела «Где хранятся логи?»](#где-хранятся-логи)
| Клиент | Логи |
| ------------------------ | -------------------------------- |
| Claude Desktop (macOS) | `~/Library/Logs/Claude/mcp*.log` |
| Claude Desktop (Windows) | `%APPDATA%\Claude\logs\` |
| VS Code | View → Output → MCP |
| Cursor | Developer Tools → Console |
***
## Полезные ссылки
[Заголовок раздела «Полезные ссылки»](#полезные-ссылки)
MCP Inspector
[Инструменты разработчика](/reference/tools/) — подробнее о Inspector
Production Checklist
[Чеклист](/reference/checklist/) — подготовка к production
Примеры кода
[25+ примеров](/reference/examples/) — работающий код
Настройка клиентов
[Клиенты](/reference/clients/) — Claude, VS Code, Cursor
# C# SDK (.NET)
> Создание MCP серверов на C# с официальным Microsoft SDK
Официальный C# SDK обеспечивает полную интеграцию MCP протокола с .NET экосистемой, включая ASP.NET Core и dependency injection с атрибутами для регистрации.
## Установка
[Заголовок раздела «Установка»](#установка)
* Official SDK
Terminal
```bash
dotnet add package ModelContextProtocol
```
* McpDotNet
Terminal
```bash
dotnet add package McpDotNet
```
**Требования:**
* .NET 8.0+
* Visual Studio 2022 или VS Code
## Базовый сервер
[Заголовок раздела «Базовый сервер»](#базовый-сервер)
Program.cs
```csharp
using ModelContextProtocol;
using ModelContextProtocol.Server;
var builder = McpServerBuilder.Create("my-server", "1.0.0");
builder.WithDescription("MCP сервер на C#");
var server = builder.Build();
await server.RunStdioAsync();
```
## Инструменты (Tools)
[Заголовок раздела «Инструменты (Tools)»](#инструменты-tools)
### Базовый инструмент
[Заголовок раздела «Базовый инструмент»](#базовый-инструмент)
Tools/CalculatorTools.cs
```csharp
using ModelContextProtocol.Server;
using System.ComponentModel;
[McpServerToolType] // Атрибут класса для автоматического обнаружения
public class CalculatorTools
{
[McpServerTool("add"), Description("Сложение двух чисел")]
public static double Add(double a, double b)
{
return a + b;
}
[McpServerTool("divide"), Description("Деление чисел")]
public static double Divide(double a, double b)
{
if (b == 0)
throw new McpException(McpErrorCode.InvalidParams, "Деление на ноль");
return a / b;
}
}
```
### Регистрация инструментов
[Заголовок раздела «Регистрация инструментов»](#регистрация-инструментов)
Program.cs
```csharp
var builder = McpServerBuilder.Create("calculator", "1.0.0");
builder.AddTools();
var server = builder.Build();
await server.RunStdioAsync();
```
### Async инструмент
[Заголовок раздела «Async инструмент»](#async-инструмент)
Tools/HttpTools.cs
```csharp
public class HttpTools
{
private readonly HttpClient _client;
public HttpTools(HttpClient client)
{
_client = client;
}
[McpTool("fetch_url", "Загрузка содержимого URL")]
public async Task FetchUrlAsync(
[McpParameter("URL для загрузки")] string url)
{
var response = await _client.GetAsync(url);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
```
### Инструмент с файловой системой
[Заголовок раздела «Инструмент с файловой системой»](#инструмент-с-файловой-системой)
Tools/FileTools.cs
```csharp
public class FileTools
{
private readonly string _allowedPath;
public FileTools(IConfiguration config)
{
_allowedPath = config["AllowedPath"] ?? "/allowed";
}
[McpTool("read_file", "Чтение файла")]
public async Task ReadFileAsync(
[McpParameter("Путь к файлу")] string path)
{
var fullPath = Path.GetFullPath(path);
if (!fullPath.StartsWith(_allowedPath))
throw new McpException(McpErrorCode.Forbidden, "Доступ запрещён");
if (!File.Exists(fullPath))
throw new McpException(McpErrorCode.NotFound, $"Файл не найден: {path}");
return await File.ReadAllTextAsync(fullPath);
}
[McpTool("list_files", "Список файлов в директории")]
public string[] ListFiles(
[McpParameter("Путь к директории")] string path,
[McpParameter("Паттерн поиска", Required = false)] string? pattern = "*")
{
var fullPath = Path.GetFullPath(path);
if (!fullPath.StartsWith(_allowedPath))
throw new McpException(McpErrorCode.Forbidden, "Доступ запрещён");
return Directory.GetFiles(fullPath, pattern ?? "*")
.Select(Path.GetFileName)
.ToArray()!;
}
}
```
### Инструмент с базой данных
[Заголовок раздела «Инструмент с базой данных»](#инструмент-с-базой-данных)
Tools/DatabaseTools.cs
```csharp
using Microsoft.EntityFrameworkCore;
public class DatabaseTools
{
private readonly AppDbContext _db;
public DatabaseTools(AppDbContext db)
{
_db = db;
}
[McpTool("get_users", "Получение списка пользователей")]
public async Task