AI クライアントから使う(MCP)
何ができるか
Section titled “何ができるか”アプリを MCP サーバー(AI クライアントからアプリを使う機能)にできます。MCP(Model Context Protocol)は、Claude や ChatGPT などの AI クライアントが、外部の「ツール」を一覧して呼び出すための取り決めです。たとえば在庫管理アプリに「品目を検索する」「入荷を記録する」ツールを用意すると、利用者は AI クライアントとの会話の中から、自分の権限の範囲でアプリを操作できます。
アプリ側で用意するのは、keelson.yaml の mcp: でのツールの宣言と、ツールごとの JSON の受け口(ハンドラ)だけです。ログイン、同意画面、AI クライアントとの MCP のやり取りは Keelson が受け持ちます。
- アプリ作者が
keelson.yamlのmcp:にツールを宣言してデプロイします - 利用者が AI クライアントに接続 URL(アプリの URL +
/mcp)を登録します - 初回は Keelson のログインと同意画面が出ます。利用者が承認すると、AI クライアントがその利用者として接続されます
- AI クライアントがツールを呼ぶと、Keelson がメンバーであること・アプリの権限・IP 制限を確かめ、引数を宣言どおりか検査します
- Keelson がアプリの
POST /api/mcp/<ツール名>を呼び、アプリが返した JSON をツールの結果として AI クライアントに返します
使えるのは、サーバー側のプログラムが動くアプリ(command があり assets がないアプリ)だけです。静的サイト・SPA・ハイブリッド構成では宣言できません。全プランで使え、プランによる違いはありません。
ツールを宣言する
Section titled “ツールを宣言する”keelson.yaml に mcp: を書いてデプロイします。次の例は、読み取りのツール search_items と、書き込みのツール create_arrival を宣言しています。
slug: stock-deskruntime: python-slimcommand: "python app.py"db: mode: libsqlmcp: enabled: true instructions: "Look up stock levels and record incoming deliveries." tools: - name: search_items description: "Search stock by item name." access: read input: type: object properties: query: type: string required: [query] - name: create_arrival description: "Record one incoming delivery." access: write permission: manage input: type: object properties: item_id: type: string quantity: type: integer minimum: 1 required: [item_id, quantity]| キー | 意味 |
|---|---|
enabled | true でツールを公開します。false にすると宣言を残したまま呼び出しを止めます |
instructions | AI クライアントに渡す、ツール全体の説明(省略可) |
tools[].name | ツール名。英小文字で始まり、英小文字・数字・_ だけ。アプリの受け口は POST /api/mcp/<name> になります |
tools[].description | AI クライアントに見せるツールの説明。AI はこれを読んで、いつ呼ぶかを決めます |
tools[].access | read(読み取り)か write(データを変更する)。読み取りと書き込み・権限を参照 |
tools[].permission | view(既定)か manage。manage のツールはアプリの管理権限を持つ人だけが使えます |
tools[].input | 引数の形(JSON Schema 2020-12)。最上位は type: object |
各キーの型・上限・検査の詳細は keelson.yaml リファレンスを参照してください。
ツールが多いときは別ファイルに分ける(mcp.file)
Section titled “ツールが多いときは別ファイルに分ける(mcp.file)”mcp.file を使うと、instructions と tools を別の YAML ファイルに置けます。keelson.yaml には enabled と file だけを書きます。
slug: stock-deskruntime: python-slimcommand: "python app.py"db: mode: libsqlmcp: enabled: true file: mcp.yamlkeelson.yaml と同じフォルダの mcp.yaml:
instructions: "Look up stock levels and record incoming deliveries."tools: - name: search_items description: "Search stock by item name." access: read input: type: object properties: query: type: string required: [query] - name: create_arrival description: "Record one incoming delivery." access: write permission: manage input: type: object properties: item_id: type: string quantity: type: integer minimum: 1 required: [item_id, quantity]- デプロイ時に Keelson CLI が
mcp.yamlの中身をkeelson.yamlに差し込んでから検査・送信します。手元のファイルは書き換えません - 別ファイルに書けるのは
instructionsとtoolsだけです。mcp.fileとmcp.instructions/mcp.toolsは同時に書けません mcp.fileを読めるのは新しい Keelson CLI だけです。古い CLI は「未対応のキー」としてデプロイを拒否します。その場合はkeelson upgradeで CLI を最新版にしてください
ハンドラを書く
Section titled “ハンドラを書く”ツールが呼ばれると、Keelson がアプリに POST /api/mcp/<ツール名> を送ります。パスはツール名で決まり、変更できません。
本文は、AI クライアントが渡した引数の JSON オブジェクトです(引数がなければ {})。宣言した input で検査済みのものだけが届きます。
ヘッダーは Keelson が組み立てたものだけが届きます。AI クライアントが送ったヘッダーは 1 つも引き継がれないため、AI クライアントのアクセストークンや、偽造された X-Keelson-* ヘッダーはアプリに届きません。
| ヘッダー | 内容 |
|---|---|
X-Keelson-User-Id | 接続した利用者のユーザー ID。本人の識別にはこれを使います |
X-Keelson-User-Email | 同じ利用者のメールアドレス |
X-Keelson-User-Name | 同じ利用者の表示名 |
X-Keelson-User-App-Perms | その利用者のアプリの権限(view または view,manage) |
X-Keelson-Auth-Source | mcp(MCP 経由の呼び出しであることを示す) |
X-Keelson-Mcp-Tool | 呼ばれたツール名 |
X-Keelson-Mcp-Client | AI クライアントの識別子(URL) |
X-Request-Id | リクエスト ID。エラーの結果にも request id: として表示されます |
Authorization ヘッダーには Keelson の内部で使う値が入ります。AI クライアントのトークンではないため、アプリでは使いません。ユーザー情報ヘッダーの使い方はログイン中のユーザー情報を使うと同じです。
応答は 2xx の JSON(1 MiB まで)で返します。JSON オブジェクトを返すと、AI クライアントが項目を読み取りやすくなります。
| アプリの応答 | AI クライアントに返る結果 |
|---|---|
| 2xx と JSON の本文 | ツールの結果として本文の JSON を返す |
| 2xx で本文が空・JSON でない・1 MiB を超える | エラー(ツールの応答が不正) |
| 4xx | エラー。本文の先頭 4 KiB を利用者と AI クライアントにそのまま見せる |
| 3xx・5xx | エラー(ツールの実行に失敗)。本文は見せない |
| 60 秒以内に応答がない | エラー(実行されたか分からない) |
- 4xx の本文は利用者と AI クライアントに見えます。 見せてよい説明だけを書きます(例:「品目 A-100 が見つかりません」)
- 1 回の呼び出しは全体で 60 秒までです。時間がかかる処理はバックグラウンドタスクに投入して、すぐに応答を返します
- Keelson は失敗した呼び出しを再試行しません
FastAPI の例
Section titled “FastAPI の例”from fastapi import FastAPI, Requestfrom fastapi.responses import JSONResponse
app = FastAPI()
@app.post("/api/mcp/search_items")async def search_items(request: Request): user_id = request.headers["X-Keelson-User-Id"] args = await request.json() # 例: {"query": "ねじ"} items = find_items(owner=user_id, query=args["query"]) # アプリの検索処理 return {"items": items}
@app.post("/api/mcp/create_arrival")async def create_arrival(request: Request): perms = request.headers.get("X-Keelson-User-App-Perms", "").split(",") if "manage" not in perms: return JSONResponse({"error": "入荷を記録する権限がありません"}, status_code=403) args = await request.json() if not item_exists(args["item_id"]): # 4xx の本文は利用者に見える return JSONResponse({"error": f"品目 {args['item_id']} が見つかりません"}, status_code=404) arrival_id = record_arrival(args["item_id"], args["quantity"]) return {"arrival_id": arrival_id}Express の例
Section titled “Express の例”app.use(express.json());
app.post("/api/mcp/search_items", (req, res) => { const userId = req.headers["x-keelson-user-id"]; const items = findItems({ owner: userId, query: req.body.query }); // アプリの検索処理 res.json({ items });});
app.post("/api/mcp/create_arrival", (req, res) => { const perms = (req.headers["x-keelson-user-app-perms"] ?? "").split(","); if (!perms.includes("manage")) { return res.status(403).json({ error: "入荷を記録する権限がありません" }); } const { item_id, quantity } = req.body; if (!itemExists(item_id)) { // 4xx の本文は利用者に見える return res.status(404).json({ error: `品目 ${item_id} が見つかりません` }); } res.json({ arrival_id: recordArrival(item_id, quantity) });});permission: manage のツールは、管理権限を持たない人からは Keelson が呼び出しを通しません。上の例のようにアプリ側でも X-Keelson-User-App-Perms を確かめておくと、宣言を変えたときにも安全です。
読み取りと書き込み・権限
Section titled “読み取りと書き込み・権限”access: writeのツールは、同意画面で「書き込みツール(データを変更できる)」として別に表示されます。 利用者は「読み取りツールだけ承認」を選べます。その場合、書き込みツールは使えません。後から使うには、接続し直して承認しますpermission: manageのツールは、アプリの管理権限(manage)を持つ人だけが使えます。 権限の割り当てはメンバーとロールを参照してください- 使えないツールは一覧に出ません。 権限が足りないツールと、同意していない書き込みツールは、AI クライアントのツール一覧から除かれます
- 呼び出しはすべて、接続した利用者本人として、その人の権限の範囲で行われます。メンバーから外れた人やアプリの閲覧権限を失った人の呼び出しは、通常 2 分以内に拒否されるようになります
利用者は、AI クライアントに接続 URL を登録します。接続 URL はアプリの URL の末尾に /mcp を付けたもの(例: https://acme--stock-desk.keelson.run/mcp)で、コンソールのアプリの MCP タブにも表示されます。接続 URL の登録方法は、各 AI クライアントの MCP 設定のドキュメントを参照してください。
- AI クライアントに接続 URL を登録します
- 初回は Keelson のログイン画面が開きます。アプリを使えるアカウントでログインします
- 同意画面で、AI クライアントに使わせるツールを確認して 承認 を選びます
- 接続できるのは、そのアプリを閲覧できるメンバーだけです
- 受け付ける AI クライアントは、
claude.aiまたはchatgpt.comの身元を名乗るものだけです。それ以外のクライアントは、接続 URL を登録してもログインの段階で止まります - アクセストークンの有効期間は 1 時間で、AI クライアントが自動で更新します。更新用のトークンは、60 日使われないか、接続から最長 180 日で切れます。切れたら接続し直します
- 同じ AI クライアントで同じアプリに接続し直すと、前の接続は解除されます
止める・解除する
Section titled “止める・解除する”| 操作 | できる人 | 効果 |
|---|---|---|
| ワークスペースの MCP を停止(設定 → セキュリティ → MCP(AI クライアント)) | Owner / Admin | ワークスペースのすべてのアプリで呼び出しを止める。接続は残り、許可に戻すとそのまま使える |
mcp.enabled: false にしてデプロイ | アプリをデプロイできる人 | そのアプリの呼び出しを止める。接続は残り、true に戻してデプロイするとそのまま使える |
| アプリの MCP タブの「接続中の AI クライアント」で 失効 | Owner / Admin、アプリの管理権限を持つ人 | その接続を解除する。AI クライアントは更新用のトークンも含めて直ちに使えなくなる |
| 「自分の接続中の AI クライアント」で 失効 | 接続した本人 | 自分の接続を解除する |
停止と mcp.enabled: false は呼び出しを止めるだけです。接続そのものを失効させるのは、解除(失効)だけです。 「自分の接続中の AI クライアント」は、設定 → セキュリティ と同意画面からリンクしています。
予約されるパス
Section titled “予約されるパス”mcp.enabled: trueのアプリでは、/mcp、/.well-known/oauth-protected-resource、/.well-known/oauth-protected-resource/mcpは Keelson が応答し、アプリには届きません- サーバー側のプログラムが動くアプリ(ハイブリッド構成のサーバー側を含む)では、
/api/mcpと/api/mcp/で始まるパスは、mcp:を宣言していなくても MCP 経由以外では 404 になります。このパスにはツールのハンドラ以外のルートを置かないでください。静的に配信される部分には影響しません
予約パスの一覧は Keelson Deploy Spec の予約 URL パスを参照してください。
| 項目 | 上限 |
|---|---|
| ツールの数 | 1 アプリ 40 本 |
instructions | 4096 文字 |
ツールの description | 1024 文字 |
ツールの input | JSON にして 64 KB・入れ子 32 段 |
| 1 回の呼び出し | 60 秒 |
| 応答の本文(2xx) | 1 MiB |
| 呼び出し回数 | 1 接続あたり 1 分 60 回 |
| 同時に実行される呼び出し | 1 アプリ 10(Keelson の中継サーバー 1 台ごとの値。中継サーバーが増えるとアプリ全体ではこれより多く同時に届くことがあります) |
回数と同時実行の上限を超えた呼び出しは、少し待ってから再試行するよう AI クライアントに返されます。上限はプランで変わりません。同時実行の 10 はアプリが受ける同時呼び出しの最大値ではないので、データベースの接続数などを 10 件前提で決めないでください。
うまくいかないとき
Section titled “うまくいかないとき”| 症状 | 確認すること |
|---|---|
| ツールが一覧に出ない | その利用者にアプリの権限があるか(permission: manage のツールは管理権限が必要)。書き込みツールなら、同意画面で承認したか。mcp.enabled が true か。ワークスペースの MCP が停止されていないか(アプリの MCP タブの状態に表示されます) |
| IP 制限のあるワークスペースで呼び出しが拒否される | IP 制限は MCP 経由の呼び出しにも適用されます。claude.ai や ChatGPT からの呼び出しは利用者の PC ではなく各社のサーバーから届くため、そのままでは許可されません。IP 制御のアクセス元を見直してください |
| 「ツールの応答が不正」と表示される | ハンドラが 2xx で JSON の本文を返しているか。本文が空・テキスト・1 MiB 超になっていないか |
| ログインの後に接続できない | AI クライアントが claude.ai または chatgpt.com の身元を名乗るものか。ログインしたアカウントがアプリを閲覧できるメンバーか |
デプロイで mcp の file が未対応のキーとして拒否される | Keelson CLI が古いため。keelson upgrade で最新版にしてからデプロイし直します |