
Company News
AWS Security Hub Adds Socket for Supply Chain Security
Socket is now in the AWS Security Hub Extended plan. Adopt it through AWS, apply committed spend, and block malicious open source packages.
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
npm install dmcp
# or
pnpm add dmcp
# or
yarn add dmcp
| Framework | OAuth Components | MCP Client | Status |
|---|---|---|---|
| React | ✅ | ✅ | Full Support |
| Vue.js | ✅ | ❌ | OAuth Only |
| Angular | ✅ | ❌ | OAuth Only |
| Svelte | ✅ | ❌ | OAuth Only |
| Vanilla JS | ✅ | ❌ | OAuth 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.
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>
)
}
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.
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)
}
All frameworks need to set up an OAuth callback route to handle authentication redirects.
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>
)
}
// 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>
)
}
// 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>
)
}
<!-- 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
})
// 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 { }
<!-- 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>
<!-- /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>
<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>
// 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)
}
}
}
// 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>
useMcp React Hookimport { useMcp } from 'dmcp/react'
function useMcp(options: UseMcpOptions): UseMcpResult
| 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') |
| Property | Type | Description |
|---|---|---|
state | string | Current connection state: 'discovering', 'authenticating', 'connecting', 'loading', 'ready', 'failed' |
tools | Tool[] | Available tools from the MCP server |
error | string | undefined | Error message if connection failed |
authUrl | string | undefined | Manual authentication URL if popup is blocked |
log | LogEntry[] | Array of log messages |
callTool | (name: string, args?: Record<string, unknown>) => Promise<any> | Function to call a tool on the MCP server |
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 |
The main package exports OAuth authentication components that can be used in any framework:
import { BrowserOAuthClientProvider, onMcpAuthorization } from 'dmcp'
BrowserOAuthClientProvidernew BrowserOAuthClientProvider(serverUrl: string, options?: {
storageKeyPrefix?: string
clientName?: string
clientUri?: string
callbackUrl?: string
})
onMcpAuthorizationonMcpAuthorization(): Promise<void>
Call this function in your OAuth callback route to handle the authentication response.
MIT
FAQs
Unknown package
We found that dmcp demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

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.

Company News
Socket is now in the AWS Security Hub Extended plan. Adopt it through AWS, apply committed spend, and block malicious open source packages.

Research
/Security News
Popular npm packages keyv and cacheable compromised.

Security News
A misconfiguration gave three Anthropic models internet access, and one, believing it was in a simulation, shipped a credential-stealing package to PyPI.