@gary149/use-mcp
v0.1.3
Published
<div class="oranda-hide">
Readme
🦑 use-mcp 🦑
A lightweight client for connecting to Model Context Protocol (MCP) servers. Provides a React hook and a Svelte store adapter to simplify authentication and tool calling.
Try it out: Chat Demo | MCP Inspector | Cloudflare Workers AI Playground
Examples in this repo:
- examples/chat-ui – React chat interface using
@gary149/use-mcp - examples/inspector – React MCP inspector
- examples/inspector-svelte – SvelteKit inspector with per‑tool inputs
Installation
npm install @gary149/use-mcp
# or
pnpm add @gary149/use-mcp
# or
yarn add @gary149/use-mcpDevelopment
To run the development environment with the React examples and servers:
pnpm devThis starts:
- Inspector: http://localhost:5001 - MCP server debugging tool
- Chat UI: http://localhost:5002 - Example chat interface
- Hono MCP Server: http://localhost:5101 - Example MCP server
- CF Agents MCP Server: http://localhost:5102 - Cloudflare Workers AI MCP server
Svelte inspector example:
cd examples/inspector-svelte
pnpm install
pnpm devThen open the local URL shown by Vite and connect to an MCP server (e.g. https://huggingface.co/mcp). The UI lists tools and provides input fields generated from each tool's JSON schema.
Testing
Integration tests are located in the test/ directory and run headlessly by default:
cd test && pnpm test # Run tests headlessly (default)
cd test && pnpm test:headed # Run tests with visible browser
cd test && pnpm test:watch # Run tests in watch mode
cd test && pnpm test:ui # Run tests with interactive UIFeatures
- 🔄 Automatic connection management with reconnection and retries
- 🔐 OAuth authentication flow handling with popup and fallback support
- 📦 Simple React hook and Svelte store adapters for MCP integration
- 🧰 Full support for MCP tools, resources, and prompts
- 📄 Access server resources and read their contents
- 💬 Use server-provided prompt templates
- 🧰 TypeScript types for editor assistance and type checking
- 📝 Comprehensive logging for debugging
- 🌐 Works with both HTTP and SSE (Server-Sent Events) transports (HTTP streaming recommended)
Quick Start (React)
import { useMcp } from '@gary149/use-mcp/react'
function MyAIComponent() {
const {
state, // Connection state: 'discovering' | 'pending_auth' | 'authenticating' | 'connecting' | 'loading' | 'ready' | 'failed'
tools, // Available tools from MCP server
resources, // Available resources from MCP server
prompts, // Available prompts from MCP server
error, // Error message if connection failed
callTool, // Function to call tools on the MCP server
readResource, // Function to read resource contents
getPrompt, // Function to get prompt messages
retry, // Retry connection manually
authenticate, // Manually trigger authentication
clearStorage, // Clear stored tokens and credentials
} = useMcp({
url: 'https://your-mcp-server.com',
clientName: 'My App',
autoReconnect: true,
})
// Handle different states
if (state === 'failed') {
return (
<div>
<p>Connection failed: {error}</p>
<button onClick={retry}>Retry</button>
<button onClick={authenticate}>Authenticate Manually</button>
</div>
)
}
if (state !== 'ready') {
return <div>Connecting to AI service...</div>
}
// Use available tools
const handleSearch = async () => {
try {
const result = await callTool('search', { query: 'example search' })
console.log('Search results:', result)
} catch (err) {
console.error('Tool call failed:', err)
}
}
return (
<div>
<h2>Available Tools: {tools.length}</h2>
<ul>
{tools.map(tool => (
<li key={tool.name}>{tool.name}</li>
))}
</ul>
<button onClick={handleSearch}>Search</button>
{/* Example: Display and read resources */}
{resources.length > 0 && (
<div>
<h3>Resources: {resources.length}</h3>
<button onClick={async () => {
const content = await readResource(resources[0].uri)
console.log('Resource content:', content)
}}>
Read First Resource
</button>
</div>
)}
{/* Example: Use prompts */}
{prompts.length > 0 && (
<div>
<h3>Prompts: {prompts.length}</h3>
<button onClick={async () => {
const result = await getPrompt(prompts[0].name)
console.log('Prompt messages:', result.messages)
}}>
Get First Prompt
</button>
</div>
)}
</div>
)
}Quick Start (Svelte/SvelteKit)
// src/lib/mcp.ts
import { browser } from '$app/environment'
import { createMcp } from '@gary149/use-mcp/svelte'
export const mcp = browser ? createMcp({
url: 'https://your-mcp-server.com',
clientName: 'My App',
autoReconnect: true,
// transportType: 'http', // recommended; SSE is legacy
}) : undefined<!-- src/routes/+page.svelte -->
<script lang="ts">
import { mcp } from '$lib/mcp'
</script>
{#if mcp}
{#if $mcp.state === 'failed'}
<p>Connection failed: {$mcp.error}</p>
<button on:click={() => mcp.retry()}>Retry</button>
<button on:click={() => mcp.authenticate()}>Authenticate Manually</button>
{:else if $mcp.state !== 'ready'}
<p>Connecting to AI service…</p>
{:else}
<h2>Available Tools: {$mcp.tools.length}</h2>
<button on:click={() => mcp.callTool('search', { query: 'example search' })}>
Search
</button>
{/if}
{:else}
<p>Loading…</p>
{/if}Setting Up OAuth Callback
To handle the OAuth authentication flow, you need to set up a callback endpoint in your app.
With React Router
// App.tsx with React Router
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import { useEffect } from 'react'
import { onMcpAuthorization } from '@gary149/use-mcp'
function OAuthCallback() {
useEffect(() => {
onMcpAuthorization()
}, [])
return (
<div>
<h1>Authenticating...</h1>
<p>This window should close automatically.</p>
</div>
)
}
function App() {
return (
<Router>
<Routes>
<Route path="/oauth/callback" element={<OAuthCallback />} />
<Route path="/" element={<YourMainComponent />} />
</Routes>
</Router>
)
}With Next.js Pages Router
// pages/oauth/callback.tsx
import { useEffect } from 'react'
import { onMcpAuthorization } from '@gary149/use-mcp'
export default function OAuthCallbackPage() {
useEffect(() => {
onMcpAuthorization()
}, [])
return (
<div>
<h1>Authenticating...</h1>
<p>This window should close automatically.</p>
</div>
)
}With SvelteKit
<!-- src/routes/oauth/callback/+page.svelte -->
<script lang="ts">
import { onMount } from 'svelte'
import { onMcpAuthorization } from '@gary149/use-mcp'
onMount(() => onMcpAuthorization())
</script>
<h1>Authenticating…</h1>
<p>This window should close automatically.</p>Note: When using HTTP streaming transport across origins, ensure your MCP server CORS configuration allows and exposes the Mcp-Session-Id header so the browser can maintain the session. If your OAuth callback is hosted on a different origin (e.g., auth subdomain), pass allowedOrigins: ['https://auth.example.com'] to createMcp(...) so the popup callback message is accepted.
API Reference
useMcp Hook
function useMcp(options: UseMcpOptions): UseMcpResultOptions
| Option | Type | Description |
|--------|------|-------------|
| url | string | Required. URL of your MCP server |
| clientName | string | Name of your client for OAuth registration |
| clientUri | string | URI of your client for OAuth registration |
| callbackUrl | string | Custom callback URL for OAuth redirect (defaults to /oauth/callback on the current origin) |
| storageKeyPrefix | string | Storage key prefix for OAuth data in localStorage (defaults to "mcp:auth") |
| clientConfig | object | Custom configuration for the MCP client identity |
| debug | boolean | Whether to enable verbose debug logging |
| autoRetry | boolean \| number | Auto retry connection if initial connection fails, with delay in ms |
| autoReconnect | boolean \| number | Auto reconnect if an established connection is lost, with delay in ms (default: 3000) |
| transportType | 'auto' \| 'http' \| 'sse' | Transport type preference: 'auto' (HTTP with SSE fallback), 'http' (HTTP only), 'sse' (SSE only) (default: 'auto') |
| preventAutoAuth | boolean | Prevent automatic authentication popup on initial connection (default: false) |
| onPopupWindow | (url: string, features: string, window: Window \| null) => void | Callback invoked just after the authentication popup window is opened |
Return Value
| Property | Type | Description |
|----------|------|-------------|
| state | string | Current connection state: 'discovering', 'pending_auth', 'authenticating', 'connecting', 'loading', 'ready', 'failed' |
| tools | Tool[] | Available tools from the MCP server |
| resources | Resource[] | Available resources from the MCP server |
| resourceTemplates | ResourceTemplate[] | Available resource templates from the MCP server |
| prompts | Prompt[] | Available prompts from the MCP server |
| error | string \| undefined | Error message if connection failed |
| authUrl | string \| undefined | Manual authentication URL if popup is blocked |
| log | { level: 'debug' \| 'info' \| 'warn' \| 'error'; message: string; timestamp: number }[] | Array of log messages |
| callTool | (name: string, args?: Record<string, unknown>) => Promise<any> | Function to call a tool on the MCP server |
| listResources | () => Promise<void> | Refresh the list of available resources |
| readResource | (uri: string) => Promise<{ contents: Array<...> }> | Read the contents of a specific resource |
| listPrompts | () => Promise<void> | Refresh the list of available prompts |
| getPrompt | (name: string, args?: Record<string, string>) => Promise<{ messages: Array<...> }> | Get a specific prompt with optional arguments |
| retry | () => void | Manually attempt to reconnect |
| disconnect | () => void | Disconnect from the MCP server |
| authenticate | () => void | Manually trigger authentication |
| clearStorage | () => void | Clear all stored authentication data |
License
MIT
