Перейти к содержимому

Здоровье MCP-сервера

MCP превратился в основной транспорт для tool-use в Claude Code, GitHub Copilot Chat, Cursor и собственных агентов. Когда MCP-сервер падает или тупит — модель не получает данных, отвечает из «головы», галлюцинирует. С точки зрения пользователя это не «ошибка сервера», а «AI плохой» — расследование занимает часы.

Notifly даёт три уровня защиты для MCP.

Если ваш MCP-сервер живёт по HTTP/SSE — самый простой активный монитор:

{
"kind": "http",
"target": "https://mcp.example.com/healthz",
"intervalSec": 60,
"consecutiveFails": 3,
"alertMessage": "MCP-сервер не отвечает — Claude теряет инструменты",
"recoveryMessage": "MCP-сервер снова в строю"
}

Для self-hosted MCP без /healthz — мониторьте сам TCP-порт:

{ "kind": "tcp", "target": "mcp.example.com:8443", "intervalSec": 60 }

См. встроенный MCP-сервер Notifly — у него такая же страница MCP.

stdio-MCP запускается локально как дочерний процесс IDE — там у вас нет HTTP-эндпоинта. Защита: ваш MCP-сервер сам пингует Notifly heartbeat каждые N минут активности.

# в обработчике одного из tool-вызовов
import os, time, requests, threading
PING = os.environ.get("MCP_HEARTBEAT_URL")
_last = 0
def maybe_ping():
global _last
if PING and time.time() - _last > 60:
try: requests.get(PING, timeout=3)
except Exception: pass
_last = time.time()
@server.tool("search")
def search(query: str):
maybe_ping()
return ...

Heartbeat-интервал ставьте 5–10 минут — если IDE не использует MCP неделю, это не «инцидент», а нормальное молчание. Алёрт прилетит, только когда сервер должен был работать (IDE открыта, инструмент дёргался) и вдруг встал.

Самое полезное — функция, которая раз в N минут вызывает реальный tool через MCP-клиент и проверяет ответ. Подходит scheduled cloud-функция:

import os, time, requests
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
import asyncio
async def probe():
params = StdioServerParameters(
command="npx", args=["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
)
async with stdio_client(params) as (read, write):
async with ClientSession(read, write) as s:
await s.initialize()
tools = await s.list_tools()
assert any(t.name == "read_file" for t in tools.tools)
await s.call_tool("read_file", {"path": "/etc/hostname"})
def handler(event, context):
t0 = time.time()
try:
asyncio.run(asyncio.wait_for(probe(), timeout=15))
except Exception as e:
notify("❌ MCP probe failed", f"{type(e).__name__}: {e}", 9)
return {"statusCode": 200}
ms = int((time.time() - t0) * 1000)
if ms > 5000:
notify("⏱️ MCP медленный", f"Probe занял {ms} мс", 7)
return {"statusCode": 200}

Аналогично — для HTTP MCP через mcp.client.http или прямой POST.

Сторонние MCP-серверы (@modelcontextprotocol/server-*, community implementations) тоже имеют релизы и тоже ломаются. Следите за versions через простой ping-скрипт:

Окно терминала
prev=$(cat /tmp/mcp-versions || true)
cur=$(npm view @modelcontextprotocol/server-filesystem version)
if [[ "$prev" != "$cur" ]]; then
curl -fsS "$NOTIFLY_URL/message?token=$NOTIFLY_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"title\":\"🆕 MCP server-filesystem $cur\",\"message\":\"Прошлая версия: $prev\",\"priority\":4}"
fi
echo "$cur" > /tmp/mcp-versions
  • какой именно MCP не отвечает (имя из вашей mcp.json);
  • какие tools он экспортировал в прошлый раз и какие сейчас;
  • сколько активных IDE-сессий полагаются на этот сервер (если знаете);
  • ссылка на логи / dashboard.