mcphost について
mcphostは、エージェントがタスク中にツールを作成・公開できるホスト型リモートMCP実行環境です。公開したツールは再デプロイなしで稼働し、会話終了後も利用でき、スケジュール実行や共有、実行ログにも対応します。
主な機能
- 01ツール呼び出しによるツール公開
- 02Python、JavaScript、HTTPツールに対応
- 03再デプロイなしで公開済みツールを実行
- 04実行予約とログ確認
- 05ツール共有とシークレット管理
活用シーン
- 01進行中の作業向けツールを作成して公開
- 02既存APIをエージェント用にラップ
- 03ツールを定期実行して履歴を確認
- 04キーを共有せず別のエージェントとツールを共有
MCP 対応
単一エンドポイントのStreamable HTTP MCPサーバーとして、公開、実行、スケジュール、ログ、計量、シークレット管理、共有のツールを提供します。クライアントはこれらのツールでホスト型実行環境を管理します。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://mcphost.dev/mcpclaude mcp add --transport http dev-mcphost-mcphost https://mcphost.dev/mcp{"mcpServers":{"dev-mcphost-mcphost":{"type":"http","url":"https://mcphost.dev/mcp"}}}Cursor で開く{"servers":{"dev-mcphost-mcphost":{"type":"http","url":"https://mcphost.dev/mcp"}}}VS Code で開く{"mcpServers":{"dev-mcphost-mcphost":{"type":"http","url":"https://mcphost.dev/mcp"}}}{"mcpServers":{"dev-mcphost-mcphost":{"serverUrl":"https://mcphost.dev/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
16| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| name | string | はい | 表示名 |
| handoff | boolean | いいえ | handoff_token(host.redeem で交換)を受け取り、生のキーを受け取らない場合は true を推奨します。デフォルトは false(生のキー、変更なし)です。 |
詳細
mcphost
エージェントが独自のツールをホストする場所 · mcphost.dev · ステータス · llms.txt · llms-install.md
レジストリで見つける:dev.mcphost/mcphost — mcphost.dev の URL 1つで始めるクイックスタートで接続できます。
これは何か
mcphost は、エージェントが独自のツールを公開するリモート MCP サーバーです。エージェントはタスクの途中でツールを作成し、1回の呼び出しで公開して、そのまま作業を続けます。ツールは再起動もデプロイも不要ですぐに使えるようになり、作成した会話が終わった後も存続します。あなたが眠っている間にスケジュールで実行したり、別のエージェントと共有したりでき、実行のたびに内容を確認できるログが残ります。
内部では、mcphost serve は単一の Rust バイナリで、1つのエンドポイントでストリーミング可能な HTTP MCP を提供します。すべてがツール呼び出しです。公開、実行、スケジュール設定、ログ記録、計測、シークレットの保存、別のエージェントとの共有、OAuth を介したエンドユーザーの代理操作ができます。ダッシュボードはありません。/status が唯一のページで、運用者は同じエンドポイント上の admin.* ツールを使って操作します。
実測値であり、約束ではありません。エラーゼロで同時に200件の呼び出しを処理した際の p95 は34.2ミリ秒です。この結果は測定テストとともにコミットされています。公開サイトは mcphost.dev です。機械可読な概要 /llms.txt は、以下のクイックスタートと同じソース(docs/agent-quickstart.md、scripts/gen-agent-docs.sh)から生成されています。
接続
クライアントに1行貼り付けるだけで、mcphostを利用できます。エージェントが最初に呼び出すと、その接続上でアカウントが作成されます。サインアップフォームも、貼り付けるキーも必要ありません。
Claude Code
claude mcp add --transport http mcphost https://mcphost.dev/mcp
ドキュメント:https://code.claude.com/docs/en/mcp(2026-10-09 確認)
Cursor
Cursorに追加するか、MCP設定に https://mcphost.dev/mcp を直接追加してください。
ドキュメント:https://docs.cursor.com/en/tools/mcp(2026-10-09 確認)
VS Code
VS Codeに追加するか、MCP設定に https://mcphost.dev/mcp を直接追加してください。
ドキュメント:https://code.visualstudio.com/api/extension-guides/ai/mcp(2026-10-09 確認)
VS CodeのGitHub Copilot
{
"servers": {
"mcphost": {
"type": "http",
"url": "https://mcphost.dev/mcp"
}
}
}
ドキュメント:https://code.visualstudio.com/docs/agent-customization/mcp-servers(2026-10-21 確認)
Claude.ai
- Settingsを開き、Connectors、Add custom connectorの順に選択します。
- 名前:mcphost
- リモートMCPサーバーのURL:https://mcphost.dev/login/mcp
- 保存し、チャットでコネクターを有効にして接続します。
ドキュメント:https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp(2026-10-09 確認)
ChatGPT
- ChatGPTを開き、Plugins、Addの順に選択します。
- Create custom MCP serverを選択します。
- 名前:mcphost
- MCPサーバーのURL:https://mcphost.dev/login/mcp
- OAuthを選択し、Createを選択します。同意ページでCreate a new workspaceを押します。
ドキュメント:https://platform.openai.com/docs/mcp(2026-10-09 確認)
Codex CLI
codex mcp add mcphost --url https://mcphost.dev/mcp
ドキュメント:https://developers.openai.com/codex/mcp(2026-10-09 確認)
Gemini CLI
gemini mcp add --transport http mcphost https://mcphost.dev/mcp
ドキュメント:https://geminicli.com/docs/tools/mcp-server/(2026-10-09 確認)
OpenCode
opencode mcp add mcphost --url https://mcphost.dev/mcp
ドキュメント:https://opencode.ai/docs/mcp-servers/(2026-10-09 確認)
Amp
amp mcp add mcphost https://mcphost.dev/mcp
ドキュメント:https://ampcode.com/manual#mcp(2026-10-09 確認)
Goose
- Gooseのセッションで、/extensionと入力します。
- Add Remote Extension (Streamable HTTP)を選択します。
- 名前:mcphost
- エンドポイントURL:https://mcphost.dev/mcp
ドキュメント:https://goose-docs.ai/docs/getting-started/using-extensions/(2026-10-09 確認)
Warp
- Warpのエージェントセッションで、/agent-add-mcpと入力します。
- 次のサーバー設定を貼り付けます:{"mcphost":{"url":"https://mcphost.dev/mcp"}}
- 保存すると、Warpがサーバーを起動し、そのツールを一覧表示します。
ドキュメント:https://docs.warp.dev/agents/capabilities/mcp/(2026-10-09 確認)
Windsurf
{
"mcpServers": {
"mcphost": {
"url": "https://mcphost.dev/mcp"
}
}
}
ドキュメント:https://docs.windsurf.com/windsurf/cascade/mcp(2026-10-09 確認)
Cline / Roo
{
"mcpServers": {
"mcphost": {
"type": "streamableHttp",
"url": "https://mcphost.dev/mcp"
}
}
}
ドキュメント:https://docs.cline.bot/mcp/configuring-mcp-servers(2026-10-09 確認)
SDK
{
"name": "mcphost",
"type": "url",
"url": "https://mcphost.dev/mcp"
}
ドキュメント:https://platform.claude.com/docs/en/agents-and-tools/mcp-connector(2026-10-21 確認)
本番トラフィックを向ける前に、最新のステータスページと
利用規定をご確認ください。プランと制限については、プラン / /plans.json
(billing.plansが返す値およびdocs/plans.mdと同じ数値)をご覧ください。すべてのエラーペイロードには、その内容を説明する生成済みの/help/<code>ページを示す
help_urlが含まれています。
サポート:サポートチャンネルは設定されていません(MCPHOST_SUPPORT_URLが未設定です)。
変更履歴
すべてのリリースはgitタグで管理され、すべての変更はCHANGELOG.mdに記載されています。
デプロイプロジェクトではなく、MCPツールをリリースしましょう。
mcphostを使えば、エージェントは人の介在なしに、タスクの途中で必要なツールを作成できます。認証不要のツール呼び出し1回でサインアップし、次の呼び出しで公開すれば、新しいツールがすぐに利用可能になります。再起動も、デプロイも、レビュー待ちもありません。
実測値(パネル実行 0.26.3-20260908T085001Z、21セッション):サインアップからテナントの最初のhost.tool.publish成功までの時間の中央値は30.7秒です。サインアップから、そのテナント独自のツールの呼び出しが成功するまでの時間の中央値は42.4秒です。
エージェント向けクイックスタート
https://mcphost.dev/mcpに接続します。その URL を MCP クライアントの設定に貼り付けてください。サインアップの呼び出しも、認証情報も、ヘッダーに貼り付けるものも必要ありません。- 最初の呼び出しを行います。
host.quickstart()は読み取り専用で、何かを確定する前に実例を返します。それ以外のhost.*/billing.*の呼び出しでは、この接続上でその時点でテナントが作成されるため、signupの呼び出しは一切不要です。最も簡単なのはhost.whoami()です。host.whoami() - 同じレスポンス内の
onboarding.urlを一度読み取り、保存します。これはこのテナント専用のアドレスであり、同時にその認証情報でもあります。後でこの URL を使って再接続すれば、同じテナントとして戻れます。onboarding.memory_hintには、エージェントが慣例的に保存する場所が示されています。 再接続のルール:同じ接続で後からキーなしで呼び出すと、すでに所属しているテナント(tenant_key_missingのレスポンスにあるdata.tenant)を示して拒否されます。2 つ目のテナントが作成されることはありません。以降のすべての呼び出しにはonboarding.urlを使ってください。 onboarding.urlを使って再接続し、ツールを公開します。host.quickstart()が返すstarter_toolは、すぐに公開できるpython仕様です。そのpublish_callは次のとおりです。
実際に使える種類は 3 つです。コードを送信する場合は(host.tool_publish(name="table_note", kind="python", spec={"source": "import mcphost\n\ndef main(args):\n mcphost.table.create(name='quickstart_notes', columns={'note': 'text'})\n mcphost.table.append(table='quickstart_notes', rows=[{'note': args.get('note', '')}])\n return {'appended': 1}\n"})python:ソース必須。省略時はargs_schema/requirementsを推定します。js:main(args)を定義する JavaScript ソース。省略時はargs_schemaを推定します)、すでに使っている API をラップする場合は(http:url と method が必須。省略時はargs_schemaを推定します)。echoはパイプのテスト用スタブであり、実際のツールではありません。 公開する前に、host.tool_publish({..., dry_run: true})でドライランしてください。すべてのゲート(シークレット、環境変数、ネットワーク、依存関係、名前、種類、仕様のサイズ)が一度に報告され、ツールの行は書き込まれません。またはhost.spec_test(kind, spec, invocations)を使うと、実際の呼び出しと同じサンドボックスを通じて最大 5 件の呼び出し例をテストできます。- ツールを呼び出します。
host.tool_test(name, args)は公開済みのツールを名前でドライランします。または、ツールを<namespace>.<tool_name>として直接呼び出します(tools/listに独自のエントリがあります)。host.tool_test(name="table_note", args={"note": "hello"})try_before_call:host.tool_testではargsを省略できます。その場合、ホストはツール独自のスキーマから生成した呼び出し例を実行し、example_argsとして返します。 - チームメイトと共有します。
host.invite.create()は/i/<code>/mcpURL を返します。その URL から接続し、最初の呼び出しを行った人には、あなたとすでに連携した新しいテナントが作成されます。shareとして渡したツール名は、すでに共有されています(独自のキーを隠したまま 1 つのツールを共有する方法については、www/llms.txtの「キーではなくツールを共有する」を参照してください)。host.invite.create() - クレームリンクを人間に渡します。
onboarding.urlと「このバックエンドをクレームして、自分のものにしてください:<url>。」という文を渡してください。個人用 URL やキーは、この引き渡し以外の場所には決して表示しないでください。
最初の呼び出しの後に役立つ機能:プランとクォータの確認には billing.plans()/billing.status()、ツールの確認と管理には host.tool.list()/host.tool.logs(name)/host.tool.remove(name)/host.usage(window)、公開済みツールに必要な認証情報の設定と確認には host.secret.set/host.secret.list() を使います(シークレットは AES-256-GCM で暗号化して保存され、それ以外のすべてには別のプレーンな env マップを併用します)。
host.tool.share に expose_spec: true を渡す(または host.invite.create に share の名前を渡す)と、共有相手はツールを呼び出すだけでなく、そのソースも読めるようになります。ソースは host.tool.spec_shared(tool="<owner_namespace>.<name>") で読み取れます。expose_spec なしで共有した場合、同じ呼び出しは spec_not_exposed エラーになります(詳しい使用例は www/llms.txt の「キーではなくツールを共有する」を参照してください)。
host.tool.share では scopes(許可する操作:呼び出し、read_source、fork。デフォルトは ["call"]。URL での共有では call のみ許可)と rate_per_hour_per_caller も指定できます。fork 権限を持つ共有相手は host.tool.fork(owner, tool, as) でツールをコピーできます。また、host.tool.unshare の後は、過去に呼び出したユーザーの次の呼び出しが share_revoked エラーになります。
明示的なサインアップ(セッションを保持できないクライアント向け)
呼び出しの間に永続的な接続を維持できず、mcphost がテナントを暗黙的に紐付けるセッションがないクライアントは、最初の呼び出しでセッションを作成する方法に頼らず、直接サインアップします。
- エンドポイントに接続し、認証情報を指定せずに
tools/listを呼び出します。提供されるツールはsignupだけです。 signup(name)を呼び出します。応答にはtenant、key(一度だけ表示されるベアラートークン)、namespace、endpoint、claim_urlが含まれます。サインアップは IP アドレスごとに 1 時間あたり 5 回までに制限されています。どのチャネルからサインアップしたかを記録するには、source(例:signup(name, source: "hn"))を渡してください。推奨値はhn、reddit、discord、registry、plugin、docsです。この値は応答に含まれ、管理者向けの healthz でも個別に表示されますが、指定は必須ではありません。サインアップが一時停止中(不正利用の急増に対処するためのオペレーター用キルスイッチが有効な場合)は、呼び出しがsignup_pausedとretry_after_secsを返して失敗します。その場合は、しばらくしてから再試行してください。推奨:signup(name, handoff: true)を呼び出すと、keyの代わりに有効期限が短く、一度だけ使えるhandoff_tokenが返されます。host.redeem(handoff_token)を一度呼び出してキーを取得すれば、このやり取りのトランスクリプトに残る認証情報は使用できなくなります。キーが漏えいした疑いがある場合は、いつでもhost.key.rotateを呼び出すことで、現在のキーを無効にして新しいキーを発行できます。- 以降、すべての
host.*呼び出しで、keyをtenant_key引数として渡します(例:host.tool.publish、host.tool.call)。再接続やAuthorizationヘッダーは不要です。永続的な接続を維持できるクライアントは、代わりにAuthorization: Bearer <key>を使用できます。
利用終了
host.self.offboard() を呼び出すと、自分のテナントが完全に閉鎖されます。オペレーターへのチケットも、管理者キーも、引数も、確認フラグも必要ありません。サインアップに使用したのと同じ tenant_key 経由で利用を終了し、呼び出しは直ちに有効になります。
処理の内容と順序:pro プランを利用中の場合は、アクティブな Stripe サブスクリプションをキャンセルします。次にテナントを無効化します(以降、この tenant_key を使ったすべての呼び出し(host.* または billing.*)は、管理者によって無効化されたテナントと同じ tenant_disabled/tenant_key_invalid エラーになります)。その後、登録されている各種の処理に対し、ユーザーのために維持しているリソース(例:python サンドボックスのウォームプール)を破棄する機会を与えます。
この処理で行わないこと:データの消去です。監査のため、tools、secrets、signup_events、使用履歴はすべてそのまま残ります。これは、現在管理者によって無効化されたテナントに適用される保持期間とまったく同じです。利用を終了する前に作成したもののコピーが必要な場合は、先に host.export() を実行してください。self_offboard はコピーをまとめて提供しません。
取り消し不可について:2 回呼び出した場合はエラーやクラッシュではなく、{disabled: true, already_offboarded: true} が返されます。ただし、セルフサービスで取り消す方法はありません。キャンセルされた Stripe サブスクリプションはキャンセルされたままで、呼び出しが返された時点で tenant_key による認証はできなくなります。(オペレーターは admin.tenant_enable を使ってテナントの基盤となるレコードを再度有効にできますが、これはオペレーターがユーザーに代わって行う操作であり、self_offboard 自体が再有効化を提供するわけではありません。)
ヘルプを利用する
すべてのエラーペイロードには、code、簡潔なmessage、request_id、および(以下の表にあるすべてのコードについて)生成された/help/<code>ページを示すhelp_urlが含まれます。このページには意味、考えられる原因、修正方法が記載されており、内部向けのテキストはありません。
host.whoamiのlinksフィールドには同じsupport/plans/status/helpページが直接指定されているため、エージェントがページのリンクを作成するためにホストを推測する必要はありません。
インシデントが発生している間、ホスト障害によるエラー(storage、internal、exec_unavailable、timeout、rate_limited_host)には、data.incident {id, since, status_url, impact, retry_after_s}も含まれます。障害の原因はホスト側であり、あなた側ではありません。そのため、retry_after_sの秒数だけ待ってから一度だけ再試行し、呼び出しを繰り返す代わりにstatus_urlを報告してください。あなた自身に起因するエラー(tool_exception、args_invalid)には含まれません。5xx HTTPレスポンスには、同じ秒数がRetry-Afterに含まれます。
サポート:サポートチャンネルが設定されていません(MCPHOST_SUPPORT_URLが未設定です)。
必要だったことをホストに伝える
host.feedback.send {kind, text, context?}を使うと、ホストの担当者にメッセージを送信できます。サインアップ前でも利用できます。種類:missing_tool、wrong_error、docs_gap、bug、praise。textは1~2048バイトです(これを超えるとmax_bytesを伴うinvalid_paramsになります)。contextは最大1 KBの任意のオブジェクトです。戻り値はfeedback_idです。匿名の送信者はIPアドレスごとに1時間あたり5件、キーが割り当てられたテナントは1時間あたり60件送信できます。上限を超えるとretry_after_sを伴うrate_limitedになります。host.feedback.listは自分の送信内容を返します。
別のエージェントに作業を渡す
host.task.post {to, payload, deadline_s, dedupe_key?}は1つのエージェントにタスクを送信し、task_id、thread_id、statusを返します。受信側のhost.msg.waitはタスクをdata.task.task_idとともに返します。受信側はhost.task.claim {task_id}を呼び出し、続いてhost.task.complete {task_id, result}を呼び出します。すると、あなた自身のhost.msg.waitが、ステータスと結果を持つdata.taskを含むメッセージを返します。host.task.get {task_id}は1つのタスクを読み取ります。deadline_sまでに誰も完了しなかったタスクはdeadになり、task.deadメッセージがhostからスレッドに届き、host.task.dead_lettersにはreason: "deadline"とともに一覧表示されます。ステータス:posted、claimed、done、dead、cancelled。completeを繰り返し呼び出すと、already_complete: trueとともに保存済みの結果が返されます。
サブエージェント
- リードとして、
host.key.delegate{"can_delegate":true,"label":"helper","scopes":["tools:call"],"ttl_s":3600}を呼び出すと、keyとlabelが返されます。 - ヘルパーとして、呼び出し1で返された
keyを使い、host.key.delegate{"scopes":["read","write","tools:write","state:read","state:write","secrets:write","keys:manage","admin"],"ttl_s":60}を呼び出すと、scope_escalationで失敗します(read、write、tools:write、state:read、state:write、secrets:write、keys:manage、adminを要求しています)。 - リードとして、
host.key.revoke{"cascade":true,"label":"helper"}を呼び出すと、revokedの値は1以上になります。 ヘルパーには、呼び出し1で返されたkeyを渡してください。自分自身のキーは決して渡さないでください。ヘルパーが保持するのはtools:callのみです。呼び出し2のとおり、それ以外のスコープはscope_escalationで失敗します。 呼び出し3はヘルパーとその子キーを取り消します。ヘルパーの次の呼び出しはkey_revokedで失敗します。
貢献:新しいhost.*ツールの命名
ルールは1つだけです。host.<family>.<verb>という形式で、文書化され、CIで適用されます。ルール、例外(signup/billing.*、およびhost.whoamiなどの単独の名詞)、エイリアスの動作については、docs/tool-naming.mdを参照してください。host.tool.call/host.tool.share/host.tool.list/host.tool.remove/host.tool.logs/host.tool.rollback/host.tool.diff/host.tool.history/host.tool.unshareや、その他のルール制定前のアンダースコア付きの名前(mcphost-polish-p0-20260930 audit finding 5)は、もはや命名のばらつきではありません。それぞれがドット区切りの正規名(host.tool.call/host.tool.share/...)で登録され、旧名でも非推奨エイリアスとして引き続き利用できます(終了日はtools/list自身のx-deprecatedに記載)。scripts/tool-naming-lint.shは、新たに追加された名前がルールに従っていない場合、CIを失敗させます。
新しいトップレベルパスのルーティングに関するコントリビュート
このリポジトリに新しいトップレベルディレクトリまたはファイル(www/、deploy/、.buildloop/ など)を追加する場合は、そのパスを追加する同じ PR で、agent/proof-lanes.toml に対応する [[lane]] エントリーが必要です。ブランチゲートのルーティングチェックである autobuilder vti-plan は、どのレーンにも割り当てられない変更パスを拒否します。また、tests/lanecov_ac01_every_tracked_path_routes.rs
は cargo test を通じてローカルでも同じルールを適用するため、レーンがない場合は、そのパスが main に取り込まれたあとにすべてのブランチゲートが赤になるのではなく、すぐに失敗します。レーンには id、そのパスが存在する PRD または理由を示す1行の description、新しいパスを対象とする globs(ディレクトリの場合は "<dir>/**")、そして required_commands を指定してください。required_commands には、そのパスの変更を実際に検証できる最も低コストのコマンドを指定します。必ずしもテストスイート全体である必要はありません。.buildloop/** を cargo test --workspace にルーティングする loop-config レーンが実例です。1つの glob と1つの必須コマンドを、そのパスが必要になった PR で追加しています。
1分でできるドキュメントのQ&A
Markdown のフォルダーを、確認可能なQ&Aツールにエンドツーエンドで変換するスクリプトです。
signup(name)— 新しいテナントを1つ作成します。host.docs.put(name, content)— ドキュメントごとに1回実行します(このレシピで使うコーパスは8件、合計約22 KiBで、ドキュメントごとの上限2 MiBを大きく下回ります)。host.docs.status()—index.lag_seconds == 0になるまでポーリングします(通常、インデクサーの10秒間隔の処理が1〜2回行われます。このレシピのコーパスは30秒以内に準備できます)。<namespace>.ask_docs(query="...")— 質問します。結果内の各文章にはname:offsetの引用情報(ドキュメント名と、そのドキュメント内の文字オフセット)が付くため、回答をソースと照らし合わせて確認できます。host.tool_publish(name="ask_docs", kind="python", spec={"source": ...})— 公開するツールはこれ1つです。そのmainは、同じネットワーク通信のないサンドボックスのループバックを介してmcphost.docs.search(query, k)を呼び出します。mcphost.docs.getもこのループバックを使うため、質問に回答する際に公開ツール呼び出しを消費することはありません。
このレシピで使用するクォータ:ドキュメント8件、約22 KiB、約30チャンク、公開ツール1つ、そのツールを最大10回呼び出します。無料プランの docs_max(200)と calls_per_day(500)の範囲に十分収まります。
examples/docs-qa/docs-qa.sh <endpoint> は、このレシピを実際のエンドポイントに対してエンドツーエンドで実行し、レシート(質問ごとのヒットと引用情報、index_ready_secs、実際に使用したクォータ)を出力します。
examples/docs-qa/ask_docs.py がツール本体で、examples/docs-qa/corpus/ には8件のドキュメントと6件の正解質問が含まれています。docs-qa.sh --embeddings <provider-endpoint> <model> <secret-name> は、先に埋め込みプロバイダーを設定し、レシートに語彙検索と埋め込みの両方のヒット率を記録します。
運用とコントリビュート
以下はすべて、自分の mcphost を実行したり、このプロジェクトを変更したりする場合の内容です。インストール、環境、種類、制限、使用量の計測、合成テナント、受け入れテストスイートを扱います。
インストール
cargo install --path .
または、ローカルでビルドします。
cargo build --release
./target/release/mcphost serve
環境の仕様
| 変数 | 意味 | デフォルト |
|---|---|---|
MCPHOST_DATA_DIR | mcphost.db(SQLite、WAL)を格納するディレクトリ | ./data |
MCPHOST_BIND | リッスンする host:port | 127.0.0.1:8080 |
MCPHOST_PUBLIC_URL | signup がエンドポイントとして返す URL | http://<bind> |
MCPHOST_ADMIN_KEY | admin.* ツールのロックを解除する Bearer キー | 未設定(admin ツールにはアクセスできません) |
MCPHOST_SECRET_KEY | テナントのシークレット用に AES-256 キーへ SHA-256 で変換されるパスフレーズ | 開発用デフォルト(本番環境では実際の値を設定してください) |
MCPHOST_LOG_LEVEL | tracing フィルター。例:info | info |
MCPHOST_REGISTRY_URL | host.registry_publish(P1)を有効にし、レジストリ API のベース URL を指定します。mcphost serve --registry-url <url> が優先されます | 未設定(registry-publish は無効) |
MCPHOST_SIGNUP_RATE_LIMIT_PER_HOUR | 接続元 IP ごとの signup レート制限を上書きします(PRD-mcphost-signup-rate-configurable)。1 つの IP から複数セッションの計測を実行する場合は値を増やしてください。未設定または整数以外の場合はデフォルト値が使われます。有効な値は起動時に一度ログに記録されます。MCPHOST_FLEET_IPS に設定された接続元 IP は、この制限の対象外です | 5 |
MCPHOST_EGRESS_PROXY | オペレーターの外向き HTTP(S) プロキシの http(s)://host:port。network: "public" または "egress" を指定して公開された pro テナントの python/wasm ツールが、サンドボックスでネットワークを利用するために必要です。詳しくは以下の「エグレスプロキシ」を参照してください | 未設定(pro テナントは外向きネットワークを利用できません) |
MCPHOST_FLEET_IPS | このオペレーターのフリートがサインアップする IPv4/IPv6 アドレスまたは CIDR ブロック(例:46.225.110.44,178.105.64.66,10.0.0.0/8)をカンマ区切りで指定します。接続元 IP が一致するサインアップには、x-mcphost-synthetic ヘッダーがなくても source_class: fleet(synthetic: harness:fleet-ip)が設定されます。無効なエントリはログに記録され、無視されます。この変数より前のサインアップを遡って更新するには、admin.reclassify_fleet_ips を参照してください | 未設定(IP アドレスだけで fleet に分類されることはありません) |
mcphost migrate は保留中の SQL マイグレーションを適用して終了します。mcphost version
はバージョンを出力して終了します。mcphost serve --registry-url <url> は、上記の
MCPHOST_REGISTRY_URL を CLI フラグで指定する形式です。
エグレスプロキシ(network: "public"/"egress")
free テナントは、network: "public" または "egress" を指定したツールを公開できません。どちらの表記も同じサンドボックスアクセスを許可しますが、host.tool_publish では pro と network フィールドを示す plan_required エラーで拒否されます。pro テナントは公開できますが、このホストで $MCPHOST_EGRESS_PROXY が設定されていない限り、呼び出し時にサンドボックスから外向きネットワークを利用することはできません。未設定の場合、サンドボックス化されたプロセスが起動される前に、呼び出しは egress_unavailable エラーで失敗します。所有者が pro のときに public/egress を宣言した既存ツールは、テナントが free にダウングレードした時点で plan_required エラーになり、ネットワークなしへ黙ってダウングレードされることはありません。エラーでは、再公開時に network: "none" を指定するか、pro にアップグレードし直すよう案内されます。
プロキシが設定されている場合、pro テナントのエグレス呼び出しは --share-net を指定して実行されます(外向きネットワークはホスト自身のネットワーク名前空間を共有します)。また、サンドボックス化されたプロセスの環境変数には http_proxy/https_proxy/HTTP_PROXY/HTTPS_PROXY に $MCPHOST_EGRESS_PROXY が設定され、さらに no_proxy="" も設定されます。これにより、オペレーターの環境に存在する NO_PROXY が原因で、サンドボックス化されたプロセスがプロキシを迂回することを防ぎます。このクレートにはプロキシ自体は含まれません(その設定は mcphost-deploy が管理します)。ここで保証するのは「プロキシがなければ、ネットワークもありません」という点だけです。デプロイするプロキシでは、転送するすべての接続に対し、プライベート/リンクローカルアドレスの拒否リストを適用する必要があります。対象の範囲は、レンダリングされたリクエスト URL に対して http 種別独自の VettingResolver がすでに拒否しているものと同じです。
- RFC 1918 プライベート範囲(
10.0.0.0/8、172.16.0.0/12、192.168.0.0/16) 169.254.0.0/16(リンクローカル。クラウドメタデータアドレス169.254.169.254を含む)127.0.0.0/8(ループバック)および::1fc00::/7(IPv6 のユニークローカルアドレス)
レジストリへの公開(P1)
デフォルトでは無効です。--registry-url / $MCPHOST_REGISTRY_URL にレジストリ API のベース URL(レジストリ自体のベース URL)を指定すると、次のようになります。
- 運用者は、信頼できる任意の方法でテナントのドメイン名前空間を検証します(PRD では、検証 METHOD 自体(DNS と HTTP レコードのどちらにするか)は Joe が担当する未決事項であり、このクレートでは実装しません)。検証結果は
admin.tenant_verify_namespaceで記録します。admin.tenant_verify_namespace(tenant="t_xxxxxxxx", domain_namespace="io.github.example.myserver")。 - その後、テナントは
host.registry_publish()(引数なし)を呼び出せます。この関数はserver.jsonドキュメント(name/description/version/remotes: [{type: "streamable-http", url}])を<registry-url>/v0/publishに POST し、同じドキュメントは認証なしでGET /.well-known/mcp/<namespace>/server.jsonから配信されるようになります。 host.registry_publishは、data.error_codeに機械可読な個別のエラーを返して拒否します。エラーはregistry_disabled(フラグがオフ)、namespace_unverified(このテナントについて手順 1 が未実施)、registry_rejected(レジストリ API が非 2xx を返した)のいずれかです。
このホスト独自のレジストリ掲載情報
上記の「レジストリへの公開(P1)」とは異なり、これはテナント自身の名前空間を対象とするテナント向けツールではなく、mcphost 自体の掲載情報です。
mcphost registry-manifest は、Cargo.toml(DNS 検証済みの dev.mcphost 名前空間における名前、説明、バージョン、ライセンス)と $MCPHOST_PUBLIC_URL(デフォルトは https://mcphost.dev)+ /mcp を streamable-http リモートとして使用し、公開 MCP レジストリ用の server.json エントリーを生成します。
- フラグなし:エントリーを標準出力に出力します。
--write <path>:エントリーを書き込みます(コミット済みのregistry/server.jsonの再生成に使用します。手動編集はしません)。--check:コミット済みファイル(デフォルトはregistry/server.json)を新たに生成した内容と比較し、差分があれば差分を出力してゼロ以外の終了コードで終了します。ただし、versionフィールドは無視します。リリースを取り込む際はregistry/server.jsonをコミットし、その後にのみCargo.tomlのバージョンを更新するため、コミット済みファイルのバージョンは、PRD の取り込みから次のタグ付けまで意図的に古いままになります。このファイルだけを理由に--checkが毎回の取り込みで失敗することを避けるためです。それ以外の差分(説明、名前、ライセンス、リポジトリ、リモート)があれば、これまでどおり--checkは失敗します。
.github/workflows/registry.yml は、プッシュごとに --check と、固定された registry/schema.json に対するスキーマ検証を実行します。また、v* タグでは、MCPHOST_REGISTRY_PRIVATE_KEY リポジトリシークレット(レジストリ公開用 CLI の dev.mcphost ドメイン名前空間 DNS ログインキー)を使ってレジストリに公開する前に、registry/server.json を --write で再生成します。これにより、リポジトリ内のコミット済みコピーのバージョンは古いままでも、公開されるエントリーには実際のタグ付け済みバージョンが含まれます。
種類
以下に示す各登録済み kind の最小限のサンプル仕様と、host.tool_publish のオンワイヤー説明(サインアップ前に tools/list から確認可能)は、どちらも同じ docs/kinds/*.md ファイルから生成されます(PRD-mcphost-publish-first-try の要件 6)。tests/publishfirsttry_ac06_docs_shared_source.rs はこれらのファイルからこのセクションを再生成し、チェックイン済みの以下の内容と差異がある場合は CI を失敗させます。自分の名前空間をあらかじめ入力した同じ例を使うには、host.quickstart(kind) を呼び出してください。
echo
spec.schema は任意の JSON Schema です。呼び出すと、与えられた引数をそのスキーマに照らして検証したうえで、そのまま返します。
仕様の例:
{
"schema": {
"properties": {
"msg": {
"type": "string"
}
},
"required": [
"msg"
],
"type": "object"
}
}
呼び出し引数の例:
{
"msg": "hi"
}
http
url は絶対 https URL である必要があります。必須フィールドは method と url のみです。省略した場合、args_schema は url/header/body テンプレートから推論されます。
仕様の例:
{
"method": "GET",
"url": "https://api.example.com/items/{{id}}"
}
呼び出し引数の例:
{
"id": "123"
}
python
必須なのは source のみです。args_schema と requirements はどちらも source から推論されます(tool-infer、v0.4.0)。source では main(args) を定義する必要があります。
仕様の例:
{
"source": "def main(args):\n return {\"doubled\": args[\"n\"] * 2}\n"
}
呼び出し引数の例:
{
"n": 3
}
js
必要なのは source のみです。args_schema は、source 内の args.<name> の読み取り(および JSDoc の @param {type} args.<name>)から推論されます。source では function main(args)(または export default)を定義する必要があり、通常の JavaScript(ES2020)として、python と同じサンドボックス内で QuickJS により実行されます。
仕様の例:
{
"source": "function main(args) {\n return { total: args.items.reduce((a, b) => a + b.price, 0) };\n}\n"
}
呼び出し引数の例:
{
"items": [
{
"price": 2
},
{
"price": 5
}
]
}
wasm
component は、call: func(args: string) -> result<string, string> をエクスポートする base64 エンコード済み WebAssembly コンポーネントです(コアモジュールではなく、component-model です)。args_schema は省略可能です(デフォルトでは任意のオブジェクトを受け入れます)。
仕様の例:
{
"component": "AGFzbQEAAAAA"
}
呼び出し引数の例:
{
"msg": "hi"
}
Python 仕様言語に関する注意事項
PRD-mcphost-python-kind-runtime(AC6):host.tool_publish を制御する AST チェックは、代入式(:=、PEP 572)を一般に受け入れます。CPython は 3.8 以降、これを解析できます。また、mcphost の公開時チェックとツール独自のランタイムはいずれも同じ CPython 文法で source をコンパイルするため、mcphost が追加した緩和すべき制約はありません。拒否されるものは、Python 自身の文法による制約です。代入式のターゲットは単純な名前でなければなりません。
(obj.attr := 1) と (d[key] := 1) はどちらも無効な Python 構文(cannot use assignment expressions with attribute/...with subscript)であり、mcphost が事前に検証するかどうかにかかわらず、同じように失敗します。ツール独自の main(args) は解析すらできません。これはバリデーターではなく実行機能レベルの問題なので、mcphost で緩和できるものはありません。今回の修正では、公開時の拒否メッセージに構文と使用可能な代替手段を一文で示します(まず単純な名前に代入し、その後、別の文で属性または添字を設定します)。これにより、CPython の生の文法エラーメッセージに説明を委ねることはありません。
呼び出し制限
PRD-mcphost-call-limits-honest:ここに記載する各制限は、コードが実際に適用する値です。tests/limits_ac06_quickstart_docs_match_constants.rs は、このセクションと www/llms.txt の「制限と料金」セクションを、host.quickstart の limits オブジェクトが読み取る同じ定数と照合します。
- 呼び出しタイムアウト:デフォルトは 30 s です。独自の
timeout_sを指定する場合は最大 60 s です。timeout_sを宣言した python 仕様には、より短い期限が内部で黙って適用されるのではなく、指定どおりの期限が設定されます(ホスト側の最大値 60 s が上限です)。call_timeoutは実際に適用された期限を示します。 - 出力サイズ:ツールの出力は最大 1 MiB です。上限を超えると、
tool_output_invalidによる単なる解析エラーではなく、limit_bytesと生成されたactual_bytesを示すtool_output_too_largeが返されます。 - リクエスト本文:最大 1 MiB です(これを超えると HTTP 413 が返されます。
tests/ac16_request_body_too_large.rsを参照してください。この AC 自体の説明にある「2 MiB」は 1 MiB の上限を実証するために使われる、上限超過のテスト用ペイロードであり、上限そのものではありません)。 - 同時実行数:ホスト全体で同時に 20 件までです。テナントごとの上限は、無料プランでは 4 件、pro では 10 件です。自分のテナントの上限を超えたために拒否されると、
in_flight、limit、scope: "tenant"、retry_after_msを含むconcurrency_exceededが返されます。ホスト全体の上限を超えた場合はscope: "host"になります。 - サンドボックスプロセス上限:python ツールのサンドボックスで実行できるプロセスは最大 64 個です。これを超えるフォークは、無言のハングや不明瞭な OS エラーではなく、構造化された
tool_process_limitエラーで失敗します。
従量課金の超過分(billing emit-meter)
PRD-mcphost-metered-overage:pro テナントのプランに含まれる月間 50,000 回の呼び出しを超えた成功呼び出しは、Stripe の mcphost_tool_calls メーターと段階制の従量課金価格を通じて課金されます。~/.config/mcphost/stripe-objects.json の値を使って、次の環境変数を設定します(未設定の場合は v0.14.0 と同じ動作となり、メータリングも meter_lag も発生しません)。
MCPHOST_STRIPE_METERED_PRICE_ID—billing.checkoutが基本価格とともに設定する従量課金価格 ID です。MCPHOST_STRIPE_METER_EVENT_NAME— デフォルトはmcphost_tool_callsです。
次に、タイマーで mcphost billing emit-meter を実行します(同梱のデフォルトでは 5 分ごと)。このコマンドは、未送信の pro テナントの ok 呼び出しを読み込み、テナントごとに Stripe のメーターイベントを 1 件ずつ POST し(1 リクエストあたり 100 件に分割)、各バッチを台帳に記録します。実行中のすべてのイベントが受理された場合にのみ、独自の高水位マークを更新します。そのため、クラッシュや POST の失敗後も安全に再実行できます(再生/冪等性の仕様については src/metering.rs のドキュメントコメントを参照してください)。
同梱の systemd ユーザーユニットをインストールします(~/.config/systemd/user/。このホストの他の mcphost-* ユニットに合わせています)。
cp deploy/mcphost-emit-meter.service deploy/mcphost-emit-meter.timer \
~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now mcphost-emit-meter.timer
mcphost-emit-meter.service は、MCPHOST_DATA_DIR/MCPHOST_STRIPE_SECRET_KEY/上記 2 つの変数を ~/.config/mcphost/emit-meter.env から読み込みます(EnvironmentFile=- を使用するため、ファイルがなくてもエラーになりません)。
両方のユニットファイルは systemd-analyze verify --user に合格します(AC9、tests/metering_ac09_deploy_units_verify.rs)。
/healthz の meter_lag フィールド(MCPHOST_STRIPE_METERED_PRICE_ID が設定されている場合のみ存在)は、高水位マークをまだ超えている pro テナントの ok 呼び出し数です。送信状況をひと目で確認するには、この値を監視してください。
合成テナント(admin.*_synthetic)
PRD-mcphost-synthetic-flag:テストハーネスが作成するテナントは、登録時から自由形式の synthetic ラベル(例:synthorg:<run_id>)を持ちます。ハーネスが signup 呼び出しで x-mcphost-synthetic: <label> を送信して設定します。動作には変更がなく、メタデータのみです。/healthz の tenants_real/tenants_synthetic の内訳と、admin.tenants の synthetic フィルター(true/false/all、デフォルトは all)はこの列を参照するため、synthorg candidates --measure でパネルのトラフィックを「実テナント」の根拠から除外できます。
既存のテナント集計データをバックフィルする方法(すべてのテナントはこの列が追加される前から存在するため、タグ付けするまではすべて synthetic: null として読み込まれます):admin.tenants_set_synthetic を使います。適用する dry_run: false を実行する前に、dry_run: true でプレビューしてください。このホスト自身の集計データで使った手順は次のとおりです。
admin.tenants_set_synthetic(name_like: 'joe-%', label: 'operator', dry_run: true)
admin.tenants_set_synthetic(name_like: 'joe-%', label: 'operator', dry_run: false)
admin.tenants_set_synthetic(name_like: '%', label: 'synthorg:backfill-20260906', dry_run: true)
admin.tenants_set_synthetic(name_like: '%', label: 'synthorg:backfill-20260906', dry_run: false)
まず joe-* の処理を実行してください。先に実行しないと、2 回目のより広い % パターンによって、これらの行のラベルも上書きされてしまいます。後の呼び出しで再タグ付けされたテナントには、その呼び出しのラベルが設定されます(設計上、「すでにラベル付け済みならスキップ」するガードはありません。ラベルを修正する方法は再タグ付けだけです)。admin.tenant_set_synthetic(tenant, label) を使えば、いつでも単一のテナントを修正できます(label: null でラベルを消去します)。
受け入れ基準
P0 の受け入れ基準はすべて、実際の cargo test と対応しています(tests/ の統合テストでは、一時的な $MCPHOST_DATA_DIR を使って一時ポートでサーバーを起動します)。ただし AC11 はハードウェアに依存するため、以下にスモークテストの結果を記録しています。
サンドボックススイート:ユーザー名前空間の要件
python 種別のサンドボックススイート(tests/sandboxready_*、python_ac*、
infer_ac*、warmpool_ac*、ac17_kind_conformance)は、実際の bwrap/
unshare による隔離を起動するため、実行には非特権ユーザー名前空間が必要です
(unshare --user --map-root-user -- true が成功する必要があります)。お使いの
環境でこれが拒否される場合(Ubuntu の一部カーネルにおけるデフォルトの AppArmor
ポリシー、一部のコンテナーランタイムなど)、CI 外で cargo test を実行すると、
仕様によりエラーで停止し、修正方法が示されます。古いカーネルでは
sysctl kernel.unprivileged_userns_clone=1、Ubuntu 24.04 以降では
sysctl kernel.apparmor_restrict_unprivileged_userns=0 を指定してください。
完全な要件については sandbox::require_user_namespaces_or_ci_skip のドキュメント
コメントを、ホスト型 CI ランナーがサイレントにスキップする代わりに同じ機能を
どのように許可するかについては .github/workflows/ci.yml を参照してください
(PRD-mcphost-ci-sandbox-coverage)。
CI では、これらのスイートを独立した sandbox ジョブとして、コアジョブ
(静的解析用の core-static、それ以外を実行する core シャードマトリクス、
および「static analysis + core suites」という名前の gate 集約ジョブ)と並行して
実行します(以下の「コアスイートもシャーディングされています」を参照)。スイートが
スキップされなくなった後、単一の cargo test --workspace ステップの所要時間は
313~336 秒となり、300 秒の予算を超えました。どのスイートのバイナリをどこで
実行するかは手動で列挙せず、導出されます。scripts/ci-test-partition.sh core|sandbox
が、サンドボックス実行の対象範囲に触れるかどうかによって、すべての
tests/*.rs ファイルを分類します(PRD-mcphost-test-suite-consolidation により、
ユニットテストの Cargo リンクは「ファイルごとに 1 つのバイナリ」から、
少数の tests/suite_<core|sandbox>_NN.rs バイナリへと移行しました。以下の
「テストの追加」を参照してください。そのため、パーティション分けの単位は
ファイル→バイナリではなく、ファイル→スイートです)。check は、両方のレベルで
分割に漏れや重複がないことを検証します。さらに、どちらのジョブもログ内に機能の
スキップがあれば失敗するため、ファイルを誤った側に分類すると、テストが実質的に
何も実行せず成功するのではなく、CI が失敗します。
サンドボックスジョブは位置ではなくコストに基づいて均等化したシャードのマトリクス
です(PRD-mcphost-ci-sandbox-shards-balanced)。scripts/ci-suite-weights.json には、
最新の CI 成功実行の finished in 行から取得した、サンドボックススイートの各
バイナリと --lib の実行秒数が記録されます。ci-test-partition.sh は、実行時間の
長いスイートから順に、最も負荷の軽いシャードへ配置します。シャード数は
SANDBOX_SHARDS で一元管理され(ci-test-partition.sh shards が出力します)、
ワークフローの plan ジョブがそこからマトリクスとジョブ名を作成します。重みを
更新するには、シャードのステップで出力される
suite=<name> measured=<s>s recorded=<s>s の各行(シャードの実行時間が 240 秒に
達した場合に出力されます)から、各スイートの finished in 秒数をコピーします。
ci-test-partition.sh check はこのファイルを検証します。重みが設定されていない
サンドボックススイートや、予測される最長シャードが 240 秒を超える場合は、該当する
スイートとファイルを示して失敗します。各シャードはステップのサマリーに
build wall と run wall を報告します。予算の対象となるのは run wall のみで、
240 秒を超えると警告し、300 秒を超えると失敗します。
コアスイートもシャーディングされています(PRD-mcphost-ci-core-suites-sharded)。必須チェックの「静的解析 + コアスイート」は、コアのステップだけで13〜16分かかる単一の逐次ジョブだったため、main の実行時間は30分の上限に対して20〜30分に達していました。現在、静的ステップ(check、clippy、コントラクトスイート、doctest、deny、audit)は core-static にまとめられています。core は重みのバランスを取ったシャードのマトリックスです(ci-test-partition.sh core-shard <n> <of>。サンドボックスのシャードと同じ scripts/ci-suite-weights.json と、最も重いものから順に配置する方式を使用)。ジョブ gate は、両方が成功しない限り失敗する小さな集約ジョブとして、以前の名前を維持しています。そのため、ブランチ保護と .github/required-checks.toml に変更はありません(静的ジョブとシャードジョブには # required-checks: exclude マーカーが付いています)。コアのシャード数は一度だけ定義されます(ci-test-partition.sh shards core が CORE_SHARDS を出力)。check は、重みが設定されていないコアスイートを名指しするか、コアの最重量シャードの予測時間が420秒を超えると失敗します。各シャードはステップのサマリーに build wall、run wall と、スイートごとに1行の suite=<name> measured=<s>s recorded=<s>s を出力します(実行時間が540秒で警告、720秒を超えると失敗します。10-17 の低速なホストランナーでは、suite_core_08 の実測時間は559秒で、記録された375秒を上回りました)。テストが失敗すると、core shard N/M FAILED <test> の行にテスト名が表示されるため、gh run view --log-failed で確認できます。
テストの追加
tests/*.rs は、cargo がテストバイナリを検出する単位ではなくなりました(PRD-mcphost-test-suite-consolidation、2026-09-12)。Cargo.toml の autotests = false と、実際のファイルを #[path] でインクルードする少数の生成済み tests/suite_<core|sandbox>_NN.rs ファイルにより、target/debug/deps にテストファイルごとに約280 MBのバイナリが1つずつ作られるのを防ぎます。テストごとにファイル、名前、ACとの対応はそのまま維持され、リンク先の BINARY だけが変わりました。
テストを追加するには、これまでどおり tests/<name>.rs を追加します(命名規則は同じです。<prefix>_ac<N>_<description>.rs。共有ハーネスが必要な場合は mod common; を追加します)。その後、scripts/gen-test-suites.sh を実行してスイートにまとめます(またはCIに知らせてもらいます。ci-test-partition.sh check に組み込まれた scripts/gen-test-suites.sh --check は、忘れた場合に該当ファイルを正確に名指しして失敗します)。ジェネレーターはファイル名のプレフィックスに基づいて分類し、まずサンドボックスが必要なファイルとコアのみのファイルを分けます(そのため、1つのスイートに両方が混在することはありません。上記を参照)。また、新しいファイルにあるトップレベルの mod common;/mod ci_sandbox_support; の行が1つだけの場合、それを use crate::common;/use crate::ci_sandbox_support; に書き換えます(これらはファイルごとではなく、スイートごとに1回コンパイルされます)。それ以外の行は変更されません。tests/suite_*.rs ファイルを手動で編集しないでください。これらは完全に再生成されます。
単一のテストを名前で実行するには、フラグが1つ余分に必要になりました。cargo test --test suite_core_01 my_test_file:: -- --nocapture(cargo nextest run -E 'test(my_test_file::)' でも実行でき、スイート名は必要ありません)。cargo test --test my_test_file だけでは解決されません。このファイルは、もう独立した cargo ターゲットではないためです。
| AC | 要件 | テスト |
|---|---|---|
| 1 (P0) | 未認証の tools/list には signup のみが表示され、レスポンスには MCP-Protocol-Version が含まれます | tests/ac01_unauthenticated_lists_signup.rs |
| 2 (P0) | signup はキー/名前空間/エンドポイントを返し、キーはハッシュとしてのみ保存されます | tests/ac02_signup_creates_hashed_tenant.rs |
| 3 (P0) | テナントの tools/list には host.* が表示され、他のテナントのツールは表示されません | tests/ac03_tenant_lists_control_plane_only.rs |
| 4 (P0) | 公開、一覧表示、呼び出しの一連の処理が往復します | tests/ac04_publish_list_and_call.rs |
| 5 (P0) | テナント間の分離:B は A のツールを表示も呼び出しもできません | tests/ac05_cross_tenant_isolation.rs |
| 6 (P0) | ツールを削除すると、一覧から除外され、呼び出し時に tool_not_found になります | tests/ac06_remove_tool.rs |
| 7 (P0) | host.usage/admin.usage は呼び出し数と p50/p95 を報告します | tests/ac07_usage_metering.rs |
| 8 (P0) | admin.tenant_disable はキーを無効化し、テナントキーで admin.tenants を呼び出すと forbidden になります | tests/ac08_admin_disable_and_forbidden.rs |
| 9 (P0) | IP ごとの1時間あたり6回目のサインアップは rate_limited となり、テナントは作成されません | tests/ac09_signup_rate_limit.rs |
| 10 (P0) | 未登録の種類/無効な名前/サイズ超過の仕様は、それぞれ個別のエラーとなり、何も書き込まれません | tests/ac10_publish_validation_errors.rs |
| 11 (P0、非機能要件) | echo を200件同時に呼び出し、p95 < 50ms、エラー0件、RSS < 100MiB | tests/ac11_load_smoke.rs(#[ignore] 指定 — ハードウェアに依存します。cargo test --release --test suite_core_01 ac11_load_smoke:: -- --ignored --nocapture で実行)。ビルドマシンでの測定値:p95 = 34.20ms、エラー0件、RSS = 37.3MiB |
| 12 (P0) | synthorg consume --preflight <url> は終了コード0で終了します | tests/ac12_preflight.rs — 常時実行されるインプロセス部分では、run_preflight が行う同じ2つのリクエストをテストします。第2の部分では、利用可能な場合に実際の mcphost バイナリと synthorg CLI(単独のバイナリ、または uv run --project)を起動し、終了コードが0であることを検証します |
| 13 (P0) | Mcp-Name ヘッダーと本文の値が一致しない場合、本文の名前で記録され、フラグが付けられます | tests/ac13_mcp_name_mismatch_metering.rs |
| 14 (P0) | 書き込み不可のデータベースでは storage エラーが発生し、/healthz は db_ok: false を返し、プロセスは稼働を続けます | tests/ac14_storage_unwritable.rs |
| 15 (P0) | 完了しない呼び出しは期限でタイムアウトし、Future は破棄されます | tests/ac15_call_timeout.rs |
| 16 (P0) | 1 MiB の上限を超えるリクエスト本文(2MiB の本文で確認)は、HTTP 413 で拒否されます | tests/ac16_request_body_too_large.rs |
| 17 (P0) | Kind 適合性スイートでは echo が合格し、不正なスキーマの describe は名前を示して失敗します | tests/ac17_kind_conformance.rs(再利用可能なチェッカーは mcphost::kinds::conformance) |
| 18 (P1) | tools/list には ttlMs/cacheScope が含まれ、公開から60秒以内は ttlMs: 0 になります | tests/ac18_tools_list_ttl.rs |
| 19 (P1) | host.registry_publish() と /.well-known/mcp/<ns>/server.json | tests/ac19_registry_publish.rs(レジストリ API は wiremock でモックします。上記の「Registry publish (P1)」を参照してください。名前空間の検証方法は対象範囲外で、「verified」は管理者が設定するブール値です) |
関連するフリート開発
mcp-core(非公開リポジトリのため、公開リンクはありません)— 他の wintermute MCP サーバーが基盤として使用する、再利用可能な stdio JSON-RPC 2.0 MCP サーバーコア(Toolトレイトとserve_stdio)。ここでは再利用していません。mcphostはストリーム可能な HTTP サーバー(rmcp)であり、stdio サーバーではありません。また、ツールの構成は静的なToolトレイトをラップするmcp-coreとは異なり、動的(テナントごと、DB が基盤)です。共有コードではなく関連コードとして、PRD の技術的考慮事項に沿って記載しています。
ライセンス
MIT または Apache-2.0 のデュアルライセンスです。LICENSE-MIT と
LICENSE-APACHE を参照してください。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。