Если Claude / GPT / Cursor умеет только чат, но не может ходить в БД, читать файлы или вызывать API — проблема не в длине prompt, а в отсутствии переиспользуемого tool layer. Этот материал для backend- и fullstack-разработчиков: от Hello World до ChromaDB knowledge-base MCP Server, с разбором Tools / Resources / Prompts, транспортов stdio и HTTP+SSE, отладки, тестов и Docker production deploy. В конце у вас будут кастомные tools, вызываемые из Cursor, и понимание, как держать Server на выделенном удалённом Mac 7×24 (протокольный контекст — в разборе MCP).
Training cutoff у LLM фиксирован; CRM, Git-репозитории и internal API недоступны из weights. До 2024 для Claude писали Function Calling, для GPT — Plugins, для Cursor — отдельный формат: смена модели = переписывание adapter layer с нуля. MCP Server инкапсулирует tool capability в изолированный процесс — один раз написали, используете в Claude Desktop / Cursor / Gemini.
Типовые сценарии: SQL-запрос к Postgres из Claude Desktop; Cursor Agent читает project docs и правит код; GPT дергает ticketing system через HTTP MCP — под капотом один и тот же Server process.
Что даёт гайд: не теорию ради теории, а путь от say_hello до production-grade knowledge-base Server с vector retrieval. Целевая аудитория: разработчики с базой Python или TypeScript, расширяющие AI в IDE или Desktop host.
Vendor lock-in: OpenAI Function Calling и Claude Tool Use — разные JSON Schema и lifecycle; каждая смена вендора требует нового adapter.
Tools не discoverable: REST живёт в static docs; runtime tools/list для автономного discovery capability отсутствует.
IDE silos: Cursor, VS Code extensions и JetBrains plugins описывают tools по-разному — N×M интеграций вместо одного Server.
Context/data split: LLM не может стабильно читать config, user prefs или live logs — нужен standardized read-only channel через Resources.
Prompt templates разбросаны: code review, incident postmortem — нет единого registry; команды копируют шаблоны вручную.
Local vs remote deploy chaos: stdio subprocess подходит для dev, но production HTTP gateway, auth и monitoring без общего паттерна (см. гайд по stdio subprocess governance).
«Подключить MCP Server к AI — как поставить IDE-плагин программисту: capability boundary смещается от chat к операциям над реальным миром.»
Эволюция: Function Calling (2023) → ChatGPT Plugins → MCP (ноябрь 2024, Anthropic open source). MCP задуман как «USB-C» между AI и external world: Host (Cursor / Claude Desktop) встраивает MCP Client и открывает 1:1 session с вашим MCP Server.
Transport layer — JSON-RPC 2.0: initialize → tools/list / tools/call → resources/read. Два lifecycle транспорта:
Полная спецификация: modelcontextprotocol.io.
| Измерение | MCP | OpenAI Function Calling | LangChain Tools |
|---|---|---|---|
| Открытость | Cross-vendor протокол, governance AAIF | Привязка к OpenAI API | Framework abstraction, не transport standard |
| Discovery | Runtime tools/list | Inline functions array в request | Code registration, нет standard discovery |
| Read-only data | Resources + URI scheme | Нет first-class аналога | Retriever concept, не protocol-level |
| Prompt templates | Prompts standard interface | Нет | PromptTemplate class |
| Transport | stdio / HTTP+SSE / Streamable HTTP | HTTPS API bundled | Зависит от Agent runtime |
| Reusability | Один Server для Cursor + Claude + Gemini | Только OpenAI ecosystem | Cross-framework — rewrite bindings |
Два основных стека: Python mcp + FastMCP (data/script, быстрый prototype) и TypeScript @modelcontextprotocol/sdk (Web/API integration, compile-time type safety). SDK repos: python-sdk, typescript-sdk.
# Python stack python -m venv .venv && source .venv/bin/activate pip install "mcp[cli]" httpx pydantic # TypeScript stack npm init -y && npm install @modelcontextprotocol/sdk zod npm install -D typescript tsx @types/node
my-mcp-server/ ├── pyproject.toml # или package.json ├── src/ │ ├── server.py # FastMCP entrypoint │ ├── tools/ # tool modules │ ├── resources/ # Resource providers │ └── prompts/ # Prompt templates ├── tests/ │ └── test_tools.py # pytest + ClientSession ├── Dockerfile └── README.md
Выбор стека: data/ML — Python; Node fullstack — TypeScript.
Virtual env + lock dependencies: pip freeze или package-lock.json — иначе schema drift между dev и prod.
MCP Inspector: npx @modelcontextprotocol/inspector — visual debug JSON-RPC frames.
Claude Desktop config: правка ~/Library/Application Support/Claude/claude_desktop_config.json, добавление command/args Server.
Cursor config: Settings → MCP → Add Server; для stdio — python -m src.server или absolute path к interpreter.
Verify Inspector: запуск Server → connect Inspector → tools/list возвращает non-empty list.
// Cursor / Claude Desktop MCP config
{
"mcpServers": {
"my-tools": {
"command": "python",
"args": ["-m", "src.server"],
"env": { "API_KEY": "your-key" }
}
}
}
FastMCP + tool say_hello — проверка полного pipeline: code → Inspector → Cursor handshake.
# src/server.py
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("hello-server")
@mcp.tool()
def say_hello(name: str = "World") -> str:
"""Приветствие по имени"""
return f"Hello, {name}! MCP is working"
if __name__ == "__main__":
mcp.run() # default stdio transport
# Debug через Inspector npx @modelcontextprotocol/inspector python -m src.server # Прямой stdio launch python -m src.server
После добавления того же command в Cursor попросите Agent: «вызови say_hello для NodeMini». JSON result в ответе означает успешный Client ↔ Server handshake по JSON-RPC.
Примечание: FastMCP генерирует JSON Schema из docstring и type hints — ручное описание параметров не требуется.
Tools — core capability MCP: AI выполняет side-effect operations через tools/call. Каждый Tool экспонирует name, description, inputSchema; FastMCP валидирует через Pydantic models.
from pydantic import BaseModel, Field
class SearchInput(BaseModel):
query: str = Field(..., description="Поисковый запрос")
limit: int = Field(10, ge=1, le=100, description="Число результатов")
@mcp.tool()
async def search_docs(params: SearchInput) -> str:
"""Поиск по документам"""
results = await index.search(params.query, params.limit)
return json.dumps(results, ensure_ascii=False)
ast.literal_eval; exec запрещён.import httpx
from datetime import datetime, timezone
@mcp.tool()
async def fetch_url(url: str) -> str:
"""HTTP GET (domain whitelist)"""
allowed = ("api.github.com", "nodemini.com")
if not any(url.startswith(f"https://{d}") for d in allowed):
raise ValueError(f"Domain not allowed: {url}")
async with httpx.AsyncClient(timeout=10.0) as client:
resp = await client.get(url)
resp.raise_for_status()
return resp.text[:8000]
@mcp.tool()
def get_current_time() -> str:
"""Текущее UTC время"""
return datetime.now(timezone.utc).isoformat()
raise ValueError("human-readable msg") — Client передаёт message обратно в LLM context.retryable; permission denied — fail fast.idempotency_key — защита от duplicate Agent calls.Tool vs Resource: Tool имеет side effects и вызывается AI; Resource — read-only context, который Host inject до диалога или AI тянет через resources/read. URI schemes кастомные: config://, user://, file://.
@mcp.resource("config://app/settings")
def app_settings() -> str:
"""Static app config (text/plain)"""
return open("config/settings.json").read()
@mcp.resource("user://{user_id}/profile")
def user_profile(user_id: str) -> str:
"""Dynamic user profile (application/json)"""
return json.dumps(get_user(user_id))
| MIME type | Назначение | Пример |
|---|---|---|
| text/plain | Logs, README | file://logs/app.log |
| application/json | Config, API response | config://env |
| application/octet-stream | Binary (base64) | PDF summary |
| text/event-stream | Live subscription | Log tail, metrics stream |
Filesystem Resource Server pattern: resources/list сканирует директории, resources/read читает по URI, resources/subscribe через watchfiles push updates — expose codebase docs для Cursor Agent без ручного copy-paste.
MCP Prompt — conversation skeleton, зарегистрированный на Server. Client получает message list через prompts/get с ролями user / assistant и parameter placeholders — team-wide code review и incident workflow без per-user prompt files.
from mcp.types import PromptMessage, TextContent
@mcp.prompt()
def code_review_prompt(language: str = "python") -> list[PromptMessage]:
"""Стандартный Code Review template"""
return [
PromptMessage(role="user", content=TextContent(
type="text",
text=f"Ты senior {language} engineer. Проверь diff по security, performance, readability."
)),
PromptMessage(role="assistant", content=TextContent(
type="text",
text="Вставь diff или укажи PR — выдам structured review по CHECKLIST."
)),
]
Variables ({ticket_id}, {severity}) versionируются на Server; upgrade Server у Client = вся команда на актуальном review standard.
| Измерение | stdio | HTTP + SSE / Streamable HTTP |
|---|---|---|
| Deploy | Local subprocess, Host-spawned | Standalone service, URL connect |
| Scale | Single machine, horizontal scale затруднён | Load balancer, multiple replicas |
| Auth | Host env vars | Bearer Token / API Key / mTLS |
| Debug | Inspector direct | curl + SSE client |
| Best for | Personal dev, local Cursor | Team sharing, SaaS integration |
# Streamable HTTP (FastMCP 2026)
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("prod-server", host="0.0.0.0", port=8080)
# ... register tools ...
if __name__ == "__main__":
mcp.run(transport="streamable-http")
Production must-haves: Bearer Token middleware, CORS whitelist (только Host domains), rate limit (например 100 req/min/IP), HTTPS termination на reverse proxy. Remote gateway ops — в гайде по HTTP gateway governance.
Внимание: HTTP MCP без auth на public internet — в 2026 по-прежнему массовая проблема (unauthorized exposed Servers). Обязательны auth и IP restrictions.
MCP Inspector — official visual debugger: connect через stdio или URL, manual tools/list / tools/call, inspect JSON-RPC round trips — на порядок быстрее, чем reverse-engineering Cursor logs.
# tests/test_tools.py
import pytest
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
@pytest.mark.asyncio
async def test_say_hello():
params = StdioServerParameters(command="python", args=["-m", "src.server"])
async with stdio_client(params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
result = await session.call_tool("say_hello", {"name": "MCP"})
assert "MCP" in result.content[0].text
| Симптом | Причина | Fix |
|---|---|---|
| Server exit сразу после start | stdout polluted print() | Logs в stderr; stdout только JSON-RPC |
| tools/list пустой | Decorator не registered / import order | @mcp.tool() до run() |
| Cursor disconnected | Wrong command path / venv не active | Absolute paths; full python path в config |
| JSON-RPC parse error | Non-JSON на stdio | Disable debug banner; log level WARNING+ |
FROM python:3.12-slim WORKDIR /app COPY pyproject.toml . RUN pip install --no-cache-dir . COPY src/ src/ EXPOSE 8080 HEALTHCHECK CMD curl -f http://localhost:8080/health || exit 1 CMD ["python", "-m", "src.server", "--transport", "streamable-http"]
Platform selection: Railway / Render — быстрая validation; AWS ECS / GCP Cloud Run — enterprise compliance; VPS + Docker Compose — минимальная стоимость, self-managed patching.
protocolVersion в initialize — Server декларирует compatible range./metrics (tool QPS, P99 latency); Sentry для unhandled exceptions; /health для K8s liveness.Vectorize internal Wiki / Markdown и expose index_document, search_knowledge, write_note — Cursor Agent сначала ищет в company knowledge base, затем пишет код с grounded context.
Requirements: incremental indexing (watchfiles на docs/), semantic search Top-K, optional scratchpad writes.
import chromadb
from chromadb.utils.embedding_functions import SentenceTransformerEmbeddingFunction
client = chromadb.PersistentClient(path="./data/chroma")
collection = client.get_or_create_collection(
"wiki", embedding_function=SentenceTransformerEmbeddingFunction()
)
@mcp.tool()
def search_knowledge(query: str, top_k: int = 5) -> str:
"""Semantic search по internal KB"""
hits = collection.query(query_texts=[query], n_results=top_k)
return json.dumps(hits["documents"][0], ensure_ascii=False)
@mcp.tool()
def index_document(path: str) -> str:
"""Index одного Markdown файла"""
text = open(path).read()
collection.upsert(ids=[path], documents=[text], metadatas=[{"path": path}])
return f"Indexed: {path}"
Cursor demo query: «найди в knowledge base документы про MCP HTTP deploy и сформулируй three-step launch checklist» — Agent вызывает search_knowledge, затем отвечает по retrieved context. На большем scale vector store заменяют на Qdrant (remote gRPC).
Official и community Servers уже покрывают типовые задачи — не обязательно писать всё с нуля:
Тренды 2026: MCP Marketplace, OAuth 2.1 tool authorization в spec roadmap, Streamable HTTP постепенно заменяет pure SSE. Learning path: ① spec → ② Hello World → ③ три Tool → ④ Resource → ⑤ pytest → ⑥ Docker → ⑦ Cursor.
От say_hello до ChromaDB knowledge base — full-stack MCP Server: Tools execution, Resources context, Prompts templates, dual transport, testing, production ops. Следующий шаг: fork community Server или wrap company API в team-standard tool layer.
Local stdio подходит для экспериментов, но несколько параллельных Server, persistent vector index и HTTP long connections быстро упирают 16GB laptop в swap. Дешёвый Linux VPS не тянет macOS-only toolchains (Xcode, codesign). Self-built HTTP gateway без session affinity и auth даёт connection leaks и unauthorized exposure — long-term stability редко совпадает с ожиданиями.
Командам, для которых MCP — production infrastructure плюс Cursor Agent и iOS/macOS CI, размещение MCP Server на выделенном cloud Mac 7×24 обычно предсказуемее, чем local laptop или generic VM. NodeMini Mac Mini cloud rental — execution layer для MCP + Agent: SSH node и Server config не меняются при смене underlying LLM. Спецификации — тарифы аренды, onboarding — Help Center.
Python FastMCP — fastest path для data/script tools; TypeScript SDK — type safety и seamless Node integration. Протокол полностью совместим. Для нескольких Server 7×24 см. тарифы аренды remote Mac.
Function Calling привязан к OpenAI; MCP — open protocol для Claude/GPT/Gemini/Cursor с Resources и Prompts. Контекст — в разборе MCP.
Лёгкий stdio — локально; несколько Server + vector store + HTTP long connections — выделенный remote Mac. Onboarding: Help Center; ops — гайд по stdio subprocess governance.