use-mcp
はリモートのModel Context Protocol (MCP) サーバーに接続するための React フックです。このフックを使用すると AI システムへの認証やツールの呼び出しを簡単に行うことができます。
React コンポーネントから MCP サーバーに接続する
use-mcp フックを使用したコンポーネントの例を試してみましょう。2025-06-18 バージョンの MCP の仕様ではクライアントとサーバーのトランスポートの方法として stdio と Streamable HTTP が定義されていますが、use-mcp では Streamable HTTP
による接続をサポートしています。HTTP もしくは SSE(Server-Sent Events)を使用して MCP サーバーに接続します。
MCP サーバーとして Git MCP を使用します。これは GitHub の任意のレポジトリを MCP サーバーとして利用できるツールです。public なレポジトリであれば認証無しで接続できます。URL はレポジトリの URL の github.com の部分を gitmcp.io に置き換えたものを指定します。例えば https://gitmcp.io/azukiazusa1/sapper-blog-app のような形式です。
React アプリケーションを作成し、以下のコマンドで use-mcp
をインストールします。
npm install use-mcp
useMcp
フックに接続先の URL を指定して呼び出します。以下のコードを追加しましょう。
import { useState } from "react";
import { useMcp, type Tool } from "use-mcp/react";
function App() {
const { state, tools, error } = useMcp({
url: "https://gitmcp.io/azukiazusa1/sapper-blog-app",
clientName: "my-mcp-client",
});
if (state === "loading" || state === "connecting") {
return <div>Loading...</div>;
}
if (state === "failed") {
return <div>Error loading MCP: {error}</div>;
}
return (
<div>
<h1>Git MCP Server</h1>
<ul>
{tools.map((tool) => (
<li key={tool.name}>
<button onClick={() => {}}>{tool.name}</button>
<p>{tool.description}</p>
</li>
))}
</ul>
</div>
);
}
export default App;
フックの戻り値の state
には MCP サーバーとの接続が成功したかどうかの状態が含まれ、以下の値を取ります。
discovering
authenticating
connecting
loading
ready
failed
この状態を使用して接続状態をレンダリングしています。MCP サーバーで利用可能なツールの一覧は tools
プロパティに含まれているので、リストとして表示しています。
ツールの呼び出しを追加してみましょう。ツールを呼び出すには callTool
メソッドにツール名と引数を渡します。ツールが要求する引数の型は tools
プロパティの各ツールの inputSchema
に定義されているので、このスキーマを参照し引数の入力フォームを表示します。
import { useState } from "react";
import { useMcp, type Tool } from "use-mcp/react";
function App() {
const [toolCallResult, setToolCallResult] = useState(null);
const [selectedTool, setSelectedTool] = useState<Tool | null>(null);
const [formData, setFormData] = useState<Record<string, any>>({});
const { state, tools, callTool, error } = useMcp({
url: "https://gitmcp.io/azukiazusa1/sapper-blog-app",
clientName: "my-mcp-client",
});
if (state === "loading") {
return <div>Loading...</div>;
}
if (state === "failed") {
return <div>Error loading MCP: {error}</div>;
}
function onClickTool(tool: Tool) {
setSelectedTool(tool);
setFormData({});
setToolCallResult(null);
}
function renderInputField(name: string, schema: any) {
const value = formData[name] || "";
const handleChange = (newValue: any) => {
setFormData((prev) => ({ ...prev, [name]: newValue }));
};
if (schema.type === "string") {
if (schema.enum) {
return (
<select value={value} onChange={(e) => handleChange(e.target.value)}>
<option value="">Select...</option>
{schema.enum.map((option: string) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
);
}
return (
<input
type="text"
value={value}
onChange={(e) => handleChange(e.target.value)}
placeholder={schema.description}
/>
);
}
if (schema.type === "number") {
return (
<input
type="number"
value={value}
onChange={(e) => handleChange(Number(e.target.value))}
placeholder={schema.description}
/>
);
}
// boolean, array など他の型は省略
}
async function handleSubmit() {
if (!selectedTool) return;
try {
const result = await callTool(selectedTool.name, formData);
setToolCallResult(result);
} catch (error) {
setToolCallResult({ error: error.message });
}
}
return (
<div>
<h1>Git MCP Server</h1>
{!selectedTool ? (
<ul>
{tools.map((tool) => (
<li key={tool.name}>
<button onClick={() => onClickTool(tool)}>{tool.name}</button>
<p>{tool.description}</p>
</li>
))}
</ul>
) : (
<div>
<h2>{selectedTool.name}</h2>
<p>{selectedTool.description}</p>
<form
onSubmit={(e) => {
e.preventDefault();
handleSubmit();
}}
>
{selectedTool.inputSchema?.properties &&
Object.entries(selectedTool.inputSchema.properties).map(
([name, schema]: [string, any]) => (
<div key={name} style={{ marginBottom: "10px" }}>
<label>
{name}
{selectedTool.inputSchema.required?.includes(name) &&
" *"}
:
</label>
<div>{renderInputField(name, schema)}</div>
{schema.description && (
<small style={{ color: "#666" }}>
{schema.description}
</small>
)}
</div>
)
)}
<button type="submit">Execute Tool</button>
<button type="button" onClick={() => setSelectedTool(null)}>
Back
</button>
</form>
</div>
)}
{toolCallResult && (
<div>
<h2>Tool Call Result</h2>
<pre>{JSON.stringify(toolCallResult, null, 2)}</pre>
</div>
)}
</div>
);
}
export default App;
このコードでは、ツールを選択するとそのツールの入力フォームが表示され、必要な引数を入力してツールを実行できます。ツールの実行結果は toolCallResult
に保存され、画面に表示されます。
OAuth 認証
多くの MCP サーバーではツールの呼び出しを行うために認証が必要です。MCP サーバーの認証の仕様では MCP サーバーは OAuth 2.1 を実装する必要があると定義されています。
use-mcp では OAuth 認証のフロー全体をサポートしています。ユーザーをログインページにリダイレクトし、認証後にコールバック URL にリダイレクトされることで認証トークンを取得しストレージに保存します。
ここでは Cloudflare Workers Bindings MCP Server を例にコード例を示します。これは Cloudflare の OAuth が組み込まれた MCP サーバーで、Cloudflare Workers のリソースを操作するツールを提供しています。
先程の App.tsx
ファイルの useMcp
フックに渡した URL を https://bindings.mcp.cloudflare.com/sse
に変更しておきましょう。
import { useMcp, type Tool } from "use-mcp/react";
function App() {
const { state, tools, callTool, error } = useMcp({
url: "https://bindings.mcp.cloudflare.com/sse",
clientName: "my-mcp-client",
});
// ...
}
React アプリケーションでコールバック URL が必要となるため、何らかのルーティングライブラリを使用して /oauth/callback
のパスを処理する必要があります。ここでは react-router-dom
を使用しましょう。
npm install react-router-dom
認証を行うためのコンポーネントを追加します。以下のコードを src/OAuthCallback.tsx
として保存します。ここでは onMcpAuthorization
関数を useEffect
フックで呼び出しています。
import { useEffect } from "react";
import { onMcpAuthorization } from "use-mcp";
export function OAuthCallback() {
useEffect(() => {
onMcpAuthorization();
}, [])
return (
<div>
<h1>Authenticating...</h1>
<p>This window should close automatically.</p>
</div>
)
}
Routes
コンポーネントを作成し、App
コンポーネントと OAuthCallback
コンポーネントをルーティングします。
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import App from "./App";
import { OAuthCallback } from "./OAuthCallback";
export function AppRoutes() {
return (
<Router>
<Routes>
<Route path="/" element={<App />} />
<Route path="/oauth/callback" element={<OAuthCallback />} />
</Routes>
</Router>
);
}
src/main.tsx
を以下のように更新して、AppRoutes
をレンダリングします。
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import { AppRoutes } from "./Routes.tsx";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<AppRoutes />
</StrictMode>
);
これで認証処理が実装されました。アプリケーションを起動し http://localhost:5173 にアクセスすると、Cloudflare の OAuth 認証ページのポップアップが表示されます。
ポップアップの「Allow」ボタンをクリックして認証を許可すると、アプリケーションにリダイレクトされ、認証が完了します。これで MCP サーバーに接続し、ツールを呼び出すことができるようになります。
認証トークンはブラウザの localStorage
に保存され、次回アプリケーションを起動したときに自動的に認証が行われます。ストレージをクリアする場合には useMcp
フックの clearStorage
メソッドを呼び出すことでトークンを削除できます。
import { useMcp, type Tool } from "use-mcp/react";
function App() {
const { state, tools, callTool, error, clearStorage } = useMcp({
url: "https://bindings.mcp.cloudflare.com/sse",
clientName: "my-mcp-client",
});
// ...
return (
<div>
<h1>Git MCP Server</h1>
<button onClick={clearStorage}>Log Out</button>
{/* ... */}
</div>
);
}
まとめ
use-mcp
は MCP サーバーに接続するための React フックで、ツールの呼び出しや認証を簡単に行うことができる。useMcp
フックを使用して MCP サーバーに接続し、ツールの一覧を取得できる。- ツールの呼び出しには
callTool
メソッドを使用する。必要な引数はtools
プロパティの各ツールのinputSchema
に定義されている。 - OAuth 認証をサポートしており、認証フローを簡単に実装できる。
/oauth/callback
のパスを設定し、onMcpAuthorization
関数を使用して認証を行う。 - 認証後はブラウザの
localStorage
にトークンが保存され、次回の起動時に自動的に認証が行われる。 clearStorage
メソッドを使用して認証トークンを削除し、ログアウトすることができる。