Skip to main content
Glama

@ingadhoc/docs-platform

Die Dokumentationsplattform von Adhoc: eine Suchmaschine, ein MCP-Kern, ein Zugangs-Gate und ein Leak-Guard, die von den Content-Repos (oba-docs, odumbo-docs, adhoc-docs) gepinnt konsumiert werden.

Davor lebten die vier Teile in den drei Repos geforkt: dieselbe Datei mit drei Dialekten, und jeder Fix wurde von Hand propagiert – oder nicht propagiert. Die Messung steht in docs/unificacion/: lib/mcp/indice.mjs hatte 41 Unterschiede zwischen den drei Kopien, und 17 waren Fixes, die ein Repo hatte und die anderen beiden nicht. Der teuerste Fall: Der Leak-Guard war in zwei Repos byte-identisch und existierte im dritten nicht.

  • ADR 0006 aus knowledge-management – ein Repo pro Content-Body, und die Plattform als separates Paket: Content und Engine haben unterschiedliche Lebenszyklen und unterschiedliche Eigentümer.

  • ADR 0007 aus knowledge-management – das Gate und der Leak-Guard gehören zur Plattform, nicht zu jeder Site: Ein Schutz, den jedes Repo neu implementiert, ist ein Schutz, den irgendein Repo nicht hat.

  • Etappe A der Spec arquitectura-plataforma-docs: dieses Paket, mit den beiden versionierten Verträgen und dem Drift-Check, der den Rückstand des Pins sichtbar macht.

Wie es konsumiert wird

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

Exakter Pin, immer per Tag. Kein ^, kein main, keine Branches: Der Pin ist es, der verhindert, dass ein Fix der Plattform drei Sites gleichzeitig bricht, und er ermöglicht ein Rollback in einer Zeile. Ein Bereich lässt den docs-drift-check absichtlich fehlschlagen – ein Pin, der nicht pinnt, ist kein Pin.

--ignore-scripts empfohlen. Dieses Paket hat kein Install-Script und wird keins bekommen; das Flag gilt für den gesamten Baum, weil das im buildCommand von öffentlichen Sites läuft. Aus demselben Grund hat das Paket eine einzige Abhängigkeit (minisearch, die die Suchmaschine braucht) und null devDependencies: minimale Oberfläche im Build.

Was der Konsument bereits hat und dieses Paket nicht deklariert: mcp-handler und zod, die lib/mcp/mcp-handler.mjs importiert. Sie sind bewusst Abhängigkeiten des Repos: Das Repo entscheidet, mit welcher Version des MCP-Frameworks deployed wird, und das Paket drückt ihm keine auf. Alle drei Repos haben sie heute.

Nach dem npm i hat das konsumierende Repo drei Klebezeilen:

// 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"

Das && ist nicht kosmetisch: Es bricht den Deploy ab, wenn der Guard mit 1 endet. Ändere es nicht in ;.

Was es exportiert

Import

Was es ist

@ingadhoc/docs-platform/indice

Suchmaschine: buscar(), leer(), mapa() über den Index, den der Build erzeugt. Es ist der einzige, der minisearch nutzt

@ingadhoc/docs-platform/mcp-handler

crearMcp({config, indice, crearIssue}): die Tools, ihre Schemas pro Achse, das Bearer und den Transport

@ingadhoc/docs-platform/gate

decidir(request, env, {audiencias}) / crearGate(config): die Entscheidung der Edge-Middleware

@ingadhoc/docs-platform/auth

Token-Vergleich in konstanter Zeit (nutzt node:crypto: nur auf der Funktionsseite)

@ingadhoc/docs-platform/tokens

die Grammatik von DOCS_MCP_TOKENS, einmal, geteilt zwischen Edge und Funktion

@ingadhoc/docs-platform/feedback

crearFeedback(config): das Tool, das das Issue von docs-feedback öffnet

@ingadhoc/docs-platform/config

cargarConfig() / validarConfig(): der Validator der docs.config.json

@ingadhoc/docs-platform/guard-fuga

correrGuard(), falls du es aus deinem Build statt aus dem Bin aufrufen willst

@ingadhoc/docs-platform/middleware

die Referenz-middleware.js (die, die in die Wurzel des Konsumenten gehört)

Bin docs-guard-fuga

der Leak-Guard, für den buildCommand

Bin docs-drift-check

der Drift-Check, für das CI des Konsumenten

Die beiden Verträge

Beide tragen schemaVersion, und beide Leser werfen, wenn der Sender eine neuere Version deklariert, als sie lesen können – oder wenn er sie nicht deklariert. Kein stilles Degradieren: Ein falscher Index, der falsch antwortet, ist schlimmer als einer, der nicht antwortet.

  1. Config ↔ Plattform: docs.config.json, mit Schema veröffentlicht in schema/docs.config.schema.json und Validator in lib/config.mjs (eigen, ohne Abhängigkeiten: ajv kommt nicht in den Build einer öffentlichen Site). Das Design jedes Felds, mit der gemessenen Evidenz, steht in docs/unificacion/diseno-eje.md; die drei aktuellen Configs übersetzt in mapeo-configs.md.

  2. Index ↔ Engine: Es wird von tools/build.mjs jedes Repos erzeugt und von lib/mcp/indice.mjs gelesen. Es ist spezifiziert in docs/unificacion/contrato-indice.md.

Die Achse, in einer Tabelle

Das Korpus deklariert eine Achse als Objekt: { tipo, default?, valores[] }.

eje.tipo

corpus

param in den Tools

leer() ohne Wert

Wildcard (Artikel außerhalb der Achse)

version

oba-docs

version

wählt den default und sagt es (elegidoPor)

ja (relacion/ gilt für alle)

project

adhoc-docs

project

strukturierte Mehrdeutigkeit (deklariert kein default)

nein

none

odumbo-docs

(wird nicht exponiert)

Die Regel von leer() ist eine und hat kein if pro Achsentyp: Sie wählt nur, wenn die Config deklariert hat, wen sie wählen soll. Was das Verhalten ändert, ist das Vorhandensein von eje.default, nicht der Typ – und es gibt einen Test, der das beweist, indem er einem Korpus mit Achse project einen default gibt.

Tests ausführen

npm install && npm test        # 227 casos

bloques braucht ein Content-Repo (es führt dessen tools/build.mjs wirklich über die Incident-Fixtures aus) und wird mit Grund übersprungen, wenn keins da ist:

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

Der Streifen des HTTP-Handlers von mcp.test.mjs (16 Fälle) wird ebenfalls mit Grund übersprungen, wenn der Checkout kein mcp-handler/zod hat, die Abhängigkeiten des Konsumenten und nicht dieses Pakets sind. Mit beiden installiert ergibt mcp 57. Ein Fall ohne seine Capability wird explizit übersprungen; er wird nicht degradiert ausgeführt.


Für jjs – offene Entscheidungen

Was dieser Zusammenbau nicht allein löst. Die ersten drei stammen aus diseno-eje.md §7 und betreffen den Vertrag; die übrigen kamen aus den vier Analysen und sind nach der Vereinheitlichung weiterhin offen.

1. Eine einzige Achse pro Korpus: Wird die Obergrenze akzeptiert?

schemaVersion: 1 erlaubt eine Achse pro Config, und das reicht heute für die drei Repos. An dem Tag, an dem ein Korpus project × version gleichzeitig braucht, drückt das Schema das nicht aus, und die Lösung ist ein schemaVersion: 2 mit ejes: [...] (Plural). Design-Empfehlung: Die Obergrenze explizit akzeptieren und sie durch echten Bedarf mit Evidenz wieder öffnen (gleiches Kriterium wie der Bump-Alarm der Etappe B). Es ist deine Entscheidung, weil es das Major betrifft.

2. metadata.types: Vokabular pro Korpus oder Adhoc-weit?

Heute hat nur adhoc-docs types, und seine 6 Werte ähneln stark einem Standard aus knowledge-management (concepto, referencia, procedimiento, troubleshooting, guia, indice). Wenn das Vokabular Adhoc-weit ist, gehört es nicht in die Config jedes Repos: Es gehört ins Paket, und die Config sagt nur, ob sie es verlangt. Das ist eine Content-Governance-Entscheidung, keine Schema-Entscheidung; solange sie nicht entschieden ist, lässt das Schema es als Liste pro Korpus (kompatibel mit beiden Ausgängen).

3. Der Opt-out des Leak-Guards in adhoc-docs: Unterschreibst du ihn?

Das Schema verpflichtet, deploy.guardDeFuga zu deklarieren, also ist die stille Auslassung nicht mehr möglich. Es bleiben die beiden Ausgänge, beide vertretbar: {"activo": false, "motivo": "…"} (dieses Repo hat keinen öffentlichen Build: Sein Gate ist unbedingt, und der Guard schützt gegen den Leak in den öffentlichen Build), oder der Guard kommt trotzdem rein, als Sicherheitsgurt. Das motivo, das heute in mapeo-configs.md steht, lautet wörtlich "PENDIENTE DE FIRMA (jjs)".

Und es gibt einen technischen Teil, der sich nicht durch Kopieren der Datei beheben lässt (FRAGE 1 aus analisis-04-seguridad.md): adhoc-docs hat keine :::interno-Blöcke, erzeugt kein site/generated.json mit Audienz und hat keine deploy.proyectos-Map. Mit dem Guard aktiv wie er ist, schlägt sein Build sofort fehl wegen "no existe site/generated.json". Die strenge Lösung ist, dass es diese beiden Dinge erzeugt.

4. Die Audienzliste bleibt dupliziert, und der Drift-Check vergleicht sie noch nicht

docs.config.json → audiences und middleware.js → AUDIENCIAS müssen übereinstimmen, und es gibt keine Möglichkeit, die Duplizierung zu vermeiden: Die Edge liest nicht vom Dateisystem. Das ist genau die Art von stillem Drift, wo der Fork begann. Es fehlt ein CI-Fall, der sie vergleicht (der heutige docs-drift-check misst den Pin, nicht diese Kohärenz).

5. Drei Dinge, die in den Repos vor dem Taggen geprüft werden müssen

  • DOCS_AUDIENCE in den drei Environments jedes Vercel-Projekts (Production, Preview und Development) vor dem Merge, der das Paket übernimmt. Mit Fail-Closed gibt ein Projekt ohne die Variable 503 zurück. Das ist die sichere Richtung, aber nicht kostenlos.

  • --esperada in den aktuellen buildCommands: Jetzt lehnt der Guard es ab, wenn er auf Vercel läuft. Wenn ein buildCommand es heute übergibt, beginnt dieser Deploy zu scheitern. Das konnte von den Snapshots aus nicht verifiziert werden.

  • Der GET des MCP gibt 503 zurück, wenn das Deployment keine bedienbare Audienz deklariert. Das ist eine sichtbare Änderung für den Konsumenten: Der Preflight von Claude Code erhält 503 statt des Schilds, wenn das Deployment falsch konfiguriert ist.

6. Gemessene Schuld, die dieses Paket nicht schließen kann

  • Der Fail-closed des Präprozessors gibt aus und schlägt danach fehl. Mit einer falsch geschriebenen Direktive (::: interno) schreibt build.mjs site/docs/** mit der internen Zeile hinein und danach endet es mit 1. Heute leakt es nicht, weil der buildCommand mit && verknüpft: Der Schutz liegt im Operator, nicht im Programm. Es ist als todo in tests/bloques.test.mjs deklariert, und die Vereinheitlichung von build.mjs behebt es – die nicht in diese Stufe eingegangen ist.

  • tests/bloques.test.mjs schreibt in <repo>/site/, weil in oba und odumbo die Build-Ausgabe hartcodiert ist. Nach dem Ausführen der Suite muss mit npm run gen neu generiert werden.

  • Grenzen des lexikalischen Ansatzes des Guards: Zahlen und Strings mit weniger als 5 Zeichen haben nie eine Sonde (ein Schlüssel 4821, ein Akronym), Bilder werden nicht gescannt, und ein Leck innerhalb von applyBlocks erzeugt keine Sonde. Es steht im Header des Guards; ich wiederhole es hier, weil es der Teil ist, der mit Abdeckung verwechselt werden kann.

  • serverInfo.version ist im Handler weiterhin auf '1.0.0' hartcodiert. Es sollte aus der package.json des gepinnten Pakets stammen, damit ein MCP-Client melden kann, gegen welche Version der Plattform er gesprochen hat. Es wurde nicht geändert: Es wäre, Verhalten zu erfinden.

  • Der Platzhalter ist Eigenschaft des tipo der Achse, nicht des Korpus. Ein Korpus mit Achse project kann kein transversales Dokument haben (eje: null bleibt für jeden Filter unsichtbar). Falls es je nötig wird, ist die strikte Ausgabe, dass der Indexvertrag es verbietet, solange der Platzhalter ausgeschaltet ist, damit der Widerspruch im Build und nicht zur Laufzeit fehlschlägt.

  • Die Spec sagt „vitest“ als Testkonvention der Stufe A, und keines der drei Repos verwendet vitest: Die tatsächliche Konvention – und die dieses Pakets – ist natives node:test. Es lohnt sich, diese Zeile zu korrigieren, bevor jemand vitest installiert, um sie zu erfüllen.

-
license - not tested
Not graded
quality - not tested
B
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 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.

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

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