В эпоху, когда большие языковые модели (LLM) становятся центральными компонентами сложных систем, каждый токен имеет значение. Разработчики, внедряющие AI-агентов, часто сталкиваются с неочевидной проблемой: стоимость использования инструментов (tools) может многократно превышать стоимость самого запроса к модели. Особенно это касается протокола Model Context Protocol (MCP), который позволяет агентам взаимодействовать с внешними данными и сервисами. Но действительно ли MCP так дорог, как кажется, или это вопрос неправильной настройки? В этой статье мы подробно разберем разницу между использованием MCP, стандартных командных интерфейсов (CLI) и «навыков» (Skills), проанализируем реальные затраты токенов и предложим практические решения для оптимизации.
Ключевая проблема, которую мы рассмотрим, заключается в том, что каждое определение инструмента, отправляемое модели, потребляет контекстное окно. Агенты платят за эти токены как за входные данные. Сервер MCP может добавлять десятки тысяч токенов в контекстное окно с каждым запросом, что делает его использование экономически нецелесообразным без правильной оптимизации. Мы проведем сравнительный анализ на основе реальных тестов с использованием GitHub MCP Server, CLI-инструмента `gh` и специализированных навыков, чтобы показать, где именно возникают издержки и как их минимизировать.
01Что такое MCP, CLI и Skills: фундаментальные различия
Прежде чем углубляться в цифры, важно понять архитектурные различия между тремя подходами к предоставлению возможностей модели. Все три метода дают агенту доступ к внешним функциям, но они кардинально различаются тем, что модель «видит» до начала выполнения задачи и что она обрабатывает во время выполнения.
Сервер MCP (Model Context Protocol) работает по принципу полной прозрачности. При каждом запросе модель получает полные имена, описания и JSON-схемы для всех подключенных инструментов. Это необходимо для того, чтобы модель могла принимать решения о вызове инструментов, но это создает огромную нагрузку на контекстное окно. Во время выполнения модель получает результат работы инструмента в том виде, в котором его возвращает сервер.

Командный интерфейс (CLI) опирается на предварительные знания модели. Модель уже «знает», как работает, например, команда `git` или `gh`, поэтому ей не нужно загружать сложные схемы. В контекст отправляется лишь упоминание о том, что CLI-инструмент доступен. Результат выполнения — это вывод команды, который разработчик может структурировать с помощью флагов (например, `--json`), чтобы сделать его более компактным и понятным для модели.
Навыки (Skills) представляют собой гибридный подход. Модель получает краткое однострочное описание каждого навыка. Полные инструкции (например, файл `SKILL.md`) загружаются в контекст только тогда, когда модель решает, что этот навык нужен для текущей задачи. После загрузки инструкции остаются в контексте, а затем модель получает вывод команды. Это позволяет экономить токены на этапе планирования, но увеличивает затраты на этапе выполнения, если навык часто используется.

02Сколько токенов добавляет сервер MCP к каждому запросу?
Один из самых распространенных вопросов: насколько дорого обходится подключение сервера MCP? Точный ответ зависит от количества инструментов, их описаний и используемой модели. Надежный способ подсчета — отправить запрос к модели с инструментами и без них, а затем сравнить разницу в количестве токенов в поле `usage.prompt_tokens`.
Важно отметить, что разные провайдеры (Anthropic, OpenAI, Google) по-разному форматируют определения инструментов перед подсчетом токенов, поэтому локальные токенизаторы могут давать неточные результаты. Ниже приведен пример скрипта на Python, который использует MCP версии 2025-06-18 для подключения к GitHub MCP Server и измерения затрат.
"""How many prompt tokens does an MCP server add to every request? Ask the model."""
import json
import os
import subprocess
import sys
import requests
API = "https://openrouter.ai/api/v1/chat/completions"
HEADERS = {"Authorization": "Bearer " + os.environ['OPENROUTER_API_KEY']}
def list_mcp_tools(command):
"""Start a stdio MCP server, run the handshake, and return its tools/list result."""
proc = subprocess.Popen(command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True)
def rpc(method, params, id=None):
msg = {"jsonrpc": "2.0", "method": method, "params": params}
if id is not None: msg["id"] = id
proc.stdin.write(json.dumps(msg) + "\n")
proc.stdin.flush()
while id is not None:
reply = json.loads(proc.stdout.readline())
if reply.get("id") == id: return reply["result"]
rpc("initialize", {"protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": {"name": "mcp-cost", "version": "1"}}, 1)
rpc("notifications/initialized", {})
tools, cursor, id = [], None, 1
while True:
page = rpc("tools/list", {"cursor": cursor} if cursor else {}, id)
tools += page["tools"]
cursor, id = page.get("nextCursor"), id
if not cursor: break
proc.kill()
return tools
def prompt_tokens(model, tools=None):
body = {"model": model, "max_tokens": 16, "messages": [{"role": "user", "content": "Say ok."}]}
if tools: body["tools"] = tools
if model.startswith("google/"):
body["provider"] = {"only": ["google-vertex"]}
r = requests.post(API, headers=HEADERS, json=body, timeout=120)
r.raise_for_status()
return r.json()
Источник: OpenRouter ↗
