@djmima/pubmed-mcp 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/README.md +804 -793
- package/dist/cli/commands.js +114 -114
- package/dist/cli/run.js +31 -31
- package/dist/pubmed/client.d.ts.map +1 -1
- package/dist/pubmed/client.js +8 -4
- package/dist/pubmed/client.js.map +1 -1
- package/dist/utils/xml.d.ts.map +1 -1
- package/dist/utils/xml.js +2 -1
- package/dist/utils/xml.js.map +1 -1
- package/package.json +3 -2
- package/skills/pubmed-cli/SKILL.md +79 -79
package/README.md
CHANGED
|
@@ -1,793 +1,804 @@
|
|
|
1
|
-
# PubMed MCP Server
|
|
2
|
-
|
|
3
|
-
An [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server that gives Claude and other LLM clients structured access to [PubMed](https://pubmed.ncbi.nlm.nih.gov/) and [PubMed Central (PMC)](https://www.ncbi.nlm.nih.gov/pmc/) via the NCBI E-utilities API.
|
|
4
|
-
|
|
5
|
-
## Tools
|
|
6
|
-
|
|
7
|
-
| Tool | 説明 |
|
|
8
|
-
|------|------|
|
|
9
|
-
| `search_articles` | PubMed構文またはキーワードで文献を検索。ATM診断・フィールド制限・日付フィルタ・ソート・ページネーション対応 |
|
|
10
|
-
| `get_article_metadata` | PMIDを指定してタイトル・抄録・著者・MeSH語・キーワードなどを取得 |
|
|
11
|
-
| `find_related_articles` | ELinkを使って関連文献や他DBへのリンクを検索 |
|
|
12
|
-
| `lookup_article_by_citation` | 雑誌名・年・巻・筆頭著者などの引用情報からPMIDを逆引き |
|
|
13
|
-
| `convert_article_ids` | PMID・PMCID・DOI を相互変換 |
|
|
14
|
-
| `get_full_text_article` | PMC Open Access記事の本文全文をプレーンテキストで取得 |
|
|
15
|
-
| `get_copyright_status` | 全文取得の可否(`has_full_text`)・ライセンス・著作権表示・OAステータスを確認。PMCのEFetchメタデータを使用(旧PMC OA Web Serviceは2026-08-25に廃止) |
|
|
16
|
-
|
|
17
|
-
同じツールは、シェルから `pubmed` コマンドとしても実行できます(「[CLI](#cli)」を参照)。
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## `search_articles` の ATM 診断とフィールド制限
|
|
22
|
-
|
|
23
|
-
PubMed はタグのない検索語に Automatic Term Mapping(ATM)を適用します。ATM は MeSH、
|
|
24
|
-
雑誌名、著者名などへ検索語を展開するため、意図しない変換や、引用句が句インデックスに
|
|
25
|
-
存在しないことによる検索のフォールバックが起こる場合があります。
|
|
26
|
-
|
|
27
|
-
`search_articles` は次の任意の `field` 値を受け取り、クエリ内のタグなし語をすべてその
|
|
28
|
-
フィールドへ制限します。
|
|
29
|
-
|
|
30
|
-
- `title`
|
|
31
|
-
- `tiab`(Title/Abstract)
|
|
32
|
-
- `mesh`
|
|
33
|
-
- `author`
|
|
34
|
-
- `journal`
|
|
35
|
-
- `affiliation`
|
|
36
|
-
|
|
37
|
-
クエリ内に明示的なフィールドタグがある語では、そのタグが `field` より優先されます。
|
|
38
|
-
`field` を省略した場合の検索動作は従来どおりです。`all` は ATM を無効化しないため、
|
|
39
|
-
公開パラメータには含めていません。
|
|
40
|
-
|
|
41
|
-
レスポンスには、NCBI ESearch の診断を正規化した次のフィールドが常に含まれます。
|
|
42
|
-
|
|
43
|
-
```json
|
|
44
|
-
{
|
|
45
|
-
"warnings": {
|
|
46
|
-
"phrases_ignored": [],
|
|
47
|
-
"quoted_phrases_not_found": [],
|
|
48
|
-
"output_messages": []
|
|
49
|
-
},
|
|
50
|
-
"errors": {
|
|
51
|
-
"phrases_not_found": [],
|
|
52
|
-
"fields_not_found": []
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
この `errors` は NCBI ESearch が返す検索語・フィールドの診断であり、通信エラーや
|
|
58
|
-
MCP ツール自体の実行エラーとは別の情報です。
|
|
59
|
-
これらのキーは診断がない場合も空配列として返ります。低件数や0件を「文献なし」と判断する
|
|
60
|
-
前に、`query_translation`、`warnings`、`errors` を確認してください。複数語を同一フィールドで
|
|
61
|
-
確実に検索する場合は各語へタグを付け、引用句が句インデックスにない場合の隣接検索には
|
|
62
|
-
`[ti:~0]` または `[tiab:~0]` を使用できます。
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
## 必要環境
|
|
67
|
-
|
|
68
|
-
- **Node.js** 22 以上(`npx` と `npm` は Node.js に同梱されています)
|
|
69
|
-
- **NCBI API キー**(任意。なくても動作するが、レートリミットが 3 req/s に制限される)
|
|
70
|
-
- **jq**(任意。[CLI](#cli) の出力から必要なフィールドを取り出すのに使う)
|
|
71
|
-
|
|
72
|
-
---
|
|
73
|
-
|
|
74
|
-
## インストール
|
|
75
|
-
|
|
76
|
-
npm パッケージ [`@djmima/pubmed-mcp`](https://www.npmjs.com/package/@djmima/pubmed-mcp) として公開しています。
|
|
77
|
-
|
|
78
|
-
- **MCP サーバーとして使う場合**は、インストールは不要です。MCP クライアントの設定に `npx -y @djmima/pubmed-mcp@latest` を書くと、
|
|
79
|
-
起動時に最新版が自動でダウンロードされます(後述の「[使い方](#使い方)」を参照)。
|
|
80
|
-
- **[CLI](#cli) を使う場合**は、グローバルにインストールします。
|
|
81
|
-
|
|
82
|
-
```bash
|
|
83
|
-
npm install -g @djmima/pubmed-mcp
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
`pubmed` と `pubmed-mcp` の 2 つのコマンドが登録されます。更新は `npm update -g @djmima/pubmed-mcp`、
|
|
87
|
-
削除は `npm rm -g @djmima/pubmed-mcp` です。
|
|
88
|
-
|
|
89
|
-
ソースコードを修正して使いたい場合は「[ソースからビルドする](#ソースからビルドする)」を参照してください。
|
|
90
|
-
|
|
91
|
-
### NCBI API キーの設定(推奨)
|
|
92
|
-
|
|
93
|
-
APIキーを取得するとレートリミットが 3 → 8 req/s に向上します。
|
|
94
|
-
|
|
95
|
-
1. [NCBI アカウント](https://www.ncbi.nlm.nih.gov/account/)を作成してAPIキーを発行
|
|
96
|
-
2. 環境変数 `NCBI_API_KEY` にセット(後述のクライアント別設定を参照)
|
|
97
|
-
|
|
98
|
-
MCP クライアントからローカルで起動する場合は、クライアント設定の `env` でキーを渡してください。
|
|
99
|
-
`.env` は起動時のカレントディレクトリから読み込まれるため、クライアント経由の起動では
|
|
100
|
-
プロジェクト直下の `.env` が読まれないことがあります。
|
|
101
|
-
|
|
102
|
-
APIキーは、このサーバーを運用する個人または組織が所有・管理するものを設定してください。
|
|
103
|
-
リポジトリにはAPIキーを同梱しません。レスポンス中にNCBI APIの `echo` が含まれる場合も、
|
|
104
|
-
`api_key` 値は `<redacted>` にマスクされます。
|
|
105
|
-
|
|
106
|
-
クライアント側ではプロセスごとに簡易レートリミッターをかけています。APIキーなしでは最大
|
|
107
|
-
3 req/s、APIキーありではNCBI上限の10 req/sに対して余裕を持たせた8 req/sで送信します(NCBIは到着時刻で数えるため、回線の揺らぎ分の余裕)。HTTP 429 が返った場合は最大2回まで待機して再試行します。
|
|
108
|
-
同一プロセス内の並列呼び出しは自動的に間隔調整されますが、Cloud Runなどで複数インスタンスを
|
|
109
|
-
動かす場合は全インスタンス合算でNCBIの上限を超えないようにしてください。目安として、単一
|
|
110
|
-
インスタンスではAPIキーありで8並列程度、APIキーなしで2並列程度までに抑える運用を推奨します。
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
## 使い方
|
|
115
|
-
|
|
116
|
-
### Claude Desktop(ローカル・stdio)
|
|
117
|
-
|
|
118
|
-
`claude_desktop_config.json` の `mcpServers` にサーバーを追加します。
|
|
119
|
-
|
|
120
|
-
**macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
121
|
-
**Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
122
|
-
|
|
123
|
-
```json
|
|
124
|
-
{
|
|
125
|
-
"mcpServers": {
|
|
126
|
-
"pubmed-local": {
|
|
127
|
-
"command": "npx",
|
|
128
|
-
"args": ["-y", "@djmima/pubmed-mcp@latest"],
|
|
129
|
-
"env": {
|
|
130
|
-
"NCBI_API_KEY": "your_api_key_here"
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
- 他のサーバーが登録済みの場合は、`mcpServers` の中に `"pubmed-local": { ... }` を並べて追加します(前の項目との間のカンマを忘れずに)。
|
|
138
|
-
- Windows で起動しない場合は、`"command": "cmd"`、`"args": ["/c", "npx", "-y", "@djmima/pubmed-mcp@latest"]` に変えてください。
|
|
139
|
-
- `@latest` を付けると、起動のたびに npm に最新版があるか確認します。版を固定したい場合は `@djmima/pubmed-mcp@1.0.0` のように書きます。
|
|
140
|
-
- サーバー名を `pubmed-local` にしておくと、リモート版(`pubmed-remote`)や同じツール名を持つ他の PubMed コネクタと区別しやすくなります。
|
|
141
|
-
|
|
142
|
-
設定後、Claude Desktop を完全に終了してから再起動してください。ウィンドウを閉じただけではアプリが常駐したままになることがあります(Windows ではタスクトレイのアイコンから終了できます)。
|
|
143
|
-
この設定のサーバーは、Claude Desktop の Code タブで開いたセッションにも読み込まれます。
|
|
144
|
-
|
|
145
|
-
起動しない場合は、ログ(Windows: `%APPDATA%\Claude\logs\mcp-server-pubmed-local.log`、macOS: `~/Library/Logs/Claude/mcp-server-pubmed-local.log`)を確認してください。
|
|
146
|
-
|
|
147
|
-
---
|
|
148
|
-
|
|
149
|
-
### Claude Code(ローカル・stdio)
|
|
150
|
-
|
|
151
|
-
`claude mcp add` で登録します。`--scope user` を付けるとすべてのプロジェクトで使えます。
|
|
152
|
-
|
|
153
|
-
```bash
|
|
154
|
-
claude mcp add --env NCBI_API_KEY=your_api_key_here --transport stdio --scope user pubmed-local -- npx -y @djmima/pubmed-mcp@latest
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
- `--` より後ろは、サーバーの起動コマンドとしてそのまま渡されます。
|
|
158
|
-
- Windows(WSL ではない環境)では、`--` の後ろを `cmd /c npx -y @djmima/pubmed-mcp@latest` にしてください。
|
|
159
|
-
- `--env` の直後にサーバー名を書くと `KEY=value` の続きとして解釈されてエラーになるため、間に別のオプション(ここでは `--transport stdio`)を挟みます。
|
|
160
|
-
- 登録内容は `~/.claude.json`(user / local スコープ)またはプロジェクト直下の `.mcp.json`(project スコープ)に保存されます。`~/.claude/settings.json` に `mcpServers` を書いても読み込まれません。
|
|
161
|
-
- Claude Desktop の Code タブだけで使う場合は、上記の `claude_desktop_config.json` への登録で読み込まれるため、この手順は不要です。
|
|
162
|
-
|
|
163
|
-
登録後、`claude mcp list` または Claude Code 内の `/mcp` で接続状態を確認できます。
|
|
164
|
-
|
|
165
|
-
---
|
|
166
|
-
|
|
167
|
-
### Codex(ローカル・stdio)
|
|
168
|
-
|
|
169
|
-
Codex のデスクトップアプリ・CLI・IDE 拡張は、同じ設定ファイル `~/.codex/config.toml`(Windows: `%USERPROFILE%\.codex\config.toml`)を共有します。次のブロックを追記してください。
|
|
170
|
-
|
|
171
|
-
```toml
|
|
172
|
-
[mcp_servers.pubmed-local]
|
|
173
|
-
command = "npx"
|
|
174
|
-
args = ["-y", "@djmima/pubmed-mcp@latest"]
|
|
175
|
-
|
|
176
|
-
[mcp_servers.pubmed-local.env]
|
|
177
|
-
NCBI_API_KEY = "your_api_key_here"
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
- Windows で起動しない場合は、`command = "cmd"`、`args = ["/c", "npx", "-y", "@djmima/pubmed-mcp@latest"]` に変えてください。
|
|
181
|
-
- Codex は OS の環境変数をそのまま MCP サーバーへ渡しません。API キーは上のように `env` に書くか、`[mcp_servers.pubmed-local]` に `env_vars = ["NCBI_API_KEY"]` を追加して Codex 側の環境変数から転送してください。
|
|
182
|
-
|
|
183
|
-
CLI からは `codex mcp add` でも登録できます。
|
|
184
|
-
|
|
185
|
-
```bash
|
|
186
|
-
codex mcp add pubmed-local --env NCBI_API_KEY=your_api_key_here -- npx -y @djmima/pubmed-mcp@latest
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
設定後は Codex を再起動してください(デスクトップアプリでは **Settings → MCP servers** の **Restart**)。同じ画面の **Add server** から登録することもできます。CLI と IDE 拡張では `/mcp` で接続中のサーバーを確認できます。
|
|
190
|
-
|
|
191
|
-
---
|
|
192
|
-
|
|
193
|
-
### Anthropic API(プログラムからの利用)
|
|
194
|
-
|
|
195
|
-
```python
|
|
196
|
-
import os
|
|
197
|
-
|
|
198
|
-
import anthropic
|
|
199
|
-
|
|
200
|
-
client = anthropic.Anthropic()
|
|
201
|
-
response = client.beta.messages.create(
|
|
202
|
-
model="claude-opus-5",
|
|
203
|
-
max_tokens=16000,
|
|
204
|
-
messages=[{
|
|
205
|
-
"role": "user",
|
|
206
|
-
"content": "Find recent papers on CRISPR gene editing in cancer treatment"
|
|
207
|
-
}],
|
|
208
|
-
mcp_servers=[{
|
|
209
|
-
"type": "url",
|
|
210
|
-
"url": "https://pubmed-mcp-PROJECT_NUMBER.asia-northeast1.run.app/mcp",
|
|
211
|
-
"name": "pubmed",
|
|
212
|
-
# /mcp は OAuth で保護されているため、アクセストークンが必要
|
|
213
|
-
"authorization_token": os.environ["PUBMED_MCP_TOKEN"],
|
|
214
|
-
}],
|
|
215
|
-
tools=[{"type": "mcp_toolset", "mcp_server_name": "pubmed"}],
|
|
216
|
-
betas=["mcp-client-2025-11-20"]
|
|
217
|
-
)
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
Anthropic API の MCP コネクタは HTTP で公開されたリモートサーバーにしか接続できないため、先に Cloud Run へデプロイしておく必要があります。
|
|
221
|
-
デプロイ方法は後述の「[Google Cloud Run へのデプロイ](#google-cloud-run-へのデプロイ)」、アクセストークンの取得方法は「[クライアント別の接続設定](#クライアント別の接続設定)」を参照してください。
|
|
222
|
-
|
|
223
|
-
---
|
|
224
|
-
|
|
225
|
-
### ソースからビルドする
|
|
226
|
-
|
|
227
|
-
ソースコードを修正して使う場合は、リポジトリをクローンしてビルドします。
|
|
228
|
-
|
|
229
|
-
```bash
|
|
230
|
-
git clone https://github.com/DJMIMA/PubMed_MCP.git
|
|
231
|
-
cd PubMed_MCP
|
|
232
|
-
npm install
|
|
233
|
-
npm run build
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
MCP クライアントの設定では、`npx -y @djmima/pubmed-mcp@latest` の代わりに `node /absolute/path/to/PubMed_MCP/dist/index.js` を指定します
|
|
237
|
-
(Windows のパスは `C:/path/to/PubMed_MCP/dist/index.js` のようにスラッシュ区切りで書きます)。
|
|
238
|
-
CLI として使う場合は、続けて `npm link` を実行すると `pubmed` と `pubmed-mcp` コマンドが登録されます(解除は `npm rm -g @djmima/pubmed-mcp`)。
|
|
239
|
-
|
|
240
|
-
`dist/` はリポジトリに含まれません。`git pull` でソースを更新したら `npm run build` を再実行し、
|
|
241
|
-
MCP クライアントを再起動してください。起動中のサーバーは再起動するまで古いビルドのまま動きます。
|
|
242
|
-
|
|
243
|
-
### ローカル開発
|
|
244
|
-
|
|
245
|
-
```bash
|
|
246
|
-
# .env ファイルを作成してAPIキーを設定
|
|
247
|
-
cp .env.example .env
|
|
248
|
-
# .env を編集して NCBI_API_KEY を記入
|
|
249
|
-
|
|
250
|
-
# stdio モードで起動(デフォルト)
|
|
251
|
-
npm run dev
|
|
252
|
-
|
|
253
|
-
# HTTP モードで起動(PORT を設定すると有効になる。OAuth の環境変数も必須)
|
|
254
|
-
PORT=8080 npm run dev
|
|
255
|
-
# → http://localhost:8080/mcp MCP エンドポイント(Bearer トークン必須)
|
|
256
|
-
# → http://localhost:8080/health ヘルスチェック
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
HTTP モードは起動時に `OAUTH_ISSUER`・`OAUTH_JWKS_URL`・`MCP_RESOURCE_URL` を読み込み、1 つでも未設定だと次のエラーで終了します。
|
|
260
|
-
|
|
261
|
-
```
|
|
262
|
-
Fatal error: Error: Missing required environment variable: OAUTH_ISSUER
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
`.env` にこれらの値を設定してから起動してください(各値の意味は「[環境変数](#環境変数)」を参照)。
|
|
266
|
-
`/health` や 401 応答を確かめるだけなら URL 形式の仮の値でも起動できますが、`/mcp` を実際に呼び出すには
|
|
267
|
-
`MCP_RESOURCE_URL` を `aud` として発行されたアクセストークンが必要です。認証なしでツールを試す場合は stdio モードを使ってください。
|
|
268
|
-
|
|
269
|
-
---
|
|
270
|
-
|
|
271
|
-
## CLI
|
|
272
|
-
|
|
273
|
-
MCP サーバーと同じツールを、シェルから `pubmed` コマンドとして実行できます。出力は MCP ツールと同じ JSON で、
|
|
274
|
-
標準出力またはファイル(`-o`)に書き出されます。結果をファイルに保存して `jq` で必要なフィールドだけを取り出せば、
|
|
275
|
-
Claude Code や Codex などのエージェントが大量のメタデータをコンテキストに読み込まずに済みます。
|
|
276
|
-
|
|
277
|
-
たとえば `TP53 AND myelodysplastic syndromes[mh]` の上位 20 件のメタデータは約 108 KB ありますが、
|
|
278
|
-
PMID・年・タイトルだけを取り出すと 3.2 KB(約 1/34)になります。全文は 1 本で数万文字あります。
|
|
279
|
-
|
|
280
|
-
### インストール
|
|
281
|
-
|
|
282
|
-
```bash
|
|
283
|
-
npm install -g @djmima/pubmed-mcp
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
`pubmed --help` が表示されれば完了です。
|
|
287
|
-
|
|
288
|
-
NCBI API キーは環境変数 `NCBI_API_KEY` から読み込みます。シェルの設定ファイル(`~/.bashrc`、`~/.zshrc` など)に
|
|
289
|
-
`export NCBI_API_KEY=your_api_key_here` を書くか、Windows では `setx NCBI_API_KEY your_api_key_here` を一度実行してから
|
|
290
|
-
ターミナルを開き直してください。
|
|
291
|
-
|
|
292
|
-
[ソースからビルドして](#ソースからビルドする) `npm link` で登録した場合は、環境変数がなければリポジトリ直下の `.env`
|
|
293
|
-
(`cp .env.example .env` で作成)も読み込むため、どのディレクトリから実行してもキーが使われます。
|
|
294
|
-
|
|
295
|
-
### コマンド
|
|
296
|
-
|
|
297
|
-
| コマンド | 対応する MCP ツール | 入力 | 1 リクエストの件数 |
|
|
298
|
-
|---|---|---|---|
|
|
299
|
-
| `pubmed search <query>` | `search_articles` | 検索式(`-` で標準入力から) | — |
|
|
300
|
-
| `pubmed metadata <pmid>...` | `get_article_metadata` | PMID | 200 |
|
|
301
|
-
| `pubmed related <pmid>...` | `find_related_articles` | PMID | 200 |
|
|
302
|
-
| `pubmed citation --journal <雑誌> --year <年> ...` | `lookup_article_by_citation` | オプション、または `--input` で JSON 配列か JSON Lines | 100 |
|
|
303
|
-
| `pubmed convert <id>...` | `convert_article_ids` | PMID・PMCID・DOI のいずれか(`--id-type` で指定) | 200 |
|
|
304
|
-
| `pubmed fulltext <pmcid>...` | `get_full_text_article` | PMCID | 20 |
|
|
305
|
-
| `pubmed copyright <pmid>...` | `get_copyright_status` | PMID | 50 |
|
|
306
|
-
|
|
307
|
-
- オプション名は MCP のパラメータ名をケバブケースにしたものです(`max_results` → `--max-results`、`date_from` → `--date-from` など)。詳しくは `pubmed <command> --help` を参照してください。
|
|
308
|
-
- ID は引数(空白またはカンマ区切り)で渡すか、`-` を指定して標準入力から 1 行 1 件で渡します。
|
|
309
|
-
- 1 リクエストの件数を超える ID は自動で分割して順番に送り、結果を 1 つの JSON にまとめます。MCP ツールの件数上限(メタデータなら 200 件)は受けません。
|
|
310
|
-
- `-o <file>` を付けると JSON をファイルに書き出し、件数とファイルサイズを標準エラー出力に表示します。
|
|
311
|
-
- 終了コードは、成功で 0、NCBI やファイル操作のエラーで 1、使い方の誤りで 2 です。エラーの内容は標準エラー出力に出ます。
|
|
312
|
-
|
|
313
|
-
### 使用例
|
|
314
|
-
|
|
315
|
-
```bash
|
|
316
|
-
# 検索して、PubMed が検索式をどう解釈したかを確認する
|
|
317
|
-
pubmed search "TP53[tiab] AND myelodysplastic syndromes[mh]" --max-results 200 -o search.json
|
|
318
|
-
jq '{total_count, query_translation, warnings, errors}' search.json
|
|
319
|
-
|
|
320
|
-
# ヒットした全件のメタデータを取得し、PMID・年・雑誌・タイトルの一覧にする
|
|
321
|
-
jq -r '.pmids[]' search.json | pubmed metadata - -o meta.json
|
|
322
|
-
jq -r '.articles[] | [.identifiers.pmid, .publication_date.year, .journal.iso_abbreviation, .title] | @tsv' meta.json
|
|
323
|
-
|
|
324
|
-
# 全文を取得できる論文だけ全文を取得し、必要な箇所だけを検索する
|
|
325
|
-
jq -r '.pmids[]' search.json | pubmed copyright - -o rights.json
|
|
326
|
-
jq -r '.statuses[] | select(.has_full_text) | .pmcid' rights.json | pubmed fulltext - -o full.json
|
|
327
|
-
jq -r '.articles[].full_text' full.json | grep -n -i 'venetoclax'
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
### エージェントから使う
|
|
331
|
-
|
|
332
|
-
[`skills/pubmed-cli/SKILL.md`](skills/pubmed-cli/SKILL.md) は、CLI の使い方(結果はファイルに保存して jq で読む、ID はまとめて 1 回で渡す、など)と
|
|
333
|
-
jq のレシピをエージェントに教える Skill です。ユーザー単位のスキルフォルダにコピーすると、どのプロジェクトでも使われます。
|
|
334
|
-
Claude Code(Claude Desktop の Code タブを含む)は `~/.claude/skills/`、Codex は `~/.agents/skills/` から読み込みます
|
|
335
|
-
(Windows では `~` が `%USERPROFILE%` になります)。
|
|
336
|
-
|
|
337
|
-
Skill は npm パッケージにも含まれているので、`npm install -g` でインストールした場合は次のコマンドでコピーできます
|
|
338
|
-
(Windows では Git Bash で実行してください)。
|
|
339
|
-
|
|
340
|
-
```bash
|
|
341
|
-
SKILL_DIR="$(npm root -g)/@djmima/pubmed-mcp/skills/pubmed-cli"
|
|
342
|
-
mkdir -p ~/.claude/skills ~/.agents/skills
|
|
343
|
-
cp -r "$SKILL_DIR" ~/.claude/skills/
|
|
344
|
-
cp -r "$SKILL_DIR" ~/.agents/skills/
|
|
345
|
-
```
|
|
346
|
-
|
|
347
|
-
ソースからビルドした場合は、リポジトリ直下で `SKILL_DIR=skills/pubmed-cli` としてから同じコマンドを実行します。
|
|
348
|
-
パッケージや Skill を更新したときは、もう一度コピーしてください。
|
|
349
|
-
|
|
350
|
-
Claude Code でコマンドを実行するたびに許可を求められないようにするには、`~/.claude/settings.json` の `permissions.allow` に
|
|
351
|
-
`pubmed` と `jq` を追加します(既に設定がある場合は配列に追記してください)。
|
|
352
|
-
|
|
353
|
-
```json
|
|
354
|
-
{
|
|
355
|
-
"permissions": {
|
|
356
|
-
"allow": ["Bash(pubmed:*)", "Bash(jq:*)"]
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
注意点:
|
|
362
|
-
|
|
363
|
-
- CLI はシェルを実行できる環境(Claude Code、Codex など)でしか使えません。claude.ai のチャットや、Cloud Run にデプロイしたカスタムコネクタからは、これまでどおり MCP サーバーを使ってください。
|
|
364
|
-
- NCBI のレート制限はプロセスごとにかかります。`pubmed` を並列で複数起動すると合計で上限を超えるため、ID はまとめて 1 回の実行で渡してください。
|
|
365
|
-
- Windows では Git Bash か PowerShell 7 でパイプラインを実行してください。Windows PowerShell 5.1 の `>` はファイルを UTF-16 で保存するため、代わりに `-o` を使ってください。
|
|
366
|
-
|
|
367
|
-
---
|
|
368
|
-
|
|
369
|
-
## Google Cloud Run へのデプロイ
|
|
370
|
-
|
|
371
|
-
このサーバーは Docker コンテナとして Google Cloud Run にデプロイできます。
|
|
372
|
-
`PORT` 環境変数が設定されると自動的に HTTP モードで起動し、Streamable HTTP トランスポートで MCP クライアントと通信します。
|
|
373
|
-
|
|
374
|
-
HTTP モードの `/mcp` は **OAuth 2.0 で保護** されています。サーバーは OAuth のリソースサーバーとして動作し、
|
|
375
|
-
リクエストごとに Bearer トークン(JWT)の署名・発行者(`iss`)・対象(`aud`)・有効期限を、認可サーバーの公開鍵(JWKS)で検証します。
|
|
376
|
-
ログイン画面やトークンの発行は外部の認可サーバーが担当します(ここでは WorkOS AuthKit を使います)。
|
|
377
|
-
|
|
378
|
-
Cloud Run 自体は `--allow-unauthenticated` で公開します。Cloud Run の IAM 認証(IAP を含む)は claude.ai からの接続と両立しないため、
|
|
379
|
-
アクセス制御は Cloud Run ではなくアプリ側の OAuth で行います。
|
|
380
|
-
|
|
381
|
-
| パス | 認証 | 内容 |
|
|
382
|
-
|------|------|------|
|
|
383
|
-
| `/mcp` | Bearer トークン必須 | MCP エンドポイント |
|
|
384
|
-
| `/.well-known/oauth-protected-resource` | 不要 | 認可サーバーの場所を示すメタデータ(RFC 9728) |
|
|
385
|
-
| `/health` | 不要 | ヘルスチェック |
|
|
386
|
-
|
|
387
|
-
```
|
|
388
|
-
Claude(Web / Desktop / モバイル)・Claude Code・Anthropic API
|
|
389
|
-
│ Authorization: Bearer <WorkOS AuthKit が発行したアクセストークン>
|
|
390
|
-
▼
|
|
391
|
-
Cloud Run(--allow-unauthenticated)
|
|
392
|
-
│ /mcp で JWT を検証し、ALLOWED_SUBJECTS で利用者を限定
|
|
393
|
-
▼
|
|
394
|
-
MCP ハンドラ
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
Claude の各アプリと Claude Code は、トークンなしのリクエストに返る 401 応答(`WWW-Authenticate` ヘッダー)から
|
|
398
|
-
メタデータをたどって認可サーバーを見つけ、ブラウザでのログインを経てトークンを取得します。
|
|
399
|
-
Anthropic API から使う場合は、呼び出し側でトークンを用意して渡します。
|
|
400
|
-
|
|
401
|
-
### 前提条件
|
|
402
|
-
|
|
403
|
-
- Google Cloud プロジェクト(課金が有効なもの)
|
|
404
|
-
- [gcloud CLI](https://cloud.google.com/sdk/docs/install) インストール済み・ログイン済み
|
|
405
|
-
- [WorkOS](https://workos.com/) アカウント(AuthKit を OAuth 認可サーバーとして使用)
|
|
406
|
-
|
|
407
|
-
### ステップ 1 — プロジェクトと API の準備
|
|
408
|
-
|
|
409
|
-
```bash
|
|
410
|
-
# デプロイ先プロジェクトをセット
|
|
411
|
-
gcloud config set project MY_PROJECT_ID
|
|
412
|
-
|
|
413
|
-
# 必要な API を有効化(初回のみ)
|
|
414
|
-
gcloud services enable \
|
|
415
|
-
run.googleapis.com \
|
|
416
|
-
artifactregistry.googleapis.com \
|
|
417
|
-
cloudbuild.googleapis.com \
|
|
418
|
-
secretmanager.googleapis.com # NCBI_API_KEY を管理する場合のみ
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
### ステップ 2 — Artifact Registry リポジトリを作成(初回のみ)
|
|
422
|
-
|
|
423
|
-
```bash
|
|
424
|
-
gcloud artifacts repositories create pubmed-mcp \
|
|
425
|
-
--repository-format=docker \
|
|
426
|
-
--location=asia-northeast1 \
|
|
427
|
-
--description="PubMed MCP Server"
|
|
428
|
-
```
|
|
429
|
-
|
|
430
|
-
### ステップ 3 — シークレットを Secret Manager に登録
|
|
431
|
-
|
|
432
|
-
NCBI API キーをコマンド履歴やログに残さないために Secret Manager を使います。
|
|
433
|
-
|
|
434
|
-
```bash
|
|
435
|
-
# NCBI API キーを登録
|
|
436
|
-
echo -n "your_ncbi_api_key" | \
|
|
437
|
-
gcloud secrets create ncbi-api-key \
|
|
438
|
-
--data-file=- \
|
|
439
|
-
--replication-policy=automatic
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
### ステップ 4 — コンテナイメージをビルドしてプッシュ
|
|
443
|
-
|
|
444
|
-
Cloud Build を使うとローカルに Docker をインストールせずにビルドできます。
|
|
445
|
-
`gcloud builds submit` はカレントディレクトリのファイルを Cloud Build に送信するため、
|
|
446
|
-
**事前にリポジトリをクローンしておく必要があります。**
|
|
447
|
-
|
|
448
|
-
```bash
|
|
449
|
-
# リポジトリをクローンしてディレクトリに移動
|
|
450
|
-
git clone https://github.com/DJMIMA/PubMed_MCP.git
|
|
451
|
-
cd PubMed_MCP
|
|
452
|
-
|
|
453
|
-
# Cloud Build でビルド(ローカルに Docker 不要)
|
|
454
|
-
gcloud builds submit \
|
|
455
|
-
--region=asia-northeast1 \
|
|
456
|
-
--tag asia-northeast1-docker.pkg.dev/MY_PROJECT_ID/pubmed-mcp/server:latest
|
|
457
|
-
```
|
|
458
|
-
|
|
459
|
-
ローカルの Docker でビルドする場合:
|
|
460
|
-
|
|
461
|
-
```bash
|
|
462
|
-
gcloud auth configure-docker asia-northeast1-docker.pkg.dev
|
|
463
|
-
|
|
464
|
-
docker build -t asia-northeast1-docker.pkg.dev/MY_PROJECT_ID/pubmed-mcp/server:latest .
|
|
465
|
-
docker push asia-northeast1-docker.pkg.dev/MY_PROJECT_ID/pubmed-mcp/server:latest
|
|
466
|
-
```
|
|
467
|
-
|
|
468
|
-
### ステップ 5 — OAuth 認可サーバー(WorkOS AuthKit)を設定
|
|
469
|
-
|
|
470
|
-
まず MCP エンドポイントの公開 URL を決めます。Cloud Run のサービスには
|
|
471
|
-
`https://サービス名-プロジェクト番号.リージョン.run.app` 形式の URL が割り当てられるため、デプロイ前に確定できます。
|
|
472
|
-
|
|
473
|
-
```bash
|
|
474
|
-
PROJECT_NUMBER=$(gcloud projects describe MY_PROJECT_ID --format='value(projectNumber)')
|
|
475
|
-
MCP_RESOURCE_URL="https://pubmed-mcp-${PROJECT_NUMBER}.asia-northeast1.run.app/mcp"
|
|
476
|
-
echo "$MCP_RESOURCE_URL"
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
この URL が `MCP_RESOURCE_URL` です。WorkOS の Resource Indicator や各クライアントに登録する URL とは**完全に同じ文字列**にしてください
|
|
480
|
-
(クライアントは接続先の URL とメタデータの `resource` が一致するかを確認し、サーバーはトークンの `aud` をこの値と照合します)。
|
|
481
|
-
Cloud Run には `https://pubmed-mcp-xxxx-an.a.run.app` 形式の URL も割り当てられ、どちらでもアクセスできますが、OAuth で使う URL はどちらか一方に統一します。
|
|
482
|
-
|
|
483
|
-
次に WorkOS ダッシュボードで AuthKit を設定します。
|
|
484
|
-
|
|
485
|
-
1. **Connect → Configuration** で **Dynamic Client Registration** を有効にする(claude.ai などの MCP クライアントが、自分自身を OAuth クライアントとして登録できるようにするため)
|
|
486
|
-
2. `MCP_RESOURCE_URL` を **Resource Indicator** として登録する(アクセストークンの `aud` がこの URL になる)
|
|
487
|
-
3. AuthKit ドメインの認可サーバーメタデータを開き、`issuer` と `jwks_uri` の値を控える
|
|
488
|
-
|
|
489
|
-
```bash
|
|
490
|
-
curl https://YOUR_AUTHKIT_DOMAIN/.well-known/oauth-authorization-server
|
|
491
|
-
# → {"issuer":"https://YOUR_AUTHKIT_DOMAIN", ..., "jwks_uri":"https://YOUR_AUTHKIT_DOMAIN/oauth2/jwks", ...}
|
|
492
|
-
```
|
|
493
|
-
|
|
494
|
-
WorkOS の Staging 環境と Production 環境は、設定も AuthKit ドメインも別々です。環境を切り替えるときは上の設定をやり直し、
|
|
495
|
-
`OAUTH_ISSUER`・`OAUTH_JWKS_URL` も差し替えてください。
|
|
496
|
-
|
|
497
|
-
### ステップ 6 — Cloud Run にデプロイ
|
|
498
|
-
|
|
499
|
-
ステップ 5 で控えた値を使ってデプロイします。`ALLOWED_SUBJECTS` には最初は仮の値(ここでは `placeholder`)を入れておきます(理由はステップ 8 を参照)。
|
|
500
|
-
|
|
501
|
-
```bash
|
|
502
|
-
# ステップ 5 で控えた issuer と jwks_uri の値に置き換える
|
|
503
|
-
OAUTH_ISSUER="https://YOUR_AUTHKIT_DOMAIN"
|
|
504
|
-
OAUTH_JWKS_URL="https://YOUR_AUTHKIT_DOMAIN/oauth2/jwks"
|
|
505
|
-
|
|
506
|
-
gcloud run deploy pubmed-mcp \
|
|
507
|
-
--image asia-northeast1-docker.pkg.dev/MY_PROJECT_ID/pubmed-mcp/server:latest \
|
|
508
|
-
--region asia-northeast1 \
|
|
509
|
-
--port 8080 \
|
|
510
|
-
--memory 512Mi \
|
|
511
|
-
--cpu 1 \
|
|
512
|
-
--timeout 300 \
|
|
513
|
-
--allow-unauthenticated \
|
|
514
|
-
--set-secrets NCBI_API_KEY=ncbi-api-key:latest \
|
|
515
|
-
--set-env-vars "OAUTH_ISSUER=${OAUTH_ISSUER},OAUTH_JWKS_URL=${OAUTH_JWKS_URL},MCP_RESOURCE_URL=${MCP_RESOURCE_URL},ALLOWED_SUBJECTS=placeholder"
|
|
516
|
-
```
|
|
517
|
-
|
|
518
|
-
| 変数 | 設定する値 |
|
|
519
|
-
|------|-----------|
|
|
520
|
-
| `OAUTH_ISSUER` | 認可サーバーメタデータの `issuer`。トークンの `iss` と完全一致で照合されるので、末尾の `/` の有無も含めてそのままコピーする |
|
|
521
|
-
| `OAUTH_JWKS_URL` | 同じメタデータの `jwks_uri`。トークンの署名検証に使う公開鍵の URL |
|
|
522
|
-
| `MCP_RESOURCE_URL` | ステップ 5 で決めた MCP エンドポイントの URL。トークンの `aud` と照合し、`/.well-known/oauth-protected-resource` の `resource` としても公開される |
|
|
523
|
-
| `ALLOWED_SUBJECTS` | 接続を許可するユーザー ID(トークンの `sub`)のカンマ区切りリスト。空にすると、AuthKit で有効なトークンを取得できるユーザー全員が接続できる |
|
|
524
|
-
|
|
525
|
-
`OAUTH_ISSUER`・`OAUTH_JWKS_URL`・`MCP_RESOURCE_URL` のどれかが欠けていると、サーバーは起動時に
|
|
526
|
-
`Missing required environment variable: ...` で終了し、デプロイは失敗します。失敗した場合は Cloud Run のログでこのメッセージを確認してください
|
|
527
|
-
(Cloud Console で設定した場合は、変数名の前後に空白が入っていないかも確認してください)。
|
|
528
|
-
|
|
529
|
-
> **`--set-env-vars` と `--update-env-vars` の違い**: `--set-env-vars` は既存の環境変数をすべて削除してから、指定した値を設定します(指定しなかった変数は消えます)。
|
|
530
|
-
> デプロイ後に一部の値だけを追加・変更するときは、既存の値とマージされる `--update-env-vars` を使ってください(`gcloud run services update` でも使えます)。
|
|
531
|
-
|
|
532
|
-
### ステップ 7 — 動作確認
|
|
533
|
-
|
|
534
|
-
`/health` と `/.well-known/oauth-protected-resource` は認証なしで応答します。`/mcp` はトークンなしでは **401 が返れば正常** です。
|
|
535
|
-
|
|
536
|
-
**Linux / macOS (bash)**
|
|
537
|
-
|
|
538
|
-
```bash
|
|
539
|
-
PROJECT_NUMBER=$(gcloud projects describe MY_PROJECT_ID --format='value(projectNumber)')
|
|
540
|
-
CLOUD_RUN_URL="https://pubmed-mcp-${PROJECT_NUMBER}.asia-northeast1.run.app"
|
|
541
|
-
|
|
542
|
-
# ヘルスチェック
|
|
543
|
-
curl "$CLOUD_RUN_URL/health"
|
|
544
|
-
# → ok
|
|
545
|
-
|
|
546
|
-
# Protected Resource Metadata(resource が MCP_RESOURCE_URL、authorization_servers が OAUTH_ISSUER になっていることを確認)
|
|
547
|
-
curl "$CLOUD_RUN_URL/.well-known/oauth-protected-resource"
|
|
548
|
-
# → {"resource":"https://pubmed-mcp-PROJECT_NUMBER.asia-northeast1.run.app/mcp","authorization_servers":["https://YOUR_AUTHKIT_DOMAIN"],"bearer_methods_supported":["header"]}
|
|
549
|
-
|
|
550
|
-
# MCP エンドポイント(トークンなしなので 401。-i でヘッダーも表示。ヒアドキュメントでクォート問題を回避)
|
|
551
|
-
curl -i "$CLOUD_RUN_URL/mcp" \
|
|
552
|
-
-X POST \
|
|
553
|
-
-H "Content-Type: application/json" \
|
|
554
|
-
-d @- <<'EOF'
|
|
555
|
-
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"0.0.1"}}}
|
|
556
|
-
EOF
|
|
557
|
-
```
|
|
558
|
-
|
|
559
|
-
`/mcp` の応答は次のようになります(抜粋。HTTP のバージョンやヘッダー名の大文字・小文字は環境によって異なります)。
|
|
560
|
-
|
|
561
|
-
```
|
|
562
|
-
HTTP/2 401
|
|
563
|
-
www-authenticate: Bearer resource_metadata="https://pubmed-mcp-PROJECT_NUMBER.asia-northeast1.run.app/.well-known/oauth-protected-resource", error="missing_token"
|
|
564
|
-
content-type: application/json; charset=utf-8
|
|
565
|
-
|
|
566
|
-
{"error":"missing_token"}
|
|
567
|
-
```
|
|
568
|
-
|
|
569
|
-
MCP クライアントは `WWW-Authenticate` ヘッダーの `resource_metadata` をたどって認可サーバーを見つけます。
|
|
570
|
-
トークンの検証に失敗した場合は `error="invalid_token"` の 401、トークンは有効でも `sub` が `ALLOWED_SUBJECTS` にない場合は 403(`{"error":"forbidden"}`)が返ります。
|
|
571
|
-
|
|
572
|
-
**Windows(コマンドプロンプト)**
|
|
573
|
-
|
|
574
|
-
```cmd
|
|
575
|
-
:: %CLOUD_RUN_URL% に URL を設定してから実行(PROJECT_NUMBER は自分のプロジェクト番号に置き換える)
|
|
576
|
-
set CLOUD_RUN_URL=https://pubmed-mcp-PROJECT_NUMBER.asia-northeast1.run.app
|
|
577
|
-
|
|
578
|
-
curl "%CLOUD_RUN_URL%/health"
|
|
579
|
-
|
|
580
|
-
curl "%CLOUD_RUN_URL%/.well-known/oauth-protected-resource"
|
|
581
|
-
|
|
582
|
-
curl -i "%CLOUD_RUN_URL%/mcp" -X POST -H "Content-Type: application/json" -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-03-26\",\"capabilities\":{},\"clientInfo\":{\"name\":\"test\",\"version\":\"0.0.1\"}}}"
|
|
583
|
-
```
|
|
584
|
-
|
|
585
|
-
**Windows(PowerShell)**
|
|
586
|
-
|
|
587
|
-
```powershell
|
|
588
|
-
$CLOUD_RUN_URL = "https://pubmed-mcp-PROJECT_NUMBER.asia-northeast1.run.app"
|
|
589
|
-
|
|
590
|
-
curl.exe "$CLOUD_RUN_URL/health"
|
|
591
|
-
|
|
592
|
-
curl.exe "$CLOUD_RUN_URL/.well-known/oauth-protected-resource"
|
|
593
|
-
|
|
594
|
-
curl.exe -i "$CLOUD_RUN_URL/mcp" -X POST -H "Content-Type: application/json" `
|
|
595
|
-
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"0.0.1"}}}'
|
|
596
|
-
```
|
|
597
|
-
|
|
598
|
-
### ステップ 8 — 自分のユーザー ID を ALLOWED_SUBJECTS に登録
|
|
599
|
-
|
|
600
|
-
Dynamic Client Registration では誰でも OAuth クライアントを登録できるため、`ALLOWED_SUBJECTS` で接続できるユーザーを限定します
|
|
601
|
-
(空のままだと AuthKit にログインできるユーザー全員が `/mcp` を使えます。AuthKit でサインアップを許可している場合は第三者も含まれます)。
|
|
602
|
-
設定する値はアクセストークンの `sub`(WorkOS のユーザー ID。`user_` で始まる値)です。
|
|
603
|
-
|
|
604
|
-
`ALLOWED_SUBJECTS` が空のときは `sub` がログに記録されません。そのため、仮の値を入れた状態で一度接続し、拒否されたときのログから確認します。
|
|
605
|
-
|
|
606
|
-
1. 後述の「[クライアント別の接続設定](#クライアント別の接続設定)」の手順で claude.ai などから接続し、WorkOS AuthKit でログインします。
|
|
607
|
-
`sub` が `ALLOWED_SUBJECTS` に含まれていないため接続は 403 で失敗し、サーバーのログに `[auth] forbidden subject: ...` が記録されます。
|
|
608
|
-
2. ログから自分の `sub` を確認します(WorkOS ダッシュボードの **Users** で確認できるユーザー ID と同じ値です)。
|
|
609
|
-
|
|
610
|
-
```bash
|
|
611
|
-
gcloud run services logs read pubmed-mcp \
|
|
612
|
-
--region asia-northeast1 \
|
|
613
|
-
--log-filter='textPayload:"forbidden subject"' \
|
|
614
|
-
--limit 5
|
|
615
|
-
# → ... [auth] forbidden subject: user_01XXXXXXXXXXXXXXXXXXXXXXXX
|
|
616
|
-
```
|
|
617
|
-
|
|
618
|
-
3. その値を設定します。`--update-env-vars` なので、ほかの環境変数はそのまま残ります。
|
|
619
|
-
|
|
620
|
-
```bash
|
|
621
|
-
gcloud run services update pubmed-mcp \
|
|
622
|
-
--region asia-northeast1 \
|
|
623
|
-
--update-env-vars ALLOWED_SUBJECTS=user_01XXXXXXXXXXXXXXXXXXXXXXXX
|
|
624
|
-
```
|
|
625
|
-
|
|
626
|
-
複数のユーザーを許可する場合は、値にカンマが含まれるため `^@^` で区切り文字を変えて指定します
|
|
627
|
-
(例: `--update-env-vars '^@^ALLOWED_SUBJECTS=user_01AAAA,user_01BBBB'`。Windows の cmd / PowerShell では `^` を `^^^^` と書きます。詳しくは `gcloud topic escaping` を参照)。
|
|
628
|
-
4. クライアントから接続し直します。
|
|
629
|
-
|
|
630
|
-
---
|
|
631
|
-
|
|
632
|
-
### クライアント別の接続設定
|
|
633
|
-
|
|
634
|
-
デプロイ後、各クライアントに MCP エンドポイントの URL を登録します。URL は `MCP_RESOURCE_URL` と**完全に同じ文字列**
|
|
635
|
-
(例: `https://pubmed-mcp-PROJECT_NUMBER.asia-northeast1.run.app/mcp`)にしてください。
|
|
636
|
-
初回接続時に WorkOS AuthKit のログイン画面が開きます。ログインしたアカウントの `sub` が `ALLOWED_SUBJECTS` に含まれていれば接続できます
|
|
637
|
-
(自分の `sub` を登録する手順はステップ 8 を参照)。
|
|
638
|
-
|
|
639
|
-
**Claude(Web 版・Claude Desktop)— カスタムコネクタ**
|
|
640
|
-
|
|
641
|
-
リモートサーバーは「カスタムコネクタ」として追加します([Claude ヘルプセンター](https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp))。
|
|
642
|
-
カスタムコネクタは Free プランでも 1 つまで利用できます。
|
|
643
|
-
|
|
644
|
-
- Pro / Max プラン
|
|
645
|
-
1. [claude.ai](https://claude.ai) または Claude Desktop で **Customize > Connectors** を開く
|
|
646
|
-
2. **+** → **Add custom connector** をクリック
|
|
647
|
-
3. URL(`MCP_RESOURCE_URL`)を入力して **Add** をクリック
|
|
648
|
-
4. 追加したコネクタの **Connect** から認証する(WorkOS AuthKit のログイン画面が開く)
|
|
649
|
-
- Team / Enterprise プラン
|
|
650
|
-
1. オーナーが **Organization settings > Connectors** を開き、**Add** → **Custom** にカーソルを合わせて **Web** を選ぶ
|
|
651
|
-
2. URL(`MCP_RESOURCE_URL`)を入力して **Add** をクリック
|
|
652
|
-
3. 各メンバーが **Customize > Connectors** でこのコネクタを探し、**Connect** から認証する
|
|
653
|
-
|
|
654
|
-
**Advanced settings** の OAuth Client ID / OAuth Client Secret は空欄のままで構いません(Dynamic Client Registration でクライアントが自動登録されます)。
|
|
655
|
-
チャットで使うときは、入力欄左下の **+** → **Connectors** から会話ごとに有効にします。
|
|
656
|
-
|
|
657
|
-
Claude Desktop の `claude_desktop_config.json` はローカル(stdio)サーバー用の設定で、`"type"` や `"url"` を書いてもリモートサーバーには接続されません。
|
|
658
|
-
Desktop でもリモートサーバーは上記のカスタムコネクタとして追加してください(Web 版で追加したコネクタは Desktop でもそのまま使えます)。
|
|
659
|
-
|
|
660
|
-
**Claude モバイルアプリ(Android / iOS)**
|
|
661
|
-
|
|
662
|
-
Web 版または Claude Desktop で追加したカスタムコネクタは、同じアカウントのモバイルアプリでもそのまま使えます。
|
|
663
|
-
モバイルアプリからのコネクタ追加はベータ機能のため、追加は Web 版か Desktop で行ってください。
|
|
664
|
-
|
|
665
|
-
**Claude Code**
|
|
666
|
-
|
|
667
|
-
```bash
|
|
668
|
-
claude mcp add --transport http --scope user pubmed-remote https://pubmed-mcp-PROJECT_NUMBER.asia-northeast1.run.app/mcp
|
|
669
|
-
```
|
|
670
|
-
|
|
671
|
-
Claude Code は `~/.claude/settings.json` の `mcpServers` を読み込まないため、`claude mcp add` で登録します。
|
|
672
|
-
登録後、Claude Code で `/mcp` を開いて `pubmed-remote` を選び、ブラウザで WorkOS AuthKit にログインして認証します。
|
|
673
|
-
|
|
674
|
-
**Anthropic API(Python)**
|
|
675
|
-
|
|
676
|
-
```python
|
|
677
|
-
import os
|
|
678
|
-
|
|
679
|
-
import anthropic
|
|
680
|
-
|
|
681
|
-
client = anthropic.Anthropic()
|
|
682
|
-
response = client.beta.messages.create(
|
|
683
|
-
model="claude-opus-5",
|
|
684
|
-
max_tokens=16000,
|
|
685
|
-
messages=[{"role": "user", "content": "..."}],
|
|
686
|
-
mcp_servers=[{
|
|
687
|
-
"type": "url",
|
|
688
|
-
"url": "https://pubmed-mcp-PROJECT_NUMBER.asia-northeast1.run.app/mcp",
|
|
689
|
-
"name": "pubmed",
|
|
690
|
-
"authorization_token": os.environ["PUBMED_MCP_TOKEN"],
|
|
691
|
-
}],
|
|
692
|
-
tools=[{"type": "mcp_toolset", "mcp_server_name": "pubmed"}],
|
|
693
|
-
betas=["mcp-client-2025-11-20"]
|
|
694
|
-
)
|
|
695
|
-
```
|
|
696
|
-
|
|
697
|
-
MCP コネクタは OAuth のログインもトークンの更新も行いません。WorkOS AuthKit がこのサーバー向けに発行したアクセストークン
|
|
698
|
-
(`aud` が `MCP_RESOURCE_URL` で、`sub` が `ALLOWED_SUBJECTS` に含まれるもの)を呼び出し側で取得して `authorization_token` に渡し、
|
|
699
|
-
有効期限が切れたら取得し直してください。
|
|
700
|
-
|
|
701
|
-
テスト用のトークンは MCP Inspector で取得できます([MCP connector ドキュメント](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector#authentication))。
|
|
702
|
-
|
|
703
|
-
1. `npx @modelcontextprotocol/inspector` を実行
|
|
704
|
-
2. **Transport type** で **Streamable HTTP** を選び、URL に `MCP_RESOURCE_URL` を入力
|
|
705
|
-
3. **Open Auth Settings** → **Quick OAuth Flow** をクリックし、WorkOS AuthKit でログイン
|
|
706
|
-
4. **Authentication complete** まで進めたら、表示された `access_token` の値をコピー
|
|
707
|
-
|
|
708
|
-
---
|
|
709
|
-
|
|
710
|
-
### イメージを更新する(再デプロイ)
|
|
711
|
-
|
|
712
|
-
```bash
|
|
713
|
-
cd PubMed_MCP
|
|
714
|
-
git pull
|
|
715
|
-
|
|
716
|
-
gcloud builds submit \
|
|
717
|
-
--region=asia-northeast1 \
|
|
718
|
-
--tag asia-northeast1-docker.pkg.dev/MY_PROJECT_ID/pubmed-mcp/server:latest
|
|
719
|
-
|
|
720
|
-
gcloud run services update pubmed-mcp \
|
|
721
|
-
--region asia-northeast1 \
|
|
722
|
-
--image asia-northeast1-docker.pkg.dev/MY_PROJECT_ID/pubmed-mcp/server:latest
|
|
723
|
-
```
|
|
724
|
-
|
|
725
|
-
`--image` だけを指定した更新では、環境変数とシークレットの設定はそのまま引き継がれます。
|
|
726
|
-
|
|
727
|
-
---
|
|
728
|
-
|
|
729
|
-
## 開発コマンド
|
|
730
|
-
|
|
731
|
-
```bash
|
|
732
|
-
npm run build # TypeScript をコンパイル → dist/
|
|
733
|
-
npm run dev # tsx で直接実行(開発用)
|
|
734
|
-
npm run cli -- search "CRISPR" --max-results 5 # CLI を tsx で直接実行(開発用)
|
|
735
|
-
npm test # テストスイートを実行
|
|
736
|
-
npm run typecheck # 型チェックのみ(コンパイルなし)
|
|
737
|
-
npm run lint # ESLint を実行
|
|
738
|
-
```
|
|
739
|
-
|
|
740
|
-
### npm へのリリース(メンテナー向け)
|
|
741
|
-
|
|
742
|
-
GitHub で Release を公開すると、[`.github/workflows/release.yml`](.github/workflows/release.yml) が npm
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
-
|
|
792
|
-
-
|
|
793
|
-
-
|
|
1
|
+
# PubMed MCP Server
|
|
2
|
+
|
|
3
|
+
An [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server that gives Claude and other LLM clients structured access to [PubMed](https://pubmed.ncbi.nlm.nih.gov/) and [PubMed Central (PMC)](https://www.ncbi.nlm.nih.gov/pmc/) via the NCBI E-utilities API.
|
|
4
|
+
|
|
5
|
+
## Tools
|
|
6
|
+
|
|
7
|
+
| Tool | 説明 |
|
|
8
|
+
|------|------|
|
|
9
|
+
| `search_articles` | PubMed構文またはキーワードで文献を検索。ATM診断・フィールド制限・日付フィルタ・ソート・ページネーション対応 |
|
|
10
|
+
| `get_article_metadata` | PMIDを指定してタイトル・抄録・著者・MeSH語・キーワードなどを取得 |
|
|
11
|
+
| `find_related_articles` | ELinkを使って関連文献や他DBへのリンクを検索 |
|
|
12
|
+
| `lookup_article_by_citation` | 雑誌名・年・巻・筆頭著者などの引用情報からPMIDを逆引き |
|
|
13
|
+
| `convert_article_ids` | PMID・PMCID・DOI を相互変換 |
|
|
14
|
+
| `get_full_text_article` | PMC Open Access記事の本文全文をプレーンテキストで取得 |
|
|
15
|
+
| `get_copyright_status` | 全文取得の可否(`has_full_text`)・ライセンス・著作権表示・OAステータスを確認。PMCのEFetchメタデータを使用(旧PMC OA Web Serviceは2026-08-25に廃止) |
|
|
16
|
+
|
|
17
|
+
同じツールは、シェルから `pubmed` コマンドとしても実行できます(「[CLI](#cli)」を参照)。
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## `search_articles` の ATM 診断とフィールド制限
|
|
22
|
+
|
|
23
|
+
PubMed はタグのない検索語に Automatic Term Mapping(ATM)を適用します。ATM は MeSH、
|
|
24
|
+
雑誌名、著者名などへ検索語を展開するため、意図しない変換や、引用句が句インデックスに
|
|
25
|
+
存在しないことによる検索のフォールバックが起こる場合があります。
|
|
26
|
+
|
|
27
|
+
`search_articles` は次の任意の `field` 値を受け取り、クエリ内のタグなし語をすべてその
|
|
28
|
+
フィールドへ制限します。
|
|
29
|
+
|
|
30
|
+
- `title`
|
|
31
|
+
- `tiab`(Title/Abstract)
|
|
32
|
+
- `mesh`
|
|
33
|
+
- `author`
|
|
34
|
+
- `journal`
|
|
35
|
+
- `affiliation`
|
|
36
|
+
|
|
37
|
+
クエリ内に明示的なフィールドタグがある語では、そのタグが `field` より優先されます。
|
|
38
|
+
`field` を省略した場合の検索動作は従来どおりです。`all` は ATM を無効化しないため、
|
|
39
|
+
公開パラメータには含めていません。
|
|
40
|
+
|
|
41
|
+
レスポンスには、NCBI ESearch の診断を正規化した次のフィールドが常に含まれます。
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"warnings": {
|
|
46
|
+
"phrases_ignored": [],
|
|
47
|
+
"quoted_phrases_not_found": [],
|
|
48
|
+
"output_messages": []
|
|
49
|
+
},
|
|
50
|
+
"errors": {
|
|
51
|
+
"phrases_not_found": [],
|
|
52
|
+
"fields_not_found": []
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
この `errors` は NCBI ESearch が返す検索語・フィールドの診断であり、通信エラーや
|
|
58
|
+
MCP ツール自体の実行エラーとは別の情報です。
|
|
59
|
+
これらのキーは診断がない場合も空配列として返ります。低件数や0件を「文献なし」と判断する
|
|
60
|
+
前に、`query_translation`、`warnings`、`errors` を確認してください。複数語を同一フィールドで
|
|
61
|
+
確実に検索する場合は各語へタグを付け、引用句が句インデックスにない場合の隣接検索には
|
|
62
|
+
`[ti:~0]` または `[tiab:~0]` を使用できます。
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 必要環境
|
|
67
|
+
|
|
68
|
+
- **Node.js** 22 以上(`npx` と `npm` は Node.js に同梱されています)
|
|
69
|
+
- **NCBI API キー**(任意。なくても動作するが、レートリミットが 3 req/s に制限される)
|
|
70
|
+
- **jq**(任意。[CLI](#cli) の出力から必要なフィールドを取り出すのに使う)
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## インストール
|
|
75
|
+
|
|
76
|
+
npm パッケージ [`@djmima/pubmed-mcp`](https://www.npmjs.com/package/@djmima/pubmed-mcp) として公開しています。
|
|
77
|
+
|
|
78
|
+
- **MCP サーバーとして使う場合**は、インストールは不要です。MCP クライアントの設定に `npx -y @djmima/pubmed-mcp@latest` を書くと、
|
|
79
|
+
起動時に最新版が自動でダウンロードされます(後述の「[使い方](#使い方)」を参照)。
|
|
80
|
+
- **[CLI](#cli) を使う場合**は、グローバルにインストールします。
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm install -g @djmima/pubmed-mcp
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`pubmed` と `pubmed-mcp` の 2 つのコマンドが登録されます。更新は `npm update -g @djmima/pubmed-mcp`、
|
|
87
|
+
削除は `npm rm -g @djmima/pubmed-mcp` です。
|
|
88
|
+
|
|
89
|
+
ソースコードを修正して使いたい場合は「[ソースからビルドする](#ソースからビルドする)」を参照してください。
|
|
90
|
+
|
|
91
|
+
### NCBI API キーの設定(推奨)
|
|
92
|
+
|
|
93
|
+
APIキーを取得するとレートリミットが 3 → 8 req/s に向上します。
|
|
94
|
+
|
|
95
|
+
1. [NCBI アカウント](https://www.ncbi.nlm.nih.gov/account/)を作成してAPIキーを発行
|
|
96
|
+
2. 環境変数 `NCBI_API_KEY` にセット(後述のクライアント別設定を参照)
|
|
97
|
+
|
|
98
|
+
MCP クライアントからローカルで起動する場合は、クライアント設定の `env` でキーを渡してください。
|
|
99
|
+
`.env` は起動時のカレントディレクトリから読み込まれるため、クライアント経由の起動では
|
|
100
|
+
プロジェクト直下の `.env` が読まれないことがあります。
|
|
101
|
+
|
|
102
|
+
APIキーは、このサーバーを運用する個人または組織が所有・管理するものを設定してください。
|
|
103
|
+
リポジトリにはAPIキーを同梱しません。レスポンス中にNCBI APIの `echo` が含まれる場合も、
|
|
104
|
+
`api_key` 値は `<redacted>` にマスクされます。
|
|
105
|
+
|
|
106
|
+
クライアント側ではプロセスごとに簡易レートリミッターをかけています。APIキーなしでは最大
|
|
107
|
+
3 req/s、APIキーありではNCBI上限の10 req/sに対して余裕を持たせた8 req/sで送信します(NCBIは到着時刻で数えるため、回線の揺らぎ分の余裕)。HTTP 429 が返った場合は最大2回まで待機して再試行します。
|
|
108
|
+
同一プロセス内の並列呼び出しは自動的に間隔調整されますが、Cloud Runなどで複数インスタンスを
|
|
109
|
+
動かす場合は全インスタンス合算でNCBIの上限を超えないようにしてください。目安として、単一
|
|
110
|
+
インスタンスではAPIキーありで8並列程度、APIキーなしで2並列程度までに抑える運用を推奨します。
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## 使い方
|
|
115
|
+
|
|
116
|
+
### Claude Desktop(ローカル・stdio)
|
|
117
|
+
|
|
118
|
+
`claude_desktop_config.json` の `mcpServers` にサーバーを追加します。
|
|
119
|
+
|
|
120
|
+
**macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
121
|
+
**Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"mcpServers": {
|
|
126
|
+
"pubmed-local": {
|
|
127
|
+
"command": "npx",
|
|
128
|
+
"args": ["-y", "@djmima/pubmed-mcp@latest"],
|
|
129
|
+
"env": {
|
|
130
|
+
"NCBI_API_KEY": "your_api_key_here"
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- 他のサーバーが登録済みの場合は、`mcpServers` の中に `"pubmed-local": { ... }` を並べて追加します(前の項目との間のカンマを忘れずに)。
|
|
138
|
+
- Windows で起動しない場合は、`"command": "cmd"`、`"args": ["/c", "npx", "-y", "@djmima/pubmed-mcp@latest"]` に変えてください。
|
|
139
|
+
- `@latest` を付けると、起動のたびに npm に最新版があるか確認します。版を固定したい場合は `@djmima/pubmed-mcp@1.0.0` のように書きます。
|
|
140
|
+
- サーバー名を `pubmed-local` にしておくと、リモート版(`pubmed-remote`)や同じツール名を持つ他の PubMed コネクタと区別しやすくなります。
|
|
141
|
+
|
|
142
|
+
設定後、Claude Desktop を完全に終了してから再起動してください。ウィンドウを閉じただけではアプリが常駐したままになることがあります(Windows ではタスクトレイのアイコンから終了できます)。
|
|
143
|
+
この設定のサーバーは、Claude Desktop の Code タブで開いたセッションにも読み込まれます。
|
|
144
|
+
|
|
145
|
+
起動しない場合は、ログ(Windows: `%APPDATA%\Claude\logs\mcp-server-pubmed-local.log`、macOS: `~/Library/Logs/Claude/mcp-server-pubmed-local.log`)を確認してください。
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### Claude Code(ローカル・stdio)
|
|
150
|
+
|
|
151
|
+
`claude mcp add` で登録します。`--scope user` を付けるとすべてのプロジェクトで使えます。
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
claude mcp add --env NCBI_API_KEY=your_api_key_here --transport stdio --scope user pubmed-local -- npx -y @djmima/pubmed-mcp@latest
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
- `--` より後ろは、サーバーの起動コマンドとしてそのまま渡されます。
|
|
158
|
+
- Windows(WSL ではない環境)では、`--` の後ろを `cmd /c npx -y @djmima/pubmed-mcp@latest` にしてください。
|
|
159
|
+
- `--env` の直後にサーバー名を書くと `KEY=value` の続きとして解釈されてエラーになるため、間に別のオプション(ここでは `--transport stdio`)を挟みます。
|
|
160
|
+
- 登録内容は `~/.claude.json`(user / local スコープ)またはプロジェクト直下の `.mcp.json`(project スコープ)に保存されます。`~/.claude/settings.json` に `mcpServers` を書いても読み込まれません。
|
|
161
|
+
- Claude Desktop の Code タブだけで使う場合は、上記の `claude_desktop_config.json` への登録で読み込まれるため、この手順は不要です。
|
|
162
|
+
|
|
163
|
+
登録後、`claude mcp list` または Claude Code 内の `/mcp` で接続状態を確認できます。
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
### Codex(ローカル・stdio)
|
|
168
|
+
|
|
169
|
+
Codex のデスクトップアプリ・CLI・IDE 拡張は、同じ設定ファイル `~/.codex/config.toml`(Windows: `%USERPROFILE%\.codex\config.toml`)を共有します。次のブロックを追記してください。
|
|
170
|
+
|
|
171
|
+
```toml
|
|
172
|
+
[mcp_servers.pubmed-local]
|
|
173
|
+
command = "npx"
|
|
174
|
+
args = ["-y", "@djmima/pubmed-mcp@latest"]
|
|
175
|
+
|
|
176
|
+
[mcp_servers.pubmed-local.env]
|
|
177
|
+
NCBI_API_KEY = "your_api_key_here"
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
- Windows で起動しない場合は、`command = "cmd"`、`args = ["/c", "npx", "-y", "@djmima/pubmed-mcp@latest"]` に変えてください。
|
|
181
|
+
- Codex は OS の環境変数をそのまま MCP サーバーへ渡しません。API キーは上のように `env` に書くか、`[mcp_servers.pubmed-local]` に `env_vars = ["NCBI_API_KEY"]` を追加して Codex 側の環境変数から転送してください。
|
|
182
|
+
|
|
183
|
+
CLI からは `codex mcp add` でも登録できます。
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
codex mcp add pubmed-local --env NCBI_API_KEY=your_api_key_here -- npx -y @djmima/pubmed-mcp@latest
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
設定後は Codex を再起動してください(デスクトップアプリでは **Settings → MCP servers** の **Restart**)。同じ画面の **Add server** から登録することもできます。CLI と IDE 拡張では `/mcp` で接続中のサーバーを確認できます。
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
### Anthropic API(プログラムからの利用)
|
|
194
|
+
|
|
195
|
+
```python
|
|
196
|
+
import os
|
|
197
|
+
|
|
198
|
+
import anthropic
|
|
199
|
+
|
|
200
|
+
client = anthropic.Anthropic()
|
|
201
|
+
response = client.beta.messages.create(
|
|
202
|
+
model="claude-opus-5",
|
|
203
|
+
max_tokens=16000,
|
|
204
|
+
messages=[{
|
|
205
|
+
"role": "user",
|
|
206
|
+
"content": "Find recent papers on CRISPR gene editing in cancer treatment"
|
|
207
|
+
}],
|
|
208
|
+
mcp_servers=[{
|
|
209
|
+
"type": "url",
|
|
210
|
+
"url": "https://pubmed-mcp-PROJECT_NUMBER.asia-northeast1.run.app/mcp",
|
|
211
|
+
"name": "pubmed",
|
|
212
|
+
# /mcp は OAuth で保護されているため、アクセストークンが必要
|
|
213
|
+
"authorization_token": os.environ["PUBMED_MCP_TOKEN"],
|
|
214
|
+
}],
|
|
215
|
+
tools=[{"type": "mcp_toolset", "mcp_server_name": "pubmed"}],
|
|
216
|
+
betas=["mcp-client-2025-11-20"]
|
|
217
|
+
)
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Anthropic API の MCP コネクタは HTTP で公開されたリモートサーバーにしか接続できないため、先に Cloud Run へデプロイしておく必要があります。
|
|
221
|
+
デプロイ方法は後述の「[Google Cloud Run へのデプロイ](#google-cloud-run-へのデプロイ)」、アクセストークンの取得方法は「[クライアント別の接続設定](#クライアント別の接続設定)」を参照してください。
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
### ソースからビルドする
|
|
226
|
+
|
|
227
|
+
ソースコードを修正して使う場合は、リポジトリをクローンしてビルドします。
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
git clone https://github.com/DJMIMA/PubMed_MCP.git
|
|
231
|
+
cd PubMed_MCP
|
|
232
|
+
npm install
|
|
233
|
+
npm run build
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
MCP クライアントの設定では、`npx -y @djmima/pubmed-mcp@latest` の代わりに `node /absolute/path/to/PubMed_MCP/dist/index.js` を指定します
|
|
237
|
+
(Windows のパスは `C:/path/to/PubMed_MCP/dist/index.js` のようにスラッシュ区切りで書きます)。
|
|
238
|
+
CLI として使う場合は、続けて `npm link` を実行すると `pubmed` と `pubmed-mcp` コマンドが登録されます(解除は `npm rm -g @djmima/pubmed-mcp`)。
|
|
239
|
+
|
|
240
|
+
`dist/` はリポジトリに含まれません。`git pull` でソースを更新したら `npm run build` を再実行し、
|
|
241
|
+
MCP クライアントを再起動してください。起動中のサーバーは再起動するまで古いビルドのまま動きます。
|
|
242
|
+
|
|
243
|
+
### ローカル開発
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
# .env ファイルを作成してAPIキーを設定
|
|
247
|
+
cp .env.example .env
|
|
248
|
+
# .env を編集して NCBI_API_KEY を記入
|
|
249
|
+
|
|
250
|
+
# stdio モードで起動(デフォルト)
|
|
251
|
+
npm run dev
|
|
252
|
+
|
|
253
|
+
# HTTP モードで起動(PORT を設定すると有効になる。OAuth の環境変数も必須)
|
|
254
|
+
PORT=8080 npm run dev
|
|
255
|
+
# → http://localhost:8080/mcp MCP エンドポイント(Bearer トークン必須)
|
|
256
|
+
# → http://localhost:8080/health ヘルスチェック
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
HTTP モードは起動時に `OAUTH_ISSUER`・`OAUTH_JWKS_URL`・`MCP_RESOURCE_URL` を読み込み、1 つでも未設定だと次のエラーで終了します。
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
Fatal error: Error: Missing required environment variable: OAUTH_ISSUER
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
`.env` にこれらの値を設定してから起動してください(各値の意味は「[環境変数](#環境変数)」を参照)。
|
|
266
|
+
`/health` や 401 応答を確かめるだけなら URL 形式の仮の値でも起動できますが、`/mcp` を実際に呼び出すには
|
|
267
|
+
`MCP_RESOURCE_URL` を `aud` として発行されたアクセストークンが必要です。認証なしでツールを試す場合は stdio モードを使ってください。
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## CLI
|
|
272
|
+
|
|
273
|
+
MCP サーバーと同じツールを、シェルから `pubmed` コマンドとして実行できます。出力は MCP ツールと同じ JSON で、
|
|
274
|
+
標準出力またはファイル(`-o`)に書き出されます。結果をファイルに保存して `jq` で必要なフィールドだけを取り出せば、
|
|
275
|
+
Claude Code や Codex などのエージェントが大量のメタデータをコンテキストに読み込まずに済みます。
|
|
276
|
+
|
|
277
|
+
たとえば `TP53 AND myelodysplastic syndromes[mh]` の上位 20 件のメタデータは約 108 KB ありますが、
|
|
278
|
+
PMID・年・タイトルだけを取り出すと 3.2 KB(約 1/34)になります。全文は 1 本で数万文字あります。
|
|
279
|
+
|
|
280
|
+
### インストール
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
npm install -g @djmima/pubmed-mcp
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
`pubmed --help` が表示されれば完了です。
|
|
287
|
+
|
|
288
|
+
NCBI API キーは環境変数 `NCBI_API_KEY` から読み込みます。シェルの設定ファイル(`~/.bashrc`、`~/.zshrc` など)に
|
|
289
|
+
`export NCBI_API_KEY=your_api_key_here` を書くか、Windows では `setx NCBI_API_KEY your_api_key_here` を一度実行してから
|
|
290
|
+
ターミナルを開き直してください。
|
|
291
|
+
|
|
292
|
+
[ソースからビルドして](#ソースからビルドする) `npm link` で登録した場合は、環境変数がなければリポジトリ直下の `.env`
|
|
293
|
+
(`cp .env.example .env` で作成)も読み込むため、どのディレクトリから実行してもキーが使われます。
|
|
294
|
+
|
|
295
|
+
### コマンド
|
|
296
|
+
|
|
297
|
+
| コマンド | 対応する MCP ツール | 入力 | 1 リクエストの件数 |
|
|
298
|
+
|---|---|---|---|
|
|
299
|
+
| `pubmed search <query>` | `search_articles` | 検索式(`-` で標準入力から) | — |
|
|
300
|
+
| `pubmed metadata <pmid>...` | `get_article_metadata` | PMID | 200 |
|
|
301
|
+
| `pubmed related <pmid>...` | `find_related_articles` | PMID | 200 |
|
|
302
|
+
| `pubmed citation --journal <雑誌> --year <年> ...` | `lookup_article_by_citation` | オプション、または `--input` で JSON 配列か JSON Lines | 100 |
|
|
303
|
+
| `pubmed convert <id>...` | `convert_article_ids` | PMID・PMCID・DOI のいずれか(`--id-type` で指定) | 200 |
|
|
304
|
+
| `pubmed fulltext <pmcid>...` | `get_full_text_article` | PMCID | 20 |
|
|
305
|
+
| `pubmed copyright <pmid>...` | `get_copyright_status` | PMID | 50 |
|
|
306
|
+
|
|
307
|
+
- オプション名は MCP のパラメータ名をケバブケースにしたものです(`max_results` → `--max-results`、`date_from` → `--date-from` など)。詳しくは `pubmed <command> --help` を参照してください。
|
|
308
|
+
- ID は引数(空白またはカンマ区切り)で渡すか、`-` を指定して標準入力から 1 行 1 件で渡します。
|
|
309
|
+
- 1 リクエストの件数を超える ID は自動で分割して順番に送り、結果を 1 つの JSON にまとめます。MCP ツールの件数上限(メタデータなら 200 件)は受けません。
|
|
310
|
+
- `-o <file>` を付けると JSON をファイルに書き出し、件数とファイルサイズを標準エラー出力に表示します。
|
|
311
|
+
- 終了コードは、成功で 0、NCBI やファイル操作のエラーで 1、使い方の誤りで 2 です。エラーの内容は標準エラー出力に出ます。
|
|
312
|
+
|
|
313
|
+
### 使用例
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
# 検索して、PubMed が検索式をどう解釈したかを確認する
|
|
317
|
+
pubmed search "TP53[tiab] AND myelodysplastic syndromes[mh]" --max-results 200 -o search.json
|
|
318
|
+
jq '{total_count, query_translation, warnings, errors}' search.json
|
|
319
|
+
|
|
320
|
+
# ヒットした全件のメタデータを取得し、PMID・年・雑誌・タイトルの一覧にする
|
|
321
|
+
jq -r '.pmids[]' search.json | pubmed metadata - -o meta.json
|
|
322
|
+
jq -r '.articles[] | [.identifiers.pmid, .publication_date.year, .journal.iso_abbreviation, .title] | @tsv' meta.json
|
|
323
|
+
|
|
324
|
+
# 全文を取得できる論文だけ全文を取得し、必要な箇所だけを検索する
|
|
325
|
+
jq -r '.pmids[]' search.json | pubmed copyright - -o rights.json
|
|
326
|
+
jq -r '.statuses[] | select(.has_full_text) | .pmcid' rights.json | pubmed fulltext - -o full.json
|
|
327
|
+
jq -r '.articles[].full_text' full.json | grep -n -i 'venetoclax'
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### エージェントから使う
|
|
331
|
+
|
|
332
|
+
[`skills/pubmed-cli/SKILL.md`](skills/pubmed-cli/SKILL.md) は、CLI の使い方(結果はファイルに保存して jq で読む、ID はまとめて 1 回で渡す、など)と
|
|
333
|
+
jq のレシピをエージェントに教える Skill です。ユーザー単位のスキルフォルダにコピーすると、どのプロジェクトでも使われます。
|
|
334
|
+
Claude Code(Claude Desktop の Code タブを含む)は `~/.claude/skills/`、Codex は `~/.agents/skills/` から読み込みます
|
|
335
|
+
(Windows では `~` が `%USERPROFILE%` になります)。
|
|
336
|
+
|
|
337
|
+
Skill は npm パッケージにも含まれているので、`npm install -g` でインストールした場合は次のコマンドでコピーできます
|
|
338
|
+
(Windows では Git Bash で実行してください)。
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
SKILL_DIR="$(npm root -g)/@djmima/pubmed-mcp/skills/pubmed-cli"
|
|
342
|
+
mkdir -p ~/.claude/skills ~/.agents/skills
|
|
343
|
+
cp -r "$SKILL_DIR" ~/.claude/skills/
|
|
344
|
+
cp -r "$SKILL_DIR" ~/.agents/skills/
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
ソースからビルドした場合は、リポジトリ直下で `SKILL_DIR=skills/pubmed-cli` としてから同じコマンドを実行します。
|
|
348
|
+
パッケージや Skill を更新したときは、もう一度コピーしてください。
|
|
349
|
+
|
|
350
|
+
Claude Code でコマンドを実行するたびに許可を求められないようにするには、`~/.claude/settings.json` の `permissions.allow` に
|
|
351
|
+
`pubmed` と `jq` を追加します(既に設定がある場合は配列に追記してください)。
|
|
352
|
+
|
|
353
|
+
```json
|
|
354
|
+
{
|
|
355
|
+
"permissions": {
|
|
356
|
+
"allow": ["Bash(pubmed:*)", "Bash(jq:*)"]
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
注意点:
|
|
362
|
+
|
|
363
|
+
- CLI はシェルを実行できる環境(Claude Code、Codex など)でしか使えません。claude.ai のチャットや、Cloud Run にデプロイしたカスタムコネクタからは、これまでどおり MCP サーバーを使ってください。
|
|
364
|
+
- NCBI のレート制限はプロセスごとにかかります。`pubmed` を並列で複数起動すると合計で上限を超えるため、ID はまとめて 1 回の実行で渡してください。
|
|
365
|
+
- Windows では Git Bash か PowerShell 7 でパイプラインを実行してください。Windows PowerShell 5.1 の `>` はファイルを UTF-16 で保存するため、代わりに `-o` を使ってください。
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## Google Cloud Run へのデプロイ
|
|
370
|
+
|
|
371
|
+
このサーバーは Docker コンテナとして Google Cloud Run にデプロイできます。
|
|
372
|
+
`PORT` 環境変数が設定されると自動的に HTTP モードで起動し、Streamable HTTP トランスポートで MCP クライアントと通信します。
|
|
373
|
+
|
|
374
|
+
HTTP モードの `/mcp` は **OAuth 2.0 で保護** されています。サーバーは OAuth のリソースサーバーとして動作し、
|
|
375
|
+
リクエストごとに Bearer トークン(JWT)の署名・発行者(`iss`)・対象(`aud`)・有効期限を、認可サーバーの公開鍵(JWKS)で検証します。
|
|
376
|
+
ログイン画面やトークンの発行は外部の認可サーバーが担当します(ここでは WorkOS AuthKit を使います)。
|
|
377
|
+
|
|
378
|
+
Cloud Run 自体は `--allow-unauthenticated` で公開します。Cloud Run の IAM 認証(IAP を含む)は claude.ai からの接続と両立しないため、
|
|
379
|
+
アクセス制御は Cloud Run ではなくアプリ側の OAuth で行います。
|
|
380
|
+
|
|
381
|
+
| パス | 認証 | 内容 |
|
|
382
|
+
|------|------|------|
|
|
383
|
+
| `/mcp` | Bearer トークン必須 | MCP エンドポイント |
|
|
384
|
+
| `/.well-known/oauth-protected-resource` | 不要 | 認可サーバーの場所を示すメタデータ(RFC 9728) |
|
|
385
|
+
| `/health` | 不要 | ヘルスチェック |
|
|
386
|
+
|
|
387
|
+
```
|
|
388
|
+
Claude(Web / Desktop / モバイル)・Claude Code・Anthropic API
|
|
389
|
+
│ Authorization: Bearer <WorkOS AuthKit が発行したアクセストークン>
|
|
390
|
+
▼
|
|
391
|
+
Cloud Run(--allow-unauthenticated)
|
|
392
|
+
│ /mcp で JWT を検証し、ALLOWED_SUBJECTS で利用者を限定
|
|
393
|
+
▼
|
|
394
|
+
MCP ハンドラ
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
Claude の各アプリと Claude Code は、トークンなしのリクエストに返る 401 応答(`WWW-Authenticate` ヘッダー)から
|
|
398
|
+
メタデータをたどって認可サーバーを見つけ、ブラウザでのログインを経てトークンを取得します。
|
|
399
|
+
Anthropic API から使う場合は、呼び出し側でトークンを用意して渡します。
|
|
400
|
+
|
|
401
|
+
### 前提条件
|
|
402
|
+
|
|
403
|
+
- Google Cloud プロジェクト(課金が有効なもの)
|
|
404
|
+
- [gcloud CLI](https://cloud.google.com/sdk/docs/install) インストール済み・ログイン済み
|
|
405
|
+
- [WorkOS](https://workos.com/) アカウント(AuthKit を OAuth 認可サーバーとして使用)
|
|
406
|
+
|
|
407
|
+
### ステップ 1 — プロジェクトと API の準備
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
# デプロイ先プロジェクトをセット
|
|
411
|
+
gcloud config set project MY_PROJECT_ID
|
|
412
|
+
|
|
413
|
+
# 必要な API を有効化(初回のみ)
|
|
414
|
+
gcloud services enable \
|
|
415
|
+
run.googleapis.com \
|
|
416
|
+
artifactregistry.googleapis.com \
|
|
417
|
+
cloudbuild.googleapis.com \
|
|
418
|
+
secretmanager.googleapis.com # NCBI_API_KEY を管理する場合のみ
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### ステップ 2 — Artifact Registry リポジトリを作成(初回のみ)
|
|
422
|
+
|
|
423
|
+
```bash
|
|
424
|
+
gcloud artifacts repositories create pubmed-mcp \
|
|
425
|
+
--repository-format=docker \
|
|
426
|
+
--location=asia-northeast1 \
|
|
427
|
+
--description="PubMed MCP Server"
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### ステップ 3 — シークレットを Secret Manager に登録
|
|
431
|
+
|
|
432
|
+
NCBI API キーをコマンド履歴やログに残さないために Secret Manager を使います。
|
|
433
|
+
|
|
434
|
+
```bash
|
|
435
|
+
# NCBI API キーを登録
|
|
436
|
+
echo -n "your_ncbi_api_key" | \
|
|
437
|
+
gcloud secrets create ncbi-api-key \
|
|
438
|
+
--data-file=- \
|
|
439
|
+
--replication-policy=automatic
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### ステップ 4 — コンテナイメージをビルドしてプッシュ
|
|
443
|
+
|
|
444
|
+
Cloud Build を使うとローカルに Docker をインストールせずにビルドできます。
|
|
445
|
+
`gcloud builds submit` はカレントディレクトリのファイルを Cloud Build に送信するため、
|
|
446
|
+
**事前にリポジトリをクローンしておく必要があります。**
|
|
447
|
+
|
|
448
|
+
```bash
|
|
449
|
+
# リポジトリをクローンしてディレクトリに移動
|
|
450
|
+
git clone https://github.com/DJMIMA/PubMed_MCP.git
|
|
451
|
+
cd PubMed_MCP
|
|
452
|
+
|
|
453
|
+
# Cloud Build でビルド(ローカルに Docker 不要)
|
|
454
|
+
gcloud builds submit \
|
|
455
|
+
--region=asia-northeast1 \
|
|
456
|
+
--tag asia-northeast1-docker.pkg.dev/MY_PROJECT_ID/pubmed-mcp/server:latest
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
ローカルの Docker でビルドする場合:
|
|
460
|
+
|
|
461
|
+
```bash
|
|
462
|
+
gcloud auth configure-docker asia-northeast1-docker.pkg.dev
|
|
463
|
+
|
|
464
|
+
docker build -t asia-northeast1-docker.pkg.dev/MY_PROJECT_ID/pubmed-mcp/server:latest .
|
|
465
|
+
docker push asia-northeast1-docker.pkg.dev/MY_PROJECT_ID/pubmed-mcp/server:latest
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### ステップ 5 — OAuth 認可サーバー(WorkOS AuthKit)を設定
|
|
469
|
+
|
|
470
|
+
まず MCP エンドポイントの公開 URL を決めます。Cloud Run のサービスには
|
|
471
|
+
`https://サービス名-プロジェクト番号.リージョン.run.app` 形式の URL が割り当てられるため、デプロイ前に確定できます。
|
|
472
|
+
|
|
473
|
+
```bash
|
|
474
|
+
PROJECT_NUMBER=$(gcloud projects describe MY_PROJECT_ID --format='value(projectNumber)')
|
|
475
|
+
MCP_RESOURCE_URL="https://pubmed-mcp-${PROJECT_NUMBER}.asia-northeast1.run.app/mcp"
|
|
476
|
+
echo "$MCP_RESOURCE_URL"
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
この URL が `MCP_RESOURCE_URL` です。WorkOS の Resource Indicator や各クライアントに登録する URL とは**完全に同じ文字列**にしてください
|
|
480
|
+
(クライアントは接続先の URL とメタデータの `resource` が一致するかを確認し、サーバーはトークンの `aud` をこの値と照合します)。
|
|
481
|
+
Cloud Run には `https://pubmed-mcp-xxxx-an.a.run.app` 形式の URL も割り当てられ、どちらでもアクセスできますが、OAuth で使う URL はどちらか一方に統一します。
|
|
482
|
+
|
|
483
|
+
次に WorkOS ダッシュボードで AuthKit を設定します。
|
|
484
|
+
|
|
485
|
+
1. **Connect → Configuration** で **Dynamic Client Registration** を有効にする(claude.ai などの MCP クライアントが、自分自身を OAuth クライアントとして登録できるようにするため)
|
|
486
|
+
2. `MCP_RESOURCE_URL` を **Resource Indicator** として登録する(アクセストークンの `aud` がこの URL になる)
|
|
487
|
+
3. AuthKit ドメインの認可サーバーメタデータを開き、`issuer` と `jwks_uri` の値を控える
|
|
488
|
+
|
|
489
|
+
```bash
|
|
490
|
+
curl https://YOUR_AUTHKIT_DOMAIN/.well-known/oauth-authorization-server
|
|
491
|
+
# → {"issuer":"https://YOUR_AUTHKIT_DOMAIN", ..., "jwks_uri":"https://YOUR_AUTHKIT_DOMAIN/oauth2/jwks", ...}
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
WorkOS の Staging 環境と Production 環境は、設定も AuthKit ドメインも別々です。環境を切り替えるときは上の設定をやり直し、
|
|
495
|
+
`OAUTH_ISSUER`・`OAUTH_JWKS_URL` も差し替えてください。
|
|
496
|
+
|
|
497
|
+
### ステップ 6 — Cloud Run にデプロイ
|
|
498
|
+
|
|
499
|
+
ステップ 5 で控えた値を使ってデプロイします。`ALLOWED_SUBJECTS` には最初は仮の値(ここでは `placeholder`)を入れておきます(理由はステップ 8 を参照)。
|
|
500
|
+
|
|
501
|
+
```bash
|
|
502
|
+
# ステップ 5 で控えた issuer と jwks_uri の値に置き換える
|
|
503
|
+
OAUTH_ISSUER="https://YOUR_AUTHKIT_DOMAIN"
|
|
504
|
+
OAUTH_JWKS_URL="https://YOUR_AUTHKIT_DOMAIN/oauth2/jwks"
|
|
505
|
+
|
|
506
|
+
gcloud run deploy pubmed-mcp \
|
|
507
|
+
--image asia-northeast1-docker.pkg.dev/MY_PROJECT_ID/pubmed-mcp/server:latest \
|
|
508
|
+
--region asia-northeast1 \
|
|
509
|
+
--port 8080 \
|
|
510
|
+
--memory 512Mi \
|
|
511
|
+
--cpu 1 \
|
|
512
|
+
--timeout 300 \
|
|
513
|
+
--allow-unauthenticated \
|
|
514
|
+
--set-secrets NCBI_API_KEY=ncbi-api-key:latest \
|
|
515
|
+
--set-env-vars "OAUTH_ISSUER=${OAUTH_ISSUER},OAUTH_JWKS_URL=${OAUTH_JWKS_URL},MCP_RESOURCE_URL=${MCP_RESOURCE_URL},ALLOWED_SUBJECTS=placeholder"
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
| 変数 | 設定する値 |
|
|
519
|
+
|------|-----------|
|
|
520
|
+
| `OAUTH_ISSUER` | 認可サーバーメタデータの `issuer`。トークンの `iss` と完全一致で照合されるので、末尾の `/` の有無も含めてそのままコピーする |
|
|
521
|
+
| `OAUTH_JWKS_URL` | 同じメタデータの `jwks_uri`。トークンの署名検証に使う公開鍵の URL |
|
|
522
|
+
| `MCP_RESOURCE_URL` | ステップ 5 で決めた MCP エンドポイントの URL。トークンの `aud` と照合し、`/.well-known/oauth-protected-resource` の `resource` としても公開される |
|
|
523
|
+
| `ALLOWED_SUBJECTS` | 接続を許可するユーザー ID(トークンの `sub`)のカンマ区切りリスト。空にすると、AuthKit で有効なトークンを取得できるユーザー全員が接続できる |
|
|
524
|
+
|
|
525
|
+
`OAUTH_ISSUER`・`OAUTH_JWKS_URL`・`MCP_RESOURCE_URL` のどれかが欠けていると、サーバーは起動時に
|
|
526
|
+
`Missing required environment variable: ...` で終了し、デプロイは失敗します。失敗した場合は Cloud Run のログでこのメッセージを確認してください
|
|
527
|
+
(Cloud Console で設定した場合は、変数名の前後に空白が入っていないかも確認してください)。
|
|
528
|
+
|
|
529
|
+
> **`--set-env-vars` と `--update-env-vars` の違い**: `--set-env-vars` は既存の環境変数をすべて削除してから、指定した値を設定します(指定しなかった変数は消えます)。
|
|
530
|
+
> デプロイ後に一部の値だけを追加・変更するときは、既存の値とマージされる `--update-env-vars` を使ってください(`gcloud run services update` でも使えます)。
|
|
531
|
+
|
|
532
|
+
### ステップ 7 — 動作確認
|
|
533
|
+
|
|
534
|
+
`/health` と `/.well-known/oauth-protected-resource` は認証なしで応答します。`/mcp` はトークンなしでは **401 が返れば正常** です。
|
|
535
|
+
|
|
536
|
+
**Linux / macOS (bash)**
|
|
537
|
+
|
|
538
|
+
```bash
|
|
539
|
+
PROJECT_NUMBER=$(gcloud projects describe MY_PROJECT_ID --format='value(projectNumber)')
|
|
540
|
+
CLOUD_RUN_URL="https://pubmed-mcp-${PROJECT_NUMBER}.asia-northeast1.run.app"
|
|
541
|
+
|
|
542
|
+
# ヘルスチェック
|
|
543
|
+
curl "$CLOUD_RUN_URL/health"
|
|
544
|
+
# → ok
|
|
545
|
+
|
|
546
|
+
# Protected Resource Metadata(resource が MCP_RESOURCE_URL、authorization_servers が OAUTH_ISSUER になっていることを確認)
|
|
547
|
+
curl "$CLOUD_RUN_URL/.well-known/oauth-protected-resource"
|
|
548
|
+
# → {"resource":"https://pubmed-mcp-PROJECT_NUMBER.asia-northeast1.run.app/mcp","authorization_servers":["https://YOUR_AUTHKIT_DOMAIN"],"bearer_methods_supported":["header"]}
|
|
549
|
+
|
|
550
|
+
# MCP エンドポイント(トークンなしなので 401。-i でヘッダーも表示。ヒアドキュメントでクォート問題を回避)
|
|
551
|
+
curl -i "$CLOUD_RUN_URL/mcp" \
|
|
552
|
+
-X POST \
|
|
553
|
+
-H "Content-Type: application/json" \
|
|
554
|
+
-d @- <<'EOF'
|
|
555
|
+
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"0.0.1"}}}
|
|
556
|
+
EOF
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
`/mcp` の応答は次のようになります(抜粋。HTTP のバージョンやヘッダー名の大文字・小文字は環境によって異なります)。
|
|
560
|
+
|
|
561
|
+
```
|
|
562
|
+
HTTP/2 401
|
|
563
|
+
www-authenticate: Bearer resource_metadata="https://pubmed-mcp-PROJECT_NUMBER.asia-northeast1.run.app/.well-known/oauth-protected-resource", error="missing_token"
|
|
564
|
+
content-type: application/json; charset=utf-8
|
|
565
|
+
|
|
566
|
+
{"error":"missing_token"}
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
MCP クライアントは `WWW-Authenticate` ヘッダーの `resource_metadata` をたどって認可サーバーを見つけます。
|
|
570
|
+
トークンの検証に失敗した場合は `error="invalid_token"` の 401、トークンは有効でも `sub` が `ALLOWED_SUBJECTS` にない場合は 403(`{"error":"forbidden"}`)が返ります。
|
|
571
|
+
|
|
572
|
+
**Windows(コマンドプロンプト)**
|
|
573
|
+
|
|
574
|
+
```cmd
|
|
575
|
+
:: %CLOUD_RUN_URL% に URL を設定してから実行(PROJECT_NUMBER は自分のプロジェクト番号に置き換える)
|
|
576
|
+
set CLOUD_RUN_URL=https://pubmed-mcp-PROJECT_NUMBER.asia-northeast1.run.app
|
|
577
|
+
|
|
578
|
+
curl "%CLOUD_RUN_URL%/health"
|
|
579
|
+
|
|
580
|
+
curl "%CLOUD_RUN_URL%/.well-known/oauth-protected-resource"
|
|
581
|
+
|
|
582
|
+
curl -i "%CLOUD_RUN_URL%/mcp" -X POST -H "Content-Type: application/json" -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-03-26\",\"capabilities\":{},\"clientInfo\":{\"name\":\"test\",\"version\":\"0.0.1\"}}}"
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
**Windows(PowerShell)**
|
|
586
|
+
|
|
587
|
+
```powershell
|
|
588
|
+
$CLOUD_RUN_URL = "https://pubmed-mcp-PROJECT_NUMBER.asia-northeast1.run.app"
|
|
589
|
+
|
|
590
|
+
curl.exe "$CLOUD_RUN_URL/health"
|
|
591
|
+
|
|
592
|
+
curl.exe "$CLOUD_RUN_URL/.well-known/oauth-protected-resource"
|
|
593
|
+
|
|
594
|
+
curl.exe -i "$CLOUD_RUN_URL/mcp" -X POST -H "Content-Type: application/json" `
|
|
595
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"0.0.1"}}}'
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
### ステップ 8 — 自分のユーザー ID を ALLOWED_SUBJECTS に登録
|
|
599
|
+
|
|
600
|
+
Dynamic Client Registration では誰でも OAuth クライアントを登録できるため、`ALLOWED_SUBJECTS` で接続できるユーザーを限定します
|
|
601
|
+
(空のままだと AuthKit にログインできるユーザー全員が `/mcp` を使えます。AuthKit でサインアップを許可している場合は第三者も含まれます)。
|
|
602
|
+
設定する値はアクセストークンの `sub`(WorkOS のユーザー ID。`user_` で始まる値)です。
|
|
603
|
+
|
|
604
|
+
`ALLOWED_SUBJECTS` が空のときは `sub` がログに記録されません。そのため、仮の値を入れた状態で一度接続し、拒否されたときのログから確認します。
|
|
605
|
+
|
|
606
|
+
1. 後述の「[クライアント別の接続設定](#クライアント別の接続設定)」の手順で claude.ai などから接続し、WorkOS AuthKit でログインします。
|
|
607
|
+
`sub` が `ALLOWED_SUBJECTS` に含まれていないため接続は 403 で失敗し、サーバーのログに `[auth] forbidden subject: ...` が記録されます。
|
|
608
|
+
2. ログから自分の `sub` を確認します(WorkOS ダッシュボードの **Users** で確認できるユーザー ID と同じ値です)。
|
|
609
|
+
|
|
610
|
+
```bash
|
|
611
|
+
gcloud run services logs read pubmed-mcp \
|
|
612
|
+
--region asia-northeast1 \
|
|
613
|
+
--log-filter='textPayload:"forbidden subject"' \
|
|
614
|
+
--limit 5
|
|
615
|
+
# → ... [auth] forbidden subject: user_01XXXXXXXXXXXXXXXXXXXXXXXX
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
3. その値を設定します。`--update-env-vars` なので、ほかの環境変数はそのまま残ります。
|
|
619
|
+
|
|
620
|
+
```bash
|
|
621
|
+
gcloud run services update pubmed-mcp \
|
|
622
|
+
--region asia-northeast1 \
|
|
623
|
+
--update-env-vars ALLOWED_SUBJECTS=user_01XXXXXXXXXXXXXXXXXXXXXXXX
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
複数のユーザーを許可する場合は、値にカンマが含まれるため `^@^` で区切り文字を変えて指定します
|
|
627
|
+
(例: `--update-env-vars '^@^ALLOWED_SUBJECTS=user_01AAAA,user_01BBBB'`。Windows の cmd / PowerShell では `^` を `^^^^` と書きます。詳しくは `gcloud topic escaping` を参照)。
|
|
628
|
+
4. クライアントから接続し直します。
|
|
629
|
+
|
|
630
|
+
---
|
|
631
|
+
|
|
632
|
+
### クライアント別の接続設定
|
|
633
|
+
|
|
634
|
+
デプロイ後、各クライアントに MCP エンドポイントの URL を登録します。URL は `MCP_RESOURCE_URL` と**完全に同じ文字列**
|
|
635
|
+
(例: `https://pubmed-mcp-PROJECT_NUMBER.asia-northeast1.run.app/mcp`)にしてください。
|
|
636
|
+
初回接続時に WorkOS AuthKit のログイン画面が開きます。ログインしたアカウントの `sub` が `ALLOWED_SUBJECTS` に含まれていれば接続できます
|
|
637
|
+
(自分の `sub` を登録する手順はステップ 8 を参照)。
|
|
638
|
+
|
|
639
|
+
**Claude(Web 版・Claude Desktop)— カスタムコネクタ**
|
|
640
|
+
|
|
641
|
+
リモートサーバーは「カスタムコネクタ」として追加します([Claude ヘルプセンター](https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp))。
|
|
642
|
+
カスタムコネクタは Free プランでも 1 つまで利用できます。
|
|
643
|
+
|
|
644
|
+
- Pro / Max プラン
|
|
645
|
+
1. [claude.ai](https://claude.ai) または Claude Desktop で **Customize > Connectors** を開く
|
|
646
|
+
2. **+** → **Add custom connector** をクリック
|
|
647
|
+
3. URL(`MCP_RESOURCE_URL`)を入力して **Add** をクリック
|
|
648
|
+
4. 追加したコネクタの **Connect** から認証する(WorkOS AuthKit のログイン画面が開く)
|
|
649
|
+
- Team / Enterprise プラン
|
|
650
|
+
1. オーナーが **Organization settings > Connectors** を開き、**Add** → **Custom** にカーソルを合わせて **Web** を選ぶ
|
|
651
|
+
2. URL(`MCP_RESOURCE_URL`)を入力して **Add** をクリック
|
|
652
|
+
3. 各メンバーが **Customize > Connectors** でこのコネクタを探し、**Connect** から認証する
|
|
653
|
+
|
|
654
|
+
**Advanced settings** の OAuth Client ID / OAuth Client Secret は空欄のままで構いません(Dynamic Client Registration でクライアントが自動登録されます)。
|
|
655
|
+
チャットで使うときは、入力欄左下の **+** → **Connectors** から会話ごとに有効にします。
|
|
656
|
+
|
|
657
|
+
Claude Desktop の `claude_desktop_config.json` はローカル(stdio)サーバー用の設定で、`"type"` や `"url"` を書いてもリモートサーバーには接続されません。
|
|
658
|
+
Desktop でもリモートサーバーは上記のカスタムコネクタとして追加してください(Web 版で追加したコネクタは Desktop でもそのまま使えます)。
|
|
659
|
+
|
|
660
|
+
**Claude モバイルアプリ(Android / iOS)**
|
|
661
|
+
|
|
662
|
+
Web 版または Claude Desktop で追加したカスタムコネクタは、同じアカウントのモバイルアプリでもそのまま使えます。
|
|
663
|
+
モバイルアプリからのコネクタ追加はベータ機能のため、追加は Web 版か Desktop で行ってください。
|
|
664
|
+
|
|
665
|
+
**Claude Code**
|
|
666
|
+
|
|
667
|
+
```bash
|
|
668
|
+
claude mcp add --transport http --scope user pubmed-remote https://pubmed-mcp-PROJECT_NUMBER.asia-northeast1.run.app/mcp
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
Claude Code は `~/.claude/settings.json` の `mcpServers` を読み込まないため、`claude mcp add` で登録します。
|
|
672
|
+
登録後、Claude Code で `/mcp` を開いて `pubmed-remote` を選び、ブラウザで WorkOS AuthKit にログインして認証します。
|
|
673
|
+
|
|
674
|
+
**Anthropic API(Python)**
|
|
675
|
+
|
|
676
|
+
```python
|
|
677
|
+
import os
|
|
678
|
+
|
|
679
|
+
import anthropic
|
|
680
|
+
|
|
681
|
+
client = anthropic.Anthropic()
|
|
682
|
+
response = client.beta.messages.create(
|
|
683
|
+
model="claude-opus-5",
|
|
684
|
+
max_tokens=16000,
|
|
685
|
+
messages=[{"role": "user", "content": "..."}],
|
|
686
|
+
mcp_servers=[{
|
|
687
|
+
"type": "url",
|
|
688
|
+
"url": "https://pubmed-mcp-PROJECT_NUMBER.asia-northeast1.run.app/mcp",
|
|
689
|
+
"name": "pubmed",
|
|
690
|
+
"authorization_token": os.environ["PUBMED_MCP_TOKEN"],
|
|
691
|
+
}],
|
|
692
|
+
tools=[{"type": "mcp_toolset", "mcp_server_name": "pubmed"}],
|
|
693
|
+
betas=["mcp-client-2025-11-20"]
|
|
694
|
+
)
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
MCP コネクタは OAuth のログインもトークンの更新も行いません。WorkOS AuthKit がこのサーバー向けに発行したアクセストークン
|
|
698
|
+
(`aud` が `MCP_RESOURCE_URL` で、`sub` が `ALLOWED_SUBJECTS` に含まれるもの)を呼び出し側で取得して `authorization_token` に渡し、
|
|
699
|
+
有効期限が切れたら取得し直してください。
|
|
700
|
+
|
|
701
|
+
テスト用のトークンは MCP Inspector で取得できます([MCP connector ドキュメント](https://platform.claude.com/docs/en/agents-and-tools/mcp-connector#authentication))。
|
|
702
|
+
|
|
703
|
+
1. `npx @modelcontextprotocol/inspector` を実行
|
|
704
|
+
2. **Transport type** で **Streamable HTTP** を選び、URL に `MCP_RESOURCE_URL` を入力
|
|
705
|
+
3. **Open Auth Settings** → **Quick OAuth Flow** をクリックし、WorkOS AuthKit でログイン
|
|
706
|
+
4. **Authentication complete** まで進めたら、表示された `access_token` の値をコピー
|
|
707
|
+
|
|
708
|
+
---
|
|
709
|
+
|
|
710
|
+
### イメージを更新する(再デプロイ)
|
|
711
|
+
|
|
712
|
+
```bash
|
|
713
|
+
cd PubMed_MCP
|
|
714
|
+
git pull
|
|
715
|
+
|
|
716
|
+
gcloud builds submit \
|
|
717
|
+
--region=asia-northeast1 \
|
|
718
|
+
--tag asia-northeast1-docker.pkg.dev/MY_PROJECT_ID/pubmed-mcp/server:latest
|
|
719
|
+
|
|
720
|
+
gcloud run services update pubmed-mcp \
|
|
721
|
+
--region asia-northeast1 \
|
|
722
|
+
--image asia-northeast1-docker.pkg.dev/MY_PROJECT_ID/pubmed-mcp/server:latest
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
`--image` だけを指定した更新では、環境変数とシークレットの設定はそのまま引き継がれます。
|
|
726
|
+
|
|
727
|
+
---
|
|
728
|
+
|
|
729
|
+
## 開発コマンド
|
|
730
|
+
|
|
731
|
+
```bash
|
|
732
|
+
npm run build # TypeScript をコンパイル → dist/
|
|
733
|
+
npm run dev # tsx で直接実行(開発用)
|
|
734
|
+
npm run cli -- search "CRISPR" --max-results 5 # CLI を tsx で直接実行(開発用)
|
|
735
|
+
npm test # テストスイートを実行
|
|
736
|
+
npm run typecheck # 型チェックのみ(コンパイルなし)
|
|
737
|
+
npm run lint # ESLint を実行
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
### npm へのリリース(メンテナー向け)
|
|
741
|
+
|
|
742
|
+
GitHub で Release を公開すると、[`.github/workflows/release.yml`](.github/workflows/release.yml) が npm に公開を申請します([staged publishing](https://docs.npmjs.com/staged-publishing/))。
|
|
743
|
+
メンテナーが npmjs.com で 2FA を使って承認するまで、新しいバージョンは公開されません。ワークフローや依存パッケージが乗っ取られても、それだけでは公開できないようにするためです。
|
|
744
|
+
npm の [Trusted Publishing](https://docs.npmjs.com/trusted-publishers/)(OIDC)を使うため、npm のトークンはリポジトリに保存しません。
|
|
745
|
+
|
|
746
|
+
変更を加える PR では、[`CHANGELOG.md`](CHANGELOG.md) の `[Unreleased]` に内容を追記しておきます。リリースの手順は次のとおりです。
|
|
747
|
+
|
|
748
|
+
1. リリース用のブランチで `npm version patch --no-git-tag-version`(または `minor` / `major`)を実行し、`package.json` のバージョンを上げる
|
|
749
|
+
(タグは手順 3 で GitHub が付けるため、ここでは付けません)
|
|
750
|
+
2. `CHANGELOG.md` の `[Unreleased]` の内容を新しいバージョンの見出し(例: `## [1.0.1] - 2026-11-01`)の下に移し、末尾の比較リンクを更新して、PR を作って main にマージする
|
|
751
|
+
3. GitHub で、main を対象に `v<バージョン>`(例: `v1.0.1`)のタグを付けた Release を公開する。リリースノートには `CHANGELOG.md` の該当部分を貼る
|
|
752
|
+
4. ワークフローがタグと `package.json` のバージョンが一致するか確かめ、型チェック・lint・テスト・ビルドを通してから公開を申請する
|
|
753
|
+
5. npmjs.com のパッケージページの **Staged Packages** タブで内容を確認し、**Approve** を押す(2FA が必要)。CLI では `npm stage approve <stage-id>` でも承認できる
|
|
754
|
+
|
|
755
|
+
バージョンの上げ方の目安は、不具合の修正やドキュメントの変更が `patch`、ツールやオプションの追加が `minor`、
|
|
756
|
+
ツール名・引数・出力の形を変えて既存の使い方が動かなくなる変更が `major` です。
|
|
757
|
+
|
|
758
|
+
初回だけは手動で公開します。Trusted Publishing はパッケージが npm に存在しないと設定できないためです。
|
|
759
|
+
|
|
760
|
+
1. 2FA を有効にした npm アカウントで `npm login` し、main の最新を `npm publish` で公開する(保留になった場合は上記の手順 5 のとおり承認する)
|
|
761
|
+
2. npmjs.com のパッケージ設定 → **Trusted Publisher** で GitHub Actions を選び、リポジトリ `DJMIMA/PubMed_MCP`、ワークフロー `release.yml` を登録する。
|
|
762
|
+
**Allowed actions** は `npm stage publish`(常に許可)だけにし、`npm publish` と `npm dist-tag` は許可しない
|
|
763
|
+
3. 同じ設定画面の **Publishing access** で **Require two-factor authentication and disallow tokens** を選ぶ
|
|
764
|
+
|
|
765
|
+
---
|
|
766
|
+
|
|
767
|
+
## 環境変数
|
|
768
|
+
|
|
769
|
+
| 変数 | 必須 | 説明 |
|
|
770
|
+
|------|------|------|
|
|
771
|
+
| `NCBI_API_KEY` | 任意 | NCBIのAPIキー。設定するとレートリミットが 3 → 8 req/s になる |
|
|
772
|
+
| `PORT` | 任意 | 設定するとHTTPモードで起動。Cloud Run はこの変数を自動で注入する |
|
|
773
|
+
| `OAUTH_ISSUER` | HTTPモードでは必須 | 認可サーバーの issuer(認可サーバーメタデータの `issuer`)。トークンの `iss` と照合する |
|
|
774
|
+
| `OAUTH_JWKS_URL` | HTTPモードでは必須 | 認可サーバーの JWKS の URL(同じメタデータの `jwks_uri`)。トークンの署名検証に使う |
|
|
775
|
+
| `MCP_RESOURCE_URL` | HTTPモードでは必須 | MCP エンドポイントの公開 URL。トークンの `aud` と照合し、Protected Resource Metadata の `resource` として公開する |
|
|
776
|
+
| `ALLOWED_SUBJECTS` | 任意(推奨) | 接続を許可するトークン `sub` のカンマ区切りリスト。空なら有効なトークンを持つ全ユーザーを許可する |
|
|
777
|
+
|
|
778
|
+
`OAUTH_ISSUER`・`OAUTH_JWKS_URL`・`MCP_RESOURCE_URL`・`ALLOWED_SUBJECTS` は HTTP モードでのみ使われ、stdio モードでは不要です。
|
|
779
|
+
値の決め方は「[Google Cloud Run へのデプロイ](#google-cloud-run-へのデプロイ)」のステップ 5〜8 を参照してください。
|
|
780
|
+
|
|
781
|
+
`.env` ファイルを使う場合は `.env.example` をコピーして編集してください。
|
|
782
|
+
本番環境では、`NCBI_API_KEY` は Cloud Run の `--set-secrets` で Secret Manager から渡し、OAuth 関連の値は `--set-env-vars` / `--update-env-vars` で設定してください。
|
|
783
|
+
|
|
784
|
+
---
|
|
785
|
+
|
|
786
|
+
## 参考リンク
|
|
787
|
+
|
|
788
|
+
- [MCP ドキュメント](https://modelcontextprotocol.io/docs)
|
|
789
|
+
- [NCBI E-utilities ドキュメント](https://www.ncbi.nlm.nih.gov/books/NBK25499/)
|
|
790
|
+
- [NCBI APIキー登録](https://www.ncbi.nlm.nih.gov/account/)
|
|
791
|
+
- [PubMed 検索ヘルプ](https://pubmed.ncbi.nlm.nih.gov/help/)
|
|
792
|
+
- [Cloud Run ドキュメント](https://cloud.google.com/run/docs)
|
|
793
|
+
- [Secret Manager ドキュメント](https://cloud.google.com/secret-manager/docs)
|
|
794
|
+
|
|
795
|
+
---
|
|
796
|
+
|
|
797
|
+
## ライセンス
|
|
798
|
+
|
|
799
|
+
このリポジトリのソースコードは [MIT License](LICENSE) で公開しています。
|
|
800
|
+
|
|
801
|
+
- このプロジェクトは NCBI / NLM(米国国立医学図書館)とは関係のない非公式のツールです。
|
|
802
|
+
- PubMed / PMC へのアクセスには NCBI の E-utilities を使います。利用時は [NCBI の免責事項・著作権表示を含む利用ポリシー](https://www.ncbi.nlm.nih.gov/home/about/policies/)(NCBI Disclaimer and Copyright notice)と [E-utilities の利用ガイドライン](https://www.ncbi.nlm.nih.gov/books/NBK25497/) に従ってください。
|
|
803
|
+
- ガイドラインに従い、NCBI へのリクエストにはこのソフトウェアの名前(`tool=pubmed-mcp`)と開発者の連絡先(`email`)を付けています。このコードを改変して別のソフトウェアとして配布する場合は、`src/pubmed/client.ts` の `TOOL_NAME` と `TOOL_EMAIL` を自分の値に変えてください。
|
|
804
|
+
- MIT License が適用されるのはこのソフトウェアのコードだけです。取得した抄録や全文の著作権は各著者・出版社に帰属します。論文ごとのライセンスは `get_copyright_status` で確認できます。
|