+ err instanceof Error ? err.stack : ''
+ }
- `;
+ `
} catch (displayError) {
- console.error(`${logPrefix} Could not display error in callback window:`, displayError);
+ console.error(`${logPrefix} Could not display error in callback window:`, displayError)
}
// Clean up potentially invalid state on error
if (stateKey) {
- localStorage.removeItem(stateKey);
+ localStorage.removeItem(stateKey)
}
// Clean up potentially dangling verifier or last_auth_url if auth failed badly
// Note: saveTokens should clean these on success
if (provider) {
- localStorage.removeItem(provider.getKey('code_verifier'));
- localStorage.removeItem(provider.getKey('last_auth_url'));
+ localStorage.removeItem(provider.getKey('code_verifier'))
+ localStorage.removeItem(provider.getKey('last_auth_url'))
}
}
}
diff --git a/src/auth/types.ts b/src/auth/types.ts
index 95159be..76baac8 100644
--- a/src/auth/types.ts
+++ b/src/auth/types.ts
@@ -1,19 +1,19 @@
-import { OAuthMetadata } from '@modelcontextprotocol/sdk/shared/auth.js';
+import { OAuthMetadata } from '@modelcontextprotocol/sdk/shared/auth.js'
/**
* Internal type for storing OAuth state in localStorage during the popup flow.
* @internal
*/
export interface StoredState {
- expiry: number;
- metadata?: OAuthMetadata; // Optional: might not be needed if auth() rediscovers
- serverUrlHash: string;
+ expiry: number
+ metadata?: OAuthMetadata // Optional: might not be needed if auth() rediscovers
+ serverUrlHash: string
// Add provider options needed on callback:
providerOptions: {
- serverUrl: string;
- storageKeyPrefix: string;
- clientName: string;
- clientUri: string;
- callbackUrl: string;
- };
-}
\ No newline at end of file
+ serverUrl: string
+ storageKeyPrefix: string
+ clientName: string
+ clientUri: string
+ callbackUrl: string
+ }
+}
diff --git a/src/index.ts b/src/index.ts
index 4e1861b..95ac23d 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -3,12 +3,12 @@
* Provides browser-specific, framework-agnostic components for MCP OAuth.
*/
-export { BrowserOAuthClientProvider } from './auth/browser-provider.js';
-export { onMcpAuthorization } from './auth/callback.js';
+export { BrowserOAuthClientProvider } from './auth/browser-provider.js'
+export { onMcpAuthorization } from './auth/callback.js'
// Optionally re-export relevant types from SDK or internal types if needed
-export type { StoredState as InternalStoredState } from './auth/types.js'; // Example if needed internally
+export type { StoredState as InternalStoredState } from './auth/types.js' // Example if needed internally
// It's generally better to have users import SDK types directly from the SDK
// export type { Tool, JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
-// export type { OAuthClientInformation, OAuthMetadata, OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth.js';
\ No newline at end of file
+// export type { OAuthClientInformation, OAuthMetadata, OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth.js';
diff --git a/src/react/README.md b/src/react/README.md
index cf380f5..3e15c47 100644
--- a/src/react/README.md
+++ b/src/react/README.md
@@ -21,17 +21,17 @@ The useMcp hook manages the connection to an MCP server, handles authentication
## Importing
```tsx
-import { useMcp } from 'use-mcp';
+import { useMcp } from 'use-mcp'
// Optional: Import types if needed
-import type { UseMcpOptions, UseMcpResult, Tool } from 'use-mcp';
+import type { UseMcpOptions, UseMcpResult, Tool } from 'use-mcp'
```
## Usage
```tsx
-import React from 'react';
-import { useMcp } from 'use-mcp/react';
-import { useChat } from 'ai/react'; // Example integration with Vercel AI SDK
+import React from 'react'
+import { useMcp } from 'use-mcp/react'
+import { useChat } from 'ai/react' // Example integration with Vercel AI SDK
function MyChatComponent() {
const mcp = useMcp({
@@ -45,7 +45,7 @@ function MyChatComponent() {
debug: process.env.NODE_ENV === 'development', // Enable debug logs in dev
autoReconnect: true, // Automatically reconnect if connection drops
autoRetry: 5000, // Retry connection every 5s if initial connection fails
- });
+ })
// Example: Using MCP tools with Vercel AI SDK's useChat
const { messages, input, handleInputChange, handleSubmit } = useChat({
@@ -55,32 +55,29 @@ function MyChatComponent() {
// Example: Handling tool calls made by the LLM
async onToolCall({ toolCall }) {
if (mcp.state !== 'ready') {
- console.error('MCP not ready, cannot handle tool call:', toolCall);
+ console.error('MCP not ready, cannot handle tool call:', toolCall)
// Return an error or indication that the tool cannot be called
return {
- toolCallId: toolCall.toolCallId,
- result: { error: 'Tool provider not available' }
- };
+ toolCallId: toolCall.toolCallId,
+ result: { error: 'Tool provider not available' },
+ }
}
try {
- console.log('Handling tool call via MCP:', toolCall);
- const result = await mcp.callTool(
- toolCall.toolName,
- toolCall.args,
- );
+ console.log('Handling tool call via MCP:', toolCall)
+ const result = await mcp.callTool(toolCall.toolName, toolCall.args)
return {
toolCallId: toolCall.toolCallId,
result,
- };
+ }
} catch (error) {
- console.error('Error calling MCP tool:', error);
+ console.error('Error calling MCP tool:', error)
return {
- toolCallId: toolCall.toolCallId,
- result: { error: error instanceof Error ? error.message : String(error) }
- };
+ toolCallId: toolCall.toolCallId,
+ result: { error: error instanceof Error ? error.message : String(error) },
+ }
}
},
- });
+ })
return (
@@ -99,8 +96,8 @@ function MyChatComponent() {
)}
- {/* Show retry button for general failures */}
- {!mcp.authUrl && }
+ {/* Show retry button for general failures */}
+ {!mcp.authUrl && }
)}
{mcp.state === 'authenticating' &&
Waiting for authentication...
}
@@ -124,50 +121,58 @@ function MyChatComponent() {
// Disable input if MCP is not ready and tools might be needed
disabled={mcp.state !== 'ready' && mcp.state !== 'loading'}
/>
-
+
{/* Optional: Display logs for debugging */}
{mcp.debug && (
)}
- {/* Button to clear stored auth data */}
-
+ {/* Button to clear stored auth data */}
+
- );
+ )
}
-export default MyChatComponent;
+export default MyChatComponent
```
### Hook Options (UseMcpOptions)
-* url (required): The /sse URL of your MCP server.
-* clientName: Name used for OAuth dynamic client registration (if applicable). Defaults to "MCP React Client".
-* clientUri: Client URI used for OAuth registration. Defaults to window.location.origin.
-* callbackUrl: The absolute URL of your OAuth callback page. Must match the redirect URI registered with your OAuth server and the route where you call onMcpAuthorization. Defaults to /oauth/callback on the current origin.
-* storageKeyPrefix: Prefix for keys used in localStorage (e.g., tokens, client info). Defaults to "mcp:auth". Useful to avoid conflicts if multiple MCP instances/apps run on the same origin.
-* clientConfig: Information about the client application sent during the MCP handshake. Includes name (default: "mcp-react-client") and version (default: "0.1.0").
-* debug: Enable verbose logging to the console and the log state array. Defaults to false.
-* autoRetry: If true or a number (milliseconds), automatically tries to reconnect if the initial connection fails. Defaults to false. Uses a 5000ms delay if set to true.
-* autoReconnect: If true or a number (milliseconds), automatically tries to reconnect if an established connection is lost. Defaults to 3000 (3 seconds). Set to false to disable.
-* popupFeatures: The features string passed to window.open for the OAuth popup. Defaults to "width=600,height=700,resizable=yes,scrollbars=yes,status=yes".
+- url (required): The /sse URL of your MCP server.
+- clientName: Name used for OAuth dynamic client registration (if applicable). Defaults to "MCP React Client".
+- clientUri: Client URI used for OAuth registration. Defaults to window.location.origin.
+- callbackUrl: The absolute URL of your OAuth callback page. Must match the redirect URI registered with your OAuth server and the route where you call onMcpAuthorization. Defaults to /oauth/callback on the current origin.
+- storageKeyPrefix: Prefix for keys used in localStorage (e.g., tokens, client info). Defaults to "mcp:auth". Useful to avoid conflicts if multiple MCP instances/apps run on the same origin.
+- clientConfig: Information about the client application sent during the MCP handshake. Includes name (default: "mcp-react-client") and version (default: "0.1.0").
+- debug: Enable verbose logging to the console and the log state array. Defaults to false.
+- autoRetry: If true or a number (milliseconds), automatically tries to reconnect if the initial connection fails. Defaults to false. Uses a 5000ms delay if set to true.
+- autoReconnect: If true or a number (milliseconds), automatically tries to reconnect if an established connection is lost. Defaults to 3000 (3 seconds). Set to false to disable.
+- popupFeatures: The features string passed to window.open for the OAuth popup. Defaults to "width=600,height=700,resizable=yes,scrollbars=yes,status=yes".
### Hook Return Value (UseMcpResult)
-* tools: An array of Tool objects provided by the server. Empty until state is 'ready'.
-* state: The current connection state ('discovering', 'authenticating', 'connecting', 'loading', 'ready', 'failed'). Use this to conditionally render UI or enable/disable features.
-* error: An error message if state is 'failed'.
-* authUrl: If authentication is required and the popup was potentially blocked, this URL string can be used to let the user manually open the auth page (e.g., ...).
-* log: An array of log messages { level, message, timestamp }. Useful for debugging when debug option is true.
-* callTool(name, args): An async function to execute a tool on the MCP server. Throws an error if the client isn't ready or the call fails.
-* retry(): Manually triggers a reconnection attempt if the state is 'failed'.
-* disconnect(): Disconnects the client from the server.
-* authenticate(): Manually attempts to start the authentication flow. Useful for triggering the popup via a user click if it was initially blocked.
-* clearStorage(): Removes all authentication-related data (tokens, client info, code verifier, state) for the configured server URL from localStorage. Useful for development or allowing users to "log out". Automatically disconnects the client.
+- tools: An array of Tool objects provided by the server. Empty until state is 'ready'.
+- state: The current connection state ('discovering', 'authenticating', 'connecting', 'loading', 'ready', 'failed'). Use this to conditionally render UI or enable/disable features.
+- error: An error message if state is 'failed'.
+- authUrl: If authentication is required and the popup was potentially blocked, this URL string can be used to let the user manually open the auth page (e.g., ...).
+- log: An array of log messages { level, message, timestamp }. Useful for debugging when debug option is true.
+- callTool(name, args): An async function to execute a tool on the MCP server. Throws an error if the client isn't ready or the call fails.
+- retry(): Manually triggers a reconnection attempt if the state is 'failed'.
+- disconnect(): Disconnects the client from the server.
+- authenticate(): Manually attempts to start the authentication flow. Useful for triggering the popup via a user click if it was initially blocked.
+- clearStorage(): Removes all authentication-related data (tokens, client info, code verifier, state) for the configured server URL from localStorage. Useful for development or allowing users to "log out". Automatically disconnects the client.
### Setting up the OAuth Callback Route
-Remember to create the callback route (e.g., /oauth/callback) specified in callbackUrl and have it execute the onMcpAuthorization function exported from the main use-mcp package. See the root README for an example.
\ No newline at end of file
+Remember to create the callback route (e.g., /oauth/callback) specified in callbackUrl and have it execute the onMcpAuthorization function exported from the main use-mcp package. See the root README for an example.
diff --git a/src/react/index.ts b/src/react/index.ts
index 257220f..c2aedd7 100644
--- a/src/react/index.ts
+++ b/src/react/index.ts
@@ -3,8 +3,8 @@
* Provides the useMcp hook and related types.
*/
-export { useMcp } from './useMcp.js';
-export type { UseMcpOptions, UseMcpResult } from './types.js';
+export { useMcp } from './useMcp.js'
+export type { UseMcpOptions, UseMcpResult } from './types.js'
// Re-export core Tool type for convenience when using hook result?
-export type { Tool } from '@modelcontextprotocol/sdk/types.js';
\ No newline at end of file
+export type { Tool } from '@modelcontextprotocol/sdk/types.js'
diff --git a/src/react/types.ts b/src/react/types.ts
index 8f08800..165c0ab 100644
--- a/src/react/types.ts
+++ b/src/react/types.ts
@@ -1,36 +1,36 @@
-import { Tool } from '@modelcontextprotocol/sdk/types.js';
+import { Tool } from '@modelcontextprotocol/sdk/types.js'
export type UseMcpOptions = {
/** The /sse URL of your remote MCP server */
- url: string;
+ url: string
/** OAuth client name for registration (if dynamic registration is used) */
- clientName?: string;
+ clientName?: string
/** OAuth client URI for registration (if dynamic registration is used) */
- clientUri?: string;
+ clientUri?: string
/** Custom callback URL for OAuth redirect (defaults to /oauth/callback on the current origin) */
- callbackUrl?: string;
+ callbackUrl?: string
/** Storage key prefix for OAuth data in localStorage (defaults to "mcp:auth") */
- storageKeyPrefix?: string;
+ storageKeyPrefix?: string
/** Custom configuration for the MCP client identity */
clientConfig?: {
- name?: string;
- version?: string;
- };
+ name?: string
+ version?: string
+ }
/** Custom headers that can be used to bypass auth */
- customHeaders?: Record;
+ customHeaders?: Record
/** Whether to enable verbose debug logging to the console and the log state */
- debug?: boolean;
+ debug?: boolean
/** Auto retry connection if initial connection fails, with delay in ms (default: false) */
- autoRetry?: boolean | number;
+ autoRetry?: boolean | number
/** Auto reconnect if an established connection is lost, with delay in ms (default: 3000) */
- autoReconnect?: boolean | number;
+ autoReconnect?: boolean | number
/** Popup window features string (dimensions and behavior) for OAuth */
- popupFeatures?: string;
-};
+ popupFeatures?: string
+}
export type UseMcpResult = {
/** List of tools available from the connected MCP server */
- tools: Tool[];
+ tools: Tool[]
/**
* The current state of the MCP connection:
* - 'discovering': Checking server existence and capabilities (including auth requirements).
@@ -40,16 +40,16 @@ export type UseMcpResult = {
* - 'ready': Connected and ready for tool calls.
* - 'failed': Connection or authentication failed. Check the `error` property.
*/
- state: 'discovering' | 'authenticating' | 'connecting' | 'loading' | 'ready' | 'failed';
+ state: 'discovering' | 'authenticating' | 'connecting' | 'loading' | 'ready' | 'failed'
/** If the state is 'failed', this provides the error message */
- error?: string;
+ error?: string
/**
* If authentication requires user interaction (e.g., popup was blocked),
* this URL can be presented to the user to complete authentication manually in a new tab.
*/
- authUrl?: string;
+ authUrl?: string
/** Array of internal log messages (useful for debugging) */
- log: { level: 'debug' | 'info' | 'warn' | 'error'; message: string; timestamp: number }[];
+ log: { level: 'debug' | 'info' | 'warn' | 'error'; message: string; timestamp: number }[]
/**
* Function to call a tool on the MCP server.
* @param name The name of the tool to call.
@@ -57,18 +57,18 @@ export type UseMcpResult = {
* @returns A promise that resolves with the tool's result.
* @throws If the client is not in the 'ready' state or the call fails.
*/
- callTool: (name: string, args?: Record) => Promise;
+ callTool: (name: string, args?: Record) => Promise
/** Manually attempts to reconnect if the state is 'failed'. */
- retry: () => void;
+ retry: () => void
/** Disconnects the client from the MCP server. */
- disconnect: () => void;
+ disconnect: () => void
/**
* Manually triggers the authentication process. Useful if the initial attempt failed
* due to a blocked popup, allowing the user to initiate it via a button click.
* @returns A promise that resolves with the authorization URL opened (or intended to be opened),
* or undefined if auth cannot be started.
*/
- authenticate: () => void;
+ authenticate: () => void
/** Clears all stored authentication data (tokens, client info, etc.) for this server URL from localStorage. */
- clearStorage: () => void;
-};
\ No newline at end of file
+ clearStorage: () => void
+}
diff --git a/src/utils/assert.ts b/src/utils/assert.ts
index 7ecbc36..544eace 100644
--- a/src/utils/assert.ts
+++ b/src/utils/assert.ts
@@ -6,6 +6,6 @@
*/
export function assert(condition: unknown, message: string): asserts condition {
if (!condition) {
- throw new Error(message);
+ throw new Error(message)
}
-}
\ No newline at end of file
+}