Skip to main content
Glama

@ingadhoc/docs-platform

Платформа документации Adhoc: один поисковый движок, одно ядро MCP, один шлюз доступа и один защитный механизм от утечек, которые потребляются пинами из репозиториев контента (oba-docs, odumbo-docs, adhoc-docs).

До этого четыре части жили в форках в трёх репозиториях: один и тот же файл с тремя диалектами, и каждый фикс распространялся вручную — или не распространялся. Измерение находится в docs/unificacion/: lib/mcp/indice.mjs имел 41 различие между тремя копиями, и 17 из них были фиксами, которые были в одном репозитории, а в двух других — нет. Самый дорогой случай: защитный механизм от утечек был байт-идентичным в двух репозиториях и отсутствовал в третьем.

  • ADR 0006 из knowledge-management — один репозиторий на корпус контента, а платформа как отдельный пакет: контент и движок имеют разные жизненные циклы и разных владельцев.

  • ADR 0007 из knowledge-management — шлюз и защитный механизм от утечек принадлежат платформе, а не каждому сайту: защита, которую каждый репозиторий реализует заново, — это защита, которой у какого-то репозитория нет.

  • Этап A спецификации arquitectura-plataforma-docs: этот пакет с двумя версионированными контрактами и drift-check, который делает видимым отставание пина.

Как потребляется

npm i --ignore-scripts github:ingadhoc/doc-platform#v0.1.0

Точный пин, всегда по тегу. Никаких ^, никаких main, никаких веток: пин — это то, что предотвращает поломку трёх сайтов одновременно из-за фикса платформы, и это то, что позволяет откат одной строкой. Диапазон намеренно вызывает сбой docs-drift-check — пин, который не пинует, не является пином.

--ignore-scripts рекомендуется. У этого пакета нет ни одного install-скрипта, и не будет; флаг предназначен для всего дерева, потому что это выполняется в buildCommand публичных сайтов. По той же причине у пакета одна единственная зависимость (minisearch, которая нужна поисковому движку) и ноль devDependencies: минимальная поверхность в сборке.

Что у потребителя уже есть и этот пакет не объявляет: mcp-handler и zod, которые импортирует lib/mcp/mcp-handler.mjs. Это зависимости репозитория, намеренно: репозиторий решает, с какой версией MCP-фреймворка разворачиваться, и пакет не навязывает свою. Все три репозитория имеют их сегодня.

После npm i у репозитория-потребителя остаются три строки клея:

// api/mcp.mjs
import { crearMcp } from '@ingadhoc/docs-platform/mcp-handler';
import { crearFeedback } from '@ingadhoc/docs-platform/feedback';
import * as indice from '@ingadhoc/docs-platform/indice';
import { config } from '../docs.mcp.config.mjs';
const { handler } = crearMcp({
  config,
  indice,
  crearIssue: crearFeedback(config.feedback),
});
export default handler; // sin default export Vercel no encuentra el handler
// middleware.js — en la RAÍZ del repo (Vercel lo exige ahí)
import { next } from '@vercel/functions';
// Por RUTA RELATIVA, no por especificador de paquete: el bundler del edge
// rechaza `@ingadhoc/docs-platform/gate` cuando el repo consumidor no es
// `"type": "module"` (Docusaurus lo impide) — "unsupported modules".
// Y ojo con renombrar a middleware.mjs: el deploy queda VERDE y SIN
// middleware (la ausencia silenciosa del gate). Hallazgo del piloto
// odumbo-docs, deployment 3mXWLwPHPgcwasEji49pGEg7Lyuv.
import { decidir } from './node_modules/@ingadhoc/docs-platform/lib/mcp/gate.mjs';
const AUDIENCIAS = ['publico', 'interno']; // adhoc-docs: ['interno']
export default function middleware(request) {
  return decidir(request, process.env, { audiencias: AUDIENCIAS }) ?? next();
}
// package.json del consumidor — el guard, dentro del buildCommand
"build:publico": "node tools/build.mjs --audience=publico && npm --prefix site run build && npx docs-guard-fuga --salida=dist/publico"

&& — не косметика: это то, что прерывает деплой, когда защитный механизм выходит с кодом 1. Не меняй его на ;.

Related MCP server: Markdown RAG MCP

Что экспортирует

Импорт

Что это

@ingadhoc/docs-platform/indice

поисковый движок: buscar(), leer(), mapa() по индексу, который выдаёт сборка. Единственный, кто использует minisearch

@ingadhoc/docs-platform/mcp-handler

crearMcp({config, indice, crearIssue}): tools, их схемы по осям, Bearer и транспорт

@ingadhoc/docs-platform/gate

decidir(request, env, {audiencias}) / crearGate(config): решение middleware на edge

@ingadhoc/docs-platform/auth

сравнение токенов за постоянное время (использует node:crypto: только на стороне функции)

@ingadhoc/docs-platform/tokens

грамматика DOCS_MCP_TOKENS, один раз, общая между edge и функцией

@ingadhoc/docs-platform/feedback

crearFeedback(config): tool, которая открывает issue в docs-feedback

@ingadhoc/docs-platform/config

cargarConfig() / validarConfig(): валидатор docs.config.json

@ingadhoc/docs-platform/guard-fuga

correrGuard(), если хочешь вызывать его из своей сборки вместо бинарника

@ingadhoc/docs-platform/middleware

эталонный middleware.js (тот, что находится в корне потребителя)

bin docs-guard-fuga

защитный механизм от утечек, для buildCommand

bin docs-drift-check

drift-check, для CI потребителя

Два контракта

Оба несут schemaVersion, и оба читателя выбрасывают ошибку, если эмитент объявляет более новую версию, чем они умеют читать — или если не объявляет её вообще. Никакой тихой деградации: неправильно отвечающий индекс хуже, чем тот, который не отвечает.

  1. config ↔ платформа: docs.config.json, со схемой, опубликованной в schema/docs.config.schema.json, и валидатором в lib/config.mjs (собственный, без зависимостей: ajv не попадает в сборку публичного сайта). Дизайн каждого поля с измеренными доказательствами находится в docs/unificacion/diseno-eje.md; три текущих конфига в переводе — в mapeo-configs.md.

  2. индекс ↔ движок: его выдаёт tools/build.mjs каждого репозитория, а читает lib/mcp/indice.mjs. Он описан в docs/unificacion/contrato-indice.md.

Ось в таблице

Корпус объявляет одну ось как объект: { tipo, default?, valores[] }.

eje.tipo

корпус

параметр в tools

leer() без значения

подстановочный знак (статьи вне оси)

version

oba-docs

version

выбирает default и сообщает об этом (elegidoPor)

да (relacion/ применяется ко всем)

project

adhoc-docs

project

структурная неоднозначность (не объявляет default)

нет

none

odumbo-docs

(не раскрывается)

Правило leer() одно и не содержит if по типу оси: оно выбирает только тогда, когда конфиг объявил, кого выбирать. Поведение меняет наличие eje.default, а не тип — и есть тест, который это проверяет, добавляя default корпусу с осью project.

Запуск тестов

npm install && npm test        # 227 casos

bloques требует репозиторий контента (он по-настоящему запускает его tools/build.mjs на фикстурах инцидентов) и пропускается с причиной, если его нет:

DOCS_REPO=~/repositorios/oba-docs node --test tests/bloques.test.mjs

Полоса HTTP-обработчика из mcp.test.mjs (16 случаев) также пропускается с причиной, если в checkout нет mcp-handler/zod, которые являются зависимостями потребителя, а не этого пакета. С обеими установленными mcp даёт 57. Случай без своей capability пропускается явно; он не выполняется в деградированном режиме.


Для jjs — открытые решения

Что этот ансамбль не решает сам. Первые три — из diseno-eje.md §7 и затрагивают контракт; остальные вышли из четырёх анализов и остаются живыми после унификации.

1. Одна ось на корпус: принимается ли потолок?

schemaVersion: 1 допускает одну ось на конфиг, и сегодня этого достаточно для трёх репозиториев. В день, когда корпусу понадобится project × version одновременно, схема этого не выражает, и выход — schemaVersion: 2 с ejes: [...] (множественное число). Рекомендация дизайна: явно принять потолок и позволить реальной потребности переоткрыть его с доказательствами (тот же критерий, что и сигнализация о бампах на Этапе B). Это твоё решение, потому что оно затрагивает major.

2. metadata.types: словарь по корпусу или единый для Adhoc?

Сегодня только у adhoc-docs есть types, и его 6 значений очень похожи на стандарт из knowledge-management (concepto, referencia, procedimiento, troubleshooting, guia, indice). Если словарь принадлежит Adhoc, он не идёт в конфиг каждого репозитория: он идёт в пакет, а конфиг только говорит, требует ли он его. Это решение по управлению контентом, а не по схеме; пока оно не принято, схема оставляет его как список по корпусу (совместимо с обоими выходами).

3. Отказ от защитного механизма от утечек в adhoc-docs: подписываешь?

Схема обязывает объявлять deploy.guardDeFuga, так что тихое опущение больше невозможно. Остаются два выхода, оба защитимы: {"activo": false, "motivo": "…"} (у этого репозитория нет публичной сборки: его шлюз безусловный, а защитный механизм защищает от утечки в публичную сборку), или защитный механизм входит всё равно, как ремень. motivo, который сегодня находится в mapeo-configs.md, буквально гласит "PENDIENTE DE FIRMA (jjs)".

И есть техническая часть, которая не исправляется копированием файла (ВОПРОС 1 из analisis-04-seguridad.md): у adhoc-docs нет блоков :::interno, он не выдаёт site/generated.json с аудиторией и у него нет карты deploy.proyectos. С активным защитным механизмом как есть его сборка падает с самого начала из-за "no existe site/generated.json". Строгий вариант — чтобы он выдавал эти две вещи.

4. Список аудиторий остаётся дублированным, и drift-check пока его не сравнивает

docs.config.json → audiences и middleware.js → AUDIENCIAS должны совпадать, и нет способа избежать дублирования: edge не читает из файловой системы. Это ровно тот тип тихого дрейфа, с которого начался форк. Не хватает случая в CI, который бы их сравнивал (сегодняшний docs-drift-check измеряет пин, а не эту согласованность).

5. Три вещи, которые нужно проверить в репозиториях перед тегированием

  • DOCS_AUDIENCE во всех трёх окружениях каждого проекта Vercel (Production, Preview и Development) до merge, который принимает пакет. При fail-closed проект без переменной возвращает 503. Это безопасное направление, но не бесплатное.

  • --esperada в текущих buildCommand: теперь защитный механизм отклоняет его при работе в Vercel. Если какой-то buildCommand передаёт его сегодня, этот деплой начнёт падать. Не удалось проверить по снимкам.

  • GET MCP возвращает 503, если деплой не объявляет обслуживаемую аудиторию. Это наблюдаемое изменение для потребителя: предварительная проверка Claude Code получает 503 вместо плаката, когда деплой неправильно сконфигурирован.

6. Измеренный долг, который этот пакет не может закрыть

  • Fail-closed препроцессора выводит и затем завершается с ошибкой. С неправильно написанной директивой (::: interno), build.mjs записывает site/docs/** с внутренней строкой внутри и затем завершается с кодом 1. Сегодня утечки нет, потому что buildCommand объединяется через &&: защита находится в операторе, а не в программе. Оно объявлено как todo в tests/bloques.test.mjs, и это исправляет унификация build.mjs — которая не вошла в этот этап.

  • tests/bloques.test.mjs записывает в <repo>/site/ потому что в oba и odumbo выходные данные сборки захардкожены. После запуска набора тестов нужно перегенерировать с помощью npm run gen.

  • Ограничения лексического подхода guard: числа и строки короче 5 символов никогда не имеют зонда (ключ 4821, аббревиатура), изображения не сканируются, и утечка внутри applyBlocks не генерирует зонд. Это указано в заголовке guard; я повторяю это здесь, потому что эту часть можно спутать с покрытием.

  • serverInfo.version по-прежнему захардкожена как '1.0.0' в обработчике. Она должна браться из package.json закреплённого пакета, чтобы клиент MCP мог сообщить, с какой версией платформы он взаимодействовал. Это не изменено: это было бы выдумыванием поведения.

  • Подстановочный знак является свойством tipo оси, а не корпуса. Корпус с осью project не может иметь поперечный документ (eje: null остаётся невидимым для любого фильтра). Если когда-нибудь это понадобится, строгий выход — чтобы контракт индекса запрещал это, пока подстановочный знак выключен, чтобы противоречие возникало на этапе сборки, а не в рантайме.

  • В спецификации сказано "vitest" как соглашение о тестах Этапа A, и ни один из трёх репозиториев не использует vitest: реальное соглашение — и соглашение этого пакета — это нативный node:test. Стоит исправить эту строку, прежде чем кто-то установит vitest, чтобы ей соответствовать.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

No tool schema history has been recorded yet.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

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

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides semantic search over markdown documentation using RAG, allowing natural language queries and integration with MCP clients.
    1
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides RAG (Retrieval Augmented Generation) access to technical documentation through MCP, enabling LLMs to search and retrieve relevant documentation on-demand.
    4
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables searching, reading, and navigating MkDocs documentation sites through MCP tools for keyword, semantic, or hybrid search, document browsing, and project metadata.
    1
    BSD 2-Clause "Simplified"

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/ingadhoc/doc-platform'

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