MCP Server’s в действии: примеры интеграции с AI-агентами

Model Context Protocol (MCP) — это открытый протокол, который позволяет AI-агентам подключаться к внешним инструментам и данным.

Содержания:

В отличие от REST API, где агент отправляет запрос и получает фиксированный ответ, MCP даёт агенту динамический контекст: он сам решает, какие инструменты и данные ему нужны, и получает их через MCP-сервер.

В этой статье я покажу на реальных примерах, как настроить MCP-сервер для Claude, LangChain и AutoGPT, разберу архитектуру, лучшие практики и ограничения.

Вы узнаете, как дать агенту доступ к файловой системе, базе данных, веб-скрапингу и внешним API — и всё это с контролем безопасности.

Введение: что такое MCP Server и зачем он нужен AI-агентам

Представьте, что вы хотите, чтобы AI-агент (например, Claude) проанализировал логи вашего приложения.

Без MCP вам пришлось бы вручную выгрузить файлы, скопировать их в чат или написать отдельный скрипт. С MCP агент сам подключается к вашему серверу, запрашивает список файлов, читает нужные и выдаёт анализ.

В этом и заключается суть протокола: агент получает доступ к инструментам (выполнить SQL-запрос, отправить email) и ресурсам (файлы, записи БД) через единый интерфейс.

MCP не заменяет REST, а дополняет его. REST хорош для статичных API, где эндпоинты известны заранее. MCP же даёт агенту возможность динамически выбирать, какой инструмент вызвать и с какими параметрами.

Например, Claude может сначала запросить схему базы данных, затем выполнить SELECT — и всё это через один MCP-сервер.

Важно: MCP не заменяет REST, а дополняет его, предоставляя агентам динамический контекст и инструменты на лету.

Пример из практики: агент Claude через MCP-сервер выполняет SQL-запрос к локальной базе данных, получает результат и использует его для генерации отчёта. Без MCP пришлось бы писать отдельный эндпоинт и передавать данные вручную.

Ключевые компоненты MCP: клиент, сервер, транспорт

MCP состоит из трёх основных компонентов: клиент (AI-агент), сервер (реализует инструменты и ресурсы) и транспорт (способ передачи сообщений).

Клиент и сервер общаются через JSON-RPC — лёгкий протокол удалённого вызова процедур.

Клиент: AI-агент (Claude, LangChain)

Клиент — это программа, которая инициирует запросы. В роли клиента может выступать Claude Desktop, LangChain-агент или AutoGPT.

Клиент знает, какие инструменты доступны на сервере, и вызывает их по мере необходимости.

Сервер: реализует инструменты и ресурсы

Сервер — это ваше приложение, которое предоставляет агенту конкретные возможности. Например, сервер может дать доступ к файловой системе, базе данных или внешнему API.

Сервер регистрирует инструменты (действия) и ресурсы (данные), а клиент их использует.

Транспорт: Stdio (локальный процесс) и SSE (удаленный)

AI агент анализирует логи через MCP

Транспорт определяет, как клиент и сервер обмениваются сообщениями. Stdio (standard input/output) используется для локальных серверов: клиент запускает сервер как дочерний процесс и общается через stdin/stdout.

SSE (Server-Sent Events) применяется для удалённых серверов: клиент подключается по HTTP и получает события.

  • Stdio — быстрый, безопасный (нет сетевых рисков), подходит для локальной разработки.
  • SSE — масштабируемый, позволяет подключать несколько клиентов, требует аутентификации.

Архитектура интеграции MCP Server с AI-агентами

Схема взаимодействия проста: агент (клиент) отправляет запрос на сервер, сервер выполняет действие и возвращает результат.

Сервер может быть локальным (запущен на той же машине, что и агент) или удалённым (доступен по сети).

Локальный сервер удобен для работы с конфиденциальными данными: файлы не покидают вашу систему.

Удалённый сервер позволяет масштабировать решение и подключать несколько агентов.

MCP поддерживает два типа объектов: инструменты (tools) и ресурсы (resources). Инструменты — это действия, которые может выполнить сервер: выполнить код, отправить email, сделать запрос к API.

Ресурсы — это данные, к которым сервер предоставляет доступ: файлы, записи базы данных, конфигурации.

Частая ошибка: путать инструменты и ресурсы. Инструмент — это глагол (выполнить, отправить), ресурс — это существительное (файл, запись).

Не пытайтесь сделать ресурс, который выполняет действие — для этого есть инструменты.

Тип Описание Пример
Инструменты Действия, которые может выполнить сервер execute_query, send_message, fetch_page
Ресурсы Данные, к которым сервер предоставляет доступ file://, database://, config://

Типы взаимодействия: инструменты vs ресурсы

Инструменты и ресурсы дополняют друг друга. Агент может сначала запросить ресурс (например, список файлов в директории), а затем вызвать инструмент для обработки этих файлов.

Разница в том, что ресурсы обычно возвращают статичные данные, а инструменты выполняют операции с побочными эффектами.

  • Инструменты: execute_query (выполнить SQL), send_message (отправить сообщение), call_api (вызвать внешний API).
  • Ресурсы: file:// (чтение файла), database:// (получение схемы БД), config:// (чтение конфигурации).

При удалённой интеграции обязательно используйте аутентификацию (OAuth2, API-ключи) и HTTPS. Никогда не доверяйте входным данным от агента — проверяйте их на сервере.

Пример 1: Интеграция MCP сервера с Claude для работы с файловой системой

Этот пример — базовый, но очень полезный. Мы создадим MCP-сервер на Python, который даст Claude доступ к локальным файлам: чтение, запись, список.

Затем настроим Claude Desktop для работы с этим сервером. В результате агент сможет анализировать файлы логов, редактировать конфиги и даже писать код прямо в вашей файловой системе.

Совет: для безопасности ограничьте доступ сервера к определённым директориям через конфигурацию allowed_paths. Никогда не давайте агенту доступ ко всей файловой системе.

Пошаговая настройка MCP сервера на Python

Начнём с установки MCP SDK. Откройте терминал и выполните:

pip install mcp

Теперь создадим файл file_server.py с инструментами list_files, read_file, write_file. Используем аннотации для описания параметров.

from mcp.server import Server, NotificationOptions from mcp.server.models import InitializationOptions import mcp.server.stdio import mcp.types as types import os # Разрешённая директория ALLOWED_PATH = "/home/user/allowed" app = Server("file-server") @app.list_tools() async def list_tools() -> list[types.Tool]: return [ types.Tool( name="list_files", description="List files in a directory", inputSchema={ "type": "object", "properties": { "path": {"type": "string", "description": "Relative path from allowed directory"} }, "required": ["path"] } ), types.Tool( name="read_file", description="Read a file", inputSchema={ "type": "object", "properties": { "path": {"type": "string", "description": "Relative path from allowed directory"} }, "required": ["path"] } ), types.Tool( name="write_file", description="Write content to a file", inputSchema={ "type": "object", "properties": { "path": {"type": "string", "description": "Relative path from allowed directory"}, "content": {"type": "string", "description": "Content to write"} }, "required": ["path", "content"] } ) ] @app.call_tool() async def call_tool(name: str, arguments: dict) -> list[types.TextContent]: if name == "list_files": full_path = os.path.join(ALLOWED_PATH, arguments["path"]) if not full_path.startswith(ALLOWED_PATH): raise ValueError("Access denied") files = os.listdir(full_path) return [types.TextContent(type="text", text="n".join(files))] elif name == "read_file": full_path = os.path.join(ALLOWED_PATH, arguments["path"]) if not full_path.startswith(ALLOWED_PATH): raise ValueError("Access denied") with open(full_path, "r") as f: content = f.read() return [types.TextContent(type="text", text=content)] elif name == "write_file": full_path = os.path.join(ALLOWED_PATH, arguments["path"]) if not full_path.startswith(ALLOWED_PATH): raise ValueError("Access denied") with open(full_path, "w") as f: f.write(arguments["content"]) return [types.TextContent(type="text", text="File written successfully")] else: raise ValueError(f"Unknown tool: {name}") async def main(): async with mcp.server.stdio.stdio_server() as (read_stream, write_stream): await app.run( read_stream, write_stream, InitializationOptions( server_name="file-server", server_version="0.1.0", capabilities=app.get_capabilities( notification_options=NotificationOptions(), experimental_capabilities={}, ), ), ) if __name__ == "__main__": import asyncio asyncio.run(main())

Запустите сервер через команду:

mcp run file_server.py

Сервер будет слушать stdin/stdout и готов к подключению.

Подключение Claude к MCP серверу

Claude подключается к базе данных

Теперь нужно настроить Claude Desktop (или Claude API) для использования этого сервера.

Найдите файл конфигурации Claude Desktop (обычно claude_desktop_config.json в папке пользователя) и добавьте туда наш сервер.

{ "mcpServers": { "file-server": { "command": "mcp", "args": ["run", "/path/to/file_server.py"], "env": {} } } }

Перезапустите Claude Desktop. Теперь в интерфейсе появится новый инструмент — вы можете попросить Claude: «Покажи список файлов в папке logs» или «Прочитай файл error.log и найди ошибки».

Claude сам вызовет соответствующие инструменты MCP-сервера.

Пример диалога:

  • Вы: «Проанализируй файл /logs/app.log и найди все упоминания ошибок».
  • Claude: «Сейчас я прочитаю файл через MCP-сервер… Вот содержимое. Я вижу 3 ошибки: …»

Таким образом, агент получает полный доступ к файловой системе в рамках разрешённой директории.

Пример 2: Интеграция MCP сервера с LangChain для доступа к базе данных

В этом примере мы создадим MCP-сервер, который оборачивает SQLite базу данных и предоставляет LangChain-агенту инструменты для выполнения запросов. Используем TypeScript и LangChain MCP адаптер.

Это позволит агенту не только выполнять SELECT, но и получать схему базы данных для построения корректных запросов.

Частая ошибка: разрешать агенту выполнять любые SQL-запросы. Всегда ограничивайте инструменты только SELECT (или используйте параметризованные запросы) для предотвращения SQL-инъекций.

Создание MCP сервера для SQLite

Установим зависимости:

npm install @modelcontextprotocol/sdk better-sqlite3

Создадим файл db_server.ts:

import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import Database from "better-sqlite3"; const db = new Database("/path/to/database.sqlite"); const server = new Server( { name: "db-server", version: "0.1.0", }, { capabilities: { tools: {}, }, } ); server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "get_schema", description: "Get the schema of the database (list of tables and columns)", inputSchema: { type: "object", properties: {}, required: [], }, }, { name: "execute_query", description: "Execute a SELECT query on the database", inputSchema: { type: "object", properties: { query: { type: "string", description: "SQL SELECT query" }, }, required: ["query"], }, }, ], }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; if (name === "get_schema") { const tables = db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all(); let schema = ""; for (const table of tables) { const columns = db.prepare(`PRAGMA table_info(${table.name})`).all(); schema += `Table ${table.name}: ${columns.map(c => c.name + " " + c.type).join(", ")}n`; } return { content: [{ type: "text", text: schema }], }; } else if (name === "execute_query") { const query = args.query; // Безопасность: разрешаем только SELECT if (!query.trim().toUpperCase().startsWith("SELECT")) { throw new Error("Only SELECT queries are allowed"); } const result = db.prepare(query).all(); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } else { throw new Error(`Unknown tool: ${name}`); } }); const transport = new StdioServerTransport(); await server.connect(transport);

Запустите сервер: npx ts-node db_server.ts.

Настройка LangChain агента с MCP

Установите пакет @langchain/mcp:

npm install @langchain/mcp

Теперь создайте агента, который использует MCP-инструменты:

import { MCPClientTool } from "@langchain/mcp"; import { ChatOpenAI } from "@langchain/openai"; import { AgentExecutor, createOpenAIToolsAgent } from "langchain/agents"; const tools = [ new MCPClientTool({ name: "get_schema", serverUrl: "stdio:///path/to/db_server.ts", // или по SSE description: "Get database schema", }), new MCPClientTool({ name: "execute_query", serverUrl: "stdio:///path/to/db_server.ts", description: "Execute a SELECT query", }), ]; const model = new ChatOpenAI({ model: "gpt-4" }); const agent = await createOpenAIToolsAgent({ llm: model, tools, prompt: "You are a database assistant. Use the get_schema tool to understand the database, then execute queries.", }); const executor = new AgentExecutor({ agent, tools, }); const result = await executor.invoke({ input: "List all users who signed up in the last month", }); console.log(result);

Агент получит схему базы данных, построит правильный SELECT-запрос и выполнит его через MCP-сервер. Результат вернётся в виде JSON.

Этот подход можно использовать для любых баз данных: PostgreSQL, MySQL, MongoDB — достаточно изменить реализацию инструментов на сервере.

Пример 3: Интеграция MCP сервера с AutoGPT для веб-скрапинга и API

AutoGPT — это автономный агент, который может выполнять многошаговые задачи. С MCP-сервером мы дадим ему инструменты для веб-скрапинга и вызова внешних REST API.

Например, агент сможет собрать данные о погоде с нескольких сайтов и агрегировать их в отчёт.

Совет: при скрапинге всегда уважайте robots.txt и условия использования сайтов. Используйте User-Agent, который идентифицирует вашего бота, и не делайте слишком много запросов в секунду.

Инструменты веб-скрапинга в MCP

LangChain агент использует веб скрапинг

Создадим MCP-сервер на Python с инструментами fetch_page и extract_data. Используем библиотеки requests и BeautifulSoup.

Важно добавить обработку ошибок: например, при недоступности сайта или некорректном URL сервер должен возвращать понятное сообщение, а не падать с исключением.

from mcp.server import Server, NotificationOptions from mcp.server.models import InitializationOptions import mcp.server.stdio import mcp.types as types import requests from bs4 import BeautifulSoup app = Server("web-scraper") @app.list_tools() async def list_tools() -> list[types.Tool]: return [ types.Tool( name="fetch_page", description="Fetch HTML content of a URL", inputSchema={ "type": "object", "properties": { "url": {"type": "string", "description": "URL to fetch"} }, "required": ["url"] } ), types.Tool( name="extract_data", description="Extract text from HTML using a CSS selector", inputSchema={ "type": "object", "properties": { "html": {"type": "string", "description": "HTML content"}, "selector": {"type": "string", "description": "CSS selector"} }, "required": ["html", "selector"] } ) ] @app.call_tool() async def call_tool(name: str, arguments: dict) -> list[types.TextContent]: if name == "fetch_page": url = arguments["url"] try: response = requests.get(url, timeout=10) response.raise_for_status() # Проверка на HTTP ошибки except requests.exceptions.RequestException as e: return [types.TextContent(type="text", text=f"Error fetching page: {str(e)}")] return [types.TextContent(type="text", text=response.text)] elif name == "extract_data": html = arguments["html"] selector = arguments["selector"] soup = BeautifulSoup(html, "html.parser") elements = soup.select(selector) text = "n".join([el.get_text(strip=True) for el in elements]) return [types.TextContent(type="text", text=text)] else: raise ValueError(f"Unknown tool: {name}") async def main(): async with mcp.server.stdio.stdio_server() as (read_stream, write_stream): await app.run( read_stream, write_stream, InitializationOptions( server_name="web-scraper", server_version="0.1.0", capabilities=app.get_capabilities( notification_options=NotificationOptions(), experimental_capabilities={}, ), ), ) if __name__ == "__main__": import asyncio asyncio.run(main())

Инструменты для вызова внешних API

Добавим инструмент call_api, который позволяет агенту вызывать любой REST API. Это удобно для интеграции с погодными сервисами, CRM, Slack и т.д.

@app.list_tools() async def list_tools() -> list[types.Tool]: return [ # ... предыдущие инструменты types.Tool( name="call_api", description="Call an external REST API", inputSchema={ "type": "object", "properties": { "method": {"type": "string", "enum": ["GET", "POST", "PUT", "DELETE"], "description": "HTTP method"}, "url": {"type": "string", "description": "API URL"}, "headers": {"type": "object", "description": "Optional headers"}, "body": {"type": "object", "description": "Optional JSON body"} }, "required": ["method", "url"] } ) ] @app.call_tool() async def call_tool(name: str, arguments: dict) -> list[types.TextContent]: if name == "call_api": method = arguments["method"] url = arguments["url"] headers = arguments.get("headers", {}) body = arguments.get("body") response = requests.request(method, url, headers=headers, json=body, timeout=10) return [types.TextContent(type="text", text=response.text)] # ... остальные инструменты

Теперь AutoGPT может, например, собрать данные о погоде: fetch_page с сайта погоды, extract_data для извлечения температуры, call_api для отправки результата в Telegram.

Подключение к AutoGPT происходит через конфигурацию — укажите в настройках AutoGPT команду запуска MCP-сервера, и агент автоматически получит доступ к инструментам.

Лучшие практики и ограничения MCP Servers

MCP — мощный протокол, но у него есть свои подводные камни. Рассмотрим безопасность, производительность и ограничения.

Важно: всегда проверяйте входные данные на стороне сервера, так как агент может быть скомпрометирован. Никогда не доверяйте аргументам инструментов без валидации.

Безопасность MCP сервера

Безопасность — ключевой аспект при интеграции MCP. Поскольку агент может вызывать любые инструменты, необходимо контролировать доступ.

  • Аутентификация клиента: для удалённых серверов используйте OAuth2 или API-ключи. Каждый запрос должен содержать токен, который сервер проверяет.
  • Валидация входных данных: проверяйте типы, длины, диапазоны. Например, в инструменте execute_query проверяйте, что запрос начинается с SELECT.
  • Ограничение доступа к ресурсам: используйте белые списки директорий, таблиц БД, URL. Никогда не давайте агенту доступ к чувствительным данным.
Угроза Мера защиты
SQL-инъекция Использовать параметризованные запросы, ограничить инструменты только SELECT
Несанкционированный доступ к файлам Белый список директорий, проверка пути
SSRF (Server-Side Request Forgery) Ограничить URL только доверенными доменами
DoS-атака Установить таймауты и лимиты на количество вызовов

Производительность и отладка

Время выполнения инструментов не должно превышать таймаут агента (обычно 30 секунд).

Если ваш инструмент выполняется дольше, агент может прервать вызов. Используйте асинхронные операции и кэширование, где это возможно.

  • Установка таймаутов: в коде сервера используйте asyncio.wait_for или timeout в requests.
  • Логирование запросов: записывайте все вызовы инструментов с параметрами и результатами. Это поможет при отладке.
  • Идемпотентность инструментов: если возможно, делайте инструменты идемпотентными (повторный вызов с теми же параметрами даёт тот же результат). Это снижает риск при повторных попытках.

Ограничения MCP:

  • MCP не поддерживает потоковую передачу больших данных (например, видео). Для этого лучше использовать отдельные протоколы.
  • Сложность отладки: так как запросы проходят через транспорт, сложно понять, где произошла ошибка — на стороне клиента или сервера. Используйте подробные логи.
  • MCP всё ещё развивается: протокол может меняться, следите за обновлениями.

Заключение: будущее MCP Servers в экосистеме AI

AutoGPT получает доступ к файловой системе

MCP становится стандартом для интеграции AI-агентов с внешними инструментами. Он уже поддерживается в Claude, LangChain, AutoGPT, и, вероятно, скоро появится в OpenAI и Google.

Протокол упрощает разработку: вам не нужно писать отдельные эндпоинты для каждого инструмента — достаточно создать MCP-сервер, и любой совместимый агент сможет им пользоваться.

Перспективы развития MCP включают поддержку потоковой передачи, улучшенную безопасность (встроенная аутентификация), а также версию 2.0 с обратной совместимостью.

Если вы разрабатываете AI-решения, рекомендую попробовать MCP уже сейчас — это даст вашим агентам доступ к реальным данным и действиям.

Попробуйте создать свой первый MCP-сервер, используя примеры из этой статьи. Начните с простого файлового сервера, затем добавьте доступ к базе данных.

Вы увидите, как сильно это расширяет возможности AI-агентов.

Ресурсы для дальнейшего изучения

Если вы хотите автоматизировать тестирование своих MCP-серверов, обратите внимание на статью Автоматизация тестирования с помощью плагинов и CI/CD-интеграций — там описаны подходы, которые можно применить и к MCP.

Часто задаваемые вопросы

Что такое MCP Server простыми словами?

MCP Server — это программа-посредник, которая даёт AI-агенту (например, Claude) доступ к вашим файлам, базам данных, API и другим инструментам.

Агент может попросить сервер выполнить действие (прочитать файл, выполнить запрос) и получить результат.

Чем MCP отличается от REST API?

REST API требует заранее определённых эндпоинтов и фиксированных ответов. MCP же позволяет агенту динамически выбирать, какие инструменты и ресурсы ему нужны. MCP не заменяет REST, а дополняет его для сценариев, где агенту нужен контекст.

Какие языки поддерживает MCP?

безопасность MCP сервера

Официальные SDK есть для Python и TypeScript. Но протокол основан на JSON-RPC, поэтому вы можете реализовать сервер на любом языке, поддерживающем JSON и сетевое взаимодействие.

Как обеспечить безопасность MCP сервера?

Используйте аутентификацию (OAuth2, API-ключи), валидируйте все входные данные, ограничивайте доступ к ресурсам через белые списки, устанавливайте таймауты и логируйте запросы.

Можно ли использовать MCP с OpenAI API?

На данный момент OpenAI не поддерживает MCP нативно. Но вы можете использовать MCP-сервер как промежуточный слой, вызывая его из вашего кода, который затем передаёт результат в OpenAI через function calling.

Виталий/ автор статьи

Руководитель проектов, эксперт по веб-разработке В коммерческой веб-разработке с 2018 года. Специализируюсь на создании цифровых продуктов, которые решают задачи бизнеса: увеличивают конверсию, автоматизируют продажи и масштабируют трафик. За плечами - управление портфелем из 150+ медиапроектов, что дало глубокое понимание механик поискового продвижения и работы с большими объемами данных. Этот опыт я трансформировал в системный подход к созданию коммерческих сайтов: каждый этап разработки - от прототипа до запуска - оцениваю через призму окупаемости и удобства для конечного пользователя.
Мой приоритет: предсказуемый результат для заказчика. Фиксированные сроки, прозрачная смета и сайт, который работает как отлаженный механизм продаж, а не просто «визитка в интернете».

Понравилась статья? Поделиться с друзьями: