mcpField
R
react-mcp

react-mcp

github.com/assistant-ui開発294.0k 回インストール1 日前に更新
リポジトリ

react-mcp について

React のブラウザーアプリから、プリセットまたはユーザー追加の Streamable HTTP MCP サーバーに接続するパッケージです。接続状態を管理し、接続済みツールを assistant-ui の model context に登録します。

主な機能

  1. 01プリセットとカスタムサーバーの管理
  2. 02サーバーと認証状態の永続化
  3. 03接続済みツールのモデルコンテキスト登録
  4. 04リソースの一覧表示と読み取り
  5. 05elicitation と OAuth 認証への対応

活用シーン

  1. 01React アプリへのユーザー管理 MCP サーバー追加
  2. 02接続サーバーのツールをチャットランタイムに提供
  3. 03サーバー設定画面の構築

MCP 対応

ブラウザーから Streamable HTTP MCP サーバーに接続します。ツールの一覧表示と呼び出し、リソースの一覧表示と読み取り、elicitation、PKCE と DCR を使う OAuth、Bearer または認証なし、手動接続に対応します。

インストール

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

$npx skills add https://github.com/assistant-ui/skills --skill react-mcp

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

同梱ファイル

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

references/
oauth.md
setup.md
ui.md

詳細

assistant-ui React MCP

最新の API については常に assistant-ui.com/llms.txt を参照してください。

@assistant-ui/react-mcp を使用すると、ユーザーはブラウザー内でプリセットまたはカスタムの Streamable HTTP MCP サーバーに接続できます。マネージャーはサーバーと認証の状態を永続化し、接続状態をプリミティブに公開し、接続された各ツールを serverId__toolName という名前のフロントエンドツールとして modelContext に登録します。

リファレンス

  • ./references/setup.md -- マネージャーの設定、ストレージ、状態、命令型メソッド、リソースの読み取り
  • ./references/ui.md -- コピーされる設定ダイアログと、すべてのマネージャー、サーバー、追加フォームのプリミティブ
  • ./references/oauth.md -- 認証の形状、OAuth コールバックの処理、CIMD、接続状態

マネージャーをマウントする

defineConnector で固定コネクターを宣言し、次に最も近い aui スコープを設定で拡張します。connectionTimeout はマネージャーのデフォルト値で、ミリ秒単位です。コネクターまたはカスタムサーバーは、自身の接続と listTools() の準備フローに対してこれを上書きできます。

"use client";

import type { ReactNode } from "react";
import { AuiConfig, AuiProvider, useAui } from "@assistant-ui/react";
import { McpManagerResource, defineConnector } from "@assistant-ui/react-mcp";

const connectors = [
  defineConnector({
    id: "linear",
    name: "Linear",
    url: "https://mcp.linear.app",
    auth: { type: "oauth", scopes: ["read"] },
    icon: "/icons/linear.svg",
  }),
  defineConnector({
    id: "weather",
    name: "Weather",
    url: "https://mcp.example.com/weather",
    auth: { type: "none" },
    connectionTimeout: 10_000,
  }),
];

export function Providers({ children }: { children: ReactNode }) {
  const aui = useAui();
  const config = AuiConfig({
    mcp: McpManagerResource({
      connectors,
      connectionTimeout: 15_000,
    }),
  });

  return (
    <AuiProvider extends={aui} config={config}>
      {children}
    </AuiProvider>
  );
}

コネクターはアプリケーションのプリセットであり、削除できません。カスタムサーバーは、McpAddFormPrimitive または aui.mcp.addCustomServer(...) を通じてユーザーが提供します。どちらの種類も、状態、ストレージ、引き出し(elicitation)、ツール登録の経路を共有します。マネージャーのオプションとストレージの有効期間のルールについては、setup を参照してください。

フロントエンドツール呼び出しの後に続行する

マネージャーは接続されたツールを自動的に登録します。チャットランタイムは、モデルが続行できるように、完了したフロントエンドツールの結果をルートに送信する必要があります。

"use client";

import type { ReactNode } from "react";
import { lastAssistantMessageIsCompleteWithToolCalls } from "ai";
import { AssistantRuntimeProvider } from "@assistant-ui/react";
import { useChatRuntime } from "@assistant-ui/ai-sdk";

export function Chat({ children }: { children: ReactNode }) {
  const runtime = useChatRuntime({
    sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,
  });

  return <AssistantRuntimeProvider runtime={runtime}>{children}</AssistantRuntimeProvider>;
}

modelContext を提供するチャットランタイムがない場合、マネージャーは最小限のものをマウントします。イベントハンドラーで直接呼び出すには、aui.mcp.server({ id }).callTool(...) を使用します。

設定 UI を使用する

スタイル付きダイアログは npx assistant-ui@latest add mcp-config でインストールします。これはコピーされるランタイム接続要素であるため、@/components/assistant-ui/elements/mcp-config.aui からインポートし、マネージャープロバイダーの下でレンダリングします。

import { McpConfigDialog } from "@/components/assistant-ui/elements/mcp-config.aui";

export function ServerSettings() {
  return <McpConfigDialog />;
}

デフォルトのトリガーを置き換えるには、要素を children として渡します。設定ページ、サイドバー、またはカスタムの追加フローには、ui のヘッドレスプリミティブを組み合わせてください。

引き出し(elicitation)リクエストをレンダリングする

MCP サーバーは、ツール呼び出しの実行中に構造化された入力を要求できます。接続されたサーバーと同じ mcpServer スコープで Items をレンダリングします。コネクターまたはカスタムサーバーで elicitation: false を設定すると、そのプロトコル機能をオプトアウトできます。

import { McpElicitationPrimitive } from "@assistant-ui/react-mcp";

type FieldSchema = {
  type?: string;
  enum?: readonly string[];
};

export function ElicitationRequests() {
  return (
    <McpElicitationPrimitive.Items>
      {() => (
        <McpElicitationPrimitive.Root>
          <McpElicitationPrimitive.Message />
          <McpElicitationPrimitive.Error />
          <McpElicitationPrimitive.Fields>
            {({ name, schema, value, setValue }) => {
              const field = schema as FieldSchema;
              if (field.type === "boolean") {
                return (
                  <label>
                    {name}
                    <input
                      type="checkbox"
                      checked={value === true}
                      onChange={(event) => setValue(event.target.checked)}
                    />
                  </label>
                );
              }
              if (field.enum) {
                return (
                  <label>
                    {name}
                    <select
                      value={typeof value === "string" ? value : ""}
                      onChange={(event) => setValue(event.target.value)}
                    >
                      {!field.enum.includes("") && <option value="">Select {name}</option>}
                      {field.enum.map((option) => (
                        <option key={option} value={option}>
                          {option}
                        </option>
                      ))}
                    </select>
                  </label>
                );
              }
              return (
                <label>
                  {name}
                  <input
                    value={typeof value === "string" || typeof value === "number" ? String(value) : ""}
                    onChange={(event) => setValue(event.target.value)}
                  />
                </label>
              );
            }}
          </McpElicitationPrimitive.Fields>
          <McpElicitationPrimitive.Accept>Submit</McpElicitationPrimitive.Accept>
          <McpElicitationPrimitive.Decline>Decline</McpElicitationPrimitive.Decline>
          <McpElicitationPrimitive.Cancel>Cancel</McpElicitationPrimitive.Cancel>
        </McpElicitationPrimitive.Root>
      )}
    </McpElicitationPrimitive.Items>
  );
}

レンダー関数は、毎回個別のアクティブなリクエストを受け取ります。数値文字列は有効な場合に強制変換されますが、ブール型フィールドはブール値を設定する必要があります。空文字列は、プロパティが enum メンバーまたはデフォルトを通じてそれを許可しない限り未回答とみなされるため、enum プロパティは select としてレンダリングしてください。Accept は、必須フィールドの欠落および無効な値に対して無効のままになります。

v1 のスコープ

このパッケージは、ツールの一覧表示と実行、リソースの一覧表示と読み取り、フォームの引き出し(elicitation)、PKCE と DCR を使用した OAuth、ベアラー認証と認証なし、Streamable HTTP トランスポート、手動での接続または切断を提供します。プロンプト、サンプリング、バックオフ付きの自動再接続、ツールごとの有効化の永続化、ツールごとの同意、トークン暗号化の組み込みは先送りされています。

よくある落とし穴

ツールがモデルに到達しない

  • サーバーが connected である必要があります。ツールの名前は MCP のツール名だけでなく serverId__toolName となります。
  • useChatRuntime に sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls を設定して、完了したフロントエンドのツール呼び出しがモデルを再開させるようにしてください。

OAuth コールバックが失敗する、または完了しない

  • コールバックルートは oauthRedirectUri と完全に一致し、マネージャープロバイダーの配下で McpOAuthCallback をレンダリングする必要があります。
  • 登録エンドポイントを持たない CIMD のみの認可サーバーには、静的な OAuth の clientId が必要です。

サーバー状態がユーザー間で漏洩する、またはストレージの差し替えでレコードが失われる

  • McpLocalStorage() はブラウザ専用で、トークンを平文で保存します。本番環境の認証状態には、HTTP only Cookie に支えられた McpCustomStorage を使用してください。
  • 別のユーザーに storage を差し替えないでください。カスタムサーバーレコードは一度しかハイドレートされないため、マネージャーを再マウントしてください。詳しくは ストレージの同一性 を参照してください。

引き出し(elicitation)フォームが空白のままになる

  • Items は保留中のリクエストがなければ何もレンダリングせず、一致するサーバースコープが必要です。サーバーが接続されていて、elicitation: false が設定されていないことを確認してください。

リソースブラウザーが最初のページで停止する

  • 返された各 nextCursor を、それが存在しなくなるまで listResources({ cursor }) に渡し、その後、選択した項目に対して readResource(uri) を呼び出してください。

関連スキル

  • tools -- ユーザーが管理する MCP サーバーを補完する、開発者所有のフロントエンドおよびバックエンドツール
  • setup -- コマンドラインのセットアップと mcp プロジェクトテンプレート
  • runtime -- useChatRuntime とランタイムプロバイダーの設定
  • elements -- コピーした mcp-config 要素のインストールと変更

コメント