mcpField
B
build-mcp-use-server

build-mcp-use-server

github.com/yigitkonur開発1344 回インストール2 日前に更新
リポジトリ

build-mcp-use-server について

mcp-use で MCP サーバーや ChatGPT アプリを構築する開発者向けスキルです。プロジェクトの確認から実装、検証までを案内し、導入済み API の型と OpenAI Apps SDK UI への準拠を重視します。

主な機能

  1. 01プロジェクト構成と mcp-use の確認
  2. 02サーバーとビューの実装ガイド
  3. 03ChatGPT 拡張機能と認証への対応
  4. 04型に基づくステートレス設計
  5. 05CLI によるツール呼び出しとビューの検証

活用シーン

  1. 01mcp-use の ChatGPT アプリの新規作成
  2. 02MCP サーバーへのインタラクティブなビュー追加
  3. 03旧 API や移行時の問題の解決

MCP 対応

mcp-use の MCPServer を使った MCP サーバー構築を案内し、mcp-use client で実際のツール呼び出しを行って実装を検証します。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/yigitkonur/skills-by-yigitkonur --skill build-mcp-use-server

インストール後、Claude Code で/build-mcp-use-serverを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

README.md
agents/
openai.yaml
references/
advanced-features.md
archestra-and-multi-host.md
auth.md
chatgpt-apps-ui.md
chatgpt-extensions.md
migration.md
server.md
skills-over-mcp.md
verification.md
views.md
scripts/
audit-server-readiness.sh
audit-server-readiness.sh.md
check-mcp-use-version.sh
check-mcp-use-version.sh.md
scaffold-mcp-use-server.sh
scaffold-mcp-use-server.sh.md

詳細

mcp-use と ChatGPT Apps で構築する

インストール済みの mcp-use パッケージ、そのエクスポートされた型、生成された宣言ファイル(mcp-env.d.ts)、および docs.mcp-use.com の公式ドキュメントを、信頼できる唯一の情報源として扱ってください。

このスキルは、公式の MCPServer API サーフェスを基盤とし、公式の mcp-use スキルの簡潔なアーキテクチャを採用するとともに、mcp-use で構築されるすべての ChatGPT アプリが、デフォルトで OpenAI Apps SDK UI(@openai/apps-sdk-ui)に準拠することを保証します。


ワークフロー

  1. プロジェクトを調査する:package.json、サーバーのエントリーポイント、エクスポートされたツール参照、views/、skills/、およびインストール済みの mcp-use のバージョンを確認します(Node.js >= 22.22.2 が必要です)。
  2. スキャフォールドを作成する、または初期化する:新規プロジェクトの場合は、公式 CLI でスキャフォールドを作成します。
    npx create-mcp-use-app@latest my-app --template mcp-apps
    
    (ヘッドレスのツールサーバーには --template mcp-server を使用します)。
  3. 関連するリファレンスを読む:
    • サーバー:ツール、リソース、プロンプト、ミドルウェア、リクエストコンテキスト、結果エンベロープ、ServerConfig。
    • ビュー:MCP Apps、React フック、インタラクションチャネル、ホスト機能、CSP。
    • OpenAI Apps SDK UI ガイド:29 種類すべてのコンポーネント、フック、Tailwind 4 のセットアップ、デザイントークン、テーマ同期。
    • ChatGPT プラグインの拡張機能:起動エントリーポイント(global、thread、file)、ネイティブの server.settings()、ツールアイコン、useDeepLink()、useModelContext()。
    • 認証:OAuth プロバイダーアダプター、mixedAuth: true、ツールレベルの securitySchemes、および ctx.auth での検証済み ID。
    • MCP を使ったスキル:再利用可能なエージェントのワークフローと skills/ 配下の規約。
    • 高度な機能:OpenAPI(fromOpenAPI)、プロキシ、通知、サブスクリプション、インタラクティブな情報要求(inputRequired)。
    • マルチホストと Archestra:ChatGPT、Claude Desktop、Archestra へのデプロイ(インストール済みサーバーのルートと所有アプリ)。
    • 移行:レガシーな v1 パターン、非推奨のインポート、古いヘルパーを v2 にアップグレードする方法。
    • 検証:mcp-use typecheck、mcp-use dev、mcp-use client、mcp-use screenshot による検証ループ。
  4. インストール済みの型に基づいて実装する:必ず静的なツール参照をエクスポートし、サーバーインスタンスをデフォルトエクスポートします。
  5. 決定論的に検証する:mcp-use client で実際のツール呼び出しを実行し、mcp-use screenshot でビューのスクリーンショットを取得します。

コア不変条件

  1. ルートサーバーのインポート: 必ず "mcp-use" から MCPServer とサーバープリミティブをインポートしてください(レガシーの "mcp-use/server" サブパスは廃止されています)。
  2. ツール参照の静的エクスポート: すべてのツール参照を必ずエクスポートしてください(export const myTool = server.tool(...))。TypeScript コンパイラーは、エクスポートされたツール名から mcp-env.d.ts 内のビューとクライアントのコントラクトを導出します。
  3. サーバーのデフォルトエクスポート: サーバーインスタンスを必ずデフォルトエクスポートしてください(export default server;)。CLI ランナー(mcp-use dev、build、start)が HTTP リスナーと Vite ビューのパイプラインを管理します。
  4. 定義優先のツールと標準スキーマ: server.tool(definition, callback) でツールを定義してください。ツール引数には inputSchema を、モデルのプロンプトには schema を使用します。モデルが値を入力するスキーマフィールドは、必ず説明してください。
  5. 生の結果エンベロープ: ツールのコールバックは、生の CallToolResult エンベロープ({ content: [...], structuredContent?: ... })を返す必要があります。非推奨の v1 ヘルパー(text()、object()、widget())は使用しないでください。予期される失敗は { isError: true, content: [...] } を返し、予期しない失敗はスローしてください。
  6. ビューのアーキテクチャ: 各ビューは views/<name>/view.tsx に配置してください。各ビューを所有するツールは必ず1つだけとし、view: { name: "<name>" } と一致させ、必須の outputSchema を指定してください。一致する structuredContent を返してください。
  7. OpenAI Apps SDK UI への準拠: ChatGPT アプリはすべて @openai/apps-sdk-ui をインストールし、@openai/apps-sdk-ui/css をインポートし、@source で Tailwind 4 を設定して、インタラクティブコンポーネントを <AppsSDKUIProvider linkComponent="a"> でラップする必要があります。
  8. ステートレスなリクエストモデル: サーバーインスタンスのスコープはリクエスト単位です。複数のリクエストにまたがる状態管理や認証に、モジュールグローバルやインメモリのセッションレジストリを使用しないでください。ctx.requestState または外部データベースを使用してください。
  9. 厳密な CLI フラグ構文: v2.7.2 以降では、ブール値の CLI フラグにインライン値を指定するとエラーになります(--tunnel=false は失敗します。--tunnel を使用するか、省略してください)。

ガードレールとよくあるアンチパターン

  • 存在しない @openai/apps-sdk-ui コンポーネントは決してインポートしないでください:
    • Card は @openai/apps-sdk-ui に存在しません。サーフェスカードは、Tailwind のユーティリティクラス(rounded-2xl border border-default bg-surface p-4 shadow-sm)でスタイルを設定した標準の <div> 要素です。
    • AvatarGroup と CopyTooltip は、公式の @openai/apps-sdk-ui コンポーネントです(@openai/apps-sdk-ui/components/Avatar と @openai/apps-sdk-ui/components/Tooltip からインポートします)。
    • Cart と Checkmark は @openai/apps-sdk-ui/components/Icon に存在しません。Check、CheckCircle、Search、Plus、Settings などを使用してください。
  • <AppsSDKUIProvider> で linkComponent を決して省略しないでください:TypeScript の契約で linkComponent が必須です(例:<AppsSDKUIProvider linkComponent="a">)。
  • useToolContext().toolOutput を型を絞り込まずに決して読み取らないでください:useToolContext() は判別共用体です。status === "pending" の場合、toolOutput は undefined です。toolOutput にアクセスする前に、必ず status === "pending" と status === "error" を処理してください。キャンセルされたアクションについては、error instanceof ToolCancelledError で型を絞り込んでください。
  • websiteUrl、icons、logging は MCPServer のトップレベルで設定してください:
    • icons?: Icon[]、websiteUrl?: string、logging?: LoggingOptions は ServerConfig のトップレベルプロパティです。架空の branding: { ... } オブジェクトに入れ子にしないでください(server.branding は読み取り専用ゲッターです)。
    • サーバーのログレベルは、logging: { enabled: true, level: "info" } で設定するか、環境変数 MCP_USE_LOG_LEVEL で上書きします。
  • レガシーな v1 の ctx.elicit() は決して使用しないでください:ステートレスなリクエストモデルへの移行に伴い、v2.0.0 で削除されました。公式のプロトコルプリミティブである inputRequired、inputRequired.elicit、inputRequired.elicitUrl、inputResponse、acceptedContent を使用してください。
  • 誤った CLI コマンドは決して使用しないでください:
    • クライアント接続の構文:mcp-use client connect <name> <url> [options](例:npx mcp-use client connect dev http://localhost:3000/mcp)。
    • スクリーンショットの構文:mcp-use screenshot (--server <name> | --mcp <url>) --tool <name> [args...] [options]。

MCPServer の基本アーキテクチャ

MCPServer とサーバーのドキュメントに基づいてください:

import { MCPServer } from "mcp-use";

const server = new MCPServer({
  name: "catalog-server",
  version: "1.0.0",
  title: "Inventory & Catalog Manager",
  description: "Manage product catalog, stock levels, and search items.",
  instructions: "Use lookup-item before creating an order. Confirm stock availability.",
  basePath: "/mcp", // default route
  host: "127.0.0.1", // "0.0.0.0" for public hosting
  port: 3000,
  legacy: "stateless", // "stateless" (default) or "reject"
  websiteUrl: "https://example.com",
  icons: [
    { src: "icons/logo.svg", mimeType: "image/svg+xml", sizes: ["20x20"] }
  ],
  logging: { enabled: true, level: "info" }, // Overridden by MCP_USE_LOG_LEVEL env var
  skills: true, // Auto-discover conventional skills/ directory
  cors: {
    origin: "*",
    credentials: true,
  },
});

export default server;

ツール定義と結果エンベロープ

ドキュメント:サーバーツール

import { MCPServer } from "mcp-use";
import { z } from "zod";

const server = new MCPServer({ name: "catalog", version: "1.0.0" });

export const getProduct = server.tool(
  {
    name: "get-product",
    title: "Get Product Details",
    description: "Fetch product metadata, pricing, and live inventory by SKU.",
    icons: [
      { src: "icons/product.svg", mimeType: "image/svg+xml", sizes: ["20x20"] }
    ],
    inputSchema: z.object({
      sku: z.string().describe("Stock Keeping Unit identifier (e.g. 'PROD-100')"),
    }),
    outputSchema: z.object({
      sku: z.string(),
      title: z.string(),
      price: z.number(),
      inStock: z.boolean(),
    }),
    annotations: {
      readOnlyHint: true,
      openWorldHint: false,
    },
    visibility: "model", // "model" (default) or "app" (hidden from LLM, visible to UI views)
    view: {
      name: "product-card", // binds to views/product-card/view.tsx
      description: "Interactive product display card",
    },
  },
  async ({ sku }, ctx) => {
    // Expected operational failure
    if (!sku.startsWith("PROD-")) {
      return {
        isError: true,
        content: [{ type: "text", text: `Invalid SKU format: ${sku}` }],
      };
    }

    const data = { sku, title: "Precision Screwdriver", price: 29.99, inStock: true };
    return {
      content: [{ type: "text", text: `Product ${data.title} (${sku}) is in stock at $${data.price}` }],
      structuredContent: data,
      _meta: { internalId: "db_98213" }, // Private to view, hidden from LLM
    };
  }
);

export default server;

ChatGPT Apps と OpenAI Apps SDK UI への準拠

ドキュメント:

1. インストールとスタイルの設定
npm install @openai/apps-sdk-ui tailwindcss @tailwindcss/vite

views/main.css(またはビュー固有の CSS)で:

@import "tailwindcss";
@import "@openai/apps-sdk-ui/css";
@source "../node_modules/@openai/apps-sdk-ui";
2. Apps SDK UI とテーマ同期を使ったビューコンポーネント

views/product-card/view.tsx を作成します:

import "./main.css";
import React, { useEffect } from "react";
import { useToolContext, useModelContext, useViewTheme, ToolCancelledError, type ViewConfig } from "mcp-use/react";
import { AppsSDKUIProvider } from "@openai/apps-sdk-ui/components/AppsSDKUIProvider";
import { Button } from "@openai/apps-sdk-ui/components/Button";
import { Badge } from "@openai/apps-sdk-ui/components/Badge";
import { applyDocumentTheme } from "@openai/apps-sdk-ui/theme";
import { Check, Plus } from "@openai/apps-sdk-ui/components/Icon";

export const viewConfig = {
  autoResize: true,
  displayModes: ["inline", "fullscreen"],
  preferredDisplayMode: "inline",
} satisfies ViewConfig;

export default function ProductCardView() {
  const { status, toolInput, toolOutput, error } = useToolContext<"get-product">();
  const theme = useViewTheme();
  const { add } = useModelContext();

  // Synchronize host theme with Apps SDK UI data-theme attribute
  useEffect(() => {
    if (theme) applyDocumentTheme(theme);
  }, [theme]);

  if (status === "pending") {
    return <div className="p-4 text-secondary text-sm">Loading SKU {toolInput?.sku}…</div>;
  }

  if (status === "error") {
    if (error instanceof ToolCancelledError) {
      return <div className="p-4 text-secondary text-sm">Action cancelled: {error.reason}</div>;
    }
    return <div className="p-4 text-danger text-sm">Error: {error.message}</div>;
  }

  return (
    <AppsSDKUIProvider linkComponent="a">
      {/* Standard surface card styled with semantic tokens */}
      <div className="w-full max-w-md rounded-2xl border border-default bg-surface p-4 shadow-sm">
        <div className="flex items-start justify-between">
          <div>
            <h2 className="heading-md">{toolOutput.title}</h2>
            <p className="text-secondary text-sm">SKU: {toolOutput.sku}</p>
          </div>
          <Badge color={toolOutput.inStock ? "success" : "warning"}>
            {toolOutput.inStock ? "In Stock" : "Backorder"}
          </Badge>
        </div>

        <div className="mt-4 flex items-center justify-between border-t border-subtle pt-3">
          <span className="text-lg font-semibold">${toolOutput.price.toFixed(2)}</span>
          <Button
            color="primary"
            onClick={() => {
              // Attach verified evidence to next ChatGPT model turn (synchronous void)
              add("selected:product", {
                type: "text",
                text: `Selected SKU ${toolOutput.sku}: $${toolOutput.price}`,
              });
            }}
          >
            <Plus className="size-4" />
            Add to Chat
          </Button>
        </div>
      </div>
    </AppsSDKUIProvider>
  );
}
3. Apps SDK UI コンポーネント一覧(29 コンポーネント)

すべて @openai/apps-sdk-ui/components/<Component> からインポートします。

カテゴリコンポーネント用途
フィードバックとステータスAlert, Badge, Indicator, EmptyMessage, ShimmerTextステータスバナー、ライブバッジ、空の状態、読み込み中のシマー表示。
アイデンティティとアイコンAvatar, Image, Iconユーザープロフィール、画像のフォールバック、700 種類以上のモノクロ SVG。
アクションButton, ButtonLink(および CopyButton)プライマリ、セカンダリ、ソフト、アウトラインのアクションボタンとコピー操作。
フォーム入力Input, Textarea, Checkbox, Switch, RadioGroup, Slider, SegmentedControl, Select, SelectControl, TagInputアクセシブルで検証機能を備えた入力とグループ化されたコントロール。
日付ピッカーDatePicker, DateRangePickerカレンダーポップアップと日付範囲セレクター。
オーバーレイMenu, Popover, Tooltipドロップダウンメニュー、アンカー付きポップオーバー、コンテキストに応じたツールチップ。
タイポグラフィとコンテンツMarkdown, CodeBlock, TextLinkスタイル付きの Markdown レンダラー、シンタックスハイライト付きコードブロック、テーマに合わせたハイパーリンク。
モーションとトランジションTransition(Animate, AnimateLayout, SlotTransitionGroup, TransitionGroup)iframe 用の滑らかな高さ、フェード、レイアウト変形トランジション。
プロバイダーAppsSDKUIProviderルーターの linkComponent 設定を提供するルートコンテキスト。
4. 公式フックの一覧(@openai/apps-sdk-ui/hooks)
  • useBreakpoint(size: BreakpointName): レスポンシブブレークポイントに一致するかどうかを示すブール値(例:useBreakpoint("md"))。
  • useAutoGrowTextarea(): テキストエリアの高さを動的に自動拡張します。
  • useAnimatedScrollTo(): キャンセル可能な、プログラムによる滑らかなスクロール。
  • useDocumentVisible(): iframe の表示状態を追跡します。
  • useIsMounted(), useLatestValue(), usePrevious(), useScrollable(), useSimulatedProgress(), useStableCallback(), useTextSelection(), useTrailingValue()。

ChatGPT プラグイン拡張機能

ドキュメント:ChatGPT プラグイン拡張機能 | 拡張機能リファレンス

1. 型付き起動エントリーポイント

tool.view.entrypoints で起動サーフェスを宣言します。

  • global:ChatGPT のトップレベルランチャーからアプリを起動します(入力スキーマは {} を受け付ける必要があります)。
  • thread:会話タブ内でアプリを起動します(入力スキーマは {} を受け付ける必要があります)。
  • file:一致する拡張子のファイルビューアーとしてアプリを起動します(入力スキーマは { file: { name: string, resourceUri: string } } を受け取る必要があります)。
export const openCsvViewer = server.tool(
  {
    name: "open-csv",
    title: "CSV Table Viewer",
    inputSchema: z.object({
      file: z.object({ name: z.string(), resourceUri: z.string() }),
    }),
    outputSchema: z.object({ file: z.object({ name: z.string(), resourceUri: z.string() }) }),
    view: {
      name: "csv-viewer",
      entrypoints: [{ type: "file", extensions: [".csv", ".tsv"] }],
    },
  },
  async ({ file }) => ({ content: [], structuredContent: { file } })
);
2. ネイティブプラグイン設定(server.settings)

型付きフィールドとレイアウトセクションを使って、ChatGPT のネイティブプラグイン設定を登録します。

server.settings({
  fields: {
    theme: { type: "string", label: "Theme", default: "system" },
    autoSync: { type: "boolean", label: "Automatic Sync", default: true },
  },
  layout: [
    {
      title: "Preferences",
      fields: ["theme", "autoSync"],
    },
  ],
  read: async (ctx) => ({ theme: "system", autoSync: true }),
  update: async (patch, ctx) => ({ theme: "system", autoSync: true, ...patch }),
});
3. 受信ディープリンク(useDeepLink)

グローバルエントリーポイントに送信された受信 URL を読み取ります。

import { useDeepLink } from "mcp-use/react";

export function AppRouter() {
  const { url } = useDeepLink(); // e.g. "/items?tag=hardware"
}
4. 選択中のモデルコンテキスト(useModelContext)

次のユーザーモデルターンとともに送信するエビデンス添付ファイルを管理します(attachments は Record<string, ModelContextBlock>、add は同期的な void です)。

import { useModelContext } from "mcp-use/react";

const { attachments, add, remove, clearAttachments } = useModelContext();

// Attach text summary (synchronous void, no title)
add("summary", { type: "text", text: "Order Summary: Total $120.00" });

// Attach image with Base64 data (PNG/JPEG/GIF/WebP, max 10MB)
add("receipt", { type: "image", data: receiptBase64, mimeType: "image/png" });

// Enumerate attached blocks
Object.entries(attachments).map(([key, block]) => (
  <span key={key}>{key}: {block.type}</span>
));

認証と混合認証

ドキュメント:認証 | 混合認証 | 認証リファレンス

MCPServer で mixedAuth: true を設定すると、1 つのエンドポイントからパブリックな検出、任意認証、保護されたツールを提供できます。

import { MCPServer } from "mcp-use";
import { oauthAuth0Provider } from "mcp-use/oauth/auth0";
import { z } from "zod";

const server = new MCPServer({
  name: "store",
  version: "1.0.0",
  oauth: oauthAuth0Provider({ domain: process.env.AUTH0_DOMAIN! }),
  mixedAuth: true, // Enables unauthenticated tools/list discovery
});

// Public tool: Anyone may call without token
export const searchCatalog = server.tool(
  {
    name: "search-catalog",
    inputSchema: z.object({ query: z.string() }),
    securitySchemes: [{ type: "noauth" }],
  },
  async ({ query }, ctx) => {
    return { content: [{ type: "text", text: `Results for ${query}` }] };
  }
);

// Protected tool: Requires sign-in with specific scopes
export const checkout = server.tool(
  {
    name: "checkout",
    inputSchema: z.object({ cartId: z.string() }),
    securitySchemes: [{ type: "oauth2", scopes: ["orders:write"] }],
  },
  async ({ cartId }, ctx) => {
    const userId = ctx.auth.user.id;
    return { content: [{ type: "text", text: `Order placed for user ${userId}` }] };
  }
);

対応プロバイダー:Clerk(mcp-use/oauth/clerk)、Auth0(mcp-use/oauth/auth0)、WorkOS(mcp-use/oauth/workos)、Supabase(mcp-use/oauth/supabase)、Keycloak(mcp-use/oauth/keycloak)、Better Auth(mcp-use/oauth/better-auth)、Scalekit(mcp-use/oauth/scalekit)、Convex(mcp-use/oauth/convex)、およびカスタム(oauthCustomProvider)。


インタラクティブな情報要求

ドキュメント:情報要求 | 高度な機能

ステートレスなリクエストモデルへの移行に伴い、v2.0.0 で ctx.elicit() は削除されました。公式のプロトコルプリミティブを使用してください。

import { MCPServer, inputRequired, inputResponse, acceptedContent } from "mcp-use";
import { z } from "zod";

const confirmSchema = z.object({ approve: z.boolean().describe("Confirm action") });

server.tool(
  {
    name: "delete-resource",
    inputSchema: z.object({ id: z.string() }),
  },
  async ({ id }, ctx) => {
    const response = inputResponse(ctx.inputResponses, "delete-approval");
    if (response.kind === "elicit" && response.action !== "accept") {
      return { isError: true, content: [{ type: "text", text: "Action cancelled" }] };
    }

    const confirmation = acceptedContent(ctx.inputResponses, "delete-approval", confirmSchema);
    if (!confirmation) {
      return inputRequired({
        inputRequests: {
          "delete-approval": inputRequired.elicit({
            message: `Permanently delete resource ${id}?`,
            requestedSchema: confirmSchema,
          }),
        },
      });
    }

    if (!confirmation.approve) {
      return { isError: true, content: [{ type: "text", text: "Action rejected" }] };
    }

    // Side-effects execute only after confirmed, validated input
    await db.delete(id);
    return { content: [{ type: "text", text: `Deleted ${id}` }] };
  }
);

外部認証には、inputRequired.elicitUrl({ message: "...", url: authUrl }) を使用してください。


MCP を介したスキル(SEP-2640)

ドキュメント:MCP を介したスキル | スキルリファレンス

ツールとともに、再利用可能な指示ワークフローを提供します。

  1. スキルを skills/<skill-name>/SKILL.md の下に配置します。
  2. 自動検出はデフォルトで有効です。MCPServer で skills: true を指定して必須にするか、skills: false を指定して無効にします。
  3. ホストは skills/list と skills/get を使用してスキルのメタデータを取得します。

CLI とツールのリファレンス

ドキュメント:CLI リファレンス | クライアント CLI | 検証

# Scaffold new v2 project
npx create-mcp-use-app@latest my-server --template mcp-apps

# Start development with hot reload, Vite views pipeline, and Inspector
mcp-use dev

# Start development with authenticated public tunnel for live ChatGPT testing
mcp-use dev --tunnel

# Typecheck server and views
mcp-use typecheck

# Build for production
mcp-use build

# Start production server
mcp-use start

# Connect live client session straight from terminal
mcp-use client connect dev http://localhost:3000/mcp

# List tools and call with arguments
mcp-use client dev tools list
mcp-use client dev tools call get-product sku=PROD-100

# Capture automated screenshot of view preview
mcp-use screenshot --server dev --tool get-product sku=PROD-100

# Deploy to mcp-use cloud (requires GitHub repo)
mcp-use deploy

公式ドキュメントへのリンク

コメント