🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

dmcp

Package Overview
Dependencies
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

dmcp

latest
Source
npmnpm
Version
0.0.14
Version published
Maintainers
1
Created
Source

🦑 dmcp 🦑

GitHub last commit  npm GitHub License

A TypeScript/JavaScript library for connecting to Model Context Protocol (MCP) servers. Provides OAuth authentication components and a React hook for easy integration with AI systems implementing the MCP standard.

Try it out: MCP Inspector | Cloudflare Workers AI Playground

Installation

npm install dmcp
# or
pnpm add dmcp
# or
yarn add dmcp

What's Included

  • 🔐 OAuth Authentication Components - Framework-agnostic browser OAuth flow handling
  • ⚛️ React Hook - Complete MCP client with connection management, tool calling, and state management
  • 🧰 TypeScript Types - Full type safety and editor support

Framework Support

FrameworkOAuth ComponentsMCP ClientStatus
ReactFull Support
Vue.jsOAuth Only
AngularOAuth Only
SvelteOAuth Only
Vanilla JSOAuth Only

Note: Currently, only React has a complete MCP client implementation. Other frameworks can use the OAuth components to handle authentication, but you'll need to implement the MCP client logic using the @modelcontextprotocol/sdk directly.

Quick Start

React (Complete MCP Client)

import { useMcp } from 'dmcp/react'

function MyAIComponent() {
  const {
    state,          // Connection state
    tools,          // Available tools from MCP server
    error,          // Error message if connection failed
    callTool,       // Function to call tools
    retry,          // Retry connection
    authenticate,   // Manual authentication trigger
    clearStorage,   // Clear stored credentials
  } = useMcp({
    url: 'https://your-mcp-server.com',
    clientName: 'My App',
    autoReconnect: true,
  })

  // Handle different connection 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>
    </div>
  )
}

Other Frameworks (OAuth Only)

For Vue.js, Angular, Svelte, and vanilla JavaScript, dmcp provides OAuth authentication components. You'll need to implement the MCP client functionality yourself using the @modelcontextprotocol/sdk.

Basic OAuth Setup

import { BrowserOAuthClientProvider, onMcpAuthorization } from 'dmcp'
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'

// Initialize OAuth provider
const authProvider = new BrowserOAuthClientProvider('https://your-mcp-server.com', {
  clientName: 'My App',
  storageKeyPrefix: 'myapp:auth'
})

// Create MCP client
const client = new Client(
  { name: 'my-app', version: '1.0.0' },
  { capabilities: {} }
)

// Create transport with auth
const transport = new SSEClientTransport(
  new URL('https://your-mcp-server.com'),
  { authProvider }
)

// Connect and use
try {
  await client.connect(transport)
  const tools = await client.request({ method: 'tools/list' })
  console.log('Available tools:', tools)
} catch (error) {
  console.error('Connection failed:', error)
}

OAuth Callback Setup

All frameworks need to set up an OAuth callback route to handle authentication redirects.

React Router

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import { useEffect } from 'react'
import { onMcpAuthorization } from 'dmcp'

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>
  )
}

Next.js Pages Router

// pages/oauth/callback.tsx
import { useEffect } from 'react'
import { onMcpAuthorization } from 'dmcp'

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

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

Next.js App Router

// app/oauth/callback/page.tsx
'use client'
import { useEffect } from 'react'
import { onMcpAuthorization } from 'dmcp'

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

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

Vue.js

<!-- OAuthCallback.vue -->
<template>
  <div>
    <h1>Authenticating...</h1>
    <p>This window should close automatically.</p>
  </div>
</template>

<script setup>
import { onMounted } from 'vue'
import { onMcpAuthorization } from 'dmcp'

onMounted(() => {
  onMcpAuthorization()
})
</script>
// router.js
import { createRouter, createWebHistory } from 'vue-router'
import OAuthCallback from './components/OAuthCallback.vue'
import Home from './components/Home.vue'

const routes = [
  { path: '/', component: Home },
  { path: '/oauth/callback', component: OAuthCallback }
]

export default createRouter({
  history: createWebHistory(),
  routes
})

Angular

// oauth-callback.component.ts
import { Component, OnInit } from '@angular/core'
import { onMcpAuthorization } from 'dmcp'

@Component({
  selector: 'app-oauth-callback',
  template: `
    <div>
      <h1>Authenticating...</h1>
      <p>This window should close automatically.</p>
    </div>
  `
})
export class OAuthCallbackComponent implements OnInit {
  ngOnInit() {
    onMcpAuthorization()
  }
}
// app-routing.module.ts
import { NgModule } from '@angular/core'
import { RouterModule, Routes } from '@angular/router'
import { OAuthCallbackComponent } from './oauth-callback.component'

const routes: Routes = [
  { path: 'oauth/callback', component: OAuthCallbackComponent },
  // other routes...
]

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Svelte/SvelteKit

<!-- src/routes/oauth/callback/+page.svelte -->
<script>
  import { onMount } from 'svelte'
  import { onMcpAuthorization } from 'dmcp'

  onMount(() => {
    onMcpAuthorization()
  })
</script>

<div>
  <h1>Authenticating...</h1>
  <p>This window should close automatically.</p>
</div>

Vanilla JavaScript

<!-- /oauth/callback.html -->
<!DOCTYPE html>
<html>
<head>
  <title>OAuth Callback</title>
</head>
<body>
  <h1>Authenticating...</h1>
  <p>This window should close automatically.</p>
  
  <script type="module">
    import { onMcpAuthorization } from 'dmcp'
    onMcpAuthorization()
  </script>
</body>
</html>

Framework-Specific Examples

Vue.js MCP Integration

<template>
  <div>
    <div v-if="connecting">Connecting to MCP server...</div>
    <div v-else-if="error" class="error">
      Error: {{ error }}
      <button @click="reconnect">Retry</button>
    </div>
    <div v-else>
      <h2>Available Tools: {{ tools.length }}</h2>
      <button @click="callExampleTool">Call Tool</button>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { BrowserOAuthClientProvider } from 'dmcp'
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'

const tools = ref([])
const error = ref(null)
const connecting = ref(true)

let client = null
let transport = null

const initMcp = async () => {
  try {
    const authProvider = new BrowserOAuthClientProvider('https://your-mcp-server.com', {
      clientName: 'Vue MCP App'
    })

    client = new Client(
      { name: 'vue-mcp-client', version: '1.0.0' },
      { capabilities: {} }
    )

    transport = new SSEClientTransport(
      new URL('https://your-mcp-server.com'),
      { authProvider }
    )

    await client.connect(transport)
    const toolsResponse = await client.request({ method: 'tools/list' })
    tools.value = toolsResponse.tools
    error.value = null
  } catch (err) {
    error.value = err.message
  } finally {
    connecting.value = false
  }
}

const callExampleTool = async () => {
  if (!client || tools.value.length === 0) return
  
  try {
    const result = await client.request({
      method: 'tools/call',
      params: {
        name: tools.value[0].name,
        arguments: {}
      }
    })
    console.log('Tool result:', result)
  } catch (err) {
    console.error('Tool call failed:', err)
  }
}

const reconnect = () => {
  connecting.value = true
  error.value = null
  initMcp()
}

onMounted(initMcp)

onUnmounted(() => {
  if (transport) {
    transport.close()
  }
})
</script>

<style>
.error {
  color: red;
  padding: 10px;
  border: 1px solid red;
  border-radius: 4px;
  margin: 10px 0;
}
</style>

Angular MCP Service

// mcp.service.ts
import { Injectable } from '@angular/core'
import { BehaviorSubject, Observable } from 'rxjs'
import { BrowserOAuthClientProvider } from 'dmcp'
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'

export interface McpState {
  connected: boolean
  tools: any[]
  error: string | null
  loading: boolean
}

@Injectable({
  providedIn: 'root'
})
export class McpService {
  private client: Client | null = null
  private transport: any = null
  
  private stateSubject = new BehaviorSubject<McpState>({
    connected: false,
    tools: [],
    error: null,
    loading: false
  })

  public state$: Observable<McpState> = this.stateSubject.asObservable()

  async connect(serverUrl: string, clientName: string = 'Angular MCP App') {
    this.updateState({ loading: true, error: null })

    try {
      const authProvider = new BrowserOAuthClientProvider(serverUrl, {
        clientName
      })

      this.client = new Client(
        { name: 'angular-mcp-client', version: '1.0.0' },
        { capabilities: {} }
      )

      this.transport = new SSEClientTransport(
        new URL(serverUrl),
        { authProvider }
      )

      await this.client.connect(this.transport)
      const toolsResponse = await this.client.request({ method: 'tools/list' })
      
      this.updateState({
        connected: true,
        tools: toolsResponse.tools,
        loading: false,
        error: null
      })
    } catch (error) {
      this.updateState({
        connected: false,
        loading: false,
        error: error instanceof Error ? error.message : 'Connection failed'
      })
    }
  }

  async callTool(name: string, args: any = {}) {
    if (!this.client) {
      throw new Error('Not connected to MCP server')
    }

    return await this.client.request({
      method: 'tools/call',
      params: { name, arguments: args }
    })
  }

  disconnect() {
    if (this.transport) {
      this.transport.close()
    }
    this.updateState({
      connected: false,
      tools: [],
      error: null,
      loading: false
    })
  }

  private updateState(partialState: Partial<McpState>) {
    const currentState = this.stateSubject.value
    this.stateSubject.next({ ...currentState, ...partialState })
  }
}
// mcp.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core'
import { McpService, McpState } from './mcp.service'
import { Observable } from 'rxjs'

@Component({
  selector: 'app-mcp',
  template: `
    <div *ngIf="state$ | async as state">
      <div *ngIf="state.loading">Connecting to MCP server...</div>
      
      <div *ngIf="state.error" class="error">
        Error: {{ state.error }}
        <button (click)="connect()">Retry</button>
      </div>
      
      <div *ngIf="state.connected">
        <h2>Available Tools: {{ state.tools.length }}</h2>
        <ul>
          <li *ngFor="let tool of state.tools">
            {{ tool.name }}
            <button (click)="callTool(tool.name)">Call</button>
          </li>
        </ul>
        <button (click)="disconnect()">Disconnect</button>
      </div>
    </div>
  `,
  styles: [`
    .error {
      color: red;
      padding: 10px;
      border: 1px solid red;
      border-radius: 4px;
      margin: 10px 0;
    }
  `]
})
export class McpComponent implements OnInit, OnDestroy {
  state$: Observable<McpState>

  constructor(private mcpService: McpService) {
    this.state$ = this.mcpService.state$
  }

  ngOnInit() {
    this.connect()
  }

  ngOnDestroy() {
    this.mcpService.disconnect()
  }

  connect() {
    this.mcpService.connect('https://your-mcp-server.com')
  }

  disconnect() {
    this.mcpService.disconnect()
  }

  async callTool(toolName: string) {
    try {
      const result = await this.mcpService.callTool(toolName)
      console.log('Tool result:', result)
    } catch (error) {
      console.error('Tool call failed:', error)
    }
  }
}

Svelte MCP Store

// lib/mcp.js
import { writable } from 'svelte/store'
import { BrowserOAuthClientProvider } from 'dmcp'
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'

export const mcpState = writable({
  connected: false,
  tools: [],
  error: null,
  loading: false
})

let client = null
let transport = null

export async function connectMcp(serverUrl, clientName = 'Svelte MCP App') {
  mcpState.update(state => ({ ...state, loading: true, error: null }))

  try {
    const authProvider = new BrowserOAuthClientProvider(serverUrl, {
      clientName
    })

    client = new Client(
      { name: 'svelte-mcp-client', version: '1.0.0' },
      { capabilities: {} }
    )

    transport = new SSEClientTransport(
      new URL(serverUrl),
      { authProvider }
    )

    await client.connect(transport)
    const toolsResponse = await client.request({ method: 'tools/list' })
    
    mcpState.set({
      connected: true,
      tools: toolsResponse.tools,
      loading: false,
      error: null
    })
  } catch (error) {
    mcpState.update(state => ({
      ...state,
      connected: false,
      loading: false,
      error: error.message
    }))
  }
}

export async function callTool(name, args = {}) {
  if (!client) {
    throw new Error('Not connected to MCP server')
  }

  return await client.request({
    method: 'tools/call',
    params: { name, arguments: args }
  })
}

export function disconnectMcp() {
  if (transport) {
    transport.close()
  }
  mcpState.set({
    connected: false,
    tools: [],
    error: null,
    loading: false
  })
}
<!-- McpComponent.svelte -->
<script>
  import { onMount, onDestroy } from 'svelte'
  import { mcpState, connectMcp, callTool, disconnectMcp } from './lib/mcp.js'

  onMount(() => {
    connectMcp('https://your-mcp-server.com')
  })

  onDestroy(() => {
    disconnectMcp()
  })

  async function handleToolCall(toolName) {
    try {
      const result = await callTool(toolName)
      console.log('Tool result:', result)
    } catch (error) {
      console.error('Tool call failed:', error)
    }
  }
</script>

<div>
  {#if $mcpState.loading}
    <div>Connecting to MCP server...</div>
  {:else if $mcpState.error}
    <div class="error">
      Error: {$mcpState.error}
      <button on:click={() => connectMcp('https://your-mcp-server.com')}>
        Retry
      </button>
    </div>
  {:else if $mcpState.connected}
    <div>
      <h2>Available Tools: {$mcpState.tools.length}</h2>
      <ul>
        {#each $mcpState.tools as tool (tool.name)}
          <li>
            {tool.name}
            <button on:click={() => handleToolCall(tool.name)}>
              Call
            </button>
          </li>
        {/each}
      </ul>
      <button on:click={disconnectMcp}>Disconnect</button>
    </div>
  {/if}
</div>

<style>
  .error {
    color: red;
    padding: 10px;
    border: 1px solid red;
    border-radius: 4px;
    margin: 10px 0;
  }
</style>

API Reference

useMcp React Hook

import { useMcp } from 'dmcp/react'

function useMcp(options: UseMcpOptions): UseMcpResult

Options

OptionTypeDescription
urlstringRequired. URL of your MCP server
clientNamestringName of your client for OAuth registration
clientUristringURI of your client for OAuth registration
callbackUrlstringCustom callback URL for OAuth redirect (defaults to /oauth/callback on the current origin)
storageKeyPrefixstringStorage key prefix for OAuth data in localStorage (defaults to "mcp:auth")
clientConfigobjectCustom configuration for the MCP client identity
debugbooleanWhether to enable verbose debug logging
autoRetryboolean | numberAuto retry connection if initial connection fails, with delay in ms
autoReconnectboolean | numberAuto 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')

Return Value

PropertyTypeDescription
statestringCurrent connection state: 'discovering', 'authenticating', 'connecting', 'loading', 'ready', 'failed'
toolsTool[]Available tools from the MCP server
errorstring | undefinedError message if connection failed
authUrlstring | undefinedManual authentication URL if popup is blocked
logLogEntry[]Array of log messages
callTool(name: string, args?: Record<string, unknown>) => Promise<any>Function to call a tool on the MCP server
retry() => voidManually attempt to reconnect
disconnect() => voidDisconnect from the MCP server
authenticate() => voidManually trigger authentication
clearStorage() => voidClear all stored authentication data

OAuth Components

The main package exports OAuth authentication components that can be used in any framework:

import { BrowserOAuthClientProvider, onMcpAuthorization } from 'dmcp'

BrowserOAuthClientProvider

new BrowserOAuthClientProvider(serverUrl: string, options?: {
  storageKeyPrefix?: string
  clientName?: string
  clientUri?: string
  callbackUrl?: string
})

onMcpAuthorization

onMcpAuthorization(): Promise<void>

Call this function in your OAuth callback route to handle the authentication response.

License

MIT

FAQs

Package last updated on 27 Jun 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts