Skip to main content
Glama
README.md
# orca-mcp

日医標準レセプトソフト(ORCA / WebORCA)の **参照系API 34本** を、任意のLLMから読めるようにするMCPサーバー。

**読み取り専用。** 登録・更新・削除のAPIは1本も載せていない。

> 日本医師会ORCA管理機構とは無関係の**非公式**なプロジェクトです。
> ORCA / 日医標準レセプトソフト は同機構の名称・商標です。

```
あなた: 「8月27日に来院した患者と、その人たちの病名を教えて」
   ↓
LLM → orca-mcp → WebORCA → 日レセのデータベース
```

## なぜ作ったか

日本のレセコンで**APIが公開されているのはORCAだけ**である。
ウィーメックス、EMシステムズ、BML、ニチイ等はいずれも閉じている。
そのORCAは全国18,369施設(2026年6月、ORCA公式稼働状況)で動いていて、レセコン国内シェア2位。

つまりORCAは、**LLMが日本の診療所の請求システムに触れる唯一の正規の入口**である。
そこにMCPが無かったので作った。

## 5分で試す — 医療機関は要らない

WebORCAオンプレ版をローカルに1つ立てて、ダミー患者を入れて、MCP経由で読む。
**実在の医療機関にも患者データにも一切触れずに、動くところまで確認できる。**

```bash
git clone https://github.com/JinTanba/orca-mcp && cd orca-mcp && bun install

# 1. ローカルにWebORCAを立てる(初回のビルドは5〜15分。日レセのパッケージが大きい)
docker compose -f docker/docker-compose.yml up -d --build

# 2. デモ用のダミー患者と病名を入れる(ローカル以外には書き込まない安全装置つき)
export ORCA_BASE_URL=http://localhost:8000/api ORCA_USER=ormaster ORCA_API_KEY=ormaster
bun scripts/seed.ts

# 3. 34本すべてを叩いて疎通を見る(応答の中身は表示しない)
bun scripts/smoke.ts

# 4. MCPサーバーとして繋いで、道具として動くところまで確認する
ORCA_E2E=1 bun test test/e2e.test.ts
```

日レセのパッケージは **amd64 でしか配布されていない**。
Apple Silicon では compose が `platform: linux/amd64` で解決する(Rosetta)。

> `docker/` の構成は**開発・デモ専用**。PostgreSQLとアプリを1コンテナに同居させ、
> `ormaster` のパスワードが既定値で、TLSも張っていない。本番運用には使わないこと。

## できること

| 分類 | ツール |
|---|---|
| 患者 | `patient` `patients` `patient_ids` `patients_by_name` `patient_insurance_combinations` `patient_memos` `patient_former_names` |
| 病名・診療 | `diseases` `medical_records` `medical_temp` `medication_code` `subjectives` `contraindication_check` |
| 受付・予約 | `reception_list` `visit_list` `appointments` `patient_appointments` |
| 会計・保険 | `income` `billing_simulation` `insurance_providers` `insurance_list` |
| 医療機関・マスタ | `system_manage` `system_daily` `system_info` `master_last_update` `push_events` |
| 入院 | `hosp_base_config` `hosp_ward_config` `hosp_patient_info` `hosp_meal` `hosp_adl` `hosp_discharge_simulation` `hosp_accounting_check` `hosp_find` |

とくに効くもの:

- **`diseases`** — 病名が**病名コード付き**で返る。カルテのテキスト病名を名寄せする必要が無い
- **`medical_records` (class=02)** — 診療行為が**レセプトの「剤」構造のまま**返る。カルテPDFから剤を組み直す推測が要らない
- **`patient_ids`** — 患者番号一覧が1回で最大1000件。患者台帳を総当たりしなくていい
- **`reception_list`** — 受付時刻が取れる。時間外・休日・深夜加算の判定材料
- **`contraindication_check`** — 薬剤併用禁忌の判定。副作用は無い(判定するだけ)

### 載せていないもの(意図的)

`patientmodv2`(患者登録) `diseasev2/v3`(病名登録) `medicalmodv2`(中途終了データ作成)
`acceptmodv2`(受付) `appointmodv2`(予約) `hsptinfmodv2`(入退院) ほか登録・更新系すべて。

診療報酬請求は法的文書である。LLMがそこに直接書き込める構造を配布するのは無責任だと考えている。
書き戻しが要るなら、人が承認する画面を持つアプリケーション側の責務にすべき。

## 使い方

### 1. 接続情報を用意する

**WebORCA オンプレ版 / ローカル** — 証明書は要らない。認証は日レセの職員ID/パスワードそのもの。

```bash
ORCA_BASE_URL=http://localhost:8000
ORCA_USER=ormaster
ORCA_API_KEY=ormaster        # 職員情報のパスワード
```

**WebORCA クラウド版** — **クライアント証明書(mTLS)とAPIキーの両方が要る。片方では通らない。**

| 渡したもの | 結果 |
|---|---|
| APIキーのみ | **接続できない**(TLSハンドシェイクで切られる。HTTPステータスすら返らない) |
| 証明書のみ | 401 Unauthorized |
| 証明書 + APIキー | 200 |

証明書はテナントごとにORCA管理機構が発行する(有効期間3年)。APIキーはベンダー管理者が確認する。
**出所が違うので、別々に入手する必要がある。**

```bash
ORCA_BASE_URL=https://weborca.cloud.orcamo.jp/api
ORCA_USER=receai             # 任意の文字列でよい
ORCA_API_KEY=...             # ベンダー管理者から受け取る(後述)
ORCA_CLIENT_CERT=/path/to/xxxxx.crt
ORCA_CLIENT_KEY=/path/to/xxxxx.pem
```

> **APIキーは医療機関自身では確認できない。**
> システム管理サイト(`ctrl-cmo.cloud.orcamo.jp`)の「APIキーの確認」は
> **ベンダー管理者アカウント**の機能で、テナント管理者(=医療機関)のメニューには無い。
> 導入したベンダー(保守業者)に依頼する。ベンダーが分からなければ
> ORCA管理機構(`weborca-application@orcamo.jp`)が窓口。
> 出典: WebORCAクラウド構築手順書 §7(6) / 別紙-システム管理サイトアクセス手順書 P.4

### 2. 動かす

```bash
bun install
cp .env.example .env      # 上の値を書く
bun test                  # 実機に繋がっていれば疎通テストが走る
bun scripts/smoke.ts      # 34本を1回ずつ叩いて疎通を一覧表示(応答の中身は出さない)
```

### 3. MCPクライアントに登録する

MCPの仕様では、**stdioサーバーの認証情報は起動時の環境変数で渡す**のが正規の方法である
(OAuthはHTTPトランスポートのためのもので、stdioには適用しない、と仕様が明記している)。
このサーバーもそれに従う。

**推奨: `.mcp.json` で変数展開する。** 鍵をファイルに書かずに済む。

```json
{
  "mcpServers": {
    "orca": {
      "command": "bun",
      "args": ["/path/to/orca-mcp/src/server.ts"],
      "env": {
        "ORCA_BASE_URL": "https://weborca.cloud.orcamo.jp/api",
        "ORCA_USER": "receai",
        "ORCA_API_KEY": "${ORCA_API_KEY}",
        "ORCA_CLIENT_CERT": "${ORCA_CLIENT_CERT}",
        "ORCA_CLIENT_KEY": "${ORCA_CLIENT_KEY}"
      }
    }
  }
}
```

`${VAR}` はクライアントが起動時にシェルの環境変数へ展開する(`${VAR:-既定値}` も使える)。
**この形なら `.mcp.json` をリポジトリに入れても鍵が漏れない。**

コマンドで登録する場合:

```bash
claude mcp add orca \
  --env ORCA_BASE_URL=https://weborca.cloud.orcamo.jp/api \
  --env ORCA_USER=receai \
  --env ORCA_API_KEY="$ORCA_API_KEY" \
  --env ORCA_CLIENT_CERT=/path/to/xxxxx.crt \
  --env ORCA_CLIENT_KEY=/path/to/xxxxx.pem \
  -- bun /path/to/orca-mcp/src/server.ts
```

**開発中のみ: `.env`。** リポジトリ直下に `.env` があれば読む(MCPクライアントから起動されると
作業ディレクトリが不定になるため、実行環境の自動読み込みには頼らない)。
これはMCPの仕様には無い便宜的なもので、**環境変数が既にあれば上書きしない**。
上の `env` 指定が常に優先される。

繋がったかは `bun scripts/mcp-check.ts` で確認できる。ツール一覧と実際の `tools/call` を1回試す。

## 実機で分かったこと(仕様書に書かれていない)

公式仕様だけでは通らない点がいくつかある。同じところで詰まる人のために残す。

| 症状 | 原因 |
|---|---|
| POSTすると全APIが `500 nil pointer dereference` | **`format=json` を付けている。**クラウド版はボディのあるリクエストでJSON変換に失敗する。XMLで送受信すること(GETやボディ無しなら `format=json` は動く) |
| クラウド版で `401 Unauthorized` | Basic認証の**パスワードはAPIキー**。画面ログインのパスワードとは別物。ユーザ名は任意の文字列でよい |
| `UNABLE_TO_GET_ISSUER_CERT_LOCALLY` | 配布物の `ca.crt` を CA として渡している。あれは**クライアント証明書の発行元**で、サーバ証明書の検証には使わない。渡すとシステムのCAを置き換えてしまう |
| 成功なのにエラー扱いになる | 成功コードの桁数がAPIごとに違う(`00` / `000` / `0000`)。`W` 始まりは警告で、応答本体は返っている |
| `処理区分未設定` `リクエスト番号がありません` | `Request_Number` や `?class=` は省略できないAPIが多い。このサーバーは定義表の既定値を必ず埋める |
| `systeminfv2` が `0006` | ORCAサーバの時計と**30分以上ずれた日時**を送っている。日レセは国内専用なのでJST固定で送ること(`TZ=UTC` の実行環境で踏む) |
| オンプレで全APIが `404` | **オンプレ版もURLに `/api` が要る。**`http://host:8000/api/api01rv2/...`。5.1以前の日レセ(WebORCAでないもの)は `/api` を付けない |
| `contraindication_check` が `13 対象期間月数がゼロ` | `Check_Term` を省いている。このサーバーは既定で `1`(当月のみ)を入れる |
| オンプレ構築で `passwd_store.sh` が「テーブル格納処理でエラー」 | 公式手順のこのスクリプトは INSERT 文を `dbstub` 経由で流すが、環境によっては `dbstub` が panic する(`interface conversion: interface {} is nil, not float64`)。やっていることは `md5pass` のハッシュを `tbl_passwd` に入れるだけなので、直接 SQL で入れれば済む(`docker/entrypoint.sh` がそうしている) |

`push_events` (`pusheventgetv2`) は疎通するが空応答しか確認できていない。
PUSH通知の設定が要る可能性があり、**未検証**。

## 疎通の実績

34本を1回ずつ実行した結果。**クラウド・オンプレの両方で電文の誤りは0本。**

| 環境 | OK | 空 | NG | SKIP |
|---|---|---|---|---|
| WebORCAクラウド版(日レセ 5.2.0・無床の在宅診療所) | 20 | 13 | **0** | 1 |
| WebORCAオンプレ版(`docker/` + `scripts/seed.ts`) | 14 | 19 | **0** | 1 |

- **OK** … データが返った
- **空** … 電文は正しいが該当データが無い(入院系8本は無床・空DBなのでここ)
- **NG** … 電文の誤り
- **SKIP** … `billing_simulation` は診療データを組み立てないと意味が無いので対象外

MCPサーバーとしての動作は `test/e2e.test.ts` が見ている。
サーバーを起動し、MCPクライアントとして繋ぎ、`tools/list` が34本を返し、
`system_info` が日レセの版数を返し、`diseases` が病名コード付きで病名を返すところまで。

## 設計

```
src/apis.ts     34本の定義表。パス・ルート要素・引数。ここが唯一の正
src/client.ts   HTTP + mTLS + xml2 の組み立てとパース
src/server.ts   定義表からMCPツールを機械的に生やすだけ
scripts/smoke.ts 全APIの疎通確認(応答の中身は表示しない)
scripts/mcp-check.ts MCPクライアントとして繋いでツール一覧と tools/call を確認
scripts/seed.ts  デモ用のダミー患者を入れる。**ローカル以外には書き込まない**
docker/          ローカルにWebORCAオンプレ版を立てる。開発・デモ専用
test/orca.test.ts 電文の組み立てと、実機に繋いだ契約テスト
test/e2e.test.ts  MCPサーバーを起動して道具として叩く端から端までの検証
```

守っていること:

1. **読み取りだけ。** 定義表に書き込み系が混ざっていないことをテストで守っている
2. **解釈しない。** ORCAが返した項目名のまま返す。語彙は日レセの標準に合わせる
3. **患者データを保存しない。** 読んで返すだけ。ログにも残さない
4. **書き込みは外に出す。** `scripts/seed.ts` はデモ環境を作るためだけの道具で、
   MCPサーバーからは呼べない。接続先がローカルでなければ実行を拒否する

## 注意

- **本番の医療機関に接続する場合は自己責任で。**「医療情報システムの安全管理に関するガイドライン」
  (3省2ガイドライン)と個人情報保護法上の要配慮個人情報の取り扱いを、導入前に必ず確認すること
- 患者データを外部のLLMに送る構成になる。**院内で完結させたい場合は、
  オンプレ版のORCA + ローカルLLM** の組み合わせを検討したほうがよい
- このサーバーは日本医師会ORCA管理機構とは無関係の非公式なもの

## 関連

- [日医標準レセプトソフト API 仕様](https://www.orca.med.or.jp/receipt/tec/api/) — 公式。53API
- [orca-api](https://github.com/orca-api/orca-api) — メドレーによるRubyクライアント(Apache-2.0)

## ライセンス

Apache-2.0