MCP Server с нуля: полное руководство по разработке AI-инструментов (2026)

Если вы хотите, чтобы Claude, GPT или Cursor запрашивали вашу БД, вызывали API или искали в локальных заметках—but каждой модели нужен свой адаптер—you попадаете в ту же N×M стену интеграции, которую MCP призван убрать. Этот практический гид для backend- и AI-разработчиков с базой Python или TypeScript. К концу вы соберёте, отладите и задеployите продакшен-ready MCP Server с Tools, Resources, Prompts, HTTP-транспортом, проектом базы знаний и пятиступенчатым Mac cloud Runbook.

Диаграмма рабочей станции разработчика: MCP Server соединяет AI-клиентов с внешними инструментами, базами данных и файловыми ресурсами

Содержание

1. Введение: зачем AI нужны внешние инструменты

LLM — мощные текстовые движки, но слепы к вашим live-системам: training cutoffs блокируют realtime-данные, и модели не могут выполнять side effects без Tool Use. Вы хотите ассистента, который читает Markdown vault, выполняет SQL или бьёт во внутренние API—без переписывания интеграций при каждом переходе с Claude на GPT или с Cursor на другую IDE.

Три ключевые боли до MCP

  1. Фрагментированная проводка tools. OpenAI Function Calling, Claude Tool Use и LangChain Tools определяют схемы по-разному—N моделей × M tools = N×M адаптеров.
  2. Нет runtime discovery. REST endpoints в статичных docs; AI не может вызвать tools/list, чтобы узнать доступное mid-session.
  3. Зависимость от локального Host. Cursor и Claude Desktop запускают STDIO подпроцессы на macOS; Linux VPS или закрытый ноутбук рвут цепочку.

Model Context Protocol (MCP) стандартизирует, как Hosts обнаруживают и вызывают Tools, читают Resources и загружают Prompt templates через JSON-RPC 2.0. Этот туториал ведёт от нуля к deployable Server—not только теория. За протокольным «почему MCP — HTTP эры AI» см. наш глубокий разбор протокола MCP.

2. Что такое MCP? Протокол до кода

Anthropic open-sourced MCP в ноябре 2024. Он стоит между AI Clients (Claude Desktop, Cursor, custom apps) и Server, который вы строите—с тремя типами capabilities:

┌────────────────────┐ ┌─────────────────────┐ │ MCP Client │ ◄─────► │ MCP Server │ │ (Claude / Cursor) │ JSON │ (вы строите это) │ │ │ -RPC │ │ └────────────────────┘ └─────────────────────┘ │ ┌─────────────┼─────────────┐ ▼ ▼ ▼ Tools Resources Prompts (действия) (чтение данных) (шаблоны)

Lifecycle: initialize handshake → capability negotiation → request/response → graceful shutdown. Транспорты: STDIO (локальный подпроцесс) или HTTP + SSE / streamable HTTP (remote).

MCP vs Function Calling vs LangChain Tools

ИзмерениеMCPOpenAI Function CallingLangChain Tools
СтандартизацияОткрытый протоколVendor-specificFramework-bound
ТранспортSTDIO / HTTPТолько HTTPТолько HTTP
Cross-modelДаНетЧастично
Resources / PromptsНативноНе поддерживаетсяНе поддерживается
Runtime discoverytools/listСтатическая schemaСтатическая schema

3. Настройка окружения

Выбор языка

Python (рекомендуется для этого гида): официальный SDK mcp с FastMCP decorators. TypeScript: @modelcontextprotocol/sdk для Node-native команд.

# Python python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate pip install "mcp[cli]" httpx pydantic # TypeScript (reference) npm init -y npm install @modelcontextprotocol/sdk

Структура проекта

my-mcp-server/ ├── server.py # entry point ├── tools/ │ ├── calculator.py │ ├── files.py │ ├── http_client.py │ ├── database.py │ └── datetime_tools.py ├── resources/ │ └── file_reader.py ├── prompts/ │ └── templates.py ├── tests/ │ └── test_tools.py ├── pyproject.toml └── README.md

Инструменты отладки

4. Hello World: ваш первый MCP Server

from mcp.server.fastmcp import FastMCP mcp = FastMCP("my-first-server") @mcp.tool() def say_hello(name: str) -> str: """Greet a person by name.""" return f"Hello, {name}! This is your first MCP tool." if __name__ == "__main__": mcp.run()

Запуск и inspect:

python server.py npx @modelcontextprotocol/inspector python server.py

Подключение в Cursor (.cursor/mcp.json):

{ "mcpServers": { "my-first-server": { "command": "python", "args": ["/absolute/path/to/server.py"], "env": {} } } }

Перезапустите Cursor, откройте MCP settings и убедитесь, что say_hello в списке tools.

5. Tools: пять практических примеров

Tools — это действия. Сигнатуры функций плюс docstrings становятся JSON Schema для модели. Pydantic models для сложных inputs.

Tool 1 — Калькулятор

import ast import operator @mcp.tool() def calculate(expression: str) -> str: """Safely evaluate a math expression like '2 + 2 * 3'.""" ops = { ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul, ast.Div: operator.truediv, } def _eval(node): if isinstance(node, ast.Num): return node.n if isinstance(node, ast.BinOp): return ops[type(node.op)](_eval(node.left), _eval(node.right)) raise ValueError("Unsupported expression") return str(_eval(ast.parse(expression, mode="eval").body))

Tool 2 — Чтение/запись файлов

from pathlib import Path ALLOWED = Path("/data/notes").resolve() @mcp.tool() def read_file(path: str) -> str: """Read a text file under the allowed directory.""" target = (ALLOWED / path).resolve() if not str(target).startswith(str(ALLOWED)): raise PermissionError("Path outside allowed root") return target.read_text(encoding="utf-8") @mcp.tool() def write_file(path: str, content: str) -> str: """Write text to a file under the allowed directory.""" target = (ALLOWED / path).resolve() if not str(target).startswith(str(ALLOWED)): raise PermissionError("Path outside allowed root") target.parent.mkdir(parents=True, exist_ok=True) target.write_text(content, encoding="utf-8") return f"Wrote {len(content)} bytes to {path}"

Tool 3 — HTTP запрос (async)

import httpx @mcp.tool() async def fetch_url(url: str, timeout: int = 10) -> str: """GET a URL and return response text (truncated to 8 KB).""" async with httpx.AsyncClient(timeout=timeout) as client: r = await client.get(url) r.raise_for_status() return r.text[:8192]

Tool 4 — Запрос к БД

import sqlite3 @mcp.tool() def query_sql(sql: str) -> list[dict]: """Run a read-only SELECT against the app SQLite database.""" if not sql.strip().upper().startswith("SELECT"): raise ValueError("Only SELECT queries allowed") conn = sqlite3.connect("app.db") conn.row_factory = sqlite3.Row rows = conn.execute(sql).fetchall() conn.close() return [dict(r) for r in rows]

Tool 5 — Время и timezone

from datetime import datetime from zoneinfo import ZoneInfo @mcp.tool() def now_in_timezone(tz: str = "UTC") -> str: """Return current time in an IANA timezone (e.g. America/New_York).""" return datetime.now(ZoneInfo(tz)).isoformat()

Best practices: возвращайте JSON-serializable типы; structured error strings вместо голых stack traces; timeouts на network и DB calls; валидируйте paths и SQL против injection.

6. Resources: динамический контент для AI

Resources поставляют данные; Tools выполняют действия. MCP адресует их по URI.

import json @mcp.resource("config://app-settings") def get_app_settings() -> str: """Return application configuration as JSON.""" return json.dumps({"version": "1.0.0", "env": "production"}) @mcp.resource("user://{user_id}/profile") def get_user_profile(user_id: str) -> str: """Return a user profile by ID.""" user = db.lookup(user_id) # your data layer return json.dumps(user)

Mime types: text/plain, application/json или binary для PDFs/images. Для filesystem Server expose directory listings и file contents как Resources, чтобы модель читала context без мутации state через Tools.

7. Prompts: библиотека переиспользуемых шаблонов

Prompts упаковывают multi-turn templates с параметрами—полезно для code review, incident triage или interview prep.

from mcp.types import PromptMessage, TextContent @mcp.prompt() def code_review_prompt(language: str, code: str) -> list[PromptMessage]: """Structured code review template.""" return [ PromptMessage( role="user", content=TextContent( type="text", text=f"""Review this {language} code for: 1. Readability and structure 2. Bugs and security issues 3. Performance improvements ```{language} {code} ```""" ) ) ]

Hosts вызывают prompts/list и prompts/get для inject consistent instructions—меньше prompt drift между sessions.

8. HTTP-транспорт: удалённые MCP Server

ХарактеристикаSTDIOHTTP + SSE / streamable HTTP
ДеплойЛокальный подпроцессRemote server
ЛатентностьОчень низкаяЗависит от сети
Multi-clientОдин Host processМного clients
Лучше дляCursor, Claude DesktopTeam SaaS, shared tools
from mcp.server.fastmcp import FastMCP mcp = FastMCP("remote-server", host="0.0.0.0", port=8000) # Auth middleware в продакшене: # - Bearer Token header validation # - API key per tenant # - CORS allowlist для web clients # - Rate limiting (e.g. 100 req/min) if __name__ == "__main__": mcp.run(transport="streamable-http")

Nginx или cloud load balancer спереди для TLS termination. Никогда не expose unauthenticated MCP HTTP endpoint в публичный internet.

9. Отладка и тесты

Workflow MCP Inspector

  1. Старт: npx @modelcontextprotocol/inspector python server.py
  2. Вызвать tools/list и проверить schemas
  3. Invoke каждый Tool с edge-case inputs
  4. Inspect JSON-RPC request/response pairs в UI

Пример автоматизированного теста

import pytest from mcp.client.session import ClientSession from mcp.client.stdio import StdioServerParameters, stdio_client @pytest.mark.asyncio async def test_calculator(): params = StdioServerParameters(command="python", args=["server.py"]) async with stdio_client(params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() result = await session.call_tool( "calculate", {"expression": "2 + 2"} ) assert "4" in result.content[0].text

Частые ошибки

ОшибкаПричинаИсправление
Tool missing в HostНеверный path в mcp.jsonAbsolute paths; restart Host
JSON serialize failureNon-serializable returnReturn str или dict
Timeout disconnectSlow sync ToolMake async; add timeout
Permission deniedPath outside allowlistConfigure allowed roots

10. Продакшен-деploy

Пятиступенчатый продакшен Runbook

Шаг 1 — Containerize

FROM python:3.12-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8000 HEALTHCHECK CMD curl -f http://localhost:8000/health || exit 1 CMD ["python", "server.py"]

Шаг 2 — Transport и authentication

Enable streamable HTTP; require Bearer Token или API Key на каждый request; restrict CORS к known Host origins.

Шаг 3 — Test before ship

Run MCP Inspector plus pytest suite; record tools/call p95 latency baselines.

Шаг 4 — Observability

Structured JSON logs, Prometheus counters per tool name, Sentry для unhandled exceptions, /health endpoint для orchestrators.

Шаг 5 — Host на durable infrastructure

Для STDIO workflows с Cursor используйте launchd на always-on Mac node с CPU и memory limits. Для HTTP mode deploy на Railway, Render, Cloud Run или за Nginx на VPS—with TLS и auth enforced.

Declare MCP protocol version в initialize responses и version Tools carefully, чтобы не ломать existing Clients.

11. Проект: MCP Server личной базы знаний

Цель: Cursor отвечает «Что я писал про MCP на прошлой неделе?» через поиск локальных Markdown notes.

Stack

Core Tools

@mcp.tool() def index_notes(directory: str) -> str: """Scan Markdown files and rebuild the vector index.""" count = indexer.rebuild(directory) return f"Indexed {count} documents" @mcp.tool() def semantic_search(query: str, top_k: int = 5) -> list[dict]: """Search notes by meaning; return title, path, and snippet.""" return vector_store.search(query, k=top_k) @mcp.tool() def create_note(title: str, content: str) -> str: """Create a new Markdown note and index it.""" path = vault.create(title, content) indexer.add(path) return str(path)

Expose vault files как Resources (note://{slug}) для read-only preview. В Cursor задавайте natural-language questions; модель вызывает semantic_search и цитирует snippets из vault.

12. Перспективы экосистемы MCP

К середине 2026 MCP поддерживается в Claude Desktop, Cursor, VS Code Copilot extensions, OpenAI Responses API tooling и растущем marketplace. Reference Servers для изучения:

Enterprise adoption движет auth standards (OAuth 2.1, scoped API keys) и audited Server registries. Next steps: read spec на modelcontextprotocol.io, publish Server на GitHub, combine MCP с Agent orchestration frameworks.

13. Проверяемые факты для цитирования (2026-06-16)

14. Заключение: от туториала к production-grade MCP

У вас полный путь: protocol mental model, Python SDK setup, пять Tools, Resources, Prompts, HTTP mode, Inspector testing, Docker packaging и knowledge-base reference project. Running entirely на local laptop works для demos—but lid-close sleep kills STDIO sessions, path и permission quirks multiply across teammates, и Linux VPS или Docker-only stacks cannot host native Cursor/Claude Desktop subprocesses или Apple toolchain sidecars без painful workarounds.

Для stable, auditable, 7×24 MCP Server, которые Cursor и Claude Desktop reach reliably, deploy на dedicated VPSMAC M4 Mac cloud node: bare-metal macOS, launchd KeepAlive, SSH in minutes, pin-able Python environments, room для HTTP gateways plus STDIO side-by-side. Это production-grade 2026 path—more controllable чем betting on primary machine staying awake, и far simpler чем forcing macOS Host workflows onto Linux VPS.