первыйБитБИТ.АГЕНТЫ/туториал

MCP — Model Context Protocol

Глава 10 из 12

AnthropicOpen StandardNov 2024

Зачем MCP?

До MCP каждый разработчик агентов писал собственные интеграции: для GitHub — свой REST-клиент, для Slack — свой, для базы данных — свой. Сотни инструментов — сотни способов подключения, авторизации, обработки ошибок.

Model Context Protocol (MCP) — открытый стандарт от Anthropic, представленный в ноябре 2024 года. Он определяет единый протокол для подключения LLM-агентов к внешним инструментам, данным и ресурсам. Аналог USB-C, но для AI: один раз реализовал сервер — работает с любым MCP-совместимым агентом.

Архитектура: Client ↔ Server

MCP построен по модели клиент — сервер поверх JSON-RPC 2.0:

  LLM-агент                    MCP-сервер (инструменты)
 ┌──────────┐                 ┌──────────────────┐
 │  Agent    │                 │  filesystem      │
 │  (LLM)    │                 │  github          │
 │           │                 │  postgres        │
 │ MCP       │  JSON-RPC 2.0   │  slack           │
 │ Client ───┼────────────────>│  MCP Server      │
 │           │  stdio / HTTP   │                  │
 └──────────┘                 └──────────────────┘

   listTools()       →  [read_file, list_files, ...]
   callTool(name)    →  { content: [...] }
   listResources()   →  [db://schema, file://...]
   readResource(uri) →  { contents: [...] }
   listPrompts()     →  [code-review, summarize]

MCP-клиент живёт внутри агента и посредничает между LLM и серверами. Один агент может подключаться к нескольким MCP-серверам одновременно.

Три примитива MCP

Tools

Функции, которые LLM может вызвать. Аналог function calling, но через стандартизированный протокол.

Resources

Данные по URI. Агент читает схему БД, конфигурацию, документацию — как файлы, но через протокол.

Prompts

Шаблоны промптов на стороне сервера. Переиспользуемые инструкции, которые агент загружает при необходимости.

mcp-primitives.ts
// Три примитива MCP

// 1. Tools — функции, которые LLM может вызвать
//    (аналог function calling, но через протокол)
server.tool("send_email", "Отправляет email", {
  to: z.string(),
  subject: z.string(),
  body: z.string()
}, async (args) => {
  await sendEmail(args)
  return { content: [{ type: "text", text: "Отправлено" }] }
})

// 2. Resources — данные, которые агент может прочитать
//    (статические или динамические, по URI)
server.resource("schema", "db://users/schema", async (uri) => ({
  contents: [{
    uri: uri.href,
    mimeType: "application/json",
    text: JSON.stringify(usersSchema)
  }]
}))

// 3. Prompts — шаблоны промптов, переиспользуемые
//    (агент может загрузить готовый промпт с сервера)
server.prompt("code-review", async () => ({
  messages: [{
    role: "user",
    content: { type: "text", text: "Проверь код на ошибки и уязвимости..." }
  }]
}))

MCP vs Function Calling vs A2A

Function CallingMCPA2A
Что соединяетLLM → локальная функцияАгент → инструменты/данныеАгент → Агент
СтандартЗависит от провайдера LLMОткрытый протоколОткрытый протокол
DiscoveryЗахардкожено в кодеlistTools() в рантаймеAgent Card по URL
ТранспортВызов функции в процессеstdio / HTTP+SSEHTTP/REST, gRPC, JSON-RPC
Где живёт инструментВ коде агентаВ отдельном процессе/сервереВ другом агенте

Function calling — механизм LLM. MCP — протокол доставки инструментов к агенту. A2A — протокол общения между агентами. Все три уровня совместимы и дополняют друг друга.

Транспорты

MCP поддерживает два транспорта. Выбор зависит от того, где живёт сервер:

stdio

Для локальных серверов. Агент запускает MCP-сервер как подпроцесс, общение идёт через stdin/stdout. Просто, безопасно, без сети.

Streamable HTTP

Для удалённых серверов. JSON-RPC поверх HTTP POST, уведомления — через SSE-стрим. Подходит для облачных сервисов и SaaS.

mcp-transports.ts
// Два транспорта MCP

// 1. stdio — для локальных серверов (CLI-инструменты, скрипты)
import { StdioServerTransport } from ".../stdio.js"
const transport = new StdioServerTransport()
// ↓ JSON-RPC сообщения идут через stdin/stdout процесса

// 2. Streamable HTTP — для удалённых серверов (веб-сервисы)
import { StreamableHTTPServerTransport } from ".../streamableHttp.js"
const transport = new StreamableHTTPServerTransport({
  sessionIdGenerator: () => crypto.randomUUID(),
})
// ↓ JSON-RPC сообщения идут через HTTP POST + SSE
//   Клиент: POST /mcp → ответ
//   Сервер: SSE-стрим для уведомлений

MCP-сервер (TypeScript)

Минимальный MCP-сервер на официальном TypeScript SDK. Регистрирует инструменты через server.tool() с Zod-схемой параметров:

filesystem-server.ts
// MCP Server на TypeScript SDK
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
import { z } from "zod"

const server = new McpServer({
  name: "filesystem-server",
  version: "1.0.0",
})

// Tool: читать файл
server.tool(
  "read_file",
  "Читает содержимое файла по пути",
  { path: z.string().describe("Абсолютный путь к файлу") },
  async ({ path }) => {
    const content = await fs.readFile(path, "utf-8")
    return { content: [{ type: "text", text: content }] }
  }
)

// Tool: список файлов в директории
server.tool(
  "list_files",
  "Возвращает список файлов в директории",
  { dir: z.string().describe("Путь к директории") },
  async ({ dir }) => {
    const files = await fs.readdir(dir)
    return { content: [{ type: "text", text: files.join("\n") }] }
  }
)

// Resource: метаданные сервера
server.resource(
  "server-info",
  "info://server",
  async (uri) => ({
    contents: [{
      uri: uri.href,
      mimeType: "application/json",
      text: JSON.stringify({ name: "filesystem-server", tools: 2 })
    }]
  })
)

// Запуск через stdio-транспорт
const transport = new StdioServerTransport()
await server.connect(transport)

MCP-клиент внутри агента

Агент подключается к серверу, запрашивает список инструментов (discovery), преобразует их в формат function calling для LLM и вызывает через протокол:

mcp-client.ts
// MCP Client — внутри агента
import { Client } from "@modelcontextprotocol/sdk/client/index.js"
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js"

// 1. Подключаемся к MCP-серверу
const transport = new StdioClientTransport({
  command: "node",
  args: ["filesystem-server.js"],
})

const client = new Client({
  name: "my-agent",
  version: "1.0.0",
})
await client.connect(transport)

// 2. Discovery — узнаём, что умеет сервер
const { tools } = await client.listTools()
console.log(tools)
// → [
//   { name: "read_file",  description: "Читает файл",  inputSchema: {...} },
//   { name: "list_files", description: "Список файлов", inputSchema: {...} }
// ]

// 3. Преобразуем MCP-tools в формат function calling для LLM
const llmTools = tools.map(t => ({
  type: "function",
  function: {
    name: t.name,
    description: t.description,
    parameters: t.inputSchema,
  },
}))

// 4. LLM выбирает инструмент
const response = await llm.chat(messages, llmTools)
const toolCall = response.tool_calls[0]

// 5. Вызываем инструмент через MCP
const result = await client.callTool({
  name: toolCall.function.name,
  arguments: JSON.parse(toolCall.function.arguments),
})

// 6. Результат — обратно в LLM
messages.push({ role: "tool", content: result.content[0].text })
const final = await llm.chat(messages)

Симуляция MCP-цикла

Полный цикл: подключение → discovery → LLM выбирает инструмент → вызов через MCP → результат обратно в LLM:

Экосистема MCP-серверов

Сотни готовых MCP-серверов от сообщества и вендоров. Подключаются за минуты:

filesystem

Чтение и запись файлов на диске

github

Репозитории, issues, pull requests

postgres / sqlite

SQL-запросы к базе данных

slack

Отправка и чтение сообщений

puppeteer

Управление браузером, скрапинг

memory

Граф знаний для долгой памяти агента

MCP + A2A + Skills — полная картина

Три стандарта закрывают разные слои агентной системы:

СлойСтандартЧто даёт
ЗнанияSkillsИнструкции, экспертиза, best practices
ИнструментыMCPДоступ к данным и функциям через протокол
СотрудничествоA2AОбщение и делегирование между агентами

Например: агент со скилом "code-reviewer" использует MCPдля чтения файлов из репозитория, а сложные задачи делегирует другому агенту через A2A.

Готово! Теперь вы знаете три ключевых стандарта агентных систем: Skills, MCP и A2A.Далее: в главе 11 — A2A протокол: как агенты общаются друг с другом.