Часть 3 из 5 · Серия «Архитектура Claude Code» → /claude-code-series
6. Расширяемость: MCP, плагины, навыки и хуки
Повторяющийся вопрос для агентов программирования: как структурировать поверхность расширений — единый унифицированный механизм, небольшое число специализированных или слоистый стек с разной контекстной ценой. Анализ здесь иллюстрирует два принципа из Table 1: composable multi-mechanism extensibility и externalized programmable policy. Возвращаясь к сквозному примеру, после того как запрос npm test прошёл систему разрешений (Section 5), следующий вопрос — какая поверхность действий доступна Claude для починки. В Claude Code модель видит не только встроенные инструменты вроде BashTool и FileReadTool, но и инструменты запроса к БД из MCP-сервера, кастомный lint-навык из .claude/skills/ и инструменты, внесённые установленным плагином. Они приходят через четыре механизма, расширяющих агента в разных точках цикла: MCP-серверы дают внешнюю интеграцию инструментов, плагины пакуют и распространяют наборы компонентов, навыки вкалывают domain-specific-инструкции, а хуки перехватывают жизненный цикл исполнения инструментов. Документация Anthropic (Anthropic, 2026d) даёт более широкий взгляд, включающий CLAUDE.md (Section 7) и субагентов (Section 8) наряду с четырьмя механизмами, разобранными здесь. Мы трактуем CLAUDE.md и субагентов в отдельных разделах, потому что они работают в разных подсистемах (построение контекста и делегирование). Но упорядочивание по контекстной цене архитектурно значимо: показывает, как каждая точка расширения балансирует выразительность против ограниченного контекстного окна.
6.1. Четыре механизма расширения
Механизмы реализованы в разных директориях исходника (Figure 5) и служат разным паттернам интеграции:
MCP servers. Model Context Protocol — основной путь внешней интеграции инструментов. MCP-серверы настраиваются из нескольких областей: project, user, local и enterprise, с дополнительными plugin- и claude.ai-серверами, объединяемыми в runtime (services/mcp/config.ts). MCP-клиент (services/mcp/client.ts) поддерживает несколько транспортов: stdio, SSE, HTTP, WebSocket, SDK, плюс IDE-специфичные варианты (sse-ide, ws-ide) и внутренний claudeai-proxy. Каждый подключённый сервер вкладывает определения инструментов как MCPTool-объекты. Выделенные встроенные инструменты ListMcpResourcesTool и ReadMcpResourceTool дают доступ к MCP-ресурсам.
Plugins. Плагины играют двойную роль: это и формат упаковки, и механизм распространения. PluginManifestSchema (utils/plugins/schemas.ts) принимает десять типов компонентов: commands, agents, skills, hooks, MCP servers, LSP servers, output styles, channels, settings, user configuration. Загрузчик плагинов (utils/plugins/pluginLoader.ts) валидирует манифесты и маршрутизирует каждый компонент в нужный реестр: commands и skills всплывают через мета-инструмент SkillTool, agents появляются в определениях, потребляемых AgentTool, hooks складываются в реестр хуков, MCP- и LSP-серверы сливаются в стандартные конфигурации, output styles меняют форматирование ответов. Одна плагин-поставка может расширить Claude Code сразу через несколько типов компонентов, что делает плагины главным средством доставки сторонних расширений.
Skills. Каждый навык определяется файлом SKILL.md с YAML-frontmatter. Функция parseSkillFrontmatterFields() (loadSkillsDir.ts) разбирает 15+ полей: display name, description, allowed tools (дают навыку доступ к дополнительным инструментам), argument hints, model overrides, execution context ('fork' для изолированного исполнения), связанные определения агентов, effort levels и shell-конфигурацию. Навыки могут определять собственные хуки, регистрируемые динамически при вызове. Связанные навыки регистрируются в памяти при старте. При вызове мета-инструмент SkillTool вкалывает инструкции навыка в контекст.
Figure 5 Where Claude Code's extension mechanisms plug into the agent loop. The pseudocode on the left is a zoom-in of the Agent Loop block in Figure 1. Every action loop has three injection points: assemble() controls what the model sees, model() controls what it can reach, and execute() controls whether and how an action actually runs.
Рисунок 5. Куда механизмы расширения Claude Code подключаются к агентному циклу. Псевдокод слева — увеличение блока Agent Loop из Figure 1. В каждом цикле действий три точки инъекции:assemble()управляет тем, что видит модель,model()— тем, что она может достичь,execute()— тем, будет ли и как выполнено действие.
# one turn of Claude Code's agent loop
while not stopped:
# (a) assemble — build what the model sees
context = assemble(
system_prompt, # instructions header
tool_schemas, # callable tool signatures
history, # prior turn messages
hook_additions, # pushed in by hooks
)
# (b) model — pick the next action
action = model(context, tools) # flat tool pool
if action.is_text_only:
stopped = run_stop_hooks(action) # may veto
continue
# (c) execute — gate and run the tool call
if not permitted(action): # permission
continue
action = run_pre_tool_hooks(action) # block/rewrite
result = execute(action) # tool runs here
result = run_post_tool_hooks(result) # mutate/annotate
history.append(action, result)
(a) assemble(): что видит модель
| Element | Что делает |
|---|---|
| CLAUDE.md files | Загружаются в контекст; файлы выше рабочей директории — при старте, файлы поддиректорий — по требованию. |
| Skill descriptions | Рекламируют навыки, чтобы модель вызвала SkillTool. |
| MCP resources & prompts | Не-инструментальный контент, который MCP-сервер пушит. |
| Output style | Заменяет response-formatting system block. |
| UserPromptSubmit hook | Инжектирует контекст или блокирует каждый ход пользователя. |
| SessionStart hook | Одноразовая инжекция контекста в начале сессии. |
(b) model(): до чего может дотянуться модель
| Element | Что делает |
|---|---|
| Built-in tools | Read / Edit / Bash / …, поставляемые с CLI. |
| MCP tools | Инструменты любого MCP-сервера в том же плоском пуле. |
| SkillTool | Мета-инструмент, запускающий навык по имени. |
| AgentTool | Мета-инструмент, рекурсивно запускающий субагента. |
(c) execute(): будет ли и как выполнено действие
| Element | Что делает |
|---|---|
| Permission rules | Декларативные allow / deny / ask на вызов. |
| PreToolUse hook | Approve / block / rewrite вызова инструмента. |
| PostToolUse hook | Мутирует вывод или инжектирует контекст после вызова. |
| Stop hook | Заставляет цикл продолжаться при остановке модели. |
| SubagentStop hook | То же для субагентов, запущенных через AgentTool. |
| Notification hook | Внешние сайд-эффекты на пользовательские уведомления. |
Hooks. Исходник определяет 27 событий хуков, охватывающих авторизацию инструментов (PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, PermissionDenied), жизненный цикл сессии (SessionStart, SessionEnd, Setup, Stop, StopFailure), пользовательское взаимодействие (UserPromptSubmit, Elicitation, ElicitationResult), координацию субагентов (SubagentStart, SubagentStop, TeammateIdle, TaskCreated, TaskCompleted), управление контекстом (PreCompact, PostCompact, InstructionsLoaded, ConfigChange), события рабочей области (CwdChanged, FileChanged, WorktreeCreate, WorktreeRemove) и уведомления (coreTypes.ts, coreSchemas.ts). Из них 15 имеют event-специфичные output-схемы с богатыми полями, поддерживающими решения о разрешениях, инжекцию контекста, изменение входа, трансформацию MCP-результатов и retry-контроль (types/hooks.ts). Персистентные команды хуков, настраиваемые через settings и плагины, используют четыре типа команд: shell-команды (type: command), LLM-prompt-хуки (type: prompt), HTTP-хуки (type: http) и agentic-verifier-хуки (type: agent) (schemas/hooks.ts). Runtime дополнительно поддерживает не-персистируемые callback-хуки (type: callback), используемые SDK и внутренним instrumentation (types/hooks.ts). Источники хуков: settings.json, плагины и managed-политика на старте; skill-хуки регистрируются динамически при вызове (utils/hooks.ts). Пять событий авторизации инструментов подробно описаны в Section 5.3.
6.2. Сборка пула инструментов (Tool Pool Assembly)
Функция assembleToolPool() в tools.ts документирована как «единый источник правды для объединения встроенных инструментов с MCP-инструментами». Сборка идёт по пятиэтапному конвейеру:
- Base tool enumeration.
getAllBaseTools()(tools.ts) возвращает массив до 54 инструментов: 19 включены всегда (например,BashTool,FileReadTool,AgentTool,SkillTool), ещё 35 условно — по feature flags, переменным окружения и типу пользователя. Anthropic-internal-пользователи получают дополнительные внутренние инструменты. Worktree-режим включаетEnterWorktreeToolиExitWorktreeTool. Agent swarms включают team-инструменты. Когда в Bun-бинарнике доступны встроенные инструменты поиска, отдельныеGlobToolиGrepToolопускаются. - Mode filtering.
getTools()(tools.ts) применяет mode-специфичную фильтрацию. В режимеCLAUDE_CODE_SIMPLEдоступны толькоBash,ReadиEdit(илиREPLToolв ветке REPL); плюс координаторские инструменты, если применимо. МетодisEnabled()каждого инструмента вызывается для runtime-проверки доступности. - Deny rule pre-filtering.
filterToolsByDenyRules()(tools.ts) убирает blanket-deny-инструменты из обзора модели до любого вызова. - MCP tool integration. MCP-инструменты из
appState.mcp.toolsфильтруются правилами deny и сливаются со встроенными. - Deduplication. Инструменты дедуплицируются по имени, причём встроенные имеют приоритет над MCP.
И REPL.tsx (через хук useMergedTools), и AgentTool.tsx (при сборке worker-набора инструментов) вызывают эту функцию, обеспечивая согласованную сборку на всех путях исполнения. При request time отложенные инструменты могут быть скрыты от контекста модели до явного запроса через ToolSearch (tools.ts).
Agent-based-расширение (кастомные определения агентов через .claude/agents/*.md и агенты плагинов) покрыто в Section 8, потому что агенты принципиально отличаются от четырёх механизмов выше: они создают новые изолированные контекстные окна, а не расширяют текущее.
6.3. Почему четыре механизма?
Поскольку каждый дополнительный механизм расширения увеличивает площадь поверхности, которую разработчикам нужно выучить, естественный вопрос — почему Claude Code использует четыре разных механизма, а не сводит всё в один или два. Ответ в наблюдении, что разные виды расширяемости накладывают разные затраты на контекстное окно, и единый механизм не покроет весь спектр — от lifecycle-хуков с нулевым контекстом до schema-heavy tool-серверов — без лишних компромиссов для авторов расширений.
Table 2 сводит это: каждый механизм меняет deployment-complexity на другой вид расширяемости. MCP-серверы дают runtime-интеграцию инструментов (модель получает новые вызываемые инструменты) ценой накладных расходов на управление серверами и контекстного бюджета, который съедают tool-схемы. Навыки формируют как агент думает (не только какими инструментами владеет) при минимальной контекстной цене — в prompt попадают только frontmatter-описания (не полное содержимое). Хуки дают сквозной lifecycle-контроль (блокировать, переписывать или аннотировать вызовы) с нулевым контекстным следом по умолчанию, хотя хуки могут opt-in и инжектировать дополнительный контекст. Плагины упаковывают любые комбинации трёх других в распространяемые пакеты, выступая слоем упаковки и доставки, а не отдельным runtime-примитивом. Градуированный порядок по контекстной цене (ноль для хуков, низкий для навыков, средний для плагинов, высокий для MCP) означает, что дешёвые расширения могут широко масштабироваться без исчерпания контекстного окна, а дорогие резервируются для случаев, где действительно нужны новые tool-поверхности.
Некоторые agent-фреймворки дают единственный механизм расширения — обычно tool-only API, где любая кастомизация приходит как дополнительные вызываемые инструменты. Другие используют два уровня, разделяя инструменты от конфигурации или инжекции инструкций. Четырёхмеханизменный подход Claude Code охватывает более широкий диапазон паттернов расширения — от zero-context event handlers до полноценной интеграции внешних сервисов — но повышает кривую обучения, когда разработчик выбирает механизм для конкретной задачи интеграции.
Table 2. Уникальные возможности каждого механизма расширения
Table 2 What each extension mechanism uniquely provides. Context cost refers to how much of the bounded context window the mechanism consumes when active.
| Механизм | Уникальная возможность | Контекстная цена | Точка инъекции |
|---|---|---|---|
| MCP servers | External service integration (multi-transport) | Высокая (tool schemas) | model(): tool pool |
| Plugins | Multi-component packaging + distribution | Средняя (варьируется) | Все три точки |
| Skills | Domain-specific instructions + meta-tool invocation | Низкая (только descriptions) | assemble(): context injection |
| Hooks | Lifecycle interception + event-driven automation | Ноль по умолчанию | execute(): pre/post tool |
Когда что использовать: если нужно подключить внешний сервис → MCP; автоматизировать workflow в конкретном проекте → хуки; упаковать инструкции для переиспользования → навыки; расширить UI Claude Code → плагины.
← Часть 2 — Agent loop и разрешения | Часть 4 — Контекст и память →