ts-mcp
v0.1.3
Published
Framework-agnostic helpers (plus React hook) for Model Context Protocol OAuth flows.
Maintainers
Readme
🦑 ts-mcp 🦑
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
Installation
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✨ Features
| | |
| --- | --------------------------------------------------------------------- |
| 🔄 | 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 |
Quick Start (React)
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>
</>
);
}Quick Start (React Native)
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>
);
}Quick Start (Angular ≥ 17)
// 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.
Setting up the OAuth callback
React Router
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>;
}Angular Router
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.
API Reference (summary)
useMcp(options) → UseMcpResult
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 |
Framework-agnostic helpers
| 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. |
License
MIT © The MCP community
