• TypeScript 99.3%
  • Shell 0.7%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Glen Maddern c260e971d9
Added openrouter (#25)
* Add models.dev data fetching script and pnpm command

- Created scripts/update-models.ts to fetch and filter models from models.dev API
- Added pnpm update-models command to package.json
- Generated initial models.json with 39 models from 3 providers
- Filtered to only include anthropic, groq, and openrouter providers
- Added tsx as dev dependency for TypeScript execution

Amp-Thread: https://ampcode.com/threads/T-918d21db-3d47-4c6f-a3d8-96a60b59674a
Co-authored-by: Amp <amp@ampcode.com>

* Create new type system and authentication for multi-provider support

- Refactored types/models.ts with new Provider and Model interfaces
- Added support for OAuth authentication alongside API keys
- Created useModels hook for favorites management and model data loading
- Added comprehensive auth utils with OAuth PKCE flow implementation
- Updated apiKeys.ts to use new auth system for backward compatibility
- Created OAuthCallback component for OAuth flow completion
- Added support for OpenRouter OAuth configuration

Amp-Thread: https://ampcode.com/threads/T-918d21db-3d47-4c6f-a3d8-96a60b59674a
Co-authored-by: Amp <amp@ampcode.com>

* Implement comprehensive ModelSelector refactor with favorites and OAuth support

- Refactored ModelSelector to use new favorites-based system with search and filtering
- Added star ratings for favorite models with local storage persistence
- Added search functionality to filter models by name/provider
- Added "Tools Only" and "Favorites" filter toggles
- Updated authentication to support OAuth PKCE flow alongside API keys
- Added OpenRouter OAuth support with proper error handling
- Updated ConversationThread, ModelSelectionModal, and ApiKeyModal to use new Provider type
- Added OAuth success message handling in ChatApp
- Updated useStreamResponse to support OpenRouter via @ai-sdk/openai
- Fixed all TypeScript compilation errors for new model system
- Added proper auth headers for all three providers (Groq, Anthropic, OpenRouter)

Amp-Thread: https://ampcode.com/threads/T-918d21db-3d47-4c6f-a3d8-96a60b59674a
Co-authored-by: Amp <amp@ampcode.com>

* Add final touches and documentation for model selector system

- Fixed unused import in useStreamResponse.ts
- Added .env.example for OpenRouter OAuth configuration
- Created comprehensive MODEL_SELECTOR_GUIDE.md with usage instructions
- Documented all features including favorites, search, filtering, and OAuth
- Added setup instructions for OpenRouter OAuth
- Included troubleshooting guide and local storage details

Amp-Thread: https://ampcode.com/threads/T-918d21db-3d47-4c6f-a3d8-96a60b59674a
Co-authored-by: Amp <amp@ampcode.com>

* Implement clean provider-first model selector with favorites workflow

- Refactored ModelSelector to show providers first, then starred models
- Created ProviderModelsModal for provider-specific model selection and starring
- Removed search/filter complexity from main dropdown
- Added handleProviderSelect to route between OAuth/API key flows
- OAuth providers show model selection after successful authentication
- API key providers show model selection after key entry
- Starred models appear grayed out when provider not configured
- Clicking unconfigured starred model redirects to provider setup
- Added OAuth success message handling to auto-open provider models
- Clean two-step workflow: configure provider → select/star models

Amp-Thread: https://ampcode.com/threads/T-918d21db-3d47-4c6f-a3d8-96a60b59674a
Co-authored-by: Amp <amp@ampcode.com>

* Fix ModelSelectionModal to use provider-first workflow

- Replaced the old flat model list in ModelSelectionModal with provider-first design
- Shows 3 provider cards (Anthropic, Groq, OpenRouter) with auth status
- Added starred models section below providers (empty initially)
- OAuth flow for OpenRouter, API key modals for Anthropic/Groq
- Provider selection leads to ProviderModelsModal for browsing and starring
- Grayed out starred models when provider not configured
- Click unconfigured starred model redirects to provider setup
- OAuth success automatically opens provider models modal
- Clean, intuitive workflow: Select Provider → Configure Auth → Browse Models → Star Favorites

Amp-Thread: https://ampcode.com/threads/T-918d21db-3d47-4c6f-a3d8-96a60b59674a
Co-authored-by: Amp <amp@ampcode.com>

* Fix OpenRouter OAuth flow to match their API specification

- Updated authorization URL from /oauth/authorize to /auth
- Changed token URL to /api/v1/auth/keys
- Removed client_id requirement (OpenRouter doesn't use it)
- Removed scopes (OpenRouter doesn't use them)
- Updated OAuth flow to use callback_url instead of redirect_uri
- Changed token exchange to use JSON body instead of form data
- Handle OpenRouter's response format {key: "..."} instead of {access_token: "..."}
- Made state parameter optional for OpenRouter (they don't use it)
- Updated sessionStorage handling for providers without state parameter
- Simplified .env.example to remove client_id requirement

Amp-Thread: https://ampcode.com/threads/T-918d21db-3d47-4c6f-a3d8-96a60b59674a
Co-authored-by: Amp <amp@ampcode.com>

* Fix model selection and favorites system

- **Fixed multiple useModels hook instances**: Removed duplicate hook from ModelSelectionModal and consolidated all model state management in ChatApp
- **Fixed auto-starring**: Models are now automatically starred when selected from any UI (provider modal or favorites list)
- **Fixed favorites persistence**: Starred models now properly persist in localStorage and are restored on page refresh
- **Fixed selected model highlighting**: Currently selected model is now highlighted in the starred models list with blue border, ring effect, and checkmark
- **Improved prop passing**: Pass all model-related functions (addToFavorites, toggleFavorite, isFavorite, getFavoriteModels) down through ChatApp → ConversationThread → ModelSelectionModal
- **Removed debug logs**: Cleaned up console.log statements added during debugging

The root cause was multiple instances of the useModels hook running simultaneously, causing state conflicts where one instance would load favorites correctly but another would reset them to an empty array. Now there's a single source of truth for all model state in ChatApp.

This fixes the specific issues where:
1. Selected models weren't being auto-starred
2. Starred models list was forgotten on page refresh
3. Selected model highlighting wasn't working in the modal

Amp-Thread: https://ampcode.com/threads/T-918d21db-3d47-4c6f-a3d8-96a60b59674a
Co-authored-by: Amp <amp@ampcode.com>

* Replace nested modals with single modal navigation

- **Improved UX**: Replaced stacked modals with a single modal that switches between views
- **Added back navigation**: Provider models view now has a back button in the top left to return to main view
- **Unified modal structure**: Single modal container with conditional rendering for main vs provider views
- **Added search functionality**: Provider models view includes a search bar to filter models
- **Better visual hierarchy**: Provider view shows provider logo and name in header
- **Removed ProviderModelsModal**: Consolidated functionality into ModelSelectionModal
- **Enhanced interaction**: Cleaner navigation flow without modal stacking

Main view shows:
- List of providers with authentication status
- Starred models section

Provider view shows:
- Back button + provider logo/name in header
- Search bar for filtering models
- List of provider's models with star/select actions
- Model count at bottom

This creates a much more intuitive navigation experience similar to mobile app patterns, avoiding the confusing nested modal behavior.

Amp-Thread: https://ampcode.com/threads/T-918d21db-3d47-4c6f-a3d8-96a60b59674a
Co-authored-by: Amp <amp@ampcode.com>

* Fix modal scrolling for overflow content

- **Fixed height constraints**: Modal now uses flexbox layout with proper height management
- **Added flex-shrink-0 to header**: Prevents header from shrinking and maintains fixed height
- **Added flex-1 min-h-0 to content**: Allows content area to take remaining space and scroll properly
- **Improved responsive behavior**: Modal content now scrolls vertically when overflowing on smaller screens

Key changes:
- Modal container: Added `flex flex-col` for vertical layout
- Header: Added `flex-shrink-0` to maintain fixed height
- Content area: Added `flex-1 min-h-0` to fill remaining space and enable scrolling

This ensures that:
1. Header stays fixed at top
2. Content area takes remaining vertical space
3. Content scrolls independently when overflowing
4. Works properly on all screen sizes, including small screens with many models

Amp-Thread: https://ampcode.com/threads/T-918d21db-3d47-4c6f-a3d8-96a60b59674a
Co-authored-by: Amp <amp@ampcode.com>

* Make provider model rows fully clickable

- **Improved UX consistency**: Provider model rows now behave like starred model rows
- **Full row clickable**: Click anywhere in the row to select and star the model
- **Event handling**: Star button uses stopPropagation to prevent row click when toggling favorites
- **Visual clarity**: Replaced "Select" button with subtle "Click to select" hint
- **Added cursor pointer**: Clear visual indication that rows are clickable

Changes:
- Added `cursor-pointer` and `onClick` to model rows in provider view
- Star button now stops event propagation to allow independent toggling
- Removed separate "Select" button for cleaner, more consistent interface
- Added "Click to select" text hint on the right side

This creates a consistent interaction pattern across both:
- Main view starred models (click row to select)
- Provider view models (click row to select and star)

Users can now efficiently browse and select models with single clicks, while still having granular control over favorites via the star button.

Amp-Thread: https://ampcode.com/threads/T-918d21db-3d47-4c6f-a3d8-96a60b59674a
Co-authored-by: Amp <amp@ampcode.com>

* localstorage saving working

---------

Co-authored-by: Amp <amp@ampcode.com>
2025-07-11 14:34:33 +10:00
.github/workflows welcome back old friend 2025-07-03 14:21:07 +10:00
.husky Adding husky config 2025-07-03 14:11:53 +10:00
examples Added openrouter (#25) 2025-07-11 14:34:33 +10:00
scripts Oauth tests (#13) 2025-07-01 13:26:26 +10:00
src docs: update README files with resources and prompts documentation 2025-07-02 16:01:04 -07:00
test Dev tooling tweaks 2025-07-04 14:45:30 +10:00
.gitignore Dev tooling tweaks 2025-07-04 14:45:30 +10:00
.prettierignore Adding transportType to API 2025-06-27 16:08:56 +10:00
.prettierrc Transfer from geelen/use-mcp 2025-06-18 21:46:43 +10:00
AGENT.md Dev tooling tweaks 2025-07-04 14:45:30 +10:00
LICENSE Transfer from geelen/use-mcp 2025-06-18 21:46:43 +10:00
oranda.json Transfer from geelen/use-mcp 2025-06-18 21:46:43 +10:00
package.json Dev tooling tweaks 2025-07-04 14:45:30 +10:00
pnpm-lock.yaml Dev tooling tweaks 2025-07-04 14:45:30 +10:00
README.md Dev tooling tweaks 2025-07-04 14:45:30 +10:00
tsconfig.json Merge pull request #10 from modelcontextprotocol/e2e-testing 2025-06-30 21:07:45 +10:00
wrangler.jsonc Sanitising URLs 2025-06-26 20:47:51 +10:00

🦑 use-mcp 🦑

GitHub last commit  npm GitHub License

A lightweight React hook for connecting to Model Context Protocol (MCP) servers. Simplifies authentication and tool calling for AI systems implementing the MCP standard.

Try it out: Chat Demo | MCP Inspector | Cloudflare Workers AI Playground

Installation

npm install use-mcp
# or
pnpm add use-mcp
# or
yarn add use-mcp

Development

To run the development environment with all examples and servers:

pnpm dev

This starts:

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 UI

Features

  • 🔄 Automatic connection management with reconnection and retries
  • 🔐 OAuth authentication flow handling with popup and fallback support
  • 📦 Simple React hook interface 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

Quick Start

import { useMcp } from '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>
  )
}

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 '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 'use-mcp'

export default function OAuthCallbackPage() {
  useEffect(() => {
    onMcpAuthorization()
  }, [])

  return (
    <div>
      <h1>Authenticating...</h1>
      <p>This window should close automatically.</p>
    </div>
  )
}

API Reference

useMcp Hook

function useMcp(options: UseMcpOptions): UseMcpResult

Options

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)

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