Skip to main content
Glama
srhtdmrkl

osha-recordkeeping-mcp

by srhtdmrkl

OSHA Recordkeeping MCP — 29 CFR Part 1904

Ein deterministischer Model Context Protocol-Server, der einem Sicherheitsmanager hilft, die Frage zu beantworten, die sich bei jeder Verletzung stellt: ist das OSHA-aufzeichnungspflichtig?

Elf Tools begleiten einen Vorfall von jemand wurde verletzt bis zu einem korrekten Log-Eintrag, wobei jedes eine zitierte Entscheidung liefert, statt einer Erinnerung des Modells an die Regel. MIT-lizenziert und kostenlos nutzbar.

Nur Referenz und Triage — keine Rechtsberatung und keine medizinische Feststellung. Jede Entscheidung trägt ihr CFR-Zitat und das Datum, an dem die zugrunde liegenden Daten zuletzt gegen eCFR verifiziert wurden, sodass die Begründung nachvollziehbar statt behauptet ist.

Verwendung

git clone https://github.com/srhtdmrkl/osha-recordkeeping-mcp.git
cd osha-recordkeeping-mcp && npm install && npm run build

Fügen Sie es dann zur claude_desktop_config.json von Claude Desktop hinzu:

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

Verwenden Sie einen absoluten Pfad zu Ihrer node-Binärdatei, wenn Sie nvm verwenden — Claude Desktop lädt Ihr Shell-Profil nicht, daher wird ein bloßes node nicht aufgelöst.

Das begleitende Skill enthält das Verfahren: wann die Kette greift, was vor dem Aufruf zu klären ist und was die Tools nicht entscheiden können.

Related MCP server: Quellgeist

Warum dieses Tool existiert

Die Bewertung der Aufzeichnungspflicht von Arbeitsunfällen nach 29 CFR Part 1904 erfolgt bei jedem Vorfall. Falsche Entscheidungen bergen direkte Compliance-Risiken: Über-Aufzeichnung bläht die Total Recordable Incident Rate (TRIR) künstlich auf, während Unter-Aufzeichnung OSHA-Zitate nach 29 CFR 1904.4 nach sich zieht.

Die Aufzeichnungspflicht nach Part 1904 bewertet mehrere unabhängige Auslöser: allgemeine Kriterien (Todesfall, Ausfalltage, Arbeitsplatzbeschränkung, Bewusstseinsverlust, PLHCP-Diagnosen nach 1904.7), spezifische Fallregeln (Nadelstiche, medizinische Entfernung, Hörverlust, TB nach 1904.8–1904.12) und Behandlungsklassifikation. Für die Behandlung definiert 1904.7(b)(5)(ii) eine geschlossene, 14 Punkte umfassende enumerierte Liste von Erste-Hilfe-Behandlungen. Die Implementierung dieser geschlossenen regulatorischen Regeln in typisierten Tools ersetzt die LLM-Interpolation über regulatorischen Text durch reproduzierbare Nachschlagelogik.

Arbeitsteilung: LLM erzählt, Tool entscheidet

Das aufrufende Modell tut, was es gut kann — eine unübersichtliche Vorfallserzählung lesen und auf kanonische Codes abbilden (Behandlungsarten, Ergebnisse). Das Tool tut, was ein Modell für eine rechtliche Entscheidung nicht tun darf — die geschlossene Liste deterministisch anwenden und eine zitierte Antwort zurückgeben. Das Tool akzeptiert niemals Freitext-Behandlungsbeschreibungen; es akzeptiert ein kontrolliertes Vokabular, damit die Entscheidung reproduzierbar ist.

Das Anker-Tool: osha_assess_recordability

Eingabe. Das Modell bildet die Erzählung auf diese ab; es übergibt niemals Freitext.

Feld

Bedeutung

work_related

1904.5 — von osha_assess_work_relatedness übernehmen, hier nicht selbst beurteilen

new_case

1904.6 — von osha_assess_new_case übernehmen

outcomes

death, days_away_from_work, restricted_work_or_transfer, loss_of_consciousness

significant_diagnoses

cancer, chronic_irreversible_disease, fractured_or_cracked_bone, punctured_eardrum (1904.7(b)(7))

specific_case_criteria

1904.8-1904.12-Auslöser — Nadelstich, medizinische Entfernung, Hörverlust, TB, blutübertragene Exposition mit Diagnose

plhcp_recommendations_not_followed

Die drei Stellen, an denen eine Empfehlung bindet, auch wenn der Mitarbeiter sie ignoriert hat (1904.7(b)(3)(ii), (b)(4)(viii), (b)(5)(v))

medical_removal_was_voluntary_and_early

Schutz für 1904.9(b)(3) — jemanden frühzeitig herauszuziehen ist nicht aufzeichnungspflichtig

tuberculosis_test_was_pre_employment

Schutz für 1904.11(b)(1) — ein positiver Einstellungs-Check ist nicht beruflich

treatments

Kontrollierte Codes. Erste-Hilfe-Codes stammen aus der geschlossenen Liste; zwei Codes sind weder Erste Hilfe noch medizinische Behandlung (1904.7(b)(5)(i))

Die ersten drei Arrays sind bewusst erforderlich. Ein Standardwert von [] kann nicht von „Ich habe geprüft und es gab keine" unterschieden werden, daher würde ein Standardwert eine unter-spezifizierte Erzählung zu einem selbstbewussten, zitierten falsch-negativen Ergebnis führen — der Unter-Aufzeichnungsrichtung, die ein Zitat nach sich zieht.

Ausgabe. Ein RuleRecord, dessen Wert recordable, basis, triggering_factors (jeweils mit eigenem Unterabschnitts-Zitat), severe_injury_reporting_note wenn 1904.39 relevant sein könnte, log_entry_notes für Konsequenzen, die ein Kriterium dem Log selbst auferlegt, und under_specified wenn überhaupt nichts behauptet wurde. Die Registrierungsebene fügt determination_final und clarification_required hinzu — siehe Elicitation unten.

Entscheidungslogik (deterministisch) — der 1904.4(b)(2)-Entscheidungsbaum in Reihenfolge:

  1. Wenn work_related falsch ist → nicht aufzeichnungspflichtig (1904.5).

  2. Wenn new_case falsch ist → kein neuer Eintrag, aber den bestehenden aktualisieren, wenn sich Tageszahlen oder Ergebnis geändert haben (1904.6). Der Baum leitet hierher; er stoppt nicht einfach.

  3. Sonst, wenn ein specific_case_criteria vorhanden ist → aufzeichnungspflichtig nach 1904.8-1904.12, ohne die Erste-Hilfe-Liste überhaupt zu konsultieren.

  4. Sonst, wenn ein outcome vorhanden ist → aufzeichnungspflichtig (allgemeine Aufzeichnungskriterien, 1904.7(b)(1)).

  5. Sonst, wenn eine significant_diagnosis vorhanden ist → aufzeichnungspflichtig auch wenn nur Erste Hilfe geleistet wurde (1904.7(b)(7)).

  6. Sonst, wenn eine treatment nicht in der geschlossenen Erste-Hilfe-Liste ist → aufzeichnungspflichtig (medizinische Behandlung über Erste Hilfe hinaus, 1904.7(b)(5)(i)).

  7. Sonst → nicht aufzeichnungspflichtig (nur Erste Hilfe und kein spezifisches Fallkriterium).

Schritt 3 existiert, weil 1904.4(a)(3) eine Disjunktion ist: 1904.7 oder die spezifischen Fälle von 1904.8-1904.12. Ohne sie kam ein kontaminierter Nadelstich, der mit Reinigung und einem Pflaster behandelt wurde, als „nicht aufzeichnungspflichtig" zurück — mit angehängtem Zitat — während das Datenschutz-Tool desselben Servers ihn korrekt als Datenschutzfall bezeichnete. Aufzeichnungskriterien, die die Erste-Hilfe-Liste nie konsultieren, müssen vor ihr geprüft werden, nicht nach ihr.

Protokolloberfläche (alle drei MCP-Primitive)

Dieser Server nutzt das volle Protokoll, nicht nur Tools:

  • Tools — die elf Entscheidungen, die unter Die Incident-Triage-Kette unten aufgeführt sind. Jedes deklariert ein outputSchema und gibt typisierte structuredContent zurück, keinen JSON-String, und jedes ist mit readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false annotiert — sicher, wiederholbar, reine Nachschlageoperationen.

  • Resources — alle fünfzehn Datensätze sind direkt exponiert, sodass ein Client die Referenzdaten als Kontext laden kann, statt sie nur über einen Tool-Aufruf zu erreichen. Das Datenmodell ist das Produkt; Resources machen es sichtbar. URIs sind osha://data/<id>, wobei <id> der Schlüssel in src/datasets.ts ist — z. B. osha://data/first-aid-treatments, osha://data/partially-exempt-industries, osha://data/privacy-cases.

  • Prompttriage_incident führt einen Vorfall als einen einzigen benutzeraufgerufenen Workflow durch die gesamte Kette: Umfang → aufzeichnungspflichtiger Arbeitgeber → Arbeitsbezug → neuer Fall → eingeschränkte Arbeit → Hörverlust → Aufzeichnungspflicht → Meldefrist → 300-Log-Spalte → Datenschutzfall → Betriebsstätte.

  • Elicitationosha_assess_recordability löst den einen Randfall, den es nicht erraten darf: OTC- vs. verschreibungspflichtige Medikamentenstärke. Nicht-verschreibungspflichtige Stärke ist Erste Hilfe; verschreibungspflichtige Stärke ist medizinische Behandlung und aufzeichnungspflichtig. Wenn die Erzählung schweigt, übergibt das Modell medication_unspecified_strength und die Stärke wird durch Nachfragen bei einem Menschen aufgelöst — niemals durch das Tool.

    Zweistufige Auflösung. Elicitation ist eine optionale MCP-Fähigkeit, daher prüft der Server getClientCapabilities() und wählt seinen Kanal:

    Client wirbt elicitation

    Kanal

    Ergebnis

    Ja

    Server fragt den Benutzer direkt

    In einem Tool-Aufruf aufgelöst

    Nein

    Gibt determination_final: false + clarification_required zurück

    Modell fragt im Chat, ruft dann mit dem aufgelösten Code erneut auf

    In beiden Fällen erreicht die Frage einen Menschen und das Tool rät nie. Das vorläufige Ergebnis bleibt konservativ — recordable: true, Basis als ausstehende Bestätigung markiert — und clarification_required trägt die Frage, den CFR-Grund und den genauen Behandlungscode, der für jede Antwort zurückzusenden ist.

    In welcher Stufe ein bestimmter Client landet, sollte man prüfen statt annehmen. Hier verifiziert: Der Chat-Client von Claude Desktop wirbt keine elicitation-Fähigkeit, ebenso wenig MCP Inspector 0.15.0 oder 1.0.0. Agentische Clients können sich unterscheiden, und ein Client, der den Benutzer über seinen eigenen Mechanismus fragt, sieht von außen identisch aus. Der Server protokolliert elicitation=supported|NOT supported auf stderr bei Verbindung — starten Sie ihn unter einem beliebigen Client und lesen Sie diese Zeile.

Herkunft & erzwungener Verfall

RuleRecord<T> (siehe src/types.ts) trägt regulatorische Regeln: cfr_cite, source_url, last_verified und, wo eCFR sie liefert, amendment_history und editorial_note. Es gibt kein effective_date-Feld; Datensätze tragen aktuellen eCFR-Text, und last_verified gibt das Datum der regulatorischen Verifizierung an.

Der Verfall wird über scripts/check-decay.ts erzwungen, das den Build fehlschlagen lässt, wenn last_verified eines Datensatzes seine Verfallsschwelle überschreitet. Es läuft bei Push und nach einem wöchentlichen CI-Zeitplan, validiert die source_url-Ziele der Unterabschnitte und prüft auf eCFR-editorial_note-Einträge.

Die Incident-Triage-Kette (ausgeliefert)

Elf deterministische Tools, die einen Vorfall von „jemand wurde verletzt" bis zu einem korrekten Log-Eintrag begleiten:

  1. osha_check_recordkeeping_obligation (1904.1, 1904.2) — die Frage, die jede andere Feststellung voraussetzt: Muss dieser Arbeitgeber überhaupt Aufzeichnungen führen? Die Größenausnahme wird über das gesamte Unternehmen anhand der Spitzenbeschäftigung im letzten Kalenderjahr gemessen – nicht als Durchschnitt, nicht für einen Standort. Die Branchenausnahme bezieht sich auf die Betriebsstätte, und das Tool löst sie anhand der geschlossenen 82-Code-Liste in Anhang A auf, wenn eine NAICS-Code angegeben wird. Beide sind teilweise: 1904.39 Meldepflicht für schwere Verletzungen überlebt beide, was die Schlussfolgerung ist, die ein ausgenommener Arbeitgeber gefährlich falsch versteht.

  2. osha_determine_recording_employer (1904.31) — eine Schwellenfrage, kein Schritt: Wenn die verletzte Person nicht auf der Lohnliste steht, ist es dann überhaupt der Fall dieses Arbeitgebers? Die tägliche Aufsicht entscheidet, nicht der Gehaltsscheck. Ein Zeitarbeiter auf der Lohnliste einer Agentur, dessen Arbeit Sie täglich leiten, ist von Ihnen aufzuzeichnen; derselbe Zeitarbeiter unter Aufsicht der Agentur nicht. Selbstständige fallen vollständig aus dem OSH Act heraus, und Eigentümer oder Partner einer Einzelfirma sind für die Aufzeichnung keine Arbeitnehmer. (b)(4) verlangt, dass der Fall genau einmal aufgezeichnet wird – niemals in beiden Protokollen.

  3. osha_assess_work_relatedness (1904.5) — das Tor, auf dem alles andere ruht, und bisher das einzige rechtliche Urteil, das dieses Projekt dem Modell überließ. 1904.5(a) vermutet Arbeitsbezogenheit für alles, was in der Arbeitsumgebung entsteht; 1904.5(b)(2) ist eine geschlossene Liste von neun Ausnahmen, die sie widerlegen können. Das Urteil ist bewusst dreiwertigwork_related, not_work_related oder requires_judgment –, weil 1904.5 Pfade enthält, die die Verordnung selbst dem Arbeitgeber zuweist: unklare Herkunft (1904.5(b)(3)), Reisestatus (b)(6), Arbeiten zu Hause (b)(7) und die „ausschließlich"-Feststellung, von der jede Ausnahme abhängt. Diese in einen booleschen Wert zu zwingen, wäre, als würde das Tool bei der umstrittensten Entscheidung in Teil 1904 raten. Es klärt auch Fälle, die das Gedächtnis falsch behält. Ein Kraftfahrzeugunfall beim Pendeln auf dem Firmengelände ist unter (b)(2)(vii) ausgenommen; ein Sturz auf demselben Gelände ist von keiner Ausnahme abgedeckt und bleibt arbeitsbezogen. Und psychische Erkrankungen kehren die übliche Richtung um – nicht arbeitsbezogen, es sei denn, der Arbeitnehmer legt freiwillig eine PLHCP-Stellungnahme vor (b)(2)(ix).

  4. osha_assess_new_case (1904.6) — ein neuer Eintrag im 300-Log oder eine Aktualisierung eines bereits vorhandenen? Die zweite Bedingung der Konjunktion in 1904.4(a). Es trennt die beiden Wiederholungsfälle, die die Verordnung bewusst unterscheidet: Ein Vorfall, der durch eine Arbeitsplatzexposition verursacht wird, ist ein neuer Fall (b)(2) – berufsbedingtes Asthma, das am Fließband ausgelöst wird –, während eine chronische Erkrankung, deren Symptome ohne Exposition wiederkehren, nur einmal aufgezeichnet wird (b)(1). Beachten Sie, dass (b)(1) keine geschlossene Liste ist: Die Verordnung sagt, „Beispiele können umfassen" Krebs, Asbestose, Byssinose und Silikose, daher fragt das Tool nach der Art der Erkrankung, anstatt Krankheitsnamen abzugleichen. Es ist auch das einzige Tool im Server, das sich einer externen Autorität unterordnet. Unter (b)(3) muss ein Arbeitgeber keinen PLHCP konsultieren, aber wenn er einen konsultiert hat, muss er der Empfehlung folgen – eine PLHCP-Stellungnahme überschreibt also die Regel-Logik vollständig, und widersprüchliche Stellungnahmen geben requires_judgment zurück, weil deren Abwägung ausdrücklich Aufgabe des Arbeitgebers ist.

  5. osha_evaluate_restricted_work (1904.7(b)(4)) — zählt die Einschränkung tatsächlich? Nicht jede tut das, und beide Fehler verschieben Fälle auf das Protokoll oder davon weg. Eine Einschränkung, die auf den Tag der Verletzung beschränkt ist, zählt nicht (b)(4)(iii); reduzierte Leistung, während weiterhin alle Routinefunktionen ausgeführt werden, zählt nicht (b)(4)(vi); „Routinefunktionen" bedeutet Tätigkeiten, die mindestens einmal pro Woche ausgeführt werden (b)(4)(ii). Eine Teilschicht zählt (b)(4)(v)), und Versetzungen teilen die Einschränkungsspalte (b)(4)(x)). Interessant ist (b)(4)(vii): Wenn eine vage Empfehlung wie „leichte Arbeit" nicht mit dem PLHCP geklärt werden kann, muss der Fall als eingeschränkte Arbeit aufgezeichnet werden. Das ist die Verordnung, die ihre eigenen Zweifel zugunsten der Aufzeichnung auflöst – und die einzige Standard-zu-Aufzeichnen-Regel in Teil 1904.

  6. osha_evaluate_hearing_loss (1904.10) — das einzige Aufzeichnungskriterium in Teil 1904, das reine Arithmetik ist, und das einzige Tool hier, das berechnet statt nachschlägt. Zwei Tests müssen beide im selben Ohr erfüllt sein: eine Standard-Schwellenwertverschiebung von 10 dB gegenüber der Basislinie und ein Gesamthörpegel von 25 dB oder mehr über dem audiometrischen Nullpunkt, jeweils gemittelt bei 2000, 3000 und 4000 Hz. Eine STS in einem Ohr und ein 25-dB-Pegel im anderen führt nicht zur Aufzeichnung. Die Altersanpassung gilt nur für den Verschiebungstest, niemals für den 25-dB-Test.

  7. osha_assess_recordability (1904.4) — ist es aufzeichnungspflichtig? (der Anker, oben)

  8. osha_check_severe_injury_reporting (1904.39) — muss es OSHA gemeldet werden, und bis wann? Gibt den tatsächlichen Fristzeitstempel zurück (8 Stunden bei einem Todesfall, 24 bei Krankenhausaufenthalt / Amputation / Verlust eines Auges), berechnet ab dem Zeitpunkt, an dem der Arbeitgeber davon erfahren hat, prüft das Berechtigungsfenster ab dem Vorfall und kennzeichnet, ob die Frist bereits überschritten ist.

  9. osha_classify_300_log_entry (1904.29) — welche Ergebnisspalte (G/H/I/J) im 300-Log gemäß der Regel des schwerwiegendsten Ergebnisses, die Spalte für Verletzungs-/Krankheitsart und Tageszählungen, die bei 180 gedeckelt sind.

  10. osha_check_privacy_case (1904.29(b)(6)-(9)) — darf der Name des Arbeitnehmers überhaupt auf das Protokoll? Eine zweite geschlossene Liste, und in beiden Richtungen geschlossen: (b)(7) zählt die sechs Fälle mit Datenschutzbedenken auf, und (b)(8) verbietet, etwas anderes als solchen zu behandeln – ein Arbeitgeber kann sie also weder aus Mitgefühl erweitern noch ignorieren. Gibt den wörtlichen Protokolleintrag ("privacy case") sowie die folgenden Pflichten zurück: die separate vertrauliche Liste ((b)(6)), Ermessen bei der Beschreibung des Falls, wenn allein die Erzählung den Arbeitnehmer identifizieren könnte ((b)(9)), und Schwärzung, wenn Aufzeichnungen an jemand anderen als einen Regierungsvertreter gehen ((b)(10)).

  11. osha_route_to_establishment_log (1904.30) — welches 300-Log der Betriebsstätte, die letzte Frage zu einem einzelnen Vorfall. Die Regel läuft der Intuition zuwider: Ein Fall folgt dem Ort, nicht der Person. Jemand, der verletzt wird, während er eine Schicht in einem anderen Werk des Arbeitgebers übernimmt, wird im Protokoll dieses Werks aufgezeichnet, was die Zahl verschiebt, die dessen Standort-TRIR antreibt. Eine Verletzung außerhalb jeder Betriebsstätte – beim Kunden, unterwegs, remote – geht in das Protokoll des Standorts, an dem der Arbeitnehmer normalerweise arbeitet.

Umfang: Teil 1904 und sonst nichts

Alles hier beantwortet eine Frage – jemand wurde verletzt; was verlangt OSHA von mir, aufzuzeichnen und zu melden? Das ist 29 CFR Teil 1904 von Anfang bis Ende, und die elf Tools oben sind die Feststellungen, die er erzwingt.

Verteilung: ein Server und eine Skill

Zwei Artefakte, weil sie unterschiedliche Fragen beantworten. Der Server entscheidet; die Skill weiß, wann sie ihn fragen muss.

Der Server – drei Einstiegspunkte, eine Engine

Einstiegspunkt

Transport

Für

dist/index.js

stdio

Claude Desktop, lokale Entwicklung

dist/http.js

Streamable HTTP

ein Container oder Node-Host

src/worker.ts

Streamable HTTP

Cloudflare Workers

Alle drei rufen dieselbe createServer() über dieselben elf Tools und fünfzehn Datensätze auf – nichts in src/tools/ weiß, welcher läuft. Diese Portabilität kam aus zwei früheren Entscheidungen und nicht aus Portierungsaufwand: Die Feststellungen sind reine Funktionen, und datasets.ts ist der einzige Kontaktpunkt mit dem JSON.

Jede Variante ist zustandslos – ein frischer Server pro Anfrage, keine Sitzungs-IDs, nichts wird zwischen Aufrufen behalten, weil jedes Tool eine reine Nachschlageoperation über gebündelte Daten ist. /health meldet das Alter jedes Datensatzes gegen seine Verfallsschwelle und gibt 503 zurück, wenn einer veraltet ist, sodass eine gehostete Bereitstellung nach derselben Regel überwacht wird wie der Build.

npm run start:http      # node host — PORT=3000 MCP_PATH=/mcp by default
npm run smoke:http      # boots it, drives it with a real client, checks /health

npm run dev:worker      # wrangler dev — runs under workerd, not Node
npm run smoke:worker    # boots workerd and drives it with a real client
npm run deploy:worker   # wrangler deploy

smoke:worker ist der einzige Check, der die Tools unter workerd ausführt. Die anderen beiden Smokes laufen auf Node und können strukturell nicht sehen, wie ein Node-Built-in in einen Codepfad eindringt – genau das, was ein Deployment zuerst aufdecken würde. nodejs_compat ist in wrangler.toml bewusst AUS, damit dieser Fehler in der Entwicklung laut ist und nicht still.

Der Worker akzeptiert nur POST. Ein zustandsloser Server initiiert keine Nachrichten, daher trägt der GET-SSE-Stream nichts und würde für immer offen bleiben; workerd bricht eine Anfrage ab, deren Antwort nie abgeschlossen wird. 405 mit Allow: POST ist die Art des Protokolls zu sagen, dass es keinen Server-zu-Client-Stream gibt.

Keine Authentifizierung, absichtlich. Der Server stellt veröffentlichten Regulierungstext bereit, speichert nichts und hat keine Nebenwirkungen, daher gehört Zugriffskontrolle davor – Cloudflare Access oder eine OAuth-Schicht – statt halb implementiert darin.

Ratenbegrenzung

Ratenbegrenzung ist die Ausnahme, und sie lebt im Worker statt davor. Die Bereitstellung ist auf workers.dev, das keine Zone im Konto ist, daher hat eine WAF-Ratenbegrenzungsregel nichts, woran sie sich festhalten kann. Deklariert als [[ratelimits]]-Bindung in wrangler.toml, was auch bedeutet, dass sie überprüft, versioniert und mit dem Deployment reist, statt in einem Dashboard zu leben, das niemand diffed.

300 Anfragen pro Minute pro Client-IP. Bewusst großzügig: Der Begrenzer schlüsselt nach IP auf, und ein Sicherheitsteam hinter einem gemeinsamen Corporate-NAT teilt sich einen einzigen Schlüssel. Eine Triage-Kette umfasst etwa 15 Anfragen, sodass mehrere Personen, die gleichzeitig arbeiten, legitimerweise 150/Minute überschreiten. Dies ist darauf ausgelegt, ein Modell abzuschneiden, das bei einem Fehler schleift – der Fehler, der eine gehostete Bereitstellung tatsächlich bedroht –, nicht um normale Nutzung zu messen. Über dem Limit gibt es 429 mit Retry-After zurück.

/health liegt über dem Check, sodass ein Uptime-Monitor, der nach Zeitplan pollt, niemals das Budget erschöpfen kann. Die Durchsetzung erfolgt pro Rechenzentrum und nicht global koordiniert, also ist es eine Abschneidung und keine exakte Quote.

Was die Tools empfangen

Der Server ruft nichts ab und speichert nichts. Aber Argumente fließen trotzdem hinein, und sie beschreiben einen realen Vorfall, daher ist „keine Benutzerdaten" eine Behauptung über Speicherung, die nichts über den Transport sagt. Die Unterscheidung ist wert, klar ausgesprochen zu werden, weil sie die ist, die ein EHS-Team bewerten muss.

Keine Eingabe ist ein Identifikator. Es gibt kein Feld in den Schemas für einen Namen, eine Mitarbeiternummer, ein Geburtsdatum, eine Adresse oder eine Freitext-Erzählung – jede Eingabe ist ein Attribut des Falls (work_related, days_away_from_work, treatments), und die Feststellung braucht nichts anderes. Das ist eine Eigenschaft der Schemas, keine Richtlinie: Es gibt kein Feld, in das ein Name eingetragen werden könnte. Die Skill weist das Modell auch an, keine Identität in einen Aufruf zu tragen, sodass die Einschränkung an beiden Enden gilt – siehe Fakten übergeben, niemals Identitäten.

Einige Attribute sind trotzdem sensibel. osha_check_privacy_case nimmt genau die Kategorien, die 1904.29(b)(7) aufzählt – sexual_assault, mental_illness, hiv_hepatitis_or_tuberculosis, contaminated_needlestick_or_sharps. Die Verordnung hebt genau diese hervor, weil sie die sind, die nicht auf einem Protokoll erscheinen dürfen, das ein Kollege lesen kann. Nur-Attribute ist auch nicht dasselbe wie anonym: Ein Artcode plus ein Vorfallsdatum an einer Betriebsstätte mit neun Personen kann jemanden identifizieren, der dort arbeitet.

Wo das landet, hängt vom Transport ab, und nur vom Transport:

Einstiegspunkt

Wohin Argumente gehen

stdio

bleibt auf der Maschine, die den Server ausführt; der KI-Host sieht es trotzdem

node HTTP / Worker

überquert das Netzwerk zu dem, der diese Bereitstellung betreibt

Nothing is logged either way — no request logging, no tool-call logging, successful or otherwise. That is deliberate. A log of these arguments would be a regulated repository in its own right, on a server that otherwise has nothing to regulate, and determinations are already reproducible from the inputs plus the last_verified dataset version carried in every response. Provenance in the response does the job an audit log would, without the retention.

So: if you are handling real cases under GDPR or HIPAA, run stdio, or self-host the worker on infrastructure you control. Pointing regulated incident data at someone else's hosted copy of this server means sending injury attributes to a third party you have no agreement with. The determinations are pure functions over bundled JSON — self-hosting costs one wrangler deploy and changes nothing about the answers.

Host- und Origin-Validierung

Authentifizierung betrifft wer fragen darf. Host-Validierung betrifft einen Browser, der dazu gebracht wird, im Namen eines anderen zu fragen, was kein vorgelagertes Gateway nachrüsten kann — daher wird dieser Teil in src/httpGuard.ts behandelt und gilt für beide HTTP-Einstiegspunkte.

Der Angriff, den sie schließt, ist DNS-Rebinding: Eine Angreifer-Domain löst erneut zu 127.0.0.1 auf, der Browser behandelt die Anfrage als gleichoriginär und sendet sie ohne Preflight, und ein lokal laufender MCP-Server antwortet. Der Host-Header ist es, der sie immer noch verrät — er trägt die Domain des Angreifers — daher ist eine exakte Host-Allowlist die Prüfung, die funktioniert.

Variable

Node (dist/http.js)

Worker

HOST

Bindungsadresse, Standard 0.0.0.0

MCP_ALLOWED_HOSTS

Standard localhost:$PORT, 127.0.0.1:$PORT, [::1]:$PORT

nicht gesetzt = uneingeschränkt

MCP_ALLOWED_ORIGINS

nicht gesetzt = uneingeschränkt

nicht gesetzt = uneingeschränkt

Beide akzeptieren eine kommagetrennte Liste; * deaktiviert die Prüfung, wenn ein vorgelagertes Gateway die Entscheidung besitzt. Origin wird nur geprüft, wenn der Header vorhanden ist, da Nicht-Browser-MCP-Clients keinen senden. /health liegt außerhalb der Allowlist — ein Uptime-Monitor ist nicht das Bedrohungsmodell.

Der Node-Einstiegspunkt standardmäßig nur auf Loopback. Eine Container- oder Reverse-Proxy-Bereitstellung wird unter einem anderen Namen erreicht und muss MCP_ALLOWED_HOSTS setzen; sie schlägt mit einem 403 fehl, der den gesehenen Header benennt, was eine Fünf-Sekunden-Korrektur ist. Das Gegenteil als Standard wäre ein Loch, das niemand bemerkt. Beachten Sie, dass die Bindungsadresse nicht der Schutz ist — die Bindung an 0.0.0.0 bleibt der Standard, damit Container funktionieren, und die Allowlist macht das sicher.

Abgelehnte Anfragen erhalten 403 mit einem JSON-RPC--32000-Fehler. Übermäßig große Bodies (>1 MB) erhalten 413, fehlerhaftes JSON erhält 400 — Client-Fehler werden nicht als Vorfälle protokolliert.

Die Skill

skills/osha-incident-triage/ trägt die Vorgehensweise: wann die Kette gilt, was vor dem Aufruf festzustellen ist, wie eine Bestimmung zu präsentieren ist und was die Werkzeuge nicht entscheiden können. Sie enthält Prozessanleitung für Incident-Triage und trägt keine regulatorische Logik direkt.

Aufbau

Die Bestimmungslogik ist rein und testbar; der Server ist Verdrahtung darum herum.

src/
  index.ts              stdio entry point — Claude Desktop, local development
  http.ts               Streamable HTTP entry point — container / node host
  worker.ts             Cloudflare Workers entry point — same server, fetch handler
  server.ts             createServer() factory + registerRuleTool/toolResult helpers
  httpGuard.ts          Host/Origin allowlisting shared by both HTTP entry points —
                        one implementation, since Node and workerd share no middleware
  datasets.ts           the one place JSON assets are loaded and named — static imports,
                        so the same module resolves with or without a filesystem
  types.ts              RuleRecord, Provenance, and the ruleRecord() constructor
  md.d.ts               ambient declaration letting SKILL.md be imported as a string,
                        so the worker can serve it without a filesystem
  tools/                one pure function per determination — no MCP imports except
                        medicationStrength.ts, which owns the elicitation exchange
  registrations/
    tools/              one registerX.ts per tool + a barrel; metadata and summaries
    resources.ts        generated from the DATASETS table
    prompts.ts          triage_incident

Ein Werkzeug hinzuzufügen bedeutet eine Datei in src/tools/ (die Regel), eine in src/registrations/tools/ (wie es beschrieben und zusammengefasst wird) und eine Zeile im Fass. Das register-Präfix hält diese Dateinamen in einer Editor-Tab-Leiste von ihren src/tools/-Gegenstücken unterscheidbar.

Zwei Invarianten, die es wert sind, beibehalten zu werden: Provenienz wird nur von ruleRecord() zusammengestellt, und Ressourcen werden aus derselben DATASETS-Tabelle generiert, aus der die Werkzeuge laden, sodass ein Datensatz nicht unter einem Pfad veröffentlicht werden kann, den kein Werkzeug liest.

Kontinuierliche Integration

.github/workflows/ci.yml führt Typprüfung, Build, Unit-Tests und Smoke-Suiten auf Node 20 und 22 aus.

Die Decay-Prüfung und npm audit laufen beide auf denselben Triggern wie der Rest der CI — Push, Pull-Request und ein wöchentlicher Zeitplan — als separate Jobs gehalten, sodass jeder Fehler für sich erkennbar ist, nicht als ein rotes X unter mehreren. npm audit blockiert den Build bei schwerwiegenden Produktions-Schwachstellenhinweisen; Dev-Abhängigkeitshinweise werden gemeldet, nicht blockierend. Der wöchentliche Zeitplan fängt einen Hinweis ab, der gegen eine bereits auf main befindliche Abhängigkeitsversion veröffentlicht wurde, wo sonst nichts einen erneuten Check auslösen würde.

tsconfig.json schließt test/ aus, sodass tsc --noEmit nur src/ prüft und ts-jest Testdateien während npm test typprüft.

Änderungskontrolle & Versionierung

CHANGELOG.md verfolgt alle Änderungen über zwei unabhängige Release-Dimensionen:

  • Code: Bestimmungslogik, Tool-Schemas und Server-Transports folgen Semantic Versioning.

  • Regulatorische Daten: Gebündelte eCFR-JSON-Datensätze unter src/data/. Eine erneute Verifizierung eines Datensatzes gegen den aktuellen eCFR-Text verschiebt sein last_verified-Datum und wird als Patch-Update veröffentlicht, selbst wenn sich der regulatorische Text nicht geändert hat, wodurch eine prüfbare Provenienz für Compliance-Teams erhalten bleibt.

  • Erzwungener Decay: CI führt scripts/check-decay.ts wöchentlich aus, um den Build fehlschlagen zu lassen, wenn ein Datensatz seine 365-Tage-Decay-Schwelle ohne manuelle Neuverifizierung überschreitet.

  • Releases: Versionstags (vX.Y.Z) auf GitHub lösen .github/workflows/release.yml aus, um vollständige Validierungssuiten (Typprüfung, Tests, Smokes, Decay, Audit) auszuführen und ein verifiziertes GitHub-Release zu erstellen.

Entwicklung

npm install
npm run build       # tsc + copy src/data → dist/data
npm test            # jest — deterministic logic
npm run check-decay # build-breaking staleness trap
npm run smoke       # end-to-end: spawn the server, list tools/resources/prompts, call a tool

Verbinden Sie sich lokal über npx @modelcontextprotocol/inspector oder fügen Sie claude_desktop_config.json hinzu, das auf dist/index.js zeigt.

npm run smoke:worker und npm run dev:worker benötigen Node 22 oder neuer, weil wrangler das tut. Alles andere läuft auf Node 20, und engines bleibt absichtlich bei >=20: Dieses Feld ist eine Aussage darüber, wer den Server installieren und ausführen kann, der nur das SDK und zod benötigt. Wrangler ist Entwicklungswerkzeug und erreicht nie einen Verbraucher, daher ist seine Anforderung nicht die des Pakets. CI hält Node 20 aus genau diesem Grund in der Matrix und überspringt dort nur den Worker-Smoke.

Evaluierungen

evals/recordkeeping-evals.xml — siebenundvierzig Fragen, die testen, ob ein LLM die richtige Antwort durch die Werkzeuge erreicht, was Unit-Tests nicht abdecken können. Jede Antwort wurde erzeugt, indem der gebaute Server mit einem echten MCP-Client betrieben wurde; die Spur befindet sich in evals/README.md. Die meisten der siebenundvierzig haben eine intuitive falsche Antwort, nach der ein aus dem Gedächtnis argumentierendes Modell greifen wird.

Haftungsausschluss

Nur Referenz und Triage. Keine Rechtsberatung, keine medizinische Feststellung. Grenzfälle der Aufzeichnungspflicht erfordern häufig einen PLHCP oder Rechtsbeistand. Arbeitsbezogenheit (1904.5) wird nur entlang ihrer deterministischen Pfade bestimmt; unklare Herkunft, Reisestatus, Arbeiten von zu Hause und jede nicht festgestellte „ausschließlich"-Feststellung geben requires_judgment zurück, nicht ein Urteil.

Install Server
A
license - permissive license
A
quality
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

  • A
    license
    Not graded
    quality
    C
    maintenance
    A deterministic MCP server for legal intake triage that provides practice-area lookup, conflict screening, matter validation, follow-up drafting, and triage logging with a hard conflicts gate.
    Apache 2.0
  • A
    license
    A
    quality
    A
    maintenance
    First-line incident triage you can trust: ranked root-cause hypotheses where every claim cites a real evidence handle — and the agent abstains rather than guess.
    1
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    MCP server for US workplace-safety standards (OSHA 29 CFR parts 1900–1990). Enables querying safety regulations via natural language through the Pipeworx gateway.
    14
    MIT

View all related MCP servers

Related MCP Connectors

  • Diagnoses, drugs & lab codes: ICD-11, SNOMED, LOINC, RxNorm, MeSH, ATC, CID-10. 37 tools, MIT.

  • FDA medical-device regulatory intelligence from keyless openFDA datasets.

  • Read-only tools over the Psychopathia Machinalis nosology: 79 conditions, 11 tools.

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/srhtdmrkl/osha-recordkeeping-mcp'

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