doc-platform
@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';
export const { handler, default: fetchHandler } = crearMcp({
config,
indice,
crearIssue: crearFeedback(config.feedback),
});// middleware.js — en la RAÍZ del repo (Vercel lo exige ahí)
import { next } from '@vercel/functions';
import { decidir } from '@ingadhoc/docs-platform/gate';
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. Не меняй его на ;.
Что экспортирует
Импорт | Что это |
| поисковый движок: |
|
|
|
|
| сравнение токенов за константное время (использует |
| грамматика |
|
|
|
|
|
|
| эталонный |
bin | предохранитель утечек, для |
bin | drift-check, для CI потребителя |
Два контракта
Оба несут schemaVersion, и оба читателя выбрасывают ошибку, если эмитент объявляет более новую версию, чем они умеют читать, — или если не объявляет её вообще. Никакой тихой деградации: неправильный индекс, который отвечает плохо, хуже, чем тот, который не отвечает.
config ↔ платформа:
docs.config.json, со схемой, опубликованной вschema/docs.config.schema.json, и валидатором вlib/config.mjs(собственный, без зависимостей:ajvне попадает в сборку публичного сайта). Дизайн каждого поля с измеренными доказательствами — вdocs/unificacion/diseno-eje.md; три текущих конфига в переводе — вmapeo-configs.md.индекс ↔ движок: его выдаёт
tools/build.mjsкаждого репозитория, а читаетlib/mcp/indice.mjs. Он описан вdocs/unificacion/contrato-indice.md.
Ось в таблице
Корпус объявляет одну ось как объект: { tipo, default?, valores[] }.
| corpus | param в tools |
| подстановочный знак (статьи вне оси) |
| oba-docs |
| выбирает | да ( |
| adhoc-docs |
| структурная неоднозначность (не объявляет | нет |
| odumbo-docs | (не раскрывается) | — | — |
Правило leer() — одно, и в нём нет if по типу оси: оно выбирает только тогда, когда конфиг объявил, кого выбирать. Поведение меняет наличие eje.default, а не тип, — и есть тест, который это проверяет, подставляя default корпусу с осью project.
Запуск тестов
npm install && npm test # 227 casosbloques требует репозиторий контента (он по-настоящему запускает его 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. Opt-out предохранителя утечек в 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, если деплой не объявляет обслуживаемую аудиторию. Это наблюдаемое изменение для потребителя: preflight от 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, чтобы ей соответствовать.
This server cannot be installed
Maintenance
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
Query any docs site via MCP. Submit a URL, ask questions, get cited answers.
A paid remote MCP for Context7 MCP docs, built to return verdicts, receipts, usage logs, and audit-r
Knowledge coverage map and health score. Ingest docs into a governed knowledge graph via MCP.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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