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 (удаленный)

Транспорт определяет, как клиент и сервер обмениваются сообщениями. 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 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

Создадим 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

MCP становится стандартом для интеграции AI-агентов с внешними инструментами. Он уже поддерживается в Claude, LangChain, AutoGPT, и, вероятно, скоро появится в OpenAI и Google.
Протокол упрощает разработку: вам не нужно писать отдельные эндпоинты для каждого инструмента — достаточно создать MCP-сервер, и любой совместимый агент сможет им пользоваться.
Перспективы развития MCP включают поддержку потоковой передачи, улучшенную безопасность (встроенная аутентификация), а также версию 2.0 с обратной совместимостью.
Если вы разрабатываете AI-решения, рекомендую попробовать MCP уже сейчас — это даст вашим агентам доступ к реальным данным и действиям.
Попробуйте создать свой первый MCP-сервер, используя примеры из этой статьи. Начните с простого файлового сервера, затем добавьте доступ к базе данных.
Вы увидите, как сильно это расширяет возможности AI-агентов.
Ресурсы для дальнейшего изучения
- Официальная документация MCP: modelcontextprotocol.io
- MCP SDK (Python, TypeScript): github.com/modelcontextprotocol
- Примеры на GitHub: github.com/modelcontextprotocol/servers
Если вы хотите автоматизировать тестирование своих MCP-серверов, обратите внимание на статью Автоматизация тестирования с помощью плагинов и CI/CD-интеграций — там описаны подходы, которые можно применить и к MCP.
Часто задаваемые вопросы
Что такое MCP Server простыми словами?
MCP Server — это программа-посредник, которая даёт AI-агенту (например, Claude) доступ к вашим файлам, базам данных, API и другим инструментам.
Агент может попросить сервер выполнить действие (прочитать файл, выполнить запрос) и получить результат.
Чем MCP отличается от REST API?
REST API требует заранее определённых эндпоинтов и фиксированных ответов. MCP же позволяет агенту динамически выбирать, какие инструменты и ресурсы ему нужны. MCP не заменяет REST, а дополняет его для сценариев, где агенту нужен контекст.
Какие языки поддерживает MCP?

Официальные SDK есть для Python и TypeScript. Но протокол основан на JSON-RPC, поэтому вы можете реализовать сервер на любом языке, поддерживающем JSON и сетевое взаимодействие.
Как обеспечить безопасность MCP сервера?
Используйте аутентификацию (OAuth2, API-ключи), валидируйте все входные данные, ограничивайте доступ к ресурсам через белые списки, устанавливайте таймауты и логируйте запросы.
Можно ли использовать MCP с OpenAI API?
На данный момент OpenAI не поддерживает MCP нативно. Но вы можете использовать MCP-сервер как промежуточный слой, вызывая его из вашего кода, который затем передаёт результат в OpenAI через function calling.