リモートMCPコネクタを作成する
ステートレスなStreamable-HTTP MCPサーバー(TypeScript、@modelcontextprotocol/sdk)を構築します。これはclaude.aiのカスタムコネクタとして動作し、オプションでインラインのビジュアルカード(MCP Apps)を備え、Vercel上にデプロイします。30以上のツールを備えた実際のプロジェクトで実証済みです。
テンプレートはこのファイルの隣にある templates/ にあります。詳細なメモは references/ にあります。ステップで必要になったときにのみ参照してください。
references/mcp-apps-cards.md— インラインカード:ui://リソース、postMessageプロトコル、CSP、クリック可能なリストreferences/deploy-vercel.md— Vercelのセットアップ、デプロイ、claude.aiへのコネクタの再追加references/gotchas.md— 実際に時間を浪費する落とし穴(デバッグ前に読むこと)
ワークフロー
- 明確化(推測できないことだけを質問する): どのデータ/APIか、読み取り専用か書き込みか、認証が必要かどうか、カードが必要かテキストのみか。デフォルト: 公開データ、読み取り専用、認証なし、テキスト + カード。
- コードを書く前に、すべての上流APIを調査する。 各エンドポイントを
curlで確認: ステータス、レスポンスの形状、日付形式、レート制限、タイムアウト、リダイレクト(301はURLが変更されたことを意味します。例:api.frankfurter.devであり.appではありません)。公開SPARQL/検索エンドポイントは遅い場合があります: 時間を計測し、クエリはシンプルに保ち、コード内でフィルタリングします。 templates/からスキャフォールド(package.json、tsconfig.json、vercel.json、api/、src/、scripts/をコピー)、my-connectorをリネームし、npm installを実行します。src/server.tsにツールを記述(それぞれregisterToolで)。ルールは以下を参照。- すべてのツールを
scripts/test-client.tsに追加する。 ランナーは、未テストのツール、空の出力、isErrorがあると失敗します。 - ローカルで検証:
npm run typecheckを実行し、PORT=<新しいポート> npm run devを起動し、ログに "listening" と表示されることを確認します(EADDRINUSEではない)。次にnpm test -- http://localhost:<ポート>/mcpを実行します。目標:Untested tools: none. Problems: 0。 - ドキュメント化: README ツールテーブル(ツールごとに1行)、CONTRIBUTING、LICENSE。
- コミット、プッシュ、デプロイはユーザーの許可を得てから行います(
references/deploy-vercel.mdを参照)。次に、実際のURLに対してテストを実行します。 - ユーザーに伝える: claude.aiでコネクタを削除して再追加すること(ツールリストをキャッシュしているため)、および3〜5個の短いテストプロンプトを送信すること。
ツール設計ルール
- 少数で、実際に機能するツール。名前は
snake_caseの動詞:search_x、get_x、list_x。 - すべての入力に制限(
min/max、default)があるZodスキーマ。各フィールドを例とともに説明。 - 説明は、何を返すか、いつ使用するかを1〜2文で記述。モデルはこれを読んでツールを選択します。
- 注釈:
readOnlyHint: true, idempotentHint: true, destructiveHint: false、さらに外部APIにはopenWorldHint: true。 - すべてのハンドラーを
safe(...)でラップする: 上流の障害はisErrorの結果となり、読み取り可能なメッセージが表示され、クラッシュすることはありません。 - すべての結果にデータソース名を記載。データがコミュニティ編集または暫定的なものである場合はその旨を記載。
- フィールドが欠落していてもクラッシュしない。代わりに "unknown" にフォールバック。
- タイポ許容: 一致しない場合、空の結果の代わりに "もしかして" の候補を返す。
- 上流の呼び出しをキャッシュする(テンプレートの
getJson/getTextはTTL、インフライト重複排除、短い障害キャッシュ、タイムアウトを備えています)。ライブデータには短いTTL(数分)を使用し、静的データには数時間を使用します。無料APIには優しくしましょう。 - テキスト(モデル用)と
structuredContent(カード用)の両方を、card(text, data)のようなヘルパーを介して返します。 - リポジトリに秘密情報を入れない。キーが必要な場合は、
process.envから読み取り、文書化する。 - 上流が遅い場合は、上流のクエリではなくコード内で負荷の高い処理をフィルタリングする。
ステートレスサーバー(Vercel対応)
リクエストごとに新しい McpServer とトランスポートが作成されます(src/handler.ts)。セッションはなく、リクエスト間でメモリも保持されません。唯一の状態はインメモリキャッシュであり、これはベストエフォートです。CORSとボディサイズ制限はハンドラー内にあります。api/mcp.ts は { fetch } と maxDuration: 30 をエクスポートします。vercel.json は /mcp を /api/mcp に書き換えます。
カード(MCP Apps)、短縮版
1つの ui://… HTMLリソース(mimeType: text/html;profile=mcp-app)を登録し、各ツールに _meta: { ui: { resourceUri }, "ui/resourceUri": resourceUri } を指定し、kind フィールドを持つ structuredContent を返します。HTMLは1つの自己完結型ファイルであり、kind によってレンダリングされます。詳細は references/mcp-apps-cards.md と templates/src/view.ts を参照してください。
ユーザーへの出力
簡潔に。報告すること: 何が構築されたか(ツールリスト)、テスト結果、URL、およびコネクタを更新するための正確な手順。注意事項は正直に述べる(未検証のUIパス、遅い上流、コミュニティデータなど)。