JavaRush /Курсы /ChatGPT Apps /Инспекция и отладка MCP: MCP Jam, Inspector, логи

Инспекция и отладка MCP: MCP Jam, Inspector, логи

ChatGPT Apps
6 уровень , 4 лекция
Открыта

1. Зачем вообще нужен MCP‑инспектор

Представьте, что вы дебажите фронтенд, но вам запретили открывать DevTools. Примерно так выглядит жизнь без MCP‑инспектора. MCP‑протокол идёт «под капотом» ChatGPT и Apps SDK; если вы смотрите только на ответ в чате и думаете: «Ну, почему он не видит мой инструмент?», — вы, по сути, стреляете в пустоту.

Инспекторы вроде MCP Inspector (официальный) или MCP Jam — это специальные MCP‑клиенты для разработчиков. Они умеют:

  • подключиться к вашему MCP‑серверу так же, как это делает ChatGPT;
  • пройти handshake / capabilities;
  • запросить список tools/resources/prompts;
  • вызывать любой tool вручную с произвольными аргументами;
  • показывать сырые JSON‑сообщения (requests / replies / errors).

По сути, это «Postman для MCP, но с мозгами». В отличие от обычного REST‑клиента, инспектор знает специфику MCP: он понимает tools/list, tools/call, умеет показывать схемы аргументов, иногда поддерживает даже OAuth‑флоу для защищённых серверов.

Если у вас нет инспектора, отладка выглядит так: вы запускаете ChatGPT, пытаетесь вызвать App, видите «Error talking to app» или то, что tool вообще не вызывается, и начинаете гадать: это модель не захотела звать инструмент, это ваш MCP не поднялся или это JSON‑ошибка? С инспектором вы можете проверить каждый слой по отдельности: сначала MCP‑сервер один на один с инспектором, потом уже связка ChatGPT ↔ MCP.

2. Мини-обзор инспекторов: MCP Inspector, Jam и компания

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

Во‑первых, это официальный MCP Inspector из репозитория Model Context Protocol. Это веб‑приложение (как правило, SPA на React), которое поднимается либо локально, либо через npx/Docker и умеет подключаться к вашему MCP‑серверу по HTTP/SSE.

Во‑вторых, есть MCP Jam‑подобные инспекторы, которые часто добавляют ещё и удобства по OAuth. Они могут сами прочитать .well-known/oauth-protected-resource, вытащить оттуда authorization_endpoint и token_endpoint, пройти PKCE‑флоу и уже в авторизованном состоянии стучаться к MCP.

MCP Jam создан разработчиками на базе MCP Inspector. Если MCP Inspector реализует минимальный набор отладочных инструментов, то MCP Jam реализует все, что понадобится разработчику в его ежедневной работе с MCP. Лично я рекомендую сразу использовать MCP Jam, чтобы потом не переучиваться.

С точки зрения нашего курса разница в том, что:

  • базовый Inspector нужен вам всегда, даже для простейшего незащищённого MCP‑сервера;
  • MCP Jam (или аналог) становится полезен, когда вы дойдёте до модулей про аутентификацию и авторизацию.

Но общая идея одна: это обычный MCP‑клиент, просто умеющий красиво показывать то, что ChatGPT делает «молча».

3. Типовой сценарий работы с MCP-инспектором

Давайте пройдёмся по типичному сценарию: вы написали новый tool в своём MCP‑сервере и хотите убедиться, что он реально работает.

В прошлой лекции вы уже подняли минимальный MCP‑сервер. Сейчас добавим к этому системный подход к проверке: прогоним полный цикл «сервер → инспектор → JSON‑логика» по шагам.

Шаг 1 — запускаем MCP‑сервер

Вы уже делали это в предыдущей лекции: допустим, у вас есть скрипт npm run mcp-dev:

# пример запуска MCP-сервера
npm run mcp-dev
# под капотом что-то вроде: ts-node src/mcp-server.ts

Важно, чтобы сервер слушал ваш выбранный транспорт: в курсе обычно это HTTP endpoint /mcp на каком‑нибудь порту, например http://localhost:4001/mcp.

Шаг 2 — запускаем MCP Jam

Второй терминал:

# один из вариантов запуска MCP Jam
npx @mcpjam/inspector@latest
# при необходимости можно добавить --port 4002 и т.п.

После этого инспектор открывается в браузере, чаще всего на http://localhost:6274 или похожем порту.

На стартовом экране MCP Jam вас попросят указать URL MCP‑сервера. Вы вводите:

http://localhost:4001/mcp

или ваш туннелированный URL, если вы уже гоняете всё через ngrok.

Шаг 3 — handshake / capabilities

Как только MCP Jam подключается, он автоматически делает то же, что делает ChatGPT:

  1. Шлёт инициализационный запрос (initialize) с данными о клиенте.
  2. Получает ответ с версией протокола и capabilities вашего сервера.
  3. На основе capabilities понимает, поддерживает ли сервер tools, resources, prompts и прочие фичи.

В UI это обычно отображается чем‑то вроде:

Connected
Protocol: mcp/2025-06-18
Capabilities:
- tools: list, call
- resources: list, read
- prompts: list, get

Если уже на этом шаге инспектор не может подключиться (connection refused, CORS, 500 и т.д.), вы сразу видите ошибку и понимаете: проблема точно не в модели и не в ChatGPT, а в вашей серверной части или сети.

Шаг 4 — discovery: смотрим tools/resources/prompts

После успешного handshake инспектор обычно сам вызывает методы вроде tools/list, resources/list, prompts/list, чтобы заполнить боковую панель. Вы увидите:

  • список инструментов с описаниями и JSON Schema входных аргументов;
  • список ресурсов, сгруппированных по коллекциям/путям;
  • список промптов с краткими описаниями.

Если вы только что добавили новый tool, но его нет в списке, значит, он неправильно зарегистрирован на сервере или сервер не поднялся с обновлённым кодом. Это гораздо проще заметить здесь, чем гадать, почему ChatGPT «не хочет» вызывать ваш инструмент.

4. Ручной вызов tools через MCP Jam

Самая полезная функция MCP Jam — ручной вызов инструментов. Это ваш личный UI для tools/call.

Выбираем инструмент и заполняем аргументы

Допустим, в предыдущем модуле вы написали tool suggest_gifts:

// где-то в src/mcp/tools/suggestGifts.ts
export const suggestGiftsTool = {
  name: "suggest_gifts",
  description: "Подбирает идеи подарков по возрасту, бюджету и интересам",
  inputSchema: {
    type: "object",
    properties: {
      age: { type: "number" },
      budget: { type: "number" },
      interests: {
        type: "array",
        items: { type: "string" }
      }
    },
    required: ["age", "budget"]
  },
  // handler определяется отдельно
};

В MCP Jam вы кликаете по suggest_gifts. Справа открывается форма, сгенерированная по inputSchema. Где‑то там вы заполняете:

{
  "age": 30,
  "budget": 100,
  "interests": ["игры", "книги"]
}

и жмёте «Call» или аналогичную кнопку.

Инспектор отправляет MCP‑запрос tools/call, и вы сразу видите:

  • сырые JSON‑данные запроса (что именно уходит на сервер);
  • сырые JSON‑данные ответа (result или error);
  • возможно, удобный превью‑формат результата.

Читаем JSON‑логи в инспекторе

Обычно инспектор показывает что‑то вроде:

// Request
{
  "id": "1",
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "suggest_gifts",
    "arguments": {
      "age": 30,
      "budget": 100,
      "interests": ["игры", "книги"]
    }
  }
}
// Reply
{
  "id": "1",
  "jsonrpc": "2.0",
  "result": {
    "content": [
      {
        "type": "text",
        "text": "1) Настольная игра ... 2) Подарочный сертификат в книжный ..."
      }
    ]
  }
}

Если ваш handler падает с исключением, вы увидите error в стиле JSON‑RPC:

{
  "id": "1",
  "jsonrpc": "2.0",
  "error": {
    "code": -32603,
    "message": "Internal error",
    "data": "TypeError: Cannot read properties of undefined ..."
  }
}

Очень важно: именно здесь вы видите протокольный уровень. Если в ответе не тот формат, который ждёт Apps SDK/ChatGPT, вы сможете это заметить ещё до того, как начнёте ругаться на «баги GPT».

5. Отладка ресурсов и промптов

Инструменты — не всё, что умеет MCP. Вы уже знаете, что есть ещё resources и prompts.

Через инспектор вы можете:

  • открыть список ресурсов (resources/list) и посмотреть их метаданные;
  • прочитать конкретный ресурс (resources/read) и убедиться, что возвращаемые данные корректны;
  • выполнить поиск по ресурсам (если реализовали такую возможность);
  • посмотреть заготовленные промпты и их текст.

Например, если у вас есть ресурс gift_catalog:

// псевдокод регистрации ресурса
registerResource({
  uri: "resource://giftgenius/catalog",
  name: "Каталог подарков",
  mimeType: "application/json",
  handler: async () => {
    return JSON.stringify(giftCatalogData);
  }
});

В инспекторе вы увидите этот ресурс, кликните по нему и сможете сразу увидеть JSON. Если оказывается, что JSON невалидный, или MIME‑тип странный, — вы поймаете это до того, как ChatGPT начнёт спотыкаться, пытаясь его прочитать или встроить в виджет.

6. Логи MCP‑сервера: что, где и как логировать

MCP Jam хорош, но его мало: вам нужны логи самого MCP‑сервера. Без них любой продакшен превратится в лотерею.

Что логировать

Полезный минимум:

  • каждое входящее MCP‑сообщение (request/notification) с:
    • временем;
    • методом (tools/call, tools/list и т.п.);
    • именем инструмента (если есть);
    • усечёнными аргументами (без чувствительных данных);
  • каждый исходящий ответ:
    • статус (успех / ошибка);
    • время выполнения;
    • укороченную версию результата или хотя бы тип;
  • технические ошибки:
    • JSON‑парсинг;
    • неожиданные исключения в handlers.

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

Куда писать логи: stdout / stderr

У MCP есть важное требование: JSON‑сообщения должны идти по «правильному каналу», а все отладочные логи — по другому. Например, если вы используете transport поверх stdout/stderr, то:

  • JSON‑RPC‑сообщения должны идти в stdout;
  • все console.log, console.error и т.п. нужно направлять в stderr.

Если вы смешаете JSON и текстовые логи в одном потоке, клиент (MCP Jam или ChatGPT) просто не сможет распарсить сообщения, потому что среди JSONа внезапно окажется строка вроде Server started at http://localhost:4001. Это одна из частых ошибок в MCP‑серверах.

В HTTP‑сценарии проблема попроще, но принцип тот же: в HTTP‑ответе должен быть чистый JSON, а все логи — в консоль/файл, но не в тело ответа.

Простой логгер для TypeScript MCP‑сервера

Давайте добавим в наш условный MCP‑сервер маленький логгер:

// src/logger.ts
export function logRequest(method: string, details: unknown) {
  console.error(
    JSON.stringify({
      level: "info",
      type: "request",
      method,
      details,
      ts: new Date().toISOString(),
    })
  );
}

export function logError(method: string, error: unknown) {
  console.error(
    JSON.stringify({
      level: "error",
      type: "error",
      method,
      error: String(error),
      ts: new Date().toISOString(),
    })
  );
}

И в обработчике tools:

// src/mcp-server.ts (фрагмент)
server.setRequestHandler("tools/call", async (req) => {
  logRequest("tools/call", {
    name: req.params?.name,
    // здесь лучше не класть всю payload, а только safe-поля
  });

  try {
    const result = await handleToolCall(req);
    return result;
  } catch (e) {
    logError("tools/call", e);
    throw e;
  }
});

Так вы будете видеть в консоли структурированные JSON‑логи, которые потом легко сопоставлять между собой по ts или дополнительному requestId.

7. Связка: MCP Jam + логи

Правильная стратегия отладки MCP почти всегда выглядит так:

  1. Вы воспроизводите проблему в инспекторе: видите, что tools/list возвращает пустой список, tools/call падает, JSON‑ответ странный и т.д.
  2. В тот же момент смотрите логи MCP‑сервера: что он пишет при запуске, какие ошибки выводит на каждое сообщение, есть ли stack trace.
  3. Сопоставляете id, method, ts в логах с тем, что видит инспектор.

Например, вы видите в инспекторе:

{
  "error": {
    "code": -32603,
    "message": "Internal error"
  }
}

И параллельно в логах:

{
  "level": "error",
  "type": "error",
  "method": "tools/call",
  "error": "TypeError: Cannot read properties of undefined (reading 'age')",
  "ts": "2025-11-21T10:15:12.345Z"
}

Всё, диагноз ясен: где‑то в handler вы ожидаете age, но схема/аргументы другие.

8. Мини‑чеклист «готов ли MCP‑сервер к интеграции с App»

Перед тем как подключать MCP‑сервер к реальному ChatGPT App, удобно пройтись по небольшому чеклисту инспектором.

Во‑первых, handshake и capabilities должны проходить без ошибок. MCP Jam должен показывать, что сервер поддерживает нужные вам сущности: хотя бы tools и, если используется, resources / prompts.

Во‑вторых, список tools/resources/prompts в инспекторе должен совпадать с тем набором инструментов, ресурсов и промптов, который вы считаете у себя реализованным. Всякие опечатки в name, забытые регистрации и т.д. ловятся здесь мгновенно.

В‑третьих, вызовы инструментов с валидными аргументами должны стабильно возвращать корректный result. Желательно попробовать несколько типичных кейсов (запросы, на которые вы реально рассчитываете в проде).

В‑четвёртых, вызовы с невалидными аргументами должны возвращать внятные error-ответы в стиле JSON‑RPC, а не падать с 500. Например, если не хватает обязательного параметра, хорошо бы вернуть структурированную ошибку, которую ChatGPT потом можно превратить в понятное пользователю сообщение.

В‑пятых, логи сервера при этом не должны засыпать консоль гигабайтами stack trace на каждый чих. Ошибки должны быть структурированы, а чувствительные данные — аккуратно отфильтрованы.

Если всё из этого выполняется в инспекторе, можно с гораздо более спокойной душой подключать MCP‑сервер к Apps SDK и играться с виджетами в Dev Mode.

9. Типичные баги MCP‑сервера и как их ловить через инспектор

Теперь давайте пройдёмся по самому вкусному — что чаще всего ломается и как это увидеть.

Конфигурация и подключение

Иногда кажется, что «сервер не работает», а проблема в том, что он вообще не слушает нужный порт или endpoint. Инспектор в таком случае честно скажет connection refused или вообще не сможет подключиться. Частые причины: неправильный URL (например, /mcp вместо /api/mcp), порт занят другим процессом, туннель не поднят или CORS режет запросы.

Невалидный JSON / смешивание логов и протокола

Одна из самых болезненных историй — когда вы печатаете console.log("Server started") в stdout, а поверх этого должны идти JSON‑RPC‑сообщения. Клиент ожидает чистый JSON, а получает текст + JSON, пытается распарсить и падает с ошибкой формата.

Решение простое: строго разделить, что идёт в протокольный поток (stdout или тело HTTP‑ответа), а что в логи (stderr или отдельный лог‑файл).

Несовпадение схемы и реализации инструмента

Ещё одна популярная ошибка: в inputSchema вы объявили одно, а в коде ожидаете другое. Например, схема говорит: age — число, interests — необязательный массив строк, а код пытается делать arguments.interests.toLowerCase(). Модель (и инспектор) честно посылают interests как null или вообще не присылают поле — и здесь всё падает.

Инспектор позволяет явно увидеть, какой JSON реально уходит в tools/call, и сопоставить это с вашим кодом.

Неправильные имена tools/resources

Если в capabilities / tools/list вы экспортируете tool как suggest_gifts_v2, а в Apps‑манифесте или виджете ожидаете suggest_gifts, то «инструмент не найден» будет сопровождать вас до конца проекта. В инспекторе по списку tools и их name‑полям это видно сразу, без попыток гадать, что думает GPT.

Медленные или подвисающие tools

Если вызов инструмента в инспекторе выполняется по 30 секунд, а потом падает по таймауту, — не стоит надеяться, что ChatGPT среагирует лучше. MCP‑инспектор поможет понять, на каком именно этапе вы тормозите: сетевой вызов, БД, внешний API. В логах хорошо иметь время начала и окончания обработки каждого запроса, чтобы сразу видеть outliers.

10. Типичные ошибки при инспекции и отладке MCP

Ошибка №1: пытаться дебажить MCP только через ChatGPT.
Многие разработчики сначала подключают MCP к App, видят, что «что‑то не работает», и начинают менять промпты, описание инструмента, иногда даже версию модели. При этом MCP‑сервер вообще не поднимается или tools/list пустой. Всегда начинайте с инспектора: если там всё плохо, модель тут ни при чём.

Ошибка №2: смешивать JSON‑RPC и логи в одном потоке.
Когда MCP‑клиент ожидает чистый JSON, а вы печатаете в stdout отладочные строки, результат предсказуем — парсинг ломается, Inspector показывает странные ошибки. Логи должны идти отдельно (stderr, файлы, внешние системы логирования), а протокольные сообщения — строго в своём канале.

Ошибка №3: не смотреть на capabilities и список tools.
Часто инструмент «пропадает» просто потому, что вы забыли его зарегистрировать или включить соответствующую capability. Если не смотреть на capabilities и tools/list в инспекторе, можно долго думать, что виновата модель, а не ваш код регистрации.

Ошибка №4: игнорировать ошибки схемы и несоответствие JSON.
Когда inputSchema и фактический JSON расходятся, модель и инспектор закономерно начинают вести себя странно. Если вы не смотрите на сырые JSON‑сообщения в инспекторе и не валидируете схему, эти ошибки будут вылезать в самых неожиданных местах.

Ошибка №5: логировать всё подряд, включая PII и токены.
В азарте отладки легко начать печатать в логи полный request body, включая возможные персональные данные или секреты. В продакшене это превращается в бомбу замедленного действия: утечки, проблемы с комплаенсом и т.д. Логируйте только то, что реально нужно для диагностики, и с усечёнными/анонимизированными данными.

Ошибка №6: не воспроизводить проблему минимальными кейсами.
Иногда баг проявляется в сложном диалоге через ChatGPT, и разработчик пытается отлаживать его как есть. Гораздо эффективнее воспроизвести тот же сценарий в инспекторе одним‑двумя MCP‑запросами, отсечь влияние промптов, истории диалога и «настроения» модели.

1
Задача
ChatGPT Apps, 6 уровень, 4 лекция
Недоступна
Минимальный tool для проверки MCP Inspector (ping_inspector)
Минимальный tool для проверки MCP Inspector (ping_inspector)
1
Задача
ChatGPT Apps, 6 уровень, 4 лекция
Недоступна
CLI “мини-инспектор” (initialize → tools/list → tools/call) без UI
CLI “мини-инспектор” (initialize → tools/list → tools/call) без UI
1
Опрос
MCP-протокол, 6 уровень, 4 лекция
Недоступен
MCP-протокол
MCP: протокол, сервер и инспекция
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ