doc-platform
@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.0Exakter 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 |
| Suchmaschine: |
|
|
|
|
| Token-Vergleich in konstanter Zeit (nutzt |
| die Grammatik von |
|
|
|
|
|
|
| die Referenz- |
Bin | der Leak-Guard, für den |
Bin | 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.
Config ↔ Plattform:
docs.config.json, mit Schema veröffentlicht inschema/docs.config.schema.jsonund Validator inlib/config.mjs(eigen, ohne Abhängigkeiten:ajvkommt nicht in den Build einer öffentlichen Site). Das Design jedes Felds, mit der gemessenen Evidenz, steht indocs/unificacion/diseno-eje.md; die drei aktuellen Configs übersetzt inmapeo-configs.md.Index ↔ Engine: Es wird von
tools/build.mjsjedes Repos erzeugt und vonlib/mcp/indice.mjsgelesen. Es ist spezifiziert indocs/unificacion/contrato-indice.md.
Die Achse, in einer Tabelle
Das Korpus deklariert eine Achse als Objekt: { tipo, default?, valores[] }.
| corpus | param in den Tools |
| Wildcard (Artikel außerhalb der Achse) |
| oba-docs |
| wählt den | ja ( |
| adhoc-docs |
| strukturierte Mehrdeutigkeit (deklariert kein | nein |
| 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 casosbloques 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.mjsDer 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_AUDIENCEin 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.--esperadain den aktuellenbuildCommands: 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) schreibtbuild.mjssite/docs/**mit der internen Zeile hinein und danach endet es mit 1. Heute leakt es nicht, weil derbuildCommandmit&&verknüpft: Der Schutz liegt im Operator, nicht im Programm. Es ist alstodointests/bloques.test.mjsdeklariert, und die Vereinheitlichung vonbuild.mjsbehebt es – die nicht in diese Stufe eingegangen ist.tests/bloques.test.mjsschreibt in<repo>/site/, weil in oba und odumbo die Build-Ausgabe hartcodiert ist. Nach dem Ausführen der Suite muss mitnpm run genneu 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 vonapplyBlockserzeugt keine Sonde. Es steht im Header des Guards; ich wiederhole es hier, weil es der Teil ist, der mit Abdeckung verwechselt werden kann.serverInfo.versionist im Handler weiterhin auf'1.0.0'hartcodiert. Es sollte aus derpackage.jsondes 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
tipoder Achse, nicht des Korpus. Ein Korpus mit Achseprojectkann kein transversales Dokument haben (eje: nullbleibt 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.
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