osha-recordkeeping-mcp
OSHA記録保持MCP — 29 CFR 1904
誰かが負傷するたびに安全管理者が直面する問い——これはOSHA記録対象か?——に答える、決定的なModel Context Protocolサーバー。
11のツールが、誰かが負傷したという出来事から正しい記録入力までを追跡し、それぞれがモデルの記憶による判断ではなく、引用付きの判定を返します。MITライセンスで無料利用可能。
参照およびトリアージ専用 — 法的助言ではなく、医学的判定でもありません。 すべての判定にはCFRの引用と、その根拠データが最後にeCFRに対して検証された日付が付随するため、推論は監査可能であり、単なる主張ではありません。
使用方法
git clone https://github.com/srhtdmrkl/osha-recordkeeping-mcp.git
cd osha-recordkeeping-mcp && npm install && npm run build次に、Claude Desktopのclaude_desktop_config.jsonに追加します:
{
"mcpServers": {
"osha": { "command": "node", "args": ["/absolute/path/to/dist/index.js"] }
}
}nodeバイナリへの絶対パスを使用してください(nvmを使用している場合 — Claude Desktopはシェルプロファイルを読み込まないため、裸のnodeは解決されません)。
関連するスキルには手順が記載されています:チェーンをいつ適用するか、呼び出し前に何を確認すべきか、そしてツールが判断できない事項は何か。
Related MCP server: Quellgeist
このツールが存在する理由
職場傷害の記録対象性の評価は、あらゆるインシデントで発生します。誤った判定は直接的なコンプライアンスリスクを伴います:過剰記録はTotal Recordable Incident Rate(TRIR)を人為的に膨張させ、過少記録は29 CFR 1904.4に基づくOSHAの引用につながります。
Part 1904に基づく記録対象性は、複数の独立したトリガーを評価します:一般基準(死亡、休業日数、作業制限、意識喪失、1904.7に基づくPLHCP診断)、特定ケースの規則(針刺し、医学的除去、聴力損失、1904.8〜1904.12に基づく結核)、および治療分類。治療については、1904.7(b)(5)(ii)が応急処置治療の閉じた14項目の列挙リストを定義しています。これらの閉じた規制規則を型付きツール内に実装することで、LLMによる規制テキストの解釈を、再現可能なルックアップロジックに置き換えます。
分業:LLMがナレーションし、ツールが判定する
呼び出し側のモデルは得意なことを行います——曖昧なインシデントのナレーションを読み、それを正規コード(治療タイプ、結果)にマッピングします。ツールはモデルが法的判定のために絶対に行ってはならないことを行います——閉じたリストを決定的に適用し、引用付きの回答を返します。ツールは自由形式の治療説明を決して受け付けません。管理された語彙を受け入れるため、判定は再現可能です。
アンカーツール:osha_assess_recordability
入力。 モデルはナレーションを以下のフィールドにマッピングします。自由テキストは渡しません:
フィールド | 意味 |
| 1904.5 — |
| 1904.6 — |
|
|
|
|
| 1904.8〜1904.12のトリガー — 針刺し、医学的除去、聴力損失、結核、診断を伴う血液曝露 |
| 1904.7(b)(3)(ii)、(b)(4)(viii)、(b)(5)(v) — 従業員が推奨を無視した場合でも拘束力を持つ3つの箇所 |
| 1904.9(b)(3)のガード — 自主的かつ早期の除去は記録対象外 |
| 1904.11(b)(1)のガード — 採用時健康診断での陽性は記録対象外 |
| 管理されたコード。応急処置コードは閉じたリストから取得。2つのコードは応急処置でも医療処置でもない(1904.7(b)(5)(i)) |
最初の3つの配列は必須であり、意図的にそう設計されています。[]のデフォルトは*「確認したが該当なし」*と区別できません。そのため、デフォルト値を設定すると、情報不足のナレーションが自信を持って誤った陰性判定を返す可能性があります——これは引用につながる過少記録の方向です。
出力。 RuleRecord(recordable、basis、各サブ節の引用を伴うtriggering_factors、1904.39が適用される可能性がある場合のsevere_injury_reporting_note、基準が記録自体に課す結果のためのlog_entry_notes、そして情報が完全に不足している場合のunder_specified)を返します。登録層はdetermination_finalとclarification_requiredを追加します — Elicitationを参照。
判定ロジック(決定的) — 1904.4(b)(2)の決定木を順に評価:
work_relatedがfalse → 記録対象外(1904.5)。new_caseがfalse → 新規入力なし、ただし日数または結果が変更された場合は既存入力を更新(1904.6)。木はここで単純に停止するのではなく、分岐します。それ以外で
specific_case_criteriaのいずれかが存在する → 記録対象(1904.8〜1904.12)、応急処置リストを参照せずに判定。それ以外で
outcomesのいずれかが存在する → 記録対象(一般記録基準、1904.7(b)(1))。それ以外で
significant_diagnosisが存在する → 記録対象(応急処置のみであっても)(1904.7(b)(7))。それ以外で
treatmentsのいずれかが閉じた応急処置リストに含まれない → 記録対象(応急処置を超える医療処置、1904.7(b)(5)(i))。それ以外 → 記録対象外(応急処置のみ、かつ特定ケース基準なし)。
ステップ3が存在する理由は、1904.4(a)(3)が選言だからです:1904.7 または 1904.8〜1904.12の特定ケース。これがないと、洗浄と包帯で処置された汚染針刺しが「記録対象外」と判定され——引用付きで——一方で同じサーバーのプライバシーツールはそれをプライバシーケースとして正しく分類する、という矛盾が生じます。応急処置リストを参照しない記録基準は、応急処置リストの前にチェックされる必要があります。
プロトコルサーフェス(MCPの3つのプリミティブすべて)
このサーバーはツールだけでなく、完全なプロトコルを使用します:
ツール — インシデントトリアージチェーンの下にリストされた11の判定。それぞれが
outputSchemaを宣言し、JSON文字列ではなく型付きのstructuredContentを返します。また、それぞれがreadOnlyHint: true、destructiveHint: false、idempotentHint: true、openWorldHint: falseと注釈付けられています — 安全で、再試行可能で、純粋な参照操作です。リソース — 15のデータセットすべてが直接公開されているため、クライアントはツール呼び出しを介さずに参照データをコンテキストとして読み込めます。データモデルが成果物であり、リソースがそれを可視化します。URIは
osha://data/<id>で、<id>はsrc/datasets.tsのキーです — 例:osha://data/first-aid-treatments、osha://data/partially-exempt-industries、osha://data/privacy-cases。プロンプト —
triage_incidentは、ユーザーが起動する単一のワークフローとして、1つのインシデントをチェーン全体で進めます:適用範囲 → 記録雇用主 → 業務関連性 → 新規ケース → 作業制限 → 聴力損失 → 記録対象性 → 報告期限 → 300ログ列 → プライバシーケース → 事業所。Elicitation —
osha_assess_recordabilityは、推測してはならない唯一のエッジケースを解決します:OTC vs. 処方強度の医薬品。非処方強度は応急処置、処方強度は医療処置であり記録対象です。ナレーションが黙示の場合、モデルはmedication_unspecified_strengthを渡し、強度は人間への質問によって解決されます — ツールが選択することは決してありません。2段階の解決。 ElicitationはオプションのMCP機能であるため、サーバーは
getClientCapabilities()をチェックしてチャネルを選択します:クライアントが
elicitationを宣伝チャネル
結果
はい
サーバーがユーザーに直接プロンプト
1回のツール呼び出しで解決
いいえ
determination_final: false+clarification_requiredを返すモデルがチャットで質問し、解決済みコードで再呼び出し
どちらの方法でも質問は人間に届き、ツールは決して推測しません。暫定結果は保守的に保たれます —
recordable: true、根拠は確認待ちとマーク — そしてclarification_requiredは質問、CFRの理由、および各回答に対して返送する正確な治療コードを保持します。特定のクライアントがどの段階に該当するかは、推測せずに確認する価値があります。 ここで検証済み:Claude Desktopのチャットクライアントは
elicitation機能を宣伝しておらず、MCP Inspector 0.15.0および1.0.0も同様です。エージェント型クライアントは異なる場合があり、独自のメカニズムでユーザーに質問するクライアントは外部からは同一に見えます。サーバーは接続時にelicitation=supported|NOT supportedをstderrに記録します — 任意のクライアントで起動してその行を読んでください。
出所と強制された陳腐化
RuleRecord<T>(src/types.tsを参照)は規制規則を保持します:cfr_cite、source_url、last_verified、そしてeCFRが提供する場合はamendment_historyとeditorial_note。effective_dateフィールドはありません。データセットは現在のeCFRテキストを保持し、last_verifiedは規制検証の日付を示します。
陳腐化はscripts/check-decay.tsを介して強制され、いずれかのレコードのlast_verifiedがその減衰しきい値を超えた場合にビルドを失敗させます。これはプッシュ時と毎週のCIスケジュールで実行され、サブパートのsource_urlターゲットを検証し、eCFRのeditorial_noteエントリをチェックします。
インシデントトリアージチェーン(同梱)
*「誰かが負傷した」*から正しい記録入力までを追跡する11の決定的ツール:
osha_check_recordkeeping_obligation(1904.1, 1904.2) — 他のすべての判定が前提とする問い:この事業者はそもそも記録を保持する義務があるのか?規模の免除は、全社のピーク時の従業員数(昨暦年)で測定される。平均でも、単一サイトでもない。業種の免除は事業所に紐づき、NAICSコードが与えられると、ツールは閉じた82コードのAppendix Aリストに対して解決する。どちらも部分的である:1904.39の重傷報告はどちらの免除でも生き残る。これは、免除された事業者が危険なほど誤って推論する点である。osha_determine_recording_employer(1904.31) — これはステップではなく閾値の問い:負傷者が給与台帳に載っていない場合、これはそもそもその事業者のケースなのか?日々の監督が決めるのであって、給与ではない。 派遣会社の給与に載っているが、あなたが毎日作業を指示する派遣社員は、あなたが記録すべきである。同じ派遣社員でも、派遣会社の監督下にある場合はあなたの記録対象ではない。自営業者はOSH法の適用範囲外であり、個人事業主のオーナーやパートナーは記録保持の目的では従業員ではない。(b)(4)は、ケースが正確に一度だけ記録されることを要求する。両方のログに記録してはならない。osha_assess_work_relatedness(1904.5) — 他のすべてが依存する門であり、これまでこのプロジェクトがモデルに委ねていた唯一の法的判断である。1904.5(a)は、作業環境で発生したものについて業務関連性を推定する。1904.5(b)(2)は、それを覆すことができる9つの例外の閉じたリストである。判定は意図的に三値である —work_related、not_work_related、またはrequires_judgment— なぜなら1904.5には、規制自体が事業者に委ねる経路が含まれているからである:原因不明(1904.5(b)(3))、出張中((b)(6))、在宅勤務((b)(7))、そしてすべての例外が依存する「専ら」という認定。これらをブール値に強制することは、ツールがPart 1904で最も争われる判断を推測することになる。また、記憶が逆になるケースも解決する。通勤中の自動車事故が会社の敷地内で発生した場合は、(b)(2)(vii)の例外に該当する。同じ敷地内での転倒はどの例外にも該当せず、業務関連のままである。そして精神疾患は通常の方向を逆転させる — 従業員がPLHCPの意見を自発的に提供しない限り業務関連ではない((b)(2)(ix))。osha_assess_new_case(1904.6) — 新しい300ログの記入項目か、それとも既存の項目の更新か?1904.4(a)の連言の2番目の条件である。規制が意図的に分離する2つの再発ケースを分割する:職場のばく露によって引き起こされたエピソードは新しいケースである((b)(2))— ライン上で誘発された職業性喘息 — 一方、ばく露なしに症状が再発する慢性疾患は一度だけ記録される((b)(1))。なお、(b)(1)は閉じたリストではない:規制は「例には含まれる場合がある」として癌、石綿肺、綿肺、珪肺を挙げているため、ツールは疾患名を照合するのではなく、状態の性質について尋ねる。また、サーバー内で外部の権威に委ねる唯一のツールでもある。(b)(3)の下では、事業者はPLHCPに相談する必要はないが、相談した場合はその勧告に従わなければならない。したがって、PLHCPの意見はルールのロジックを完全に上書きし、矛盾する意見はrequires_judgmentを返す。なぜなら、それらを比較検討することは明示的に事業者の仕事だからである。osha_evaluate_restricted_work(1904.7(b)(4)) — その制限は実際にカウントされるのか?すべてがカウントされるわけではなく、どちらの誤りもケースをログに載せたり外したりする。負傷当日に限定された制限はカウントされない((b)(4)(iii))。すべての日常業務を遂行しながらも生産量が減少した場合はカウントされない((b)(4)(vi))。「日常業務」とは、少なくとも週に1回行われる活動を意味する((b)(4)(ii))。部分的なシフトはカウントされる((b)(4)(v))。転勤は制限の列を共有する((b)(4)(x))。興味深いのは(b)(4)(vii)である:*「軽作業」*のような曖昧な勧告をPLHCPに確認できない場合、そのケースは制限業務として記録されなければならない。これは、規制が記録に向けて自らの疑念を解決するものであり、Part 1904で唯一のデフォルトで記録するルールである。osha_evaluate_hearing_loss(1904.10) — Part 1904で純粋に算術的な唯一の記録基準であり、ここで検索ではなく計算する唯一のツールである。同じ耳で2つのテストが両方とも満たされなければならない:ベースラインに対する10 dBの標準閾値シフト、および聴力ゼロから25 dB以上の合計聴力レベル。それぞれ2000、3000、4000 Hzで平均する。一方の耳でSTS、もう一方の耳で25 dBレベルがあっても記録されない。年齢調整はシフトテストにのみ適用され、25 dBテストには決して適用されない。osha_assess_recordability(1904.4) — 記録可能か?(上記のアンカー)osha_check_severe_injury_reporting(1904.39) — OSHAに報告しなければならないか、いつまでに?事業者がそれを知った時点から計算された実際の期限タイムスタンプ(死亡は8時間、入院・切断・眼球喪失は24時間)を返し、インシデントからの適格期間をチェックし、時計がすでに超過しているかどうかをフラグする。osha_classify_300_log_entry(1904.29) — 最も深刻な結果のルールに基づく300ログの結果列(G/H/I/J)、傷害・疾病の種類の列、および180日で上限が設定された日数。osha_check_privacy_case(1904.29(b)(6)-(9)) — 従業員の名前をログに載せてもよいのか?2番目の閉じたリストであり、両方向で閉じている:(b)(7)は6つのプライバシー懸念ケースを列挙し、(b)(8)はそれ以外をプライバシーケースとして扱うことを禁止する。したがって、事業者はそれを無視できないのと同様に、同情から拡張することもできない。リテラルなログエントリ("privacy case")に加えて、それに続く義務を返す:別の機密リスト((b)(6))、ナラティブだけで従業員を特定できる場合のケースの説明における裁量((b)(9))、および記録が政府代表者以外の誰かに渡される場合の編集((b)(10))。osha_route_to_establishment_log(1904.30) — どの事業所の300ログか。個々のインシデントに関する最後の質問。ルールは直感に反する:ケースは人ではなく場所に従う。雇用主の別の工場でシフトをカバーしている間に負傷した人は、その工場のログに記録される。これにより、そのサイトのTRIRを駆動する数値が移動する。すべての事業所から離れた場所での負傷(顧客サイト、移動中、リモート)は、従業員が通常勤務するサイトのログに記録される。
範囲:Part 1904のみ、それ以外は対象外
ここにあるすべては1つの問いに答える — 誰かが負傷した。OSHAは私に何を記録し報告することを要求するか? それは29 CFR Part 1904全体であり、上記の11のツールはそれが強制する判定である。
配布:サーバーとスキル
2つの成果物。異なる問いに答えるからである。サーバーは決定する。スキルはいつそれを尋ねるかを知っている。
サーバー — 3つのエントリポイント、1つのエンジン
エントリポイント | トランスポート | 用途 |
| stdio | Claude Desktop、ローカル開発 |
| Streamable HTTP | コンテナまたはノードホスト |
| Streamable HTTP | Cloudflare Workers |
3つすべてが同じcreateServer()を、同じ11のツールと15のデータセットに対して呼び出す。src/tools/内の何も、どれが実行されているかを知らない。その移植性は、移植の努力ではなく、2つの以前の決定から生まれた:判定は純粋関数であり、datasets.tsはJSONとの唯一の接点である。
すべてのバリアントはステートレスである — リクエストごとに新しいサーバー、セッションIDなし、呼び出し間で保持されるものは何もない。すべてのツールがバンドルされたデータに対する純粋なルックアップだからである。/healthは各データセットの経過時間を減衰しきい値に対して報告し、1つが古くなると503を返す。したがって、ホストされたデプロイは、ビルドと同じルールで監視される。
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 deploysmoke:workerは、workerdの下でツールを実行する唯一のチェックである。他の2つのスモークはNode上で実行され、構造的にノード組み込みがコードパスに忍び込むのを見ることができない。これはまさにデプロイが最初に表面化させるものである。nodejs_compatはwrangler.tomlで意図的にOFFになっており、その失敗が開発中に静かではなく大きなものになるようにしている。
ワーカーはPOSTのみを受け付ける。ステートレスなサーバーはメッセージを開始しないため、GET SSEストリームは何も運ばず、永遠に開いたままになる。workerdは応答が完了しないリクエストをキャンセルする。405とAllow: POSTは、サーバーからクライアントへのストリームが存在しないことをプロトコルが伝える方法である。
認証は意図的にない。サーバーは公開された規制テキストを公開し、何も保存せず、副作用もない。したがって、アクセス制御はその前にあるべきである — Cloudflare AccessやOAuthレイヤー — 内部で中途半端に実装するのではなく。
レート制限
レート制限は例外であり、その前ではなくワーカー内に存在する。デプロイはworkers.dev上にあり、これはアカウント内のゾーンではないため、WAFレート制限ルールはアタッチするものがない。[[ratelimits]]バインディングとしてwrangler.tomlに宣言されており、これは誰も差分を取らないダッシュボードに住むのではなく、レビューされ、バージョン管理され、デプロイと一緒に移動することを意味する。
クライアントIPあたり毎分300リクエスト。 意図的に寛大である:リミッターはIPをキーとし、単一の企業NATの背後にある安全チームは単一のキーを共有する。1つのトリアージチェーンは約15リクエストであるため、複数の人が同時に作業すると正当に毎分150を超える。これは、ホストされたデプロイを実際に脅かす失敗であるエラーでループするモデルを遮断するためのサイズであり、通常の使用を計測するためではない。制限を超えると429とRetry-Afterが返される。
/healthはチェックの上に位置するため、スケジュールでポーリングする稼働監視が予算を消費することは決してない。強制はグローバルに調整されるのではなくデータセンターごとであるため、正確なクォータではなく遮断である。
ツールが受け取るもの
サーバーは何も取得せず、何も保存しない。しかし、引数は依然として流入し、それらは実際のインシデントを記述する。したがって、「ユーザーデータなし」は、転送については何も言わないストレージに関する主張である。この区別は、EHSチームが評価しなければならないものであるため、明確に述べる価値がある。
入力は識別子ではない。 スキーマのどこにも、名前、従業員番号、生年月日、住所、自由形式のナラティブのためのフィールドはない。すべての入力はケースの属性(work_related、days_away_from_work、treatments)であり、判定にはそれ以外は必要ない。これはポリシーではなくスキーマの特性である:名前を入れるフィールドがない。スキルはモデルに、呼び出しにアイデンティティを持ち込まないように指示するため、制約は両端で保持される — 事実を渡し、アイデンティティは渡さないを参照。
一部の属性はとにかく機密である。 osha_check_privacy_caseは、1904.29(b)(7)が列挙するカテゴリのみを受け取る — sexual_assault、mental_illness、hiv_hepatitis_or_tuberculosis、contaminated_needlestick_or_sharps。規制がこれらを特に選ぶのは、同僚が読めるログに載ってはならないものだからである。属性のみは匿名と同じではない:9人の事業所での性質コードとインシデント日付は、そこで働く誰かにとって誰かを特定できる。
それがどこに着地するかは、トランスポートに依存し、トランスポートのみに依存する:
エントリポイント | 引数が行く場所 |
stdio | サーバーを実行しているマシンに留まる。AIホストは依然としてそれを見る |
node HTTP / worker | ネットワークを越えて、そのデプロイを運用する誰かに渡る |
どちらの場合も何もログに記録されません — リクエストのログも、ツール呼び出しのログも、成功・失敗を問わず一切記録されません。これは意図的です。これらの引数のログは、それ自体が規制対象の保管庫となり得ますが、このサーバーには他に規制対象となるものが何もありません。また、判定結果は、入力と、すべてのレスポンスに含まれる last_verified データセットバージョンからすでに再現可能です。レスポンス内の来歴情報は、監査ログと同じ役割を、保持を伴わずに果たします。
したがって、GDPR または HIPAA の下で実際のケースを扱う場合は、stdio で実行するか、自分が管理するインフラストラクチャ上でワーカーをセルフホストしてください。 規制対象のインシデントデータを、誰か他の人がホストするこのサーバーのコピーに向けることは、契約を結んでいない第三者に傷害属性を送信することを意味します。判定はバンドルされた JSON に対する純粋関数です — セルフホストには wrangler deploy 1回のコストがかかるだけで、回答は何も変わりません。
ホストとオリジンの検証
認証は誰が質問してよいかに関するものです。ホスト検証は、ブラウザが他人の代わりに質問させられることに関するものであり、上流のゲートウェイでは後付けできません — そのため、この部分は src/httpGuard.ts で処理され、両方の HTTP エントリポイントに適用されます。
これが防ぐ攻撃は DNS リバインディングです。攻撃者のドメインが 127.0.0.1 に再解決され、ブラウザがリクエストを同一オリジンとみなしてプリフライトなしで送信し、ローカルで実行されている MCP サーバーが応答します。Host ヘッダーがそれを依然として見破ります — 攻撃者のドメインが含まれているためです — したがって、完全一致のホスト許可リストが有効なチェックです。
変数 | Node ( | Worker |
| バインドアドレス、デフォルトは | — |
| デフォルトは | 未設定 = 無制限 |
| 未設定 = 無制限 | 未設定 = 無制限 |
どちらもカンマ区切りのリストを受け付けます。* は、前段のゲートウェイが判断を担う場合にチェックを無効にします。Origin はヘッダーが存在する場合にのみチェックされます。ブラウザ以外の MCP クライアントは Origin を送信しないためです。/health は許可リストの外にあります — 稼働監視は脅威モデルではありません。
Node のエントリポイントはデフォルトでループバックのみに制限されています。 コンテナやリバースプロキシでのデプロイは別の名前で到達されるため、MCP_ALLOWED_HOSTS を設定する必要があります。設定しない場合は、受け取ったヘッダーを明示した 403 で失敗しますが、これは5秒で修正できます。逆のデフォルトは誰も気づかない穴になります。バインドアドレスは保護ではないことに注意してください — 0.0.0.0 へのバインドがデフォルトのままなのはコンテナが動作するようにするためであり、許可リストがそれを安全にしているのです。
拒否されたリクエストには、JSON-RPC の -32000 エラー付きで 403 が返されます。過大なボディ(>1 MB)には 413、不正な JSON には 400 が返されます — クライアント側のミスはインシデントとして記録されません。
スキル
skills/osha-incident-triage/ は手順を担います。チェーンが適用されるタイミング、呼び出し前に確定すべきこと、判定の提示方法、そしてツールが決定できないことです。インシデントトリアージのプロセスガイダンスが含まれており、規制ロジックを直接は含みません。
レイアウト
判定ロジックは純粋でテスト可能です。サーバーはその周りの配線にすぎません。
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ツールを追加するには、src/tools/ に1つのファイル(ルール)、src/registrations/tools/ に1つのファイル(説明と要約の方法)、そしてバレルファイルに1行が必要です。register プレフィックスにより、エディタのタブバーでこれらのファイル名が src/tools/ 側の対応物と区別されます。
維持する価値のある2つの不変条件があります。来歴情報は ruleRecord() によってのみ組み立てられること、そして Resources はツールが読み込むのと同じ DATASETS テーブルから生成されることです。これにより、どのツールも読み込まないパスでデータセットが公開されることはありません。
継続的インテグレーション
.github/workflows/ci.yml は、Node 20 と 22 で型チェック、ビルド、ユニットテスト、スモークテストスイートを実行します。
陳腐化チェックと npm audit はどちらも、CI の他のジョブと同じトリガー(プッシュ、プルリクエスト、毎週のスケジュール)で実行されます。それぞれ別のジョブとして維持されているため、どちらかの失敗が他の複数の赤い X に埋もれず、単独で判読できます。npm audit は、低レベルの本番依存関係に関する脆弱性アドバイザリでビルドをブロックします。開発依存関係のアドバイザリは報告のみで、ブロックはしません。毎週のスケジュールは、すでに main にある依存関係バージョンに対して公開されたアドバイザリを捕捉します。そうでなければ、再チェックをトリガーするプッシュが何も起こらないためです。
tsconfig.json は test/ を除外しているため、tsc --noEmit は src/ のみをチェックし、ts-jest は npm test 中にテストファイルの型チェックを行います。
変更管理とバージョニング
CHANGELOG.md は、2つの独立したリリース次元にわたってすべての変更を追跡します。
コード: 判定ロジック、ツールスキーマ、サーバートランスポートはセマンティックバージョニングに従います。
規制データ:
src/data/配下のバンドルされた eCFR JSON データセット。データセットを現在の eCFR テキストに対して再検証すると、last_verifiedの日付が更新され、規制テキストが変更されていない場合でもパッチアップデートとしてリリースされます。これにより、コンプライアンスチーム向けの監査可能な来歴が維持されます。強制陳腐化: CI は
scripts/check-decay.tsを毎週実行し、手動による再検証なしにいずれかのデータセットが365日の陳腐化しきい値を超えた場合にビルドを失敗させます。リリース: GitHub 上のバージョンタグ(
vX.Y.Z)は.github/workflows/release.ymlをトリガーし、完全な検証スイート(型チェック、テスト、スモークテスト、陳腐化チェック、監査)を実行して、検証済みの GitHub Release を作成します。
開発
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 toolnpx @modelcontextprotocol/inspector でローカルに接続するか、dist/index.js を指すように claude_desktop_config.json に追加します。
npm run smoke:worker と npm run dev:worker は Node 22 以降が必要です。wrangler が Node 22 以降を必要とするためです。それ以外はすべて Node 20 で動作し、engines は意図的に >=20 のままです。このフィールドは、サーバーをインストールして実行できる人に関する主張であり、サーバーに必要なのは SDK と zod だけです。Wrangler は開発ツールであり、消費者に届くことはないため、その要件はパッケージの要件ではありません。CI がまさにその理由で Node 20 をマトリックスに含めており、そこではワーカーのスモークテストだけがスキップされます。
評価
evals/recordkeeping-evals.xml — 47の質問で、LLM がツールを通じて正しい回答に到達するかどうかをテストします。これはユニットテストではカバーできません。すべての回答は、実際の MCP クライアントでビルド済みサーバーを駆動して生成されました。トレースは evals/README.md にあります。47の質問のほとんどには、記憶から推論するモデルが手を伸ばす直感的な誤答があります。
免責事項
参考およびトリアージ専用です。法的助言ではなく、医学的判定でもありません。記録要否の境界事例は、しばしば PLHCP または弁護士の判断が必要です。仕事関連性(1904.5)は、その決定的な経路に沿ってのみ判定されます。原因が不明な場合、出張中の状態、在宅勤務、および「専ら(solely
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 Servers
- AlicenseNot gradedqualityCmaintenanceA 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
- AlicenseAqualityAmaintenanceFirst-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.11MIT
- AlicenseNot gradedqualityCmaintenanceMCP server for US workplace-safety standards (OSHA 29 CFR parts 1900–1990). Enables querying safety regulations via natural language through the Pipeworx gateway.14MIT
- FlicenseNot gradedqualityCmaintenanceProvides policy-grounded triage of Trust & Safety reports via MCP, with tools for triage, policy search, and operational telemetry.
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.
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/srhtdmrkl/osha-recordkeeping-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server