重要: このスキルの使い方
このファイルはナビゲーションガイドのみを提供します。MCPサーバーの機能を実装する前に、以下の手順を必ず実行してください:
- この概要を読んで、どのリファレンスファイルが関連するかを理解する
- 実装する機能に対応する特定のリファレンスファイルを常に読む
- それらのファイルの詳細なパターンを実装に適用する
このファイル内のクイックリファレンス例だけに頼らないでください - これらは最小限の例に過ぎません。リファレンスファイルには、重要なベストプラクティス、セキュリティに関する考慮事項、高度なパターンが含まれています。
MCPサーバーベストプラクティス
mcp-useを使用して、ツール、リソース、プロンプト、ウィジェットを備えたプロダクション対応のMCPサーバーを構築するための包括的なガイド。
⚠️ 最初に: 新規プロジェクトですか、それとも既存プロジェクトですか?
何をする前に、現在mcp-useプロジェクト内にいるかどうかを確認してください。
検出方法: ワークスペースに"mcp-use"を依存関係としてリストしたpackage.jsonがあるか、または"mcp-use/server"からインポートする.tsファイルがあるかを確認します。
├─ mcp-useプロジェクトが見つかった → スキャフォールディングしないでください。すでにプロジェクト内にいます。
│ └─ 機能を追加するには、以下の「クイックナビゲーション」に進んでください。
│
├─ mcp-useプロジェクトがない(空のディレクトリ、無関係なプロジェクト、またはグリーンフィールド)
│ └─ 最初に `npx create-mcp-use-app` でスキャフォールディングし、その後機能を追加します。
│ 以下の「新規プロジェクトのスキャフォールディング」を参照してください。
│
└─ 無関係なプロジェクト(例: Next.jsアプリ)内にいて、ユーザーがMCPサーバーを希望する場合
└─ ユーザーにどこに作成するか尋ね、そのディレクトリでスキャフォールディングします。
既存の無関係なプロジェクトのルート内でスキャフォールディングしないでください。
MCPServerボイラープレート、package.json、プロジェクト構造を手動で作成しないでください。 CLIは、TypeScript設定、開発スクリプト、インスペクター統合、ホットリロード、ウィジェットコンパイルをセットアップしますが、これらは手動で再現するのが困難です。
新規プロジェクトのスキャフォールディング
npx create-mcp-use-app my-server
cd my-server
npm run dev
スキャフォールディングの詳細とCLIフラグについては、quickstart.md を参照してください。
クイックナビゲーション
構築するものに基づいてパスを選択してください:
🚀 基礎
対象: 新しい会話でMCP作業を開始するときは、常にこれらを最初に読んでください。後でアーキテクチャや概念を明確にするために参照してください。
- concepts.md - MCPプリミティブ(ツール、リソース、プロンプト、ウィジェット)とそれぞれを使用するタイミング
- architecture.md - サーバー構造(Honoベース)、ミドルウェアシステム、server.use() vs server.app
- quickstart.md - スキャフォールディング、セットアップ、最初のツール例
- deployment.md - Manufact Cloudへのデプロイ、セルフホスティング、Docker、デプロイメントの管理
ツール/リソース/ウィジェットのセクションに進む前に、これらをロードしてください。
🔐 認証を追加しますか?
対象: OAuth(WorkOS、Supabase、カスタム)でサーバーを保護する場合
-
- 対象: 初めて認証を追加する場合、
ctx.authを理解する場合、またはプロバイダーを選択する場合 - 内容:
oauth設定、ユーザーコンテキストの形状、プロバイダー比較、よくある間違い
- 対象: 初めて認証を追加する場合、
-
- 対象: 認証にWorkOS AuthKitを使用する場合
- 内容: セットアップ、環境変数、DCR vs 事前登録、ロール/権限、WorkOS API呼び出し
-
- 対象: 認証にSupabaseを使用する場合
- 内容: セットアップ、環境変数、HS256 vs ES256、RLS対応API呼び出し
-
- 対象: 他のIDプロバイダー(GitHub、Okta、Azure AD、Googleなど)を使用する場合
- 内容: カスタム検証、ユーザー情報の抽出、プロバイダー例
🔧 サーバーバックエンドの構築(UIなし)?
対象: MCP機能(アクション、データ、テンプレート)の実装。構築するプリミティブに応じて特定のファイルを読んでください。
-
- 対象: AIが呼び出せるバックエンドアクション(send-email、fetch-data、create-user)を作成する場合
- 内容: ツール定義、スキーマ、アノテーション、コンテキスト、エラーハンドリング
-
- 対象: クライアントが取得できる読み取り専用データ(設定、ユーザープロファイル、ドキュメント)を公開する場合
- 内容: 静的リソース、動的リソース、パラメーター化されたリソーステンプレート、URI補完
-
- 対象: AIインタラクション(コードレビュー、要約)のための再利用可能なメッセージテンプレートを作成する場合
- 内容: プロンプト定義、パラメーター化、引数補完、プロンプトのベストプラクティス
-
- 対象: ツール/リソースからのレスポンス(テキスト、JSON、マークダウン、画像、エラー)をフォーマットする場合
- 内容:
text()、object()、markdown()、image()、error()、mix()
🎨 ビジュアルウィジェットの構築(インタラクティブUI)?
対象: データの閲覧、比較、選択のためのReactベースのビジュアルインターフェースを作成する場合
-
- 対象: 最初のウィジェットを作成する場合、または既存のツールにUIを追加する場合
- 内容: ウィジェットのセットアップ、
useWidget()フック、isPendingチェック、プロパティ処理
-
- 対象: ウィジェット内のUI状態(選択、フィルター、タブ)を管理する場合
- 内容:
useState、setState、状態の永続性、ツール状態とウィジェット状態の使い分け
-
- 対象: ウィジェット内にボタン、フォームを追加したり、ツールを呼び出したりする場合
- 内容:
useCallTool()、フォーム処理、アクションボタン、楽観的更新
-
- 対象: テーマ、レスポンシブレイアウト、アクセシビリティをサポートするウィジェットのスタイリング
- 内容:
useWidgetTheme()、ライト/ダークモード、autoSize、レイアウトパターン、CSSベストプラクティス
-
- 対象: 非同期データ、エラーバウンダリー、パフォーマンス最適化を備えた複雑なウィジェットを構築する場合
- 内容: ローディング状態、エラーハンドリング、メモ化、コード分割
📚 完全な例が必要ですか?
対象: 一般的なユースケースの完全な実装を確認したい場合
- common-patterns.md
- エンドツーエンドの例: 天気アプリ、TODOリスト、レシピブラウザ
- 表示内容: サーバーコード + ウィジェットコード + コンテキスト内のベストプラクティス
ディシジョンツリー
何が必要ですか?
├─ スクラッチからの新規プロジェクト
│ └─> quickstart.md(スキャフォールディング + セットアップ)
│
├─ OAuth / ユーザー認証
│ └─> authentication/overview.md → プロバイダー固有のガイド
│
├─ シンプルなバックエンドアクション(UIなし)
│ └─> ツールを使用: server/tools.md
│
├─ クライアント向け読み取り専用データ
│ └─> リソースを使用: server/resources.md
│
├─ 再利用可能なプロンプトテンプレート
│ └─> プロンプトを使用: server/prompts.md
│
├─ ビジュアル/インタラクティブUI
│ └─> ウィジェットを使用: widgets/basics.md
│
└─ 本番環境にデプロイ
└─> deployment.md(クラウドデプロイ、セルフホスティング、Docker)
コア原則
- アクションにはツール - 入力/出力を伴うバックエンド操作
- データにはリソース - クライアントが取得できる読み取り専用データ
- テンプレートにはプロンプト - 再利用可能なメッセージテンプレート
- UIにはウィジェット - 役立つ場合のビジュアルインターフェース
- まずモックデータ - 迅速にプロトタイプ作成し、後でAPIに接続
❌ よくある間違い
本番MCPサーバーで見られるこれらのアンチパターンを避けてください:
ツール定義
- ❌ 生のオブジェクトを返し、レスポンスヘルパーを使用しない
- ✅
text()、object()、widget()、error()ヘルパーを使用する
- ✅
- ❌ すべてのフィールドでZodスキーマの
.describe()をスキップする- ✅ AIの理解を向上させるために、すべてのスキーマフィールドに説明を追加する
- ❌ 入力検証やサニタイズがない
- ✅ Zodで入力を検証し、ユーザー提供データをサニタイズする
- ❌
error()ヘルパーを返す代わりにエラーをスローする- ✅ 優雅なエラーレスポンスには
error("message")を使用する
- ✅ 優雅なエラーレスポンスには
ウィジェット開発
- ❌
isPendingを確認せずにpropsにアクセスする- ✅ 常に
if (isPending) return <Loading/>を確認する
- ✅ 常に
- ❌ ウィジェットがサーバー状態(フィルター、選択)を処理する
- ✅ ウィジェットは
useStateで自身のUI状態を管理する
- ✅ ウィジェットは
- ❌
McpUseProviderラッパーやautoSizeがない- ✅ ルートコンポーネントをラップ:
<McpUseProvider autoSize>
- ✅ ルートコンポーネントをラップ:
- ❌ テーマ対応していないインラインスタイル
- ✅ ライト/ダークモードのサポートには
useWidgetTheme()を使用する
- ✅ ライト/ダークモードのサポートには
セキュリティと本番環境
- ❌ コード内のハードコードされたAPIキーやシークレット
- ✅
process.env.API_KEYを使用し、.env.exampleにドキュメント化する
- ✅
- ❌ ツールハンドラーにエラーハンドリングがない
- ✅ try/catchでラップし、失敗時は
error()を返す
- ✅ try/catchでラップし、失敗時は
- ❌ キャッシュなしの高コスト操作
- ✅ TTL付きでAPI呼び出しや計算をキャッシュする
- ❌ CORS設定がない
- ✅ 本番デプロイメント用にCORSを設定する
🔒 黄金ルール
意見に基づくアーキテクチャガイドライン:
1. 1ツール = 1機能
広範なアクションを焦点を絞ったツールに分割する:
- ❌
manage-users(曖昧すぎる) - ✅
create-user、delete-user、list-users
2. 完全なデータを upfront で返す
ツール呼び出しは高コストです。遅延ローディングは避ける:
- ❌
list-products+get-product-details(2回の呼び出し) - ✅
list-productsが詳細を含む完全なデータを返す
3. ウィジェットは自身の状態を所有する
UI状態は、別のツールではなく、ウィジェット内に存在する:
- ❌
select-itemツール、set-filterツール - ✅ ウィジェットは
useStateまたはsetStateで管理する
4. exposeAsTool のデフォルトは false
ウィジェットはデフォルトでリソースとしてのみ登録されます。カスタムツール(推奨)を使用するか、exposeAsTool: true を設定してウィジェットをモデルに公開します:
// ✅ 適切な型推論には4つのステップすべてが必要:
// ステップ1: スキーマを個別に定義
const propsSchema = z.object({
title: z.string(),
items: z.array(z.string()),
});
// ステップ2: メタデータでスキーマ変数を参照
export const widgetMetadata: WidgetMetadata = {
description: "...",
props: propsSchema, // ← インラインの z.object() ではない
exposeAsTool: false,
};
// ステップ3: スキーマ変数から Props 型を推論
type Props = z.infer<typeof propsSchema>;
// ステップ4: 型付き Props を useWidget で使用
export default function MyWidget() {
const { props, isPending } = useWidget<Props>(); // ← <Props> を追加
// ...
}
⚠️ よくある間違い: ステップ1-2のみ行い、ステップ3-4をスキップする(型安全性が失われる)
5. 境界でのみ検証する
- 内部コードとフレームワークの保証を信頼する
- ユーザー入力、外部APIレスポンスを検証する
- 発生し得ないシナリオに対するエラーハンドリングは追加しない
6. ブラウジング/比較にはウィジェットを優先する
迷ったら、ウィジェットを追加します。ビジュアルUIは以下を改善します:
- 複数アイテムのブラウジング
- データの横並び比較
- インタラクティブな選択ワークフロー
クイックリファレンス
最小限のサーバー
import { MCPServer, text } from "mcp-use/server";
import { z } from "zod";
const server = new MCPServer({
name: "my-server",
title: "My Server",
version: "1.0.0",
});
server.tool(
{
name: "greet",
description: "ユーザーに挨拶する",
schema: z.object({ name: z.string().describe("ユーザー名") }),
},
async ({ name }) => text("こんにちは " + name + "!"),
);
server.listen();
レスポンスヘルパー
| ヘルパー | 使用する場合 | 例 |
|---|---|---|
text() | 単純な文字列レスポンス | text("成功!") |
object() | 構造化データ | object({ status: "ok" }) |
markdown() | フォーマット済みテキスト | markdown("# タイトル\n内容") |
widget() | ビジュアルUI | widget({ props: {...}, output: text(...) }) |
mix() | 複数のコンテンツ | mix(text("こんにちは"), image(url)) |
error() | エラーレスポンス | error("データの取得に失敗しました") |
resource() | リソース参照の埋め込み | resource("docs://guide", "text/markdown") |