A lightweight TypeScript-first toolkit for connecting web apps to any Model Context Protocol (MCP) server.
useMcpReact hook – drop-in for React / Next.js- Framework-agnostic core (
BrowserOAuthClientProvider,onMcpAuthorization) - Handles OAuth 2 PKCE in the browser (popup & fallback)
- Transparent HTTP ⇢ SSE transport fallback with auto-reconnect
- Tiny, tree-shakable & 100 % typed (ES modules +
.d.ts)
Try it out: MCP Inspector · Workers AI Playground
npm i ts-mcp # pnpm add ts-mcp / yarn add ts-mcpPeer-dependencies (only if you use them):
npm i react react-dom # for the React hook (web)
npm i react-native @react-native-async-storage/async-storage # for React Native
npm i @angular/core # for the Angular service example| 🔄 | Automatic connection lifecycle with retry & reconnect |
| 🔐 | Full OAuth PKCE flow (popup + manual fallback URL) |
| 🌐 | Dual transport – streaming HTTP or SSE (auto-detect) |
| 🪝 | Simple React / React Native hook API (useMcp) |
| 🧩 | Works in Angular, Vue, vanilla TS – export is just TypeScript |
| 📝 | Built-in rolling log for easy debugging |
import { useMcp } from "ts-mcp/react";
export default function Chat() {
const { state, tools, error, callTool, retry, authenticate, clearStorage } =
useMcp({
url: "https://my-mcp.example.com/sse",
clientName: "My React App",
autoReconnect: true,
debug: process.env.NODE_ENV === "development",
});
if (state === "failed") {
return (
<div>
<p>Connection failed: {error}</p>
<button onClick={retry}>Retry</button>
<button onClick={authenticate}>Auth Popup</button>
</div>
);
}
if (state !== "ready") return <p>Connecting…</p>;
const search = () => callTool("search", { query: "hello" });
return (
<>
<p>{tools.length} tool(s) online</p>
<button onClick={search}>Search</button>
</>
);
}import React from "react";
import { View, Text, Button } from "react-native";
import { useMcp, AsyncStorageOAuthClientProvider } from "ts-mcp/react-native";
export default function App() {
const provider = React.useMemo(
() => new AsyncStorageOAuthClientProvider("https://my-mcp.example.com"),
[]
);
const { state, tools, authUrl, authenticate } = useMcp({
url: "https://my-mcp.example.com/sse",
provider,
debug: __DEV__,
});
if (authUrl) {
// You can open the authUrl with `Linking.openURL(authUrl)`
}
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<Text>{state}</Text>
<Text>{tools.length} tools</Text>
{state === "failed" && <Button title="Retry" onPress={authenticate} />}
</View>
);
}// Prefer the ready-made service shipped by the library:
import { McpService } from 'ts-mcp/angular';
// Add it to your component / constructor as usual
constructor(private readonly mcp: McpService) {}
async ngOnInit() {
await this.mcp.init();
const tools = await this.mcp.listTools();
}Want a custom wrapper? The original service implementation is still available here — copy & modify at will.
import { useEffect } from "react";
import { onMcpAuthorization } from "ts-mcp";
export default function OAuthCallback() {
useEffect(() => {
onMcpAuthorization(
new BrowserOAuthClientProvider("https://my-mcp.example.com")
);
}, []);
return <p>Authenticating… You can close this window.</p>;
}import { Component, OnInit } from "@angular/core";
import { onMcpAuthorization } from "ts-mcp";
@Component({ selector: "app-mcp-callback", template: "<p>Authenticating…</p>" })
export class McpCallbackComponent implements OnInit {
ngOnInit() {
onMcpAuthorization(
new BrowserOAuthClientProvider("https://my-mcp.example.com")
);
}
}Add a route for /oauth/callback that points to this component.
UseMcpOptions (selected):
| Name | Type | Default | Description |
|---|---|---|---|
url |
string |
– | Required – MCP SSE/HTTP endpoint |
clientName |
string |
"MCP React Client" | Friendly name in OAuth registration |
autoRetry |
boolean | number |
false |
Retry initial connection after failure (ms) |
autoReconnect |
boolean | number |
3000 |
Reconnect after disconnect (ms) |
debug |
boolean |
false |
Verbose console & in-hook log |
UseMcpResult (selected):
| Property | Type | Notes |
|---|---|---|
state |
'discovering' | 'authenticating' | 'connecting' | 'loading' | 'ready' | 'failed' |
Full lifecycle |
tools |
Tool[] |
Populated once state === 'ready' |
callTool |
(name, args?) ⇒ Promise<any> |
JSON-RPC |
retry() |
() ⇒ void |
Manual reconnect when failed |
authenticate() |
() ⇒ Promise<void> |
Opens/forces OAuth popup |
clearStorage() |
() ⇒ void |
Wipes tokens, client info, state |
| Export | Use case |
|---|---|
BrowserOAuthClientProvider |
Drop-in OAuth provider for any front-end. Stores tokens in localStorage. |
onMcpAuthorization() |
Run on your /oauth/callback page to complete PKCE exchange & notify opener. |
MIT © The MCP community