Skip to main content
Glama
ivantagesam

OpsBridge MCP

by ivantagesam

OpsBridge MCP

Сервер Model Context Protocol (MCP), который предоставляет AI-клиенту контролируемый и аудируемый доступ к данным о клиентах и тикетах поддержки бизнеса — включая одно реальное действие записи, ограниченное проверкой одобрения на стороне сервера, а не инструкцией в промпте.

Это целенаправленная техническая демонстрация, а не продукт. Это портфолио-проект, созданный, чтобы показать одну вещь хорошо: корректно реализованный MCP-сервер на TypeScript с той инженерной дисциплиной, которая отличает демо, которое просто работает, от того, которое действительно безопасно направить на LLM — валидация схем, параметризованный SQL, шлюз одобрения, реализованный в коде приложения, и журнал аудита, всё проверено против реального SDK и реального протокола, а не предположено. Он не развёрнут нигде, у него нет реальных клиентов, и он не претендует на готовность к продакшену — см. Ограничения и Что бы я изменил для продакшена для точного указания границы.

Какую проблему это решает

AI-клиенты всё чаще ожидают, что они будут совершать реальные действия в реальных системах, а не просто отвечать на вопросы. Это создаёт конкретную инженерную проблему: как позволить модели читать живые бизнес-данные и выполнять значимое действие, не давая ей (а) неограниченный доступ к базе данных или (б) полагаясь на то, что промпт — единственное, что стоит между «модель предложила это» и «это действительно произошло»?

OpsBridge — это небольшой, полный ответ на эту проблему для одного конкретного случая: системы тикетов поддержки. Он предоставляет ровно те данные, которые нужны AI-ассистенту (клиенты, тикеты), и ровно один способ что-либо изменить (создать тикет) — и этот единственный путь записи не может быть выполнен, если вызывающий код явно не укажет approved: true, что проверяется в серверном коде, который выполняется независимо от того, что «решает» модель. Всё остальное в проекте — схемы, обработка ошибок, журнал аудита — существует для того, чтобы сделать эту единственную гарантию действительно надёжной.

Related MCP server: SQLite MCP Server

Что MCP делает в этой архитектуре

Протокол Model Context Protocol — это слой, который позволяет AI-клиенту (Claude Code, Claude Desktop, MCP Inspector или любому другому, кто говорит на MCP) обнаруживать, что может делать этот сервер, и вызывать его без какого-либо пользовательского интеграционного кода для каждого клиента. Конкретно в этом проекте MCP отвечает за:

  • Обнаружение инструментов — сервер рекламирует search_customers, get_customer, list_customer_tickets и create_support_ticket, каждый с входными и выходными данными, описанными в JSON Schema, автоматически генерируемыми из Zod-схем этого проекта.

  • Структурированный контракт запроса/ответа — каждый вызов инструмента проверяется на соответствие его схеме до того, как код этого проекта вообще выполнится, и каждый ответ — либо обычный результат, либо корректно сформированный результат isError: true — никогда не сырое исключение или некорректный ответ.

  • Транспорт — JSON-RPC 2.0 через stdio. Клиент запускает node dist/index.js как подпроцесс и общается с ним через stdin/stdout; сетевого порта нет.

MCP не выполняет никакой реальной работы — это причина, по которой универсальный AI-клиент может использовать этот сервер вообще без специального связующего кода. Бизнес-логика, валидация и гарантии безопасности — это собственная работа этого проекта.

Архитектура

flowchart TD
    Client["Claude Code / MCP Client"]
    Protocol["MCP Protocol<br/>(JSON-RPC over stdio)"]
    Server["OpsBridge MCP Server<br/>src/server.ts · src/index.ts"]
    Tools["Tool Layer<br/>src/tools/*.ts"]
    Approval["Approval / Validation<br/>src/domain/*.ts"]
    DB[("SQLite Database<br/>src/db/*.ts")]
    Audit["Audit Log (stderr)<br/>src/lib/audit.ts"]

    Client --> Protocol --> Server --> Tools --> Approval --> DB
    Tools -.->|every call, success or failure| Audit
src/
  db/        SQLite schema, synthetic seed data, idempotent seeding
  domain/    Repository functions (customers, tickets) — plain TS, no MCP knowledge
  tools/     One file per MCP tool: Zod schema, audit-log wrapper, thin handler
  lib/       Audit logging (lib/audit.ts) and typed error classes (lib/errors.ts)
  server.ts  Builds the McpServer and registers all tools
  index.ts   Entrypoint — opens/seeds the DB, connects stdio transport

Слои продуманы и однонаправленны: каждый слой знает только о слое под ним, и domain/ не имеет импорта ничего из @modelcontextprotocol/sdk — это чистый TypeScript, работающий с базой данных better-sqlite3. Именно это позволяет тестовому набору проверять реальный сквозной путь вызова инструмента (реальный MCP Client, общающийся с реальным McpServer) вместо мокирования границ слоёв. Полное описание, включая точные пути кода: docs/architecture.md.

Предоставляемые инструменты

Инструмент

Тип

Назначение

search_customers

чтение

Поиск клиентов по имени или email (частичное, без учёта регистра)

get_customer

чтение

Получение деталей одного клиента по id

list_customer_tickets

чтение

Список тикетов клиента, опционально фильтруется по статусу

create_support_ticket

запись

Создание нового тикета — требует явного approved: true

На основе SQLite с синтетическими, вымышленными данными: 10 клиентов, 18 предзаполненных тикетов поддержки.

Технологический стек

Слой

Выбор

Почему

Язык

TypeScript, строгий режим + noUncheckedIndexedAccess / exactOptionalPropertyTypes

Ловит реальные ошибки на границах слоёв, которые важны для этого проекта (необязательные поля, индексированный доступ)

MCP SDK

@modelcontextprotocol/sdk 1.30.0

Текущая опубликованная мажорная версия — на момент написания v2 не существует; проверено по собственным .d.ts файлам установленного пакета, а не по туториалам

Валидация схем

zod ^4

Единый источник истины и для валидации во время выполнения, и для JSON Schema, отправляемой клиентам

База данных

better-sqlite3 ^12 (синхронная)

Нет сложности с асинхронным драйвером/пулом для однопроцессного локального сервера; ^12, а не более новый 13.x, потому что 13.x требует Node 22+, а этот проект нацелен на Node 20+

Среда выполнения

Node.js 20+

Заявленный базовый уровень проекта

Тесты

vitest ^4

Подключает реальный MCP Client к реальному McpServer через InMemoryTransport — см. Тестирование

Линтер

eslint ^10 + typescript-eslint ^8

typescript-eslint пока не поддерживает TypeScript 7 (новый компилятор на Go), поэтому TypeScript закреплён на ветке 5.9.x — осознанный выбор совместимости, а не упущение

Dev-раннер

tsx

Запускает src/index.ts напрямую без шага сборки во время разработки

Механизм одобрения

create_support_ticket — единственное значимое действие в системе, поэтому именно здесь проект добавляет жёсткий шлюз:

// src/domain/tickets.ts
export function createSupportTicket(db, input: CreateTicketInput): Ticket {
  if (input.approved !== true) {
    throw new ApprovalRequiredError(
      "Ticket creation was not approved. Set approved=true to confirm this action before it is created.",
    );
  }
  // ... only reaches the INSERT after this point
}

Две вещи делают это реальным механизмом принуждения, а не предложением:

  1. Он выполняется в доменном слое, ниже слоя MCP-инструментов, до выполнения любого SQL — нет пути кода от обработчика инструмента к INSERT в базу данных, который обходит его.

  2. approvedобязательное логическое значение в схеме входа инструмента, не необязательное. Если его опустить, вызов не пройдёт валидацию схемы до того, как этот код вообще выполнится; если передать false, он будет отклонён здесь.

Описание инструмента также просит модель сначала подтвердить с пользователем — но это рекомендательный текст для поведения модели, а не то, что делает систему безопасной. Гарантия сохраняется, даже если модель игнорирует описание и вызывает инструмент напрямую; сервер, а не промпт, является последней линией обороны.

Что это не гарантирует: что флаг действительно установил человек — approved: true — это просто ещё один аргумент, который модель может предоставить по собственной инициативе, и человек никогда не увидит запрос. Полное закрытие этого пробела потребовало бы, чтобы сервер принудительно выполнял интерактивный цикл подтверждения обратно к человеку (elicitation в MCP); этот проект намеренно не добавляет этого, поскольку это реальное изменение модели взаимодействия для гарантии, которую этот проект не заявляет. См. Ограничения.

Вопросы безопасности

  • Одобрение реализовано в коде приложения, а не в промпте — см. выше.

  • Каждый вызов инструмента записывается в журнал аудита в stderr (src/lib/audit.ts, применяется на уровне инструментов через обёртку withAudit() вокруг всех четырёх инструментов): имя инструмента, временная метка, успех/неудача и нечувствительный идентификатор (customer_id, где применимо); строки create_support_ticket также записывают, было ли одобрено действие. Никогда не записывается чувствительное содержимое вызова — ни темы/описания тикетов, ни сырой текст поискового запроса, ни email/телефон/имя.

  • Весь SQL параметризован через подготовленные выражения better-sqlite3 — нет конкатенации строк, поэтому нет поверхности для SQL-инъекций, даже несмотря на то, что входные данные в конечном итоге исходят от LLM. Паттерн LIKE в search_customers также экранирует %/_, чтобы поисковый текст сопоставлялся буквально, а не как подстановочный знак (иначе запрос просто "%" вернул бы все строки).

  • Входные данные проверяются с помощью Zod до того, как они достигнут любой бизнес-логики — ограничения длины, ограничения перечислений для priority/status — отклоняя некорректный ввод с понятной ошибкой вместо передачи его дальше.

  • Сохранённый текст тикета рассматривается как данные, а не как инструкции. subject/description — это свободный текст, и тикет, созданный сейчас, будет прочитан дословно последующим вызовом list_customer_tickets — это вектор инъекции второго порядка. Текст ответа явно отмечает, что это содержимое является сохранённым пользовательским вводом, а не директивами. Это смягчение, а не гарантия.

  • Нет аутентификации или авторизации. Это локальное демо для одного пользователя — любой, кто может запустить процесс, имеет полный доступ ко всем инструментам, включая полные PII клиентов. Явно вне области действия здесь; это должно измениться, прежде чем этот паттерн коснётся реальных многопользовательских данных.

  • В проекте нет секретов. Никаких API-ключей, токенов или учётных данных; единственная внешняя зависимость — локальный файл SQLite, который находится в .gitignore.

Примеры взаимодействия с Claude

Промпты для чтения, после подключения:

  • «Найди клиента по имени Chen.»

  • «Получи полные данные для клиента cust_004.»

  • «Какие открытые тикеты у cust_005?»

Интересный случай — путь записи:

Вы: «Создай приоритетный тикет поддержки для cust_002 о том, что их трекинг-номера не синхронизируются — но сначала спроси меня, прежде чем реально создавать его.»

Ожидаемое поведение: модель вызывает search_customers/get_customer по мере необходимости, затем либо просит вас подтвердить перед вызовом create_support_ticket, либо вызывает его один раз с approved false/опущенным, получает отказ и возвращает вам предложенный тикет. В любом случае ничего не записывается, пока вы действительно не согласитесь и модель не вызовет его снова с approved: true.

Более подробные сценарии, включая принудительное отклонение напрямую, чтобы увидеть исходное сообщение о принуждении: docs/demo-script.md.

Локальная настройка

Требуется Node.js 20+.

npm install
npm run db:seed     # creates and seeds data/opsbridge.db (10 customers, 18 tickets)
npm run build        # compiles TypeScript to dist/
npm run dev           # runs src/index.ts directly with tsx (auto-seeds on first run)
# or, after `npm run build`:
npm start              # runs dist/index.js

Сервер общается через stdio — нет HTTP-порта, нечего открывать в браузере напрямую.

Подключение к Claude Code: этот репозиторий содержит файл .mcp.json в скоупе проекта (сгенерирован через claude mcp add opsbridge --scope project -- node dist/index.js — то есть ровно то, что создаёт сам CLI, а не написанное вручную). Сначала выполните сборку, затем один раз одобрите его:

npm run build
claude          # prompts to trust this project's .mcp.json server on first run — approve it
claude mcp list # should show: opsbridge: node dist/index.js - ✔ Connected

Подключение любого другого MCP-клиента (Claude Desktop и т. п.) — большинство читают JSON-конфиг с парой command/args:

{
  "mcpServers": {
    "opsbridge": {
      "command": "node",
      "args": ["/absolute/path/to/opsbridge-mcp/dist/index.js"]
    }
  }
}

Ручная проверка без полноценного клиента — MCP Inspector с намеренно зафиксированной версией (без указания версии npx @modelcontextprotocol/inspector может срезолвиться в устаревшую кэшированную сборку вместо текущего релиза):

npx @modelcontextprotocol/inspector@2.3.0 node dist/index.js       # web UI
npx @modelcontextprotocol/inspector@2.3.0 --cli node dist/index.js -- --method tools/list   # headless

Тестирование

npm test        # vitest — 33 tests across 6 files
npm run typecheck
npm run lint

Тесты соединяют реальный Client MCP с реальным McpServer через InMemoryTransport из SDK и используют свежую in-memory базу данных SQLite для каждого теста (tests/helpers.ts) — проверяется реальный путь, который проходит настоящий клиент: запрос → валидация Zod → обработчик инструмента → ответ, а не только доменные функции по отдельности. Покрытие включает: успешный и пустой поиск, клиент не найден, список тикетов с фильтром по статусу и без него, некорректный ввод для каждого инструмента, отклонение создания тикета и при approved: false, и при полностью отсутствующем approved, успешное создание, защиту от повторной отправки, экранирование LIKE-подстановочных символов, попытку промпт-инъекции текстом и содержимое журнала аудита (включая то, что PII никогда не появляется в строке лога) для каждого инструмента.

Ограничения

Намеренные сокращения области для сфокусированного демо, а не упущения:

  • Нет аутентификации, авторизации или разграничения данных по пользователю — см. Security considerations.

  • Флаг одобрения — не подтверждённый человеческий сигнал — это булево значение, которое модель может выставить по своей инициативе; см. Approval mechanism.

  • Нет пагинации — поиск ограничен 10 результатами; списки тикетов ничем не ограничены, но набор данных крошечный.

  • Нет инструментов обновления и удаления — запись выполняется только при создании тикета.

  • Только stdio-транспорт — нет HTTP/SSE, нет сценария удалённого развёртывания.

  • Нет ограничения частоты запросов и ключа идемпотентности у create_support_ticket — повторный вызов создаёт второй независимый тикет, а не отбрасывается как дубликат.

  • SQLite, один процесс — нет пула соединений; из инструментов миграции только CREATE TABLE IF NOT EXISTS.

  • Журнал аудита — локальный поток stderr — никуда не отправляется, его нельзя запрашивать, нет политики хранения.

Что я бы изменил для продакшена

Если бы этот паттерн был нацелен на реальных клиентов, а не на синтетические демо-данные:

  • Уйти со stdio на Streamable HTTP с OAuth bearer-аутентификацией, разграниченной по тенанту/клиенту — SDK уже поддерживает этот транспорт; текущая stdio-модель неявно доверяет любому, кто может запустить процесс, что нормально только для локального демо и ни для чего больше.

  • Добавить настоящую авторизацию — сопоставлять аутентифицированного вызывающего с тем, к каким клиентам и тикетам он может обращаться; сейчас каждый инструмент не имеет никакого разграничения.

  • Сделать одобрение проверяемым, а не просто формально присутствующим — использовать MCP elicitation, чтобы потребовать реального обратного подтверждения от человека, либо требовать короткоживущий токен, выпущенный отдельным шагом подтверждения вне контроля модели.

  • Заменить SQLite на Postgres с пулом соединений и настоящим инструментом миграций.

  • Отправлять журнал аудита в долговечное и доступное для запросов хранилище (не в stderr) с политикой хранения и контроля доступа, подходящей тому, что в нём аудитируется.

  • Добавить rate limiting и ключ идемпотентности на путь записи.

  • Добавить пагинацию в search_customers и list_customer_tickets.

  • Добавить наблюдаемость — задержку, частоту ошибок и объём вызовов по каждому инструменту.

  • Запускать typecheck/тесты/линтер в CI при каждом изменении, а не только локально по требованию.

Ничего из этого здесь не реализовано — цель проекта в том, чтобы корректно продемонстрировать паттерн в малом масштабе, а не заранее собирать инфраструктуру, которая нужна реальному развёртыванию, но не нужна демо.

F
license - not found
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • Runtime permission, approval, and audit layer for AI agent tool execution.

  • Deterministic compliance and vertical knowledge bases for autonomous agents. Free 24hr trial.

  • Pre-action allow/deny for AI agents. 24 statutes, 13 jurisdictions: EU AI Act, GDPR, DPDP.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ivantagesam/opsbridge-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server