MCP

MCP — открытый стандарт для расширения возможностей AI-агентов внешними инструментами. Creo поддерживает подключение MCP-серверов через два транспорта (stdio и http) с прозрачной интеграцией инструментов в единый tool registry.

graph TB
    subgraph "Config"
        GlobalMcp["~/.config/creo/mcp.json<br/>глобальный"]
        ProjectMcp[".creo/mcp.json<br/>проектный"]
    end

    subgraph "Registration"
        RegisterTool["mcp_register tool<br/>(через диалог с агентом)"]
        Manual["Ручное редактирование<br/>mcp.json"]
    end

    subgraph "Connection"
        LoadConfig["LoadConfig<br/>merge global + project"]
        ConnectAll["ConnectAll<br/>параллельное подключение"]
        Client1["Client #1<br/>stdio process"]
        Client2["Client #2<br/>http endpoint"]
    end

    subgraph "Tool Bridging"
        Adapters["ToolAdapter<br/>MCP → tool.Tool"]
        Registry["tool.Registry<br/>единый реестр"]
    end

    GlobalMcp --> LoadConfig
    ProjectMcp --> LoadConfig
    RegisterTool --> WriteConfig
    Manual --> LoadConfig
    LoadConfig --> ConnectAll
    ConnectAll --> Client1
    ConnectAll --> Client2
    Client1 --> Adapters
    Client2 --> Adapters
    Adapters --> Registry

Файл mcp.json содержит карту серверов: имя → конфигурация.

Scope Путь Применение
Глобальный ~/.config/creo/mcp.json Действует во всех проектах
Проектный .creo/mcp.json (в корне проекта) Действует только в текущем проекте, можно коммитить в git

Проектный mcp.json перекрывает глобальный при совпадении имён серверов.

1type ServerConfig struct {
2    Type        string            `json:"type"`           // "stdio" | "http"
3    Command     string            `json:"command,omitempty"`  // stdio only
4    Args        []string          `json:"args,omitempty"`     // stdio only
5    Env         map[string]string `json:"env,omitempty"`     // stdio only
6    URL         string            `json:"url,omitempty"`     // http only
7    Headers     map[string]string `json:"headers,omitempty"` // http only
8    AutoApprove bool              `json:"autoApprove,omitempty"`
9}

LoadConfig(globalDir, projectDir) читает оба файла и merge'ит:

1result := Config{}
2// 1. Читать глобальный mcp.json → result
3// 2. Читать проектный mcp.json → projectCfg
4// 3. maps.Copy(result, projectCfg) — project перебивает global

Агент может зарегистрировать MCP-сервер через инструмент mcp_register. Процесс:

  1. Агент вызывает mcp_register с параметрами (name, scope, type, command/url, ...)
  2. WriteConfig записывает entry в mcp.json (project или global scope)
  3. NewClient + Connect — подключение к серверу
  4. onRegister(client) — callback регистрирует инструменты в tool registry
  5. System message регенерируется для включения новых инструментов
mcp_register(
    name: "filesystem",
    scope: "project",        // "project" | "global"
    type: "stdio",            // "stdio" | "http"
    command: "npx",           // stdio only
    args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/user"],
    autoApprove: false        // опционально
)
Параметр Тип Обязательный Описание
name string да Уникальное имя сервера (ключ в mcp.json)
scope string да "global" или "project"
type string да "stdio" или "http"
command string для stdio Путь к исполняемому файлу
args string[] нет Аргументы командной строки (stdio)
env object нет Переменные окружения {KEY: value} (stdio)
url string для http URL endpoint
headers object нет HTTP-заголовки (http)
autoApprove boolean нет Пропускать подтверждения для всех инструментов сервера

Локальный процесс. Creo запускает команду через exec.Command с args и env:

1cmd := exec.Command(c.cfg.Command, c.cfg.Args...)
2if len(c.cfg.Env) > 0 {
3    cmd.Env = append(os.Environ(), envSlice(c.cfg.Env)...)
4}
5transport := &mcp.CommandTransport{Command: cmd}

Пример — gopls:

1{
2    "gopls": {
3        "type": "stdio",
4        "command": "gopls",
5        "args": ["mcp"]
6    }
7}

Удалённый endpoint. HTTP-клиент с кастомными заголовками для авторизации:

1transport := &mcp.StreamableClientTransport{
2    Endpoint:             c.cfg.URL,
3    DisableStandaloneSSE: true,
4    HTTPClient:           newHTTPClientWithHeaders(c.cfg.Headers),
5}

HTTP-клиент имеет 30s timeout и инжектит заголовки через headerTransport:

1type headerTransport struct {
2    base    http.RoundTripper
3    headers map[string]string
4}

Пример — Context7:

1{
2    "context7": {
3        "type": "http",
4        "url": "https://mcp.context7.com/mcp"
5    }
6}

Пример с авторизацией:

1{
2    "gitverse": {
3        "type": "http",
4        "url": "https://mcp.gitverse.ru",
5        "headers": {"Authorization": "Bearer <token>"}
6    }
7}

ConnectAll подключается ко всем серверам из конфига конкурентно — каждый сервер в своей горутине. Медленные серверы (например, gopls индексирующий большой workspace) не блокируют остальные.

 1func ConnectAll(ctx context.Context, cfg Config) []*Client {
 2    var wg sync.WaitGroup
 3    for name, serverCfg := range cfg {
 4        wg.Go(func() {
 5            c := NewClient(name, serverCfg)
 6            if err := c.Connect(ctx); err != nil {
 7                log.Printf("mcp: failed to connect to server %q: %v", name, err)
 8                return
 9            }
10            results[idx] = result{client: c, ok: true}
11        })
12    }
13    wg.Wait()
14    return connectedClients
15}

Асинхронная загрузка — MCP-серверы подключаются в фоне, не блокируют запуск TUI. Инструменты появляются по мере подключения.

1type Client struct {
2    name    string
3    cfg     ServerConfig
4    session *mcp.ClientSession
5    tools   []*mcp.Tool
6}
Метод Описание
NewClient(name, cfg) Создание клиента
Connect(ctx) Подключение + ListTools — обнаружение инструментов
CallTool(ctx, name, args) Вызов инструмента на сервере
Close() Закрытие соединения
Tools() Список обнаруженных инструментов
Name() Имя сервера

MCP-инструменты адаптируются к интерфейсу tool.Tool через ToolAdapter:

1type ToolAdapter struct {
2    serverName  string
3    mcpTool     *mcp.Tool
4    client      *Client
5    autoApprove bool
6}
Метод Поведение
Definition() LLM tool definition: name, description, inputSchema → model.Definition
Summary() MCP-описание инструмента для system prompt
Name() Имя инструмента (без префикса сервера)
ServerName() Имя MCP-сервера
IsAutoApproved() true если autoApprove: true в конфиге
Execute(ctx, args) client.CallTool → конвертация результата в tool.Result
Annotations() MCP-аннотации (ReadOnly, Destructive, Idempotent, OpenWorld)
FormatCall(args) Форматирование для отображения
FormatTitle(args) Заголовок для мини-режима

convertMCPContent преобразует MCP CallToolResult в model.Contents:

  • mcp.TextContentmodel.TextContent
  • Пустой результат → "(no output)"

convertInputSchema преобразует MCP inputSchema в model.Definition через JSON marshal/unmarshal round-trip.

AdaptersFor(clients) создаёт ToolAdapter для каждого инструмента каждого клиента:

1func AdaptersFor(clients []*Client) []*ToolAdapter {
2    var adapters []*ToolAdapter
3    for _, c := range clients {
4        for _, mt := range c.Tools() {
5            adapters = append(adapters, NewToolAdapter(c.Name(), mt, c))
6        }
7    }
8    return adapters
9}

Адаптеры регистрируются в едином tool.Registry наравне со встроенными инструментами. System prompt автоматически включает MCP-инструменты после подключения.

Имя MCP-инструмента — mcpTool.Name (без префикса сервера). Коллизии между инструментами из разных серверов или со встроенными инструментами — ответственность пользователя. Last-registered wins через registry.

Флаг autoApprove: true в конфиге сервера полностью отключает подтверждения для всех инструментов этого сервера:

1func (t *ToolAdapter) IsAutoApproved() bool {
2    return t.autoApprove  // из client.cfg.AutoApprove
3}

Инструменты такого сервера никогда не запрашивают подтверждение, независимо от YOLO-режима и области сессии.

Файл Назначение
internal/mcp/mcp.go Package doc
internal/mcp/config.go ServerConfig, Config, LoadConfig, WriteConfig, ConfigPath
internal/mcp/client.go Client, Connect, ConnectAll, CloseAll, CallTool
internal/mcp/register.go RegisterTool — инструмент mcp_register для агента
internal/mcp/tools.go ToolAdapter, AdaptersFor, convertMCPContent, convertInputSchema