inital upload

This commit is contained in:
jackbeeby
2025-05-15 13:35:49 +10:00
commit 8c53ff1000
9092 changed files with 1833300 additions and 0 deletions

21
node_modules/@modelcontextprotocol/sdk/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Anthropic, PBC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

840
node_modules/@modelcontextprotocol/sdk/README.md generated vendored Normal file
View File

@@ -0,0 +1,840 @@
# MCP TypeScript SDK ![NPM Version](https://img.shields.io/npm/v/%40modelcontextprotocol%2Fsdk) ![MIT licensed](https://img.shields.io/npm/l/%40modelcontextprotocol%2Fsdk)
## Table of Contents
- [Overview](#overview)
- [Installation](#installation)
- [Quickstart](#quickstart)
- [What is MCP?](#what-is-mcp)
- [Core Concepts](#core-concepts)
- [Server](#server)
- [Resources](#resources)
- [Tools](#tools)
- [Prompts](#prompts)
- [Running Your Server](#running-your-server)
- [stdio](#stdio)
- [Streamable HTTP](#streamable-http)
- [Testing and Debugging](#testing-and-debugging)
- [Examples](#examples)
- [Echo Server](#echo-server)
- [SQLite Explorer](#sqlite-explorer)
- [Advanced Usage](#advanced-usage)
- [Low-Level Server](#low-level-server)
- [Writing MCP Clients](#writing-mcp-clients)
- [Server Capabilities](#server-capabilities)
- [Proxy OAuth Server](#proxy-authorization-requests-upstream)
- [Backwards Compatibility](#backwards-compatibility)
## Overview
The Model Context Protocol allows applications to provide context for LLMs in a standardized way, separating the concerns of providing context from the actual LLM interaction. This TypeScript SDK implements the full MCP specification, making it easy to:
- Build MCP clients that can connect to any MCP server
- Create MCP servers that expose resources, prompts and tools
- Use standard transports like stdio and Streamable HTTP
- Handle all MCP protocol messages and lifecycle events
## Installation
```bash
npm install @modelcontextprotocol/sdk
```
## Quick Start
Let's create a simple MCP server that exposes a calculator tool and some data:
```typescript
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// Create an MCP server
const server = new McpServer({
name: "Demo",
version: "1.0.0"
});
// Add an addition tool
server.tool("add",
{ a: z.number(), b: z.number() },
async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }]
})
);
// Add a dynamic greeting resource
server.resource(
"greeting",
new ResourceTemplate("greeting://{name}", { list: undefined }),
async (uri, { name }) => ({
contents: [{
uri: uri.href,
text: `Hello, ${name}!`
}]
})
);
// Start receiving messages on stdin and sending messages on stdout
const transport = new StdioServerTransport();
await server.connect(transport);
```
## What is MCP?
The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) lets you build servers that expose data and functionality to LLM applications in a secure, standardized way. Think of it like a web API, but specifically designed for LLM interactions. MCP servers can:
- Expose data through **Resources** (think of these sort of like GET endpoints; they are used to load information into the LLM's context)
- Provide functionality through **Tools** (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect)
- Define interaction patterns through **Prompts** (reusable templates for LLM interactions)
- And more!
## Core Concepts
### Server
The McpServer is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:
```typescript
const server = new McpServer({
name: "My App",
version: "1.0.0"
});
```
### Resources
Resources are how you expose data to LLMs. They're similar to GET endpoints in a REST API - they provide data but shouldn't perform significant computation or have side effects:
```typescript
// Static resource
server.resource(
"config",
"config://app",
async (uri) => ({
contents: [{
uri: uri.href,
text: "App configuration here"
}]
})
);
// Dynamic resource with parameters
server.resource(
"user-profile",
new ResourceTemplate("users://{userId}/profile", { list: undefined }),
async (uri, { userId }) => ({
contents: [{
uri: uri.href,
text: `Profile data for user ${userId}`
}]
})
);
```
### Tools
Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects:
```typescript
// Simple tool with parameters
server.tool(
"calculate-bmi",
{
weightKg: z.number(),
heightM: z.number()
},
async ({ weightKg, heightM }) => ({
content: [{
type: "text",
text: String(weightKg / (heightM * heightM))
}]
})
);
// Async tool with external API call
server.tool(
"fetch-weather",
{ city: z.string() },
async ({ city }) => {
const response = await fetch(`https://api.weather.com/${city}`);
const data = await response.text();
return {
content: [{ type: "text", text: data }]
};
}
);
```
### Prompts
Prompts are reusable templates that help LLMs interact with your server effectively:
```typescript
server.prompt(
"review-code",
{ code: z.string() },
({ code }) => ({
messages: [{
role: "user",
content: {
type: "text",
text: `Please review this code:\n\n${code}`
}
}]
})
);
```
## Running Your Server
MCP servers in TypeScript need to be connected to a transport to communicate with clients. How you start the server depends on the choice of transport:
### stdio
For command-line tools and direct integrations:
```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new McpServer({
name: "example-server",
version: "1.0.0"
});
// ... set up server resources, tools, and prompts ...
const transport = new StdioServerTransport();
await server.connect(transport);
```
### Streamable HTTP
For remote servers, set up a Streamable HTTP transport that handles both client requests and server-to-client notifications.
#### With Session Management
In some cases, servers need to be stateful. This is achieved by [session management](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#session-management).
```typescript
import express from "express";
import { randomUUID } from "node:crypto";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js"
const app = express();
app.use(express.json());
// Map to store transports by session ID
const transports: { [sessionId: string]: StreamableHTTPServerTransport } = {};
// Handle POST requests for client-to-server communication
app.post('/mcp', async (req, res) => {
// Check for existing session ID
const sessionId = req.headers['mcp-session-id'] as string | undefined;
let transport: StreamableHTTPServerTransport;
if (sessionId && transports[sessionId]) {
// Reuse existing transport
transport = transports[sessionId];
} else if (!sessionId && isInitializeRequest(req.body)) {
// New initialization request
transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => randomUUID(),
onsessioninitialized: (sessionId) => {
// Store the transport by session ID
transports[sessionId] = transport;
}
});
// Clean up transport when closed
transport.onclose = () => {
if (transport.sessionId) {
delete transports[transport.sessionId];
}
};
const server = new McpServer({
name: "example-server",
version: "1.0.0"
});
// ... set up server resources, tools, and prompts ...
// Connect to the MCP server
await server.connect(transport);
} else {
// Invalid request
res.status(400).json({
jsonrpc: '2.0',
error: {
code: -32000,
message: 'Bad Request: No valid session ID provided',
},
id: null,
});
return;
}
// Handle the request
await transport.handleRequest(req, res, req.body);
});
// Reusable handler for GET and DELETE requests
const handleSessionRequest = async (req: express.Request, res: express.Response) => {
const sessionId = req.headers['mcp-session-id'] as string | undefined;
if (!sessionId || !transports[sessionId]) {
res.status(400).send('Invalid or missing session ID');
return;
}
const transport = transports[sessionId];
await transport.handleRequest(req, res);
};
// Handle GET requests for server-to-client notifications via SSE
app.get('/mcp', handleSessionRequest);
// Handle DELETE requests for session termination
app.delete('/mcp', handleSessionRequest);
app.listen(3000);
```
#### Without Session Management (Stateless)
For simpler use cases where session management isn't needed:
```typescript
const app = express();
app.use(express.json());
app.post('/mcp', async (req: Request, res: Response) => {
// In stateless mode, create a new instance of transport and server for each request
// to ensure complete isolation. A single instance would cause request ID collisions
// when multiple clients connect concurrently.
try {
const server = getServer();
const transport: StreamableHTTPServerTransport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
res.on('close', () => {
console.log('Request closed');
transport.close();
server.close();
});
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
} catch (error) {
console.error('Error handling MCP request:', error);
if (!res.headersSent) {
res.status(500).json({
jsonrpc: '2.0',
error: {
code: -32603,
message: 'Internal server error',
},
id: null,
});
}
}
});
app.get('/mcp', async (req: Request, res: Response) => {
console.log('Received GET MCP request');
res.writeHead(405).end(JSON.stringify({
jsonrpc: "2.0",
error: {
code: -32000,
message: "Method not allowed."
},
id: null
}));
});
app.delete('/mcp', async (req: Request, res: Response) => {
console.log('Received DELETE MCP request');
res.writeHead(405).end(JSON.stringify({
jsonrpc: "2.0",
error: {
code: -32000,
message: "Method not allowed."
},
id: null
}));
});
// Start the server
const PORT = 3000;
app.listen(PORT, () => {
console.log(`MCP Stateless Streamable HTTP Server listening on port ${PORT}`);
});
```
This stateless approach is useful for:
- Simple API wrappers
- RESTful scenarios where each request is independent
- Horizontally scaled deployments without shared session state
### Testing and Debugging
To test your server, you can use the [MCP Inspector](https://github.com/modelcontextprotocol/inspector). See its README for more information.
## Examples
### Echo Server
A simple server demonstrating resources, tools, and prompts:
```typescript
import { McpServer, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
const server = new McpServer({
name: "Echo",
version: "1.0.0"
});
server.resource(
"echo",
new ResourceTemplate("echo://{message}", { list: undefined }),
async (uri, { message }) => ({
contents: [{
uri: uri.href,
text: `Resource echo: ${message}`
}]
})
);
server.tool(
"echo",
{ message: z.string() },
async ({ message }) => ({
content: [{ type: "text", text: `Tool echo: ${message}` }]
})
);
server.prompt(
"echo",
{ message: z.string() },
({ message }) => ({
messages: [{
role: "user",
content: {
type: "text",
text: `Please process this message: ${message}`
}
}]
})
);
```
### SQLite Explorer
A more complex example showing database integration:
```typescript
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import sqlite3 from "sqlite3";
import { promisify } from "util";
import { z } from "zod";
const server = new McpServer({
name: "SQLite Explorer",
version: "1.0.0"
});
// Helper to create DB connection
const getDb = () => {
const db = new sqlite3.Database("database.db");
return {
all: promisify<string, any[]>(db.all.bind(db)),
close: promisify(db.close.bind(db))
};
};
server.resource(
"schema",
"schema://main",
async (uri) => {
const db = getDb();
try {
const tables = await db.all(
"SELECT sql FROM sqlite_master WHERE type='table'"
);
return {
contents: [{
uri: uri.href,
text: tables.map((t: {sql: string}) => t.sql).join("\n")
}]
};
} finally {
await db.close();
}
}
);
server.tool(
"query",
{ sql: z.string() },
async ({ sql }) => {
const db = getDb();
try {
const results = await db.all(sql);
return {
content: [{
type: "text",
text: JSON.stringify(results, null, 2)
}]
};
} catch (err: unknown) {
const error = err as Error;
return {
content: [{
type: "text",
text: `Error: ${error.message}`
}],
isError: true
};
} finally {
await db.close();
}
}
);
```
## Advanced Usage
### Dynamic Servers
If you want to offer an initial set of tools/prompts/resources, but later add additional ones based on user action or external state change, you can add/update/remove them _after_ the Server is connected. This will automatically emit the corresponding `listChanged` notificaions:
```ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
const server = new McpServer({
name: "Dynamic Example",
version: "1.0.0"
});
const listMessageTool = server.tool(
"listMessages",
{ channel: z.string() },
async ({ channel }) => ({
content: [{ type: "text", text: await listMessages(channel) }]
})
);
const putMessageTool = server.tool(
"putMessage",
{ channel: z.string(), message: z.string() },
async ({ channel, message }) => ({
content: [{ type: "text", text: await putMessage(channel, string) }]
})
);
// Until we upgrade auth, `putMessage` is disabled (won't show up in listTools)
putMessageTool.disable()
const upgradeAuthTool = server.tool(
"upgradeAuth",
{ permission: z.enum(["write', vadmin"])},
// Any mutations here will automatically emit `listChanged` notifications
async ({ permission }) => {
const { ok, err, previous } = await upgradeAuthAndStoreToken(permission)
if (!ok) return {content: [{ type: "text", text: `Error: ${err}` }]}
// If we previously had read-only access, 'putMessage' is now available
if (previous === "read") {
putMessageTool.enable()
}
if (permission === 'write') {
// If we've just upgraded to 'write' permissions, we can still call 'upgradeAuth'
// but can only upgrade to 'admin'.
upgradeAuthTool.update({
paramSchema: { permission: z.enum(["admin"]) }, // change validation rules
})
} else {
// If we're now an admin, we no longer have anywhere to upgrade to, so fully remove that tool
upgradeAuthTool.remove()
}
}
)
// Connect as normal
const transport = new StdioServerTransport();
await server.connect(transport);
```
### Low-Level Server
For more control, you can use the low-level Server class directly:
```typescript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
ListPromptsRequestSchema,
GetPromptRequestSchema
} from "@modelcontextprotocol/sdk/types.js";
const server = new Server(
{
name: "example-server",
version: "1.0.0"
},
{
capabilities: {
prompts: {}
}
}
);
server.setRequestHandler(ListPromptsRequestSchema, async () => {
return {
prompts: [{
name: "example-prompt",
description: "An example prompt template",
arguments: [{
name: "arg1",
description: "Example argument",
required: true
}]
}]
};
});
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
if (request.params.name !== "example-prompt") {
throw new Error("Unknown prompt");
}
return {
description: "Example prompt",
messages: [{
role: "user",
content: {
type: "text",
text: "Example prompt text"
}
}]
};
});
const transport = new StdioServerTransport();
await server.connect(transport);
```
### Writing MCP Clients
The SDK provides a high-level client interface:
```typescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const transport = new StdioClientTransport({
command: "node",
args: ["server.js"]
});
const client = new Client(
{
name: "example-client",
version: "1.0.0"
}
);
await client.connect(transport);
// List prompts
const prompts = await client.listPrompts();
// Get a prompt
const prompt = await client.getPrompt({
name: "example-prompt",
arguments: {
arg1: "value"
}
});
// List resources
const resources = await client.listResources();
// Read a resource
const resource = await client.readResource({
uri: "file:///example.txt"
});
// Call a tool
const result = await client.callTool({
name: "example-tool",
arguments: {
arg1: "value"
}
});
```
### Proxy Authorization Requests Upstream
You can proxy OAuth requests to an external authorization provider:
```typescript
import express from 'express';
import { ProxyOAuthServerProvider, mcpAuthRouter } from '@modelcontextprotocol/sdk';
const app = express();
const proxyProvider = new ProxyOAuthServerProvider({
endpoints: {
authorizationUrl: "https://auth.external.com/oauth2/v1/authorize",
tokenUrl: "https://auth.external.com/oauth2/v1/token",
revocationUrl: "https://auth.external.com/oauth2/v1/revoke",
},
verifyAccessToken: async (token) => {
return {
token,
clientId: "123",
scopes: ["openid", "email", "profile"],
}
},
getClient: async (client_id) => {
return {
client_id,
redirect_uris: ["http://localhost:3000/callback"],
}
}
})
app.use(mcpAuthRouter({
provider: proxyProvider,
issuerUrl: new URL("http://auth.external.com"),
baseUrl: new URL("http://mcp.example.com"),
serviceDocumentationUrl: new URL("https://docs.example.com/"),
}))
```
This setup allows you to:
- Forward OAuth requests to an external provider
- Add custom token validation logic
- Manage client registrations
- Provide custom documentation URLs
- Maintain control over the OAuth flow while delegating to an external provider
### Backwards Compatibility
Clients and servers with StreamableHttp tranport can maintain [backwards compatibility](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#backwards-compatibility) with the deprecated HTTP+SSE transport (from protocol version 2024-11-05) as follows
#### Client-Side Compatibility
For clients that need to work with both Streamable HTTP and older SSE servers:
```typescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
let client: Client|undefined = undefined
const baseUrl = new URL(url);
try {
client = new Client({
name: 'streamable-http-client',
version: '1.0.0'
});
const transport = new StreamableHTTPClientTransport(
new URL(baseUrl)
);
await client.connect(transport);
console.log("Connected using Streamable HTTP transport");
} catch (error) {
// If that fails with a 4xx error, try the older SSE transport
console.log("Streamable HTTP connection failed, falling back to SSE transport");
client = new Client({
name: 'sse-client',
version: '1.0.0'
});
const sseTransport = new SSEClientTransport(baseUrl);
await client.connect(sseTransport);
console.log("Connected using SSE transport");
}
```
#### Server-Side Compatibility
For servers that need to support both Streamable HTTP and older clients:
```typescript
import express from "express";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
const server = new McpServer({
name: "backwards-compatible-server",
version: "1.0.0"
});
// ... set up server resources, tools, and prompts ...
const app = express();
app.use(express.json());
// Store transports for each session type
const transports = {
streamable: {} as Record<string, StreamableHTTPServerTransport>,
sse: {} as Record<string, SSEServerTransport>
};
// Modern Streamable HTTP endpoint
app.all('/mcp', async (req, res) => {
// Handle Streamable HTTP transport for modern clients
// Implementation as shown in the "With Session Management" example
// ...
});
// Legacy SSE endpoint for older clients
app.get('/sse', async (req, res) => {
// Create SSE transport for legacy clients
const transport = new SSEServerTransport('/messages', res);
transports.sse[transport.sessionId] = transport;
res.on("close", () => {
delete transports.sse[transport.sessionId];
});
await server.connect(transport);
});
// Legacy message endpoint for older clients
app.post('/messages', async (req, res) => {
const sessionId = req.query.sessionId as string;
const transport = transports.sse[sessionId];
if (transport) {
await transport.handlePostMessage(req, res, req.body);
} else {
res.status(400).send('No transport found for sessionId');
}
});
app.listen(3000);
```
**Note**: The SSE transport is now deprecated in favor of Streamable HTTP. New implementations should use Streamable HTTP, and existing SSE implementations should plan to migrate.
## Documentation
- [Model Context Protocol documentation](https://modelcontextprotocol.io)
- [MCP Specification](https://spec.modelcontextprotocol.io)
- [Example Servers](https://github.com/modelcontextprotocol/servers)
## Contributing
Issues and pull requests are welcome on GitHub at https://github.com/modelcontextprotocol/typescript-sdk.
## License
This project is licensed under the MIT License—see the [LICENSE](LICENSE) file for details.

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=cli.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":""}

131
node_modules/@modelcontextprotocol/sdk/dist/cjs/cli.js generated vendored Normal file
View File

@@ -0,0 +1,131 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const ws_1 = __importDefault(require("ws"));
// eslint-disable-next-line @typescript-eslint/no-explicit-any
global.WebSocket = ws_1.default;
const express_1 = __importDefault(require("express"));
const index_js_1 = require("./client/index.js");
const sse_js_1 = require("./client/sse.js");
const stdio_js_1 = require("./client/stdio.js");
const websocket_js_1 = require("./client/websocket.js");
const index_js_2 = require("./server/index.js");
const sse_js_2 = require("./server/sse.js");
const stdio_js_2 = require("./server/stdio.js");
const types_js_1 = require("./types.js");
async function runClient(url_or_command, args) {
const client = new index_js_1.Client({
name: "mcp-typescript test client",
version: "0.1.0",
}, {
capabilities: {
sampling: {},
},
});
let clientTransport;
let url = undefined;
try {
url = new URL(url_or_command);
}
catch (_a) {
// Ignore
}
if ((url === null || url === void 0 ? void 0 : url.protocol) === "http:" || (url === null || url === void 0 ? void 0 : url.protocol) === "https:") {
clientTransport = new sse_js_1.SSEClientTransport(new URL(url_or_command));
}
else if ((url === null || url === void 0 ? void 0 : url.protocol) === "ws:" || (url === null || url === void 0 ? void 0 : url.protocol) === "wss:") {
clientTransport = new websocket_js_1.WebSocketClientTransport(new URL(url_or_command));
}
else {
clientTransport = new stdio_js_1.StdioClientTransport({
command: url_or_command,
args,
});
}
console.log("Connected to server.");
await client.connect(clientTransport);
console.log("Initialized.");
await client.request({ method: "resources/list" }, types_js_1.ListResourcesResultSchema);
await client.close();
console.log("Closed.");
}
async function runServer(port) {
if (port !== null) {
const app = (0, express_1.default)();
let servers = [];
app.get("/sse", async (req, res) => {
console.log("Got new SSE connection");
const transport = new sse_js_2.SSEServerTransport("/message", res);
const server = new index_js_2.Server({
name: "mcp-typescript test server",
version: "0.1.0",
}, {
capabilities: {},
});
servers.push(server);
server.onclose = () => {
console.log("SSE connection closed");
servers = servers.filter((s) => s !== server);
};
await server.connect(transport);
});
app.post("/message", async (req, res) => {
console.log("Received message");
const sessionId = req.query.sessionId;
const transport = servers
.map((s) => s.transport)
.find((t) => t.sessionId === sessionId);
if (!transport) {
res.status(404).send("Session not found");
return;
}
await transport.handlePostMessage(req, res);
});
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}/sse`);
});
}
else {
const server = new index_js_2.Server({
name: "mcp-typescript test server",
version: "0.1.0",
}, {
capabilities: {
prompts: {},
resources: {},
tools: {},
logging: {},
},
});
const transport = new stdio_js_2.StdioServerTransport();
await server.connect(transport);
console.log("Server running on stdio");
}
}
const args = process.argv.slice(2);
const command = args[0];
switch (command) {
case "client":
if (args.length < 2) {
console.error("Usage: client <server_url_or_command> [args...]");
process.exit(1);
}
runClient(args[1], args.slice(2)).catch((error) => {
console.error(error);
process.exit(1);
});
break;
case "server": {
const port = args[1] ? parseInt(args[1]) : null;
runServer(port).catch((error) => {
console.error(error);
process.exit(1);
});
break;
}
default:
console.error("Unrecognized command:", command);
}
//# sourceMappingURL=cli.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,118 @@
import type { OAuthClientMetadata, OAuthClientInformation, OAuthTokens, OAuthMetadata, OAuthClientInformationFull } from "../shared/auth.js";
/**
* Implements an end-to-end OAuth client to be used with one MCP server.
*
* This client relies upon a concept of an authorized "session," the exact
* meaning of which is application-defined. Tokens, authorization codes, and
* code verifiers should not cross different sessions.
*/
export interface OAuthClientProvider {
/**
* The URL to redirect the user agent to after authorization.
*/
get redirectUrl(): string | URL;
/**
* Metadata about this OAuth client.
*/
get clientMetadata(): OAuthClientMetadata;
/**
* Loads information about this OAuth client, as registered already with the
* server, or returns `undefined` if the client is not registered with the
* server.
*/
clientInformation(): OAuthClientInformation | undefined | Promise<OAuthClientInformation | undefined>;
/**
* If implemented, this permits the OAuth client to dynamically register with
* the server. Client information saved this way should later be read via
* `clientInformation()`.
*
* This method is not required to be implemented if client information is
* statically known (e.g., pre-registered).
*/
saveClientInformation?(clientInformation: OAuthClientInformationFull): void | Promise<void>;
/**
* Loads any existing OAuth tokens for the current session, or returns
* `undefined` if there are no saved tokens.
*/
tokens(): OAuthTokens | undefined | Promise<OAuthTokens | undefined>;
/**
* Stores new OAuth tokens for the current session, after a successful
* authorization.
*/
saveTokens(tokens: OAuthTokens): void | Promise<void>;
/**
* Invoked to redirect the user agent to the given URL to begin the authorization flow.
*/
redirectToAuthorization(authorizationUrl: URL): void | Promise<void>;
/**
* Saves a PKCE code verifier for the current session, before redirecting to
* the authorization flow.
*/
saveCodeVerifier(codeVerifier: string): void | Promise<void>;
/**
* Loads the PKCE code verifier for the current session, necessary to validate
* the authorization result.
*/
codeVerifier(): string | Promise<string>;
}
export type AuthResult = "AUTHORIZED" | "REDIRECT";
export declare class UnauthorizedError extends Error {
constructor(message?: string);
}
/**
* Orchestrates the full auth flow with a server.
*
* This can be used as a single entry point for all authorization functionality,
* instead of linking together the other lower-level functions in this module.
*/
export declare function auth(provider: OAuthClientProvider, { serverUrl, authorizationCode }: {
serverUrl: string | URL;
authorizationCode?: string;
}): Promise<AuthResult>;
/**
* Looks up RFC 8414 OAuth 2.0 Authorization Server Metadata.
*
* If the server returns a 404 for the well-known endpoint, this function will
* return `undefined`. Any other errors will be thrown as exceptions.
*/
export declare function discoverOAuthMetadata(serverUrl: string | URL, opts?: {
protocolVersion?: string;
}): Promise<OAuthMetadata | undefined>;
/**
* Begins the authorization flow with the given server, by generating a PKCE challenge and constructing the authorization URL.
*/
export declare function startAuthorization(serverUrl: string | URL, { metadata, clientInformation, redirectUrl, scope, }: {
metadata?: OAuthMetadata;
clientInformation: OAuthClientInformation;
redirectUrl: string | URL;
scope?: string;
}): Promise<{
authorizationUrl: URL;
codeVerifier: string;
}>;
/**
* Exchanges an authorization code for an access token with the given server.
*/
export declare function exchangeAuthorization(serverUrl: string | URL, { metadata, clientInformation, authorizationCode, codeVerifier, redirectUri, }: {
metadata?: OAuthMetadata;
clientInformation: OAuthClientInformation;
authorizationCode: string;
codeVerifier: string;
redirectUri: string | URL;
}): Promise<OAuthTokens>;
/**
* Exchange a refresh token for an updated access token.
*/
export declare function refreshAuthorization(serverUrl: string | URL, { metadata, clientInformation, refreshToken, }: {
metadata?: OAuthMetadata;
clientInformation: OAuthClientInformation;
refreshToken: string;
}): Promise<OAuthTokens>;
/**
* Performs OAuth 2.0 Dynamic Client Registration according to RFC 7591.
*/
export declare function registerClient(serverUrl: string | URL, { metadata, clientMetadata, }: {
metadata?: OAuthMetadata;
clientMetadata: OAuthClientMetadata;
}): Promise<OAuthClientInformationFull>;
//# sourceMappingURL=auth.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/client/auth.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,257 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UnauthorizedError = void 0;
exports.auth = auth;
exports.discoverOAuthMetadata = discoverOAuthMetadata;
exports.startAuthorization = startAuthorization;
exports.exchangeAuthorization = exchangeAuthorization;
exports.refreshAuthorization = refreshAuthorization;
exports.registerClient = registerClient;
const pkce_challenge_1 = __importDefault(require("pkce-challenge"));
const types_js_1 = require("../types.js");
const auth_js_1 = require("../shared/auth.js");
class UnauthorizedError extends Error {
constructor(message) {
super(message !== null && message !== void 0 ? message : "Unauthorized");
}
}
exports.UnauthorizedError = UnauthorizedError;
/**
* Orchestrates the full auth flow with a server.
*
* This can be used as a single entry point for all authorization functionality,
* instead of linking together the other lower-level functions in this module.
*/
async function auth(provider, { serverUrl, authorizationCode }) {
const metadata = await discoverOAuthMetadata(serverUrl);
// Handle client registration if needed
let clientInformation = await Promise.resolve(provider.clientInformation());
if (!clientInformation) {
if (authorizationCode !== undefined) {
throw new Error("Existing OAuth client information is required when exchanging an authorization code");
}
if (!provider.saveClientInformation) {
throw new Error("OAuth client information must be saveable for dynamic registration");
}
const fullInformation = await registerClient(serverUrl, {
metadata,
clientMetadata: provider.clientMetadata,
});
await provider.saveClientInformation(fullInformation);
clientInformation = fullInformation;
}
// Exchange authorization code for tokens
if (authorizationCode !== undefined) {
const codeVerifier = await provider.codeVerifier();
const tokens = await exchangeAuthorization(serverUrl, {
metadata,
clientInformation,
authorizationCode,
codeVerifier,
redirectUri: provider.redirectUrl,
});
await provider.saveTokens(tokens);
return "AUTHORIZED";
}
const tokens = await provider.tokens();
// Handle token refresh or new authorization
if (tokens === null || tokens === void 0 ? void 0 : tokens.refresh_token) {
try {
// Attempt to refresh the token
const newTokens = await refreshAuthorization(serverUrl, {
metadata,
clientInformation,
refreshToken: tokens.refresh_token,
});
await provider.saveTokens(newTokens);
return "AUTHORIZED";
}
catch (error) {
console.error("Could not refresh OAuth tokens:", error);
}
}
// Start new authorization flow
const { authorizationUrl, codeVerifier } = await startAuthorization(serverUrl, {
metadata,
clientInformation,
redirectUrl: provider.redirectUrl,
scope: provider.clientMetadata.scope
});
await provider.saveCodeVerifier(codeVerifier);
await provider.redirectToAuthorization(authorizationUrl);
return "REDIRECT";
}
/**
* Looks up RFC 8414 OAuth 2.0 Authorization Server Metadata.
*
* If the server returns a 404 for the well-known endpoint, this function will
* return `undefined`. Any other errors will be thrown as exceptions.
*/
async function discoverOAuthMetadata(serverUrl, opts) {
var _a;
const url = new URL("/.well-known/oauth-authorization-server", serverUrl);
let response;
try {
response = await fetch(url, {
headers: {
"MCP-Protocol-Version": (_a = opts === null || opts === void 0 ? void 0 : opts.protocolVersion) !== null && _a !== void 0 ? _a : types_js_1.LATEST_PROTOCOL_VERSION
}
});
}
catch (error) {
// CORS errors come back as TypeError
if (error instanceof TypeError) {
response = await fetch(url);
}
else {
throw error;
}
}
if (response.status === 404) {
return undefined;
}
if (!response.ok) {
throw new Error(`HTTP ${response.status} trying to load well-known OAuth metadata`);
}
return auth_js_1.OAuthMetadataSchema.parse(await response.json());
}
/**
* Begins the authorization flow with the given server, by generating a PKCE challenge and constructing the authorization URL.
*/
async function startAuthorization(serverUrl, { metadata, clientInformation, redirectUrl, scope, }) {
const responseType = "code";
const codeChallengeMethod = "S256";
let authorizationUrl;
if (metadata) {
authorizationUrl = new URL(metadata.authorization_endpoint);
if (!metadata.response_types_supported.includes(responseType)) {
throw new Error(`Incompatible auth server: does not support response type ${responseType}`);
}
if (!metadata.code_challenge_methods_supported ||
!metadata.code_challenge_methods_supported.includes(codeChallengeMethod)) {
throw new Error(`Incompatible auth server: does not support code challenge method ${codeChallengeMethod}`);
}
}
else {
authorizationUrl = new URL("/authorize", serverUrl);
}
// Generate PKCE challenge
const challenge = await (0, pkce_challenge_1.default)();
const codeVerifier = challenge.code_verifier;
const codeChallenge = challenge.code_challenge;
authorizationUrl.searchParams.set("response_type", responseType);
authorizationUrl.searchParams.set("client_id", clientInformation.client_id);
authorizationUrl.searchParams.set("code_challenge", codeChallenge);
authorizationUrl.searchParams.set("code_challenge_method", codeChallengeMethod);
authorizationUrl.searchParams.set("redirect_uri", String(redirectUrl));
if (scope) {
authorizationUrl.searchParams.set("scope", scope);
}
return { authorizationUrl, codeVerifier };
}
/**
* Exchanges an authorization code for an access token with the given server.
*/
async function exchangeAuthorization(serverUrl, { metadata, clientInformation, authorizationCode, codeVerifier, redirectUri, }) {
const grantType = "authorization_code";
let tokenUrl;
if (metadata) {
tokenUrl = new URL(metadata.token_endpoint);
if (metadata.grant_types_supported &&
!metadata.grant_types_supported.includes(grantType)) {
throw new Error(`Incompatible auth server: does not support grant type ${grantType}`);
}
}
else {
tokenUrl = new URL("/token", serverUrl);
}
// Exchange code for tokens
const params = new URLSearchParams({
grant_type: grantType,
client_id: clientInformation.client_id,
code: authorizationCode,
code_verifier: codeVerifier,
redirect_uri: String(redirectUri),
});
if (clientInformation.client_secret) {
params.set("client_secret", clientInformation.client_secret);
}
const response = await fetch(tokenUrl, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: params,
});
if (!response.ok) {
throw new Error(`Token exchange failed: HTTP ${response.status}`);
}
return auth_js_1.OAuthTokensSchema.parse(await response.json());
}
/**
* Exchange a refresh token for an updated access token.
*/
async function refreshAuthorization(serverUrl, { metadata, clientInformation, refreshToken, }) {
const grantType = "refresh_token";
let tokenUrl;
if (metadata) {
tokenUrl = new URL(metadata.token_endpoint);
if (metadata.grant_types_supported &&
!metadata.grant_types_supported.includes(grantType)) {
throw new Error(`Incompatible auth server: does not support grant type ${grantType}`);
}
}
else {
tokenUrl = new URL("/token", serverUrl);
}
// Exchange refresh token
const params = new URLSearchParams({
grant_type: grantType,
client_id: clientInformation.client_id,
refresh_token: refreshToken,
});
if (clientInformation.client_secret) {
params.set("client_secret", clientInformation.client_secret);
}
const response = await fetch(tokenUrl, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: params,
});
if (!response.ok) {
throw new Error(`Token refresh failed: HTTP ${response.status}`);
}
return auth_js_1.OAuthTokensSchema.parse(await response.json());
}
/**
* Performs OAuth 2.0 Dynamic Client Registration according to RFC 7591.
*/
async function registerClient(serverUrl, { metadata, clientMetadata, }) {
let registrationUrl;
if (metadata) {
if (!metadata.registration_endpoint) {
throw new Error("Incompatible auth server: does not support dynamic client registration");
}
registrationUrl = new URL(metadata.registration_endpoint);
}
else {
registrationUrl = new URL("/register", serverUrl);
}
const response = await fetch(registrationUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(clientMetadata),
});
if (!response.ok) {
throw new Error(`Dynamic client registration failed: HTTP ${response.status}`);
}
return auth_js_1.OAuthClientInformationFullSchema.parse(await response.json());
}
//# sourceMappingURL=auth.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,889 @@
import { Protocol, ProtocolOptions, RequestOptions } from "../shared/protocol.js";
import { Transport } from "../shared/transport.js";
import { CallToolRequest, CallToolResultSchema, ClientCapabilities, ClientNotification, ClientRequest, ClientResult, CompatibilityCallToolResultSchema, CompleteRequest, GetPromptRequest, Implementation, ListPromptsRequest, ListResourcesRequest, ListResourceTemplatesRequest, ListToolsRequest, LoggingLevel, Notification, ReadResourceRequest, Request, Result, ServerCapabilities, SubscribeRequest, UnsubscribeRequest } from "../types.js";
export type ClientOptions = ProtocolOptions & {
/**
* Capabilities to advertise as being supported by this client.
*/
capabilities?: ClientCapabilities;
};
/**
* An MCP client on top of a pluggable transport.
*
* The client will automatically begin the initialization flow with the server when connect() is called.
*
* To use with custom types, extend the base Request/Notification/Result types and pass them as type parameters:
*
* ```typescript
* // Custom schemas
* const CustomRequestSchema = RequestSchema.extend({...})
* const CustomNotificationSchema = NotificationSchema.extend({...})
* const CustomResultSchema = ResultSchema.extend({...})
*
* // Type aliases
* type CustomRequest = z.infer<typeof CustomRequestSchema>
* type CustomNotification = z.infer<typeof CustomNotificationSchema>
* type CustomResult = z.infer<typeof CustomResultSchema>
*
* // Create typed client
* const client = new Client<CustomRequest, CustomNotification, CustomResult>({
* name: "CustomClient",
* version: "1.0.0"
* })
* ```
*/
export declare class Client<RequestT extends Request = Request, NotificationT extends Notification = Notification, ResultT extends Result = Result> extends Protocol<ClientRequest | RequestT, ClientNotification | NotificationT, ClientResult | ResultT> {
private _clientInfo;
private _serverCapabilities?;
private _serverVersion?;
private _capabilities;
private _instructions?;
/**
* Initializes this client with the given name and version information.
*/
constructor(_clientInfo: Implementation, options?: ClientOptions);
/**
* Registers new capabilities. This can only be called before connecting to a transport.
*
* The new capabilities will be merged with any existing capabilities previously given (e.g., at initialization).
*/
registerCapabilities(capabilities: ClientCapabilities): void;
protected assertCapability(capability: keyof ServerCapabilities, method: string): void;
connect(transport: Transport, options?: RequestOptions): Promise<void>;
/**
* After initialization has completed, this will be populated with the server's reported capabilities.
*/
getServerCapabilities(): ServerCapabilities | undefined;
/**
* After initialization has completed, this will be populated with information about the server's name and version.
*/
getServerVersion(): Implementation | undefined;
/**
* After initialization has completed, this may be populated with information about the server's instructions.
*/
getInstructions(): string | undefined;
protected assertCapabilityForMethod(method: RequestT["method"]): void;
protected assertNotificationCapability(method: NotificationT["method"]): void;
protected assertRequestHandlerCapability(method: string): void;
ping(options?: RequestOptions): Promise<{
_meta?: import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough"> | undefined;
}>;
complete(params: CompleteRequest["params"], options?: RequestOptions): Promise<import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
_meta: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
}, {
completion: import("zod").ZodObject<{
values: import("zod").ZodArray<import("zod").ZodString, "many">;
total: import("zod").ZodOptional<import("zod").ZodNumber>;
hasMore: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
values: import("zod").ZodArray<import("zod").ZodString, "many">;
total: import("zod").ZodOptional<import("zod").ZodNumber>;
hasMore: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
values: import("zod").ZodArray<import("zod").ZodString, "many">;
total: import("zod").ZodOptional<import("zod").ZodNumber>;
hasMore: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, import("zod").ZodTypeAny, "passthrough">>;
}>, import("zod").ZodTypeAny, "passthrough">>;
setLoggingLevel(level: LoggingLevel, options?: RequestOptions): Promise<{
_meta?: import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough"> | undefined;
}>;
getPrompt(params: GetPromptRequest["params"], options?: RequestOptions): Promise<import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
_meta: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
}, {
description: import("zod").ZodOptional<import("zod").ZodString>;
messages: import("zod").ZodArray<import("zod").ZodObject<{
role: import("zod").ZodEnum<["user", "assistant"]>;
content: import("zod").ZodUnion<[import("zod").ZodObject<{
type: import("zod").ZodLiteral<"text">;
text: import("zod").ZodString;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"text">;
text: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"text">;
text: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<{
type: import("zod").ZodLiteral<"image">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"image">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"image">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<{
type: import("zod").ZodLiteral<"audio">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"audio">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"audio">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<{
type: import("zod").ZodLiteral<"resource">;
resource: import("zod").ZodUnion<[import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>]>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"resource">;
resource: import("zod").ZodUnion<[import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>]>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"resource">;
resource: import("zod").ZodUnion<[import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>]>;
}, import("zod").ZodTypeAny, "passthrough">>]>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
role: import("zod").ZodEnum<["user", "assistant"]>;
content: import("zod").ZodUnion<[import("zod").ZodObject<{
type: import("zod").ZodLiteral<"text">;
text: import("zod").ZodString;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"text">;
text: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"text">;
text: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<{
type: import("zod").ZodLiteral<"image">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"image">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"image">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<{
type: import("zod").ZodLiteral<"audio">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"audio">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"audio">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<{
type: import("zod").ZodLiteral<"resource">;
resource: import("zod").ZodUnion<[import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>]>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"resource">;
resource: import("zod").ZodUnion<[import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>]>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"resource">;
resource: import("zod").ZodUnion<[import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>]>;
}, import("zod").ZodTypeAny, "passthrough">>]>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
role: import("zod").ZodEnum<["user", "assistant"]>;
content: import("zod").ZodUnion<[import("zod").ZodObject<{
type: import("zod").ZodLiteral<"text">;
text: import("zod").ZodString;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"text">;
text: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"text">;
text: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<{
type: import("zod").ZodLiteral<"image">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"image">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"image">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<{
type: import("zod").ZodLiteral<"audio">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"audio">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"audio">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<{
type: import("zod").ZodLiteral<"resource">;
resource: import("zod").ZodUnion<[import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>]>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"resource">;
resource: import("zod").ZodUnion<[import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>]>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"resource">;
resource: import("zod").ZodUnion<[import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>]>;
}, import("zod").ZodTypeAny, "passthrough">>]>;
}, import("zod").ZodTypeAny, "passthrough">>, "many">;
}>, import("zod").ZodTypeAny, "passthrough">>;
listPrompts(params?: ListPromptsRequest["params"], options?: RequestOptions): Promise<import("zod").objectOutputType<import("zod").objectUtil.extendShape<import("zod").objectUtil.extendShape<{
_meta: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
}, {
nextCursor: import("zod").ZodOptional<import("zod").ZodString>;
}>, {
prompts: import("zod").ZodArray<import("zod").ZodObject<{
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
arguments: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
required: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
required: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
required: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, import("zod").ZodTypeAny, "passthrough">>, "many">>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
arguments: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
required: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
required: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
required: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, import("zod").ZodTypeAny, "passthrough">>, "many">>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
arguments: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
required: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
required: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
required: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, import("zod").ZodTypeAny, "passthrough">>, "many">>;
}, import("zod").ZodTypeAny, "passthrough">>, "many">;
}>, import("zod").ZodTypeAny, "passthrough">>;
listResources(params?: ListResourcesRequest["params"], options?: RequestOptions): Promise<import("zod").objectOutputType<import("zod").objectUtil.extendShape<import("zod").objectUtil.extendShape<{
_meta: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
}, {
nextCursor: import("zod").ZodOptional<import("zod").ZodString>;
}>, {
resources: import("zod").ZodArray<import("zod").ZodObject<{
uri: import("zod").ZodString;
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
uri: import("zod").ZodString;
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
uri: import("zod").ZodString;
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod").ZodTypeAny, "passthrough">>, "many">;
}>, import("zod").ZodTypeAny, "passthrough">>;
listResourceTemplates(params?: ListResourceTemplatesRequest["params"], options?: RequestOptions): Promise<import("zod").objectOutputType<import("zod").objectUtil.extendShape<import("zod").objectUtil.extendShape<{
_meta: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
}, {
nextCursor: import("zod").ZodOptional<import("zod").ZodString>;
}>, {
resourceTemplates: import("zod").ZodArray<import("zod").ZodObject<{
uriTemplate: import("zod").ZodString;
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
uriTemplate: import("zod").ZodString;
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
uriTemplate: import("zod").ZodString;
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, import("zod").ZodTypeAny, "passthrough">>, "many">;
}>, import("zod").ZodTypeAny, "passthrough">>;
readResource(params: ReadResourceRequest["params"], options?: RequestOptions): Promise<import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
_meta: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
}, {
contents: import("zod").ZodArray<import("zod").ZodUnion<[import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>]>, "many">;
}>, import("zod").ZodTypeAny, "passthrough">>;
subscribeResource(params: SubscribeRequest["params"], options?: RequestOptions): Promise<{
_meta?: import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough"> | undefined;
}>;
unsubscribeResource(params: UnsubscribeRequest["params"], options?: RequestOptions): Promise<{
_meta?: import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough"> | undefined;
}>;
callTool(params: CallToolRequest["params"], resultSchema?: typeof CallToolResultSchema | typeof CompatibilityCallToolResultSchema, options?: RequestOptions): Promise<import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
_meta: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
}, {
content: import("zod").ZodArray<import("zod").ZodUnion<[import("zod").ZodObject<{
type: import("zod").ZodLiteral<"text">;
text: import("zod").ZodString;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"text">;
text: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"text">;
text: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<{
type: import("zod").ZodLiteral<"image">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"image">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"image">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<{
type: import("zod").ZodLiteral<"audio">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"audio">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"audio">;
data: import("zod").ZodString;
mimeType: import("zod").ZodString;
}, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<{
type: import("zod").ZodLiteral<"resource">;
resource: import("zod").ZodUnion<[import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>]>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"resource">;
resource: import("zod").ZodUnion<[import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>]>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"resource">;
resource: import("zod").ZodUnion<[import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
text: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
uri: import("zod").ZodString;
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
}, {
blob: import("zod").ZodString;
}>, import("zod").ZodTypeAny, "passthrough">>]>;
}, import("zod").ZodTypeAny, "passthrough">>]>, "many">;
isError: import("zod").ZodOptional<import("zod").ZodDefault<import("zod").ZodBoolean>>;
}>, import("zod").ZodTypeAny, "passthrough"> | import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
_meta: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
}, {
toolResult: import("zod").ZodUnknown;
}>, import("zod").ZodTypeAny, "passthrough">>;
listTools(params?: ListToolsRequest["params"], options?: RequestOptions): Promise<import("zod").objectOutputType<import("zod").objectUtil.extendShape<import("zod").objectUtil.extendShape<{
_meta: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
}, {
nextCursor: import("zod").ZodOptional<import("zod").ZodString>;
}>, {
tools: import("zod").ZodArray<import("zod").ZodObject<{
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
inputSchema: import("zod").ZodObject<{
type: import("zod").ZodLiteral<"object">;
properties: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"object">;
properties: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"object">;
properties: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
}, import("zod").ZodTypeAny, "passthrough">>;
annotations: import("zod").ZodOptional<import("zod").ZodObject<{
title: import("zod").ZodOptional<import("zod").ZodString>;
readOnlyHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
destructiveHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
idempotentHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
openWorldHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
title: import("zod").ZodOptional<import("zod").ZodString>;
readOnlyHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
destructiveHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
idempotentHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
openWorldHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
title: import("zod").ZodOptional<import("zod").ZodString>;
readOnlyHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
destructiveHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
idempotentHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
openWorldHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, import("zod").ZodTypeAny, "passthrough">>>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
inputSchema: import("zod").ZodObject<{
type: import("zod").ZodLiteral<"object">;
properties: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"object">;
properties: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"object">;
properties: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
}, import("zod").ZodTypeAny, "passthrough">>;
annotations: import("zod").ZodOptional<import("zod").ZodObject<{
title: import("zod").ZodOptional<import("zod").ZodString>;
readOnlyHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
destructiveHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
idempotentHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
openWorldHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
title: import("zod").ZodOptional<import("zod").ZodString>;
readOnlyHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
destructiveHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
idempotentHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
openWorldHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
title: import("zod").ZodOptional<import("zod").ZodString>;
readOnlyHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
destructiveHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
idempotentHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
openWorldHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, import("zod").ZodTypeAny, "passthrough">>>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
name: import("zod").ZodString;
description: import("zod").ZodOptional<import("zod").ZodString>;
inputSchema: import("zod").ZodObject<{
type: import("zod").ZodLiteral<"object">;
properties: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
type: import("zod").ZodLiteral<"object">;
properties: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
type: import("zod").ZodLiteral<"object">;
properties: import("zod").ZodOptional<import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>>;
}, import("zod").ZodTypeAny, "passthrough">>;
annotations: import("zod").ZodOptional<import("zod").ZodObject<{
title: import("zod").ZodOptional<import("zod").ZodString>;
readOnlyHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
destructiveHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
idempotentHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
openWorldHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
title: import("zod").ZodOptional<import("zod").ZodString>;
readOnlyHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
destructiveHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
idempotentHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
openWorldHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
title: import("zod").ZodOptional<import("zod").ZodString>;
readOnlyHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
destructiveHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
idempotentHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
openWorldHint: import("zod").ZodOptional<import("zod").ZodBoolean>;
}, import("zod").ZodTypeAny, "passthrough">>>;
}, import("zod").ZodTypeAny, "passthrough">>, "many">;
}>, import("zod").ZodTypeAny, "passthrough">>;
sendRootsListChanged(): Promise<void>;
}
//# sourceMappingURL=index.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,234 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Client = void 0;
const protocol_js_1 = require("../shared/protocol.js");
const types_js_1 = require("../types.js");
/**
* An MCP client on top of a pluggable transport.
*
* The client will automatically begin the initialization flow with the server when connect() is called.
*
* To use with custom types, extend the base Request/Notification/Result types and pass them as type parameters:
*
* ```typescript
* // Custom schemas
* const CustomRequestSchema = RequestSchema.extend({...})
* const CustomNotificationSchema = NotificationSchema.extend({...})
* const CustomResultSchema = ResultSchema.extend({...})
*
* // Type aliases
* type CustomRequest = z.infer<typeof CustomRequestSchema>
* type CustomNotification = z.infer<typeof CustomNotificationSchema>
* type CustomResult = z.infer<typeof CustomResultSchema>
*
* // Create typed client
* const client = new Client<CustomRequest, CustomNotification, CustomResult>({
* name: "CustomClient",
* version: "1.0.0"
* })
* ```
*/
class Client extends protocol_js_1.Protocol {
/**
* Initializes this client with the given name and version information.
*/
constructor(_clientInfo, options) {
var _a;
super(options);
this._clientInfo = _clientInfo;
this._capabilities = (_a = options === null || options === void 0 ? void 0 : options.capabilities) !== null && _a !== void 0 ? _a : {};
}
/**
* Registers new capabilities. This can only be called before connecting to a transport.
*
* The new capabilities will be merged with any existing capabilities previously given (e.g., at initialization).
*/
registerCapabilities(capabilities) {
if (this.transport) {
throw new Error("Cannot register capabilities after connecting to transport");
}
this._capabilities = (0, protocol_js_1.mergeCapabilities)(this._capabilities, capabilities);
}
assertCapability(capability, method) {
var _a;
if (!((_a = this._serverCapabilities) === null || _a === void 0 ? void 0 : _a[capability])) {
throw new Error(`Server does not support ${capability} (required for ${method})`);
}
}
async connect(transport, options) {
await super.connect(transport);
// When transport sessionId is already set this means we are trying to reconnect.
// In this case we don't need to initialize again.
if (transport.sessionId !== undefined) {
return;
}
try {
const result = await this.request({
method: "initialize",
params: {
protocolVersion: types_js_1.LATEST_PROTOCOL_VERSION,
capabilities: this._capabilities,
clientInfo: this._clientInfo,
},
}, types_js_1.InitializeResultSchema, options);
if (result === undefined) {
throw new Error(`Server sent invalid initialize result: ${result}`);
}
if (!types_js_1.SUPPORTED_PROTOCOL_VERSIONS.includes(result.protocolVersion)) {
throw new Error(`Server's protocol version is not supported: ${result.protocolVersion}`);
}
this._serverCapabilities = result.capabilities;
this._serverVersion = result.serverInfo;
this._instructions = result.instructions;
await this.notification({
method: "notifications/initialized",
});
}
catch (error) {
// Disconnect if initialization fails.
void this.close();
throw error;
}
}
/**
* After initialization has completed, this will be populated with the server's reported capabilities.
*/
getServerCapabilities() {
return this._serverCapabilities;
}
/**
* After initialization has completed, this will be populated with information about the server's name and version.
*/
getServerVersion() {
return this._serverVersion;
}
/**
* After initialization has completed, this may be populated with information about the server's instructions.
*/
getInstructions() {
return this._instructions;
}
assertCapabilityForMethod(method) {
var _a, _b, _c, _d, _e;
switch (method) {
case "logging/setLevel":
if (!((_a = this._serverCapabilities) === null || _a === void 0 ? void 0 : _a.logging)) {
throw new Error(`Server does not support logging (required for ${method})`);
}
break;
case "prompts/get":
case "prompts/list":
if (!((_b = this._serverCapabilities) === null || _b === void 0 ? void 0 : _b.prompts)) {
throw new Error(`Server does not support prompts (required for ${method})`);
}
break;
case "resources/list":
case "resources/templates/list":
case "resources/read":
case "resources/subscribe":
case "resources/unsubscribe":
if (!((_c = this._serverCapabilities) === null || _c === void 0 ? void 0 : _c.resources)) {
throw new Error(`Server does not support resources (required for ${method})`);
}
if (method === "resources/subscribe" &&
!this._serverCapabilities.resources.subscribe) {
throw new Error(`Server does not support resource subscriptions (required for ${method})`);
}
break;
case "tools/call":
case "tools/list":
if (!((_d = this._serverCapabilities) === null || _d === void 0 ? void 0 : _d.tools)) {
throw new Error(`Server does not support tools (required for ${method})`);
}
break;
case "completion/complete":
if (!((_e = this._serverCapabilities) === null || _e === void 0 ? void 0 : _e.completions)) {
throw new Error(`Server does not support completions (required for ${method})`);
}
break;
case "initialize":
// No specific capability required for initialize
break;
case "ping":
// No specific capability required for ping
break;
}
}
assertNotificationCapability(method) {
var _a;
switch (method) {
case "notifications/roots/list_changed":
if (!((_a = this._capabilities.roots) === null || _a === void 0 ? void 0 : _a.listChanged)) {
throw new Error(`Client does not support roots list changed notifications (required for ${method})`);
}
break;
case "notifications/initialized":
// No specific capability required for initialized
break;
case "notifications/cancelled":
// Cancellation notifications are always allowed
break;
case "notifications/progress":
// Progress notifications are always allowed
break;
}
}
assertRequestHandlerCapability(method) {
switch (method) {
case "sampling/createMessage":
if (!this._capabilities.sampling) {
throw new Error(`Client does not support sampling capability (required for ${method})`);
}
break;
case "roots/list":
if (!this._capabilities.roots) {
throw new Error(`Client does not support roots capability (required for ${method})`);
}
break;
case "ping":
// No specific capability required for ping
break;
}
}
async ping(options) {
return this.request({ method: "ping" }, types_js_1.EmptyResultSchema, options);
}
async complete(params, options) {
return this.request({ method: "completion/complete", params }, types_js_1.CompleteResultSchema, options);
}
async setLoggingLevel(level, options) {
return this.request({ method: "logging/setLevel", params: { level } }, types_js_1.EmptyResultSchema, options);
}
async getPrompt(params, options) {
return this.request({ method: "prompts/get", params }, types_js_1.GetPromptResultSchema, options);
}
async listPrompts(params, options) {
return this.request({ method: "prompts/list", params }, types_js_1.ListPromptsResultSchema, options);
}
async listResources(params, options) {
return this.request({ method: "resources/list", params }, types_js_1.ListResourcesResultSchema, options);
}
async listResourceTemplates(params, options) {
return this.request({ method: "resources/templates/list", params }, types_js_1.ListResourceTemplatesResultSchema, options);
}
async readResource(params, options) {
return this.request({ method: "resources/read", params }, types_js_1.ReadResourceResultSchema, options);
}
async subscribeResource(params, options) {
return this.request({ method: "resources/subscribe", params }, types_js_1.EmptyResultSchema, options);
}
async unsubscribeResource(params, options) {
return this.request({ method: "resources/unsubscribe", params }, types_js_1.EmptyResultSchema, options);
}
async callTool(params, resultSchema = types_js_1.CallToolResultSchema, options) {
return this.request({ method: "tools/call", params }, resultSchema, options);
}
async listTools(params, options) {
return this.request({ method: "tools/list", params }, types_js_1.ListToolsResultSchema, options);
}
async sendRootsListChanged() {
return this.notification({ method: "notifications/roots/list_changed" });
}
}
exports.Client = Client;
//# sourceMappingURL=index.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,70 @@
import { type ErrorEvent, type EventSourceInit } from "eventsource";
import { Transport } from "../shared/transport.js";
import { JSONRPCMessage } from "../types.js";
import { OAuthClientProvider } from "./auth.js";
export declare class SseError extends Error {
readonly code: number | undefined;
readonly event: ErrorEvent;
constructor(code: number | undefined, message: string | undefined, event: ErrorEvent);
}
/**
* Configuration options for the `SSEClientTransport`.
*/
export type SSEClientTransportOptions = {
/**
* An OAuth client provider to use for authentication.
*
* When an `authProvider` is specified and the SSE connection is started:
* 1. The connection is attempted with any existing access token from the `authProvider`.
* 2. If the access token has expired, the `authProvider` is used to refresh the token.
* 3. If token refresh fails or no access token exists, and auth is required, `OAuthClientProvider.redirectToAuthorization` is called, and an `UnauthorizedError` will be thrown from `connect`/`start`.
*
* After the user has finished authorizing via their user agent, and is redirected back to the MCP client application, call `SSEClientTransport.finishAuth` with the authorization code before retrying the connection.
*
* If an `authProvider` is not provided, and auth is required, an `UnauthorizedError` will be thrown.
*
* `UnauthorizedError` might also be thrown when sending any message over the SSE transport, indicating that the session has expired, and needs to be re-authed and reconnected.
*/
authProvider?: OAuthClientProvider;
/**
* Customizes the initial SSE request to the server (the request that begins the stream).
*
* NOTE: Setting this property will prevent an `Authorization` header from
* being automatically attached to the SSE request, if an `authProvider` is
* also given. This can be worked around by setting the `Authorization` header
* manually.
*/
eventSourceInit?: EventSourceInit;
/**
* Customizes recurring POST requests to the server.
*/
requestInit?: RequestInit;
};
/**
* Client transport for SSE: this will connect to a server using Server-Sent Events for receiving
* messages and make separate POST requests for sending messages.
*/
export declare class SSEClientTransport implements Transport {
private _eventSource?;
private _endpoint?;
private _abortController?;
private _url;
private _eventSourceInit?;
private _requestInit?;
private _authProvider?;
onclose?: () => void;
onerror?: (error: Error) => void;
onmessage?: (message: JSONRPCMessage) => void;
constructor(url: URL, opts?: SSEClientTransportOptions);
private _authThenStart;
private _commonHeaders;
private _startOrAuth;
start(): Promise<void>;
/**
* Call this method after the user has finished authorizing via their user agent and is redirected back to the MCP client application. This will exchange the authorization code for an access token, enabling the next connection attempt to successfully auth.
*/
finishAuth(authorizationCode: string): Promise<void>;
close(): Promise<void>;
send(message: JSONRPCMessage): Promise<void>;
}
//# sourceMappingURL=sse.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../../src/client/sse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AACnE,OAAO,EAAoB,mBAAmB,EAAqB,MAAM,WAAW,CAAC;AAErF,qBAAa,QAAS,SAAQ,KAAK;aAEf,IAAI,EAAE,MAAM,GAAG,SAAS;aAExB,KAAK,EAAE,UAAU;gBAFjB,IAAI,EAAE,MAAM,GAAG,SAAS,EACxC,OAAO,EAAE,MAAM,GAAG,SAAS,EACX,KAAK,EAAE,UAAU;CAIpC;AAED;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,mBAAmB,CAAC;IAEnC;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;IAElC;;OAEG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B,CAAC;AAEF;;;GAGG;AACH,qBAAa,kBAAmB,YAAW,SAAS;IAClD,OAAO,CAAC,YAAY,CAAC,CAAc;IACnC,OAAO,CAAC,SAAS,CAAC,CAAM;IACxB,OAAO,CAAC,gBAAgB,CAAC,CAAkB;IAC3C,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,gBAAgB,CAAC,CAAkB;IAC3C,OAAO,CAAC,YAAY,CAAC,CAAc;IACnC,OAAO,CAAC,aAAa,CAAC,CAAsB;IAE5C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;gBAG5C,GAAG,EAAE,GAAG,EACR,IAAI,CAAC,EAAE,yBAAyB;YAQpB,cAAc;YAoBd,cAAc;IAY5B,OAAO,CAAC,YAAY;IAmEd,KAAK;IAUX;;OAEG;IACG,UAAU,CAAC,iBAAiB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtB,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CAuCnD"}

View File

@@ -0,0 +1,173 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SSEClientTransport = exports.SseError = void 0;
const eventsource_1 = require("eventsource");
const types_js_1 = require("../types.js");
const auth_js_1 = require("./auth.js");
class SseError extends Error {
constructor(code, message, event) {
super(`SSE error: ${message}`);
this.code = code;
this.event = event;
}
}
exports.SseError = SseError;
/**
* Client transport for SSE: this will connect to a server using Server-Sent Events for receiving
* messages and make separate POST requests for sending messages.
*/
class SSEClientTransport {
constructor(url, opts) {
this._url = url;
this._eventSourceInit = opts === null || opts === void 0 ? void 0 : opts.eventSourceInit;
this._requestInit = opts === null || opts === void 0 ? void 0 : opts.requestInit;
this._authProvider = opts === null || opts === void 0 ? void 0 : opts.authProvider;
}
async _authThenStart() {
var _a;
if (!this._authProvider) {
throw new auth_js_1.UnauthorizedError("No auth provider");
}
let result;
try {
result = await (0, auth_js_1.auth)(this._authProvider, { serverUrl: this._url });
}
catch (error) {
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
throw error;
}
if (result !== "AUTHORIZED") {
throw new auth_js_1.UnauthorizedError();
}
return await this._startOrAuth();
}
async _commonHeaders() {
const headers = {};
if (this._authProvider) {
const tokens = await this._authProvider.tokens();
if (tokens) {
headers["Authorization"] = `Bearer ${tokens.access_token}`;
}
}
return headers;
}
_startOrAuth() {
return new Promise((resolve, reject) => {
var _a;
this._eventSource = new eventsource_1.EventSource(this._url.href, (_a = this._eventSourceInit) !== null && _a !== void 0 ? _a : {
fetch: (url, init) => this._commonHeaders().then((headers) => fetch(url, {
...init,
headers: {
...headers,
Accept: "text/event-stream"
}
})),
});
this._abortController = new AbortController();
this._eventSource.onerror = (event) => {
var _a;
if (event.code === 401 && this._authProvider) {
this._authThenStart().then(resolve, reject);
return;
}
const error = new SseError(event.code, event.message, event);
reject(error);
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
};
this._eventSource.onopen = () => {
// The connection is open, but we need to wait for the endpoint to be received.
};
this._eventSource.addEventListener("endpoint", (event) => {
var _a;
const messageEvent = event;
try {
this._endpoint = new URL(messageEvent.data, this._url);
if (this._endpoint.origin !== this._url.origin) {
throw new Error(`Endpoint origin does not match connection origin: ${this._endpoint.origin}`);
}
}
catch (error) {
reject(error);
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
void this.close();
return;
}
resolve();
});
this._eventSource.onmessage = (event) => {
var _a, _b;
const messageEvent = event;
let message;
try {
message = types_js_1.JSONRPCMessageSchema.parse(JSON.parse(messageEvent.data));
}
catch (error) {
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
return;
}
(_b = this.onmessage) === null || _b === void 0 ? void 0 : _b.call(this, message);
};
});
}
async start() {
if (this._eventSource) {
throw new Error("SSEClientTransport already started! If using Client class, note that connect() calls start() automatically.");
}
return await this._startOrAuth();
}
/**
* Call this method after the user has finished authorizing via their user agent and is redirected back to the MCP client application. This will exchange the authorization code for an access token, enabling the next connection attempt to successfully auth.
*/
async finishAuth(authorizationCode) {
if (!this._authProvider) {
throw new auth_js_1.UnauthorizedError("No auth provider");
}
const result = await (0, auth_js_1.auth)(this._authProvider, { serverUrl: this._url, authorizationCode });
if (result !== "AUTHORIZED") {
throw new auth_js_1.UnauthorizedError("Failed to authorize");
}
}
async close() {
var _a, _b, _c;
(_a = this._abortController) === null || _a === void 0 ? void 0 : _a.abort();
(_b = this._eventSource) === null || _b === void 0 ? void 0 : _b.close();
(_c = this.onclose) === null || _c === void 0 ? void 0 : _c.call(this);
}
async send(message) {
var _a, _b, _c;
if (!this._endpoint) {
throw new Error("Not connected");
}
try {
const commonHeaders = await this._commonHeaders();
const headers = new Headers({ ...commonHeaders, ...(_a = this._requestInit) === null || _a === void 0 ? void 0 : _a.headers });
headers.set("content-type", "application/json");
const init = {
...this._requestInit,
method: "POST",
headers,
body: JSON.stringify(message),
signal: (_b = this._abortController) === null || _b === void 0 ? void 0 : _b.signal,
};
const response = await fetch(this._endpoint, init);
if (!response.ok) {
if (response.status === 401 && this._authProvider) {
const result = await (0, auth_js_1.auth)(this._authProvider, { serverUrl: this._url });
if (result !== "AUTHORIZED") {
throw new auth_js_1.UnauthorizedError();
}
// Purposely _not_ awaited, so we don't call onerror twice
return this.send(message);
}
const text = await response.text().catch(() => null);
throw new Error(`Error POSTing to endpoint (HTTP ${response.status}): ${text}`);
}
}
catch (error) {
(_c = this.onerror) === null || _c === void 0 ? void 0 : _c.call(this, error);
throw error;
}
}
}
exports.SSEClientTransport = SSEClientTransport;
//# sourceMappingURL=sse.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,72 @@
import { IOType } from "node:child_process";
import { Stream } from "node:stream";
import { Transport } from "../shared/transport.js";
import { JSONRPCMessage } from "../types.js";
export type StdioServerParameters = {
/**
* The executable to run to start the server.
*/
command: string;
/**
* Command line arguments to pass to the executable.
*/
args?: string[];
/**
* The environment to use when spawning the process.
*
* If not specified, the result of getDefaultEnvironment() will be used.
*/
env?: Record<string, string>;
/**
* How to handle stderr of the child process. This matches the semantics of Node's `child_process.spawn`.
*
* The default is "inherit", meaning messages to stderr will be printed to the parent process's stderr.
*/
stderr?: IOType | Stream | number;
/**
* The working directory to use when spawning the process.
*
* If not specified, the current working directory will be inherited.
*/
cwd?: string;
};
/**
* Environment variables to inherit by default, if an environment is not explicitly given.
*/
export declare const DEFAULT_INHERITED_ENV_VARS: string[];
/**
* Returns a default environment object including only environment variables deemed safe to inherit.
*/
export declare function getDefaultEnvironment(): Record<string, string>;
/**
* Client transport for stdio: this will connect to a server by spawning a process and communicating with it over stdin/stdout.
*
* This transport is only available in Node.js environments.
*/
export declare class StdioClientTransport implements Transport {
private _process?;
private _abortController;
private _readBuffer;
private _serverParams;
private _stderrStream;
onclose?: () => void;
onerror?: (error: Error) => void;
onmessage?: (message: JSONRPCMessage) => void;
constructor(server: StdioServerParameters);
/**
* Starts the server process and prepares to communicate with it.
*/
start(): Promise<void>;
/**
* The stderr stream of the child process, if `StdioServerParameters.stderr` was set to "pipe" or "overlapped".
*
* If stderr piping was requested, a PassThrough stream is returned _immediately_, allowing callers to
* attach listeners before the start method is invoked. This prevents loss of any early
* error output emitted by the child process.
*/
get stderr(): Stream | null;
private processReadBuffer;
close(): Promise<void>;
send(message: JSONRPCMessage): Promise<void>;
}
//# sourceMappingURL=stdio.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../../src/client/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAG1D,OAAO,EAAE,MAAM,EAAe,MAAM,aAAa,CAAC;AAElD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,MAAM,qBAAqB,GAAG;IAClC;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAEhB;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE7B;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAElC;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,UAgBmB,CAAC;AAE3D;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAkB9D;AAED;;;;GAIG;AACH,qBAAa,oBAAqB,YAAW,SAAS;IACpD,OAAO,CAAC,QAAQ,CAAC,CAAe;IAChC,OAAO,CAAC,gBAAgB,CAA0C;IAClE,OAAO,CAAC,WAAW,CAAgC;IACnD,OAAO,CAAC,aAAa,CAAwB;IAC7C,OAAO,CAAC,aAAa,CAA4B;IAEjD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;gBAElC,MAAM,EAAE,qBAAqB;IAOzC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA4D5B;;;;;;OAMG;IACH,IAAI,MAAM,IAAI,MAAM,GAAG,IAAI,CAM1B;IAED,OAAO,CAAC,iBAAiB;IAenB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CAc7C"}

View File

@@ -0,0 +1,170 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.StdioClientTransport = exports.DEFAULT_INHERITED_ENV_VARS = void 0;
exports.getDefaultEnvironment = getDefaultEnvironment;
const cross_spawn_1 = __importDefault(require("cross-spawn"));
const node_process_1 = __importDefault(require("node:process"));
const node_stream_1 = require("node:stream");
const stdio_js_1 = require("../shared/stdio.js");
/**
* Environment variables to inherit by default, if an environment is not explicitly given.
*/
exports.DEFAULT_INHERITED_ENV_VARS = node_process_1.default.platform === "win32"
? [
"APPDATA",
"HOMEDRIVE",
"HOMEPATH",
"LOCALAPPDATA",
"PATH",
"PROCESSOR_ARCHITECTURE",
"SYSTEMDRIVE",
"SYSTEMROOT",
"TEMP",
"USERNAME",
"USERPROFILE",
]
: /* list inspired by the default env inheritance of sudo */
["HOME", "LOGNAME", "PATH", "SHELL", "TERM", "USER"];
/**
* Returns a default environment object including only environment variables deemed safe to inherit.
*/
function getDefaultEnvironment() {
const env = {};
for (const key of exports.DEFAULT_INHERITED_ENV_VARS) {
const value = node_process_1.default.env[key];
if (value === undefined) {
continue;
}
if (value.startsWith("()")) {
// Skip functions, which are a security risk.
continue;
}
env[key] = value;
}
return env;
}
/**
* Client transport for stdio: this will connect to a server by spawning a process and communicating with it over stdin/stdout.
*
* This transport is only available in Node.js environments.
*/
class StdioClientTransport {
constructor(server) {
this._abortController = new AbortController();
this._readBuffer = new stdio_js_1.ReadBuffer();
this._stderrStream = null;
this._serverParams = server;
if (server.stderr === "pipe" || server.stderr === "overlapped") {
this._stderrStream = new node_stream_1.PassThrough();
}
}
/**
* Starts the server process and prepares to communicate with it.
*/
async start() {
if (this._process) {
throw new Error("StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.");
}
return new Promise((resolve, reject) => {
var _a, _b, _c, _d, _e, _f;
this._process = (0, cross_spawn_1.default)(this._serverParams.command, (_a = this._serverParams.args) !== null && _a !== void 0 ? _a : [], {
env: (_b = this._serverParams.env) !== null && _b !== void 0 ? _b : getDefaultEnvironment(),
stdio: ["pipe", "pipe", (_c = this._serverParams.stderr) !== null && _c !== void 0 ? _c : "inherit"],
shell: false,
signal: this._abortController.signal,
windowsHide: node_process_1.default.platform === "win32" && isElectron(),
cwd: this._serverParams.cwd,
});
this._process.on("error", (error) => {
var _a, _b;
if (error.name === "AbortError") {
// Expected when close() is called.
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
return;
}
reject(error);
(_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error);
});
this._process.on("spawn", () => {
resolve();
});
this._process.on("close", (_code) => {
var _a;
this._process = undefined;
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
});
(_d = this._process.stdin) === null || _d === void 0 ? void 0 : _d.on("error", (error) => {
var _a;
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
});
(_e = this._process.stdout) === null || _e === void 0 ? void 0 : _e.on("data", (chunk) => {
this._readBuffer.append(chunk);
this.processReadBuffer();
});
(_f = this._process.stdout) === null || _f === void 0 ? void 0 : _f.on("error", (error) => {
var _a;
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
});
if (this._stderrStream && this._process.stderr) {
this._process.stderr.pipe(this._stderrStream);
}
});
}
/**
* The stderr stream of the child process, if `StdioServerParameters.stderr` was set to "pipe" or "overlapped".
*
* If stderr piping was requested, a PassThrough stream is returned _immediately_, allowing callers to
* attach listeners before the start method is invoked. This prevents loss of any early
* error output emitted by the child process.
*/
get stderr() {
var _a, _b;
if (this._stderrStream) {
return this._stderrStream;
}
return (_b = (_a = this._process) === null || _a === void 0 ? void 0 : _a.stderr) !== null && _b !== void 0 ? _b : null;
}
processReadBuffer() {
var _a, _b;
while (true) {
try {
const message = this._readBuffer.readMessage();
if (message === null) {
break;
}
(_a = this.onmessage) === null || _a === void 0 ? void 0 : _a.call(this, message);
}
catch (error) {
(_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error);
}
}
}
async close() {
this._abortController.abort();
this._process = undefined;
this._readBuffer.clear();
}
send(message) {
return new Promise((resolve) => {
var _a;
if (!((_a = this._process) === null || _a === void 0 ? void 0 : _a.stdin)) {
throw new Error("Not connected");
}
const json = (0, stdio_js_1.serializeMessage)(message);
if (this._process.stdin.write(json)) {
resolve();
}
else {
this._process.stdin.once("drain", resolve);
}
});
}
}
exports.StdioClientTransport = StdioClientTransport;
function isElectron() {
return "type" in node_process_1.default;
}
//# sourceMappingURL=stdio.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../../../src/client/stdio.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,124 @@
import { Transport } from "../shared/transport.js";
import { JSONRPCMessage } from "../types.js";
import { OAuthClientProvider } from "./auth.js";
export declare class StreamableHTTPError extends Error {
readonly code: number | undefined;
constructor(code: number | undefined, message: string | undefined);
}
/**
* Configuration options for reconnection behavior of the StreamableHTTPClientTransport.
*/
export interface StreamableHTTPReconnectionOptions {
/**
* Maximum backoff time between reconnection attempts in milliseconds.
* Default is 30000 (30 seconds).
*/
maxReconnectionDelay: number;
/**
* Initial backoff time between reconnection attempts in milliseconds.
* Default is 1000 (1 second).
*/
initialReconnectionDelay: number;
/**
* The factor by which the reconnection delay increases after each attempt.
* Default is 1.5.
*/
reconnectionDelayGrowFactor: number;
/**
* Maximum number of reconnection attempts before giving up.
* Default is 2.
*/
maxRetries: number;
}
/**
* Configuration options for the `StreamableHTTPClientTransport`.
*/
export type StreamableHTTPClientTransportOptions = {
/**
* An OAuth client provider to use for authentication.
*
* When an `authProvider` is specified and the connection is started:
* 1. The connection is attempted with any existing access token from the `authProvider`.
* 2. If the access token has expired, the `authProvider` is used to refresh the token.
* 3. If token refresh fails or no access token exists, and auth is required, `OAuthClientProvider.redirectToAuthorization` is called, and an `UnauthorizedError` will be thrown from `connect`/`start`.
*
* After the user has finished authorizing via their user agent, and is redirected back to the MCP client application, call `StreamableHTTPClientTransport.finishAuth` with the authorization code before retrying the connection.
*
* If an `authProvider` is not provided, and auth is required, an `UnauthorizedError` will be thrown.
*
* `UnauthorizedError` might also be thrown when sending any message over the transport, indicating that the session has expired, and needs to be re-authed and reconnected.
*/
authProvider?: OAuthClientProvider;
/**
* Customizes HTTP requests to the server.
*/
requestInit?: RequestInit;
/**
* Options to configure the reconnection behavior.
*/
reconnectionOptions?: StreamableHTTPReconnectionOptions;
/**
* Session ID for the connection. This is used to identify the session on the server.
* When not provided and connecting to a server that supports session IDs, the server will generate a new session ID.
*/
sessionId?: string;
};
/**
* Client transport for Streamable HTTP: this implements the MCP Streamable HTTP transport specification.
* It will connect to a server using HTTP POST for sending messages and HTTP GET with Server-Sent Events
* for receiving messages.
*/
export declare class StreamableHTTPClientTransport implements Transport {
private _abortController?;
private _url;
private _requestInit?;
private _authProvider?;
private _sessionId?;
private _reconnectionOptions;
onclose?: () => void;
onerror?: (error: Error) => void;
onmessage?: (message: JSONRPCMessage) => void;
constructor(url: URL, opts?: StreamableHTTPClientTransportOptions);
private _authThenStart;
private _commonHeaders;
private _startOrAuthSse;
/**
* Calculates the next reconnection delay using backoff algorithm
*
* @param attempt Current reconnection attempt count for the specific stream
* @returns Time to wait in milliseconds before next reconnection attempt
*/
private _getNextReconnectionDelay;
/**
* Schedule a reconnection attempt with exponential backoff
*
* @param lastEventId The ID of the last received event for resumability
* @param attemptCount Current reconnection attempt count for this specific stream
*/
private _scheduleReconnection;
private _handleSseStream;
start(): Promise<void>;
/**
* Call this method after the user has finished authorizing via their user agent and is redirected back to the MCP client application. This will exchange the authorization code for an access token, enabling the next connection attempt to successfully auth.
*/
finishAuth(authorizationCode: string): Promise<void>;
close(): Promise<void>;
send(message: JSONRPCMessage | JSONRPCMessage[], options?: {
resumptionToken?: string;
onresumptiontoken?: (token: string) => void;
}): Promise<void>;
get sessionId(): string | undefined;
/**
* Terminates the current session by sending a DELETE request to the server.
*
* Clients that no longer need a particular session
* (e.g., because the user is leaving the client application) SHOULD send an
* HTTP DELETE to the MCP endpoint with the Mcp-Session-Id header to explicitly
* terminate the session.
*
* The server MAY respond with HTTP 405 Method Not Allowed, indicating that
* the server does not allow clients to terminate sessions.
*/
terminateSession(): Promise<void>;
}
//# sourceMappingURL=streamableHttp.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"streamableHttp.d.ts","sourceRoot":"","sources":["../../../src/client/streamableHttp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAkE,cAAc,EAAwB,MAAM,aAAa,CAAC;AACnI,OAAO,EAAoB,mBAAmB,EAAqB,MAAM,WAAW,CAAC;AAWrF,qBAAa,mBAAoB,SAAQ,KAAK;aAE1B,IAAI,EAAE,MAAM,GAAG,SAAS;gBAAxB,IAAI,EAAE,MAAM,GAAG,SAAS,EACxC,OAAO,EAAE,MAAM,GAAG,SAAS;CAI9B;AA2BD;;GAEG;AACH,MAAM,WAAW,iCAAiC;IAChD;;;OAGG;IACH,oBAAoB,EAAE,MAAM,CAAC;IAE7B;;;OAGG;IACH,wBAAwB,EAAE,MAAM,CAAC;IAEjC;;;OAGG;IACH,2BAA2B,EAAE,MAAM,CAAC;IAEpC;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,oCAAoC,GAAG;IACjD;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,mBAAmB,CAAC;IAEnC;;OAEG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAE1B;;OAEG;IACH,mBAAmB,CAAC,EAAE,iCAAiC,CAAC;IAExD;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;GAIG;AACH,qBAAa,6BAA8B,YAAW,SAAS;IAC7D,OAAO,CAAC,gBAAgB,CAAC,CAAkB;IAC3C,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,YAAY,CAAC,CAAc;IACnC,OAAO,CAAC,aAAa,CAAC,CAAsB;IAC5C,OAAO,CAAC,UAAU,CAAC,CAAS;IAC5B,OAAO,CAAC,oBAAoB,CAAoC;IAEhE,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;gBAG5C,GAAG,EAAE,GAAG,EACR,IAAI,CAAC,EAAE,oCAAoC;YAS/B,cAAc;YAoBd,cAAc;YAmBd,eAAe;IA6C7B;;;;;OAKG;IACH,OAAO,CAAC,yBAAyB;IAWjC;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;IAwB7B,OAAO,CAAC,gBAAgB;IAoElB,KAAK;IAUX;;OAEG;IACG,UAAU,CAAC,iBAAiB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAOtB,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,cAAc,EAAE,EAAE,OAAO,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA+F1J,IAAI,SAAS,IAAI,MAAM,GAAG,SAAS,CAElC;IAED;;;;;;;;;;OAUG;IACG,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC;CAgCxC"}

View File

@@ -0,0 +1,353 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StreamableHTTPClientTransport = exports.StreamableHTTPError = void 0;
const types_js_1 = require("../types.js");
const auth_js_1 = require("./auth.js");
const stream_1 = require("eventsource-parser/stream");
// Default reconnection options for StreamableHTTP connections
const DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS = {
initialReconnectionDelay: 1000,
maxReconnectionDelay: 30000,
reconnectionDelayGrowFactor: 1.5,
maxRetries: 2,
};
class StreamableHTTPError extends Error {
constructor(code, message) {
super(`Streamable HTTP error: ${message}`);
this.code = code;
}
}
exports.StreamableHTTPError = StreamableHTTPError;
/**
* Client transport for Streamable HTTP: this implements the MCP Streamable HTTP transport specification.
* It will connect to a server using HTTP POST for sending messages and HTTP GET with Server-Sent Events
* for receiving messages.
*/
class StreamableHTTPClientTransport {
constructor(url, opts) {
var _a;
this._url = url;
this._requestInit = opts === null || opts === void 0 ? void 0 : opts.requestInit;
this._authProvider = opts === null || opts === void 0 ? void 0 : opts.authProvider;
this._sessionId = opts === null || opts === void 0 ? void 0 : opts.sessionId;
this._reconnectionOptions = (_a = opts === null || opts === void 0 ? void 0 : opts.reconnectionOptions) !== null && _a !== void 0 ? _a : DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS;
}
async _authThenStart() {
var _a;
if (!this._authProvider) {
throw new auth_js_1.UnauthorizedError("No auth provider");
}
let result;
try {
result = await (0, auth_js_1.auth)(this._authProvider, { serverUrl: this._url });
}
catch (error) {
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
throw error;
}
if (result !== "AUTHORIZED") {
throw new auth_js_1.UnauthorizedError();
}
return await this._startOrAuthSse({ resumptionToken: undefined });
}
async _commonHeaders() {
var _a;
const headers = {};
if (this._authProvider) {
const tokens = await this._authProvider.tokens();
if (tokens) {
headers["Authorization"] = `Bearer ${tokens.access_token}`;
}
}
if (this._sessionId) {
headers["mcp-session-id"] = this._sessionId;
}
return new Headers({ ...headers, ...(_a = this._requestInit) === null || _a === void 0 ? void 0 : _a.headers });
}
async _startOrAuthSse(options) {
var _a, _b;
const { resumptionToken } = options;
try {
// Try to open an initial SSE stream with GET to listen for server messages
// This is optional according to the spec - server may not support it
const headers = await this._commonHeaders();
headers.set("Accept", "text/event-stream");
// Include Last-Event-ID header for resumable streams if provided
if (resumptionToken) {
headers.set("last-event-id", resumptionToken);
}
const response = await fetch(this._url, {
method: "GET",
headers,
signal: (_a = this._abortController) === null || _a === void 0 ? void 0 : _a.signal,
});
if (!response.ok) {
if (response.status === 401 && this._authProvider) {
// Need to authenticate
return await this._authThenStart();
}
// 405 indicates that the server does not offer an SSE stream at GET endpoint
// This is an expected case that should not trigger an error
if (response.status === 405) {
return;
}
throw new StreamableHTTPError(response.status, `Failed to open SSE stream: ${response.statusText}`);
}
this._handleSseStream(response.body, options);
}
catch (error) {
(_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error);
throw error;
}
}
/**
* Calculates the next reconnection delay using backoff algorithm
*
* @param attempt Current reconnection attempt count for the specific stream
* @returns Time to wait in milliseconds before next reconnection attempt
*/
_getNextReconnectionDelay(attempt) {
// Access default values directly, ensuring they're never undefined
const initialDelay = this._reconnectionOptions.initialReconnectionDelay;
const growFactor = this._reconnectionOptions.reconnectionDelayGrowFactor;
const maxDelay = this._reconnectionOptions.maxReconnectionDelay;
// Cap at maximum delay
return Math.min(initialDelay * Math.pow(growFactor, attempt), maxDelay);
}
/**
* Schedule a reconnection attempt with exponential backoff
*
* @param lastEventId The ID of the last received event for resumability
* @param attemptCount Current reconnection attempt count for this specific stream
*/
_scheduleReconnection(options, attemptCount = 0) {
var _a;
// Use provided options or default options
const maxRetries = this._reconnectionOptions.maxRetries;
// Check if we've exceeded maximum retry attempts
if (maxRetries > 0 && attemptCount >= maxRetries) {
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, new Error(`Maximum reconnection attempts (${maxRetries}) exceeded.`));
return;
}
// Calculate next delay based on current attempt count
const delay = this._getNextReconnectionDelay(attemptCount);
// Schedule the reconnection
setTimeout(() => {
// Use the last event ID to resume where we left off
this._startOrAuthSse(options).catch(error => {
var _a;
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, new Error(`Failed to reconnect SSE stream: ${error instanceof Error ? error.message : String(error)}`));
// Schedule another attempt if this one failed, incrementing the attempt counter
this._scheduleReconnection(options, attemptCount + 1);
});
}, delay);
}
_handleSseStream(stream, options) {
if (!stream) {
return;
}
const { onresumptiontoken, replayMessageId } = options;
let lastEventId;
const processStream = async () => {
var _a, _b, _c, _d;
// this is the closest we can get to trying to catch network errors
// if something happens reader will throw
try {
// Create a pipeline: binary stream -> text decoder -> SSE parser
const reader = stream
.pipeThrough(new TextDecoderStream())
.pipeThrough(new stream_1.EventSourceParserStream())
.getReader();
while (true) {
const { value: event, done } = await reader.read();
if (done) {
break;
}
// Update last event ID if provided
if (event.id) {
lastEventId = event.id;
onresumptiontoken === null || onresumptiontoken === void 0 ? void 0 : onresumptiontoken(event.id);
}
if (!event.event || event.event === "message") {
try {
const message = types_js_1.JSONRPCMessageSchema.parse(JSON.parse(event.data));
if (replayMessageId !== undefined && (0, types_js_1.isJSONRPCResponse)(message)) {
message.id = replayMessageId;
}
(_a = this.onmessage) === null || _a === void 0 ? void 0 : _a.call(this, message);
}
catch (error) {
(_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error);
}
}
}
}
catch (error) {
// Handle stream errors - likely a network disconnect
(_c = this.onerror) === null || _c === void 0 ? void 0 : _c.call(this, new Error(`SSE stream disconnected: ${error}`));
// Attempt to reconnect if the stream disconnects unexpectedly and we aren't closing
if (this._abortController && !this._abortController.signal.aborted) {
// Use the exponential backoff reconnection strategy
if (lastEventId !== undefined) {
try {
this._scheduleReconnection({
resumptionToken: lastEventId,
onresumptiontoken,
replayMessageId
}, 0);
}
catch (error) {
(_d = this.onerror) === null || _d === void 0 ? void 0 : _d.call(this, new Error(`Failed to reconnect: ${error instanceof Error ? error.message : String(error)}`));
}
}
}
}
};
processStream();
}
async start() {
if (this._abortController) {
throw new Error("StreamableHTTPClientTransport already started! If using Client class, note that connect() calls start() automatically.");
}
this._abortController = new AbortController();
}
/**
* Call this method after the user has finished authorizing via their user agent and is redirected back to the MCP client application. This will exchange the authorization code for an access token, enabling the next connection attempt to successfully auth.
*/
async finishAuth(authorizationCode) {
if (!this._authProvider) {
throw new auth_js_1.UnauthorizedError("No auth provider");
}
const result = await (0, auth_js_1.auth)(this._authProvider, { serverUrl: this._url, authorizationCode });
if (result !== "AUTHORIZED") {
throw new auth_js_1.UnauthorizedError("Failed to authorize");
}
}
async close() {
var _a, _b;
// Abort any pending requests
(_a = this._abortController) === null || _a === void 0 ? void 0 : _a.abort();
(_b = this.onclose) === null || _b === void 0 ? void 0 : _b.call(this);
}
async send(message, options) {
var _a, _b, _c;
try {
const { resumptionToken, onresumptiontoken } = options || {};
if (resumptionToken) {
// If we have at last event ID, we need to reconnect the SSE stream
this._startOrAuthSse({ resumptionToken, replayMessageId: (0, types_js_1.isJSONRPCRequest)(message) ? message.id : undefined }).catch(err => { var _a; return (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, err); });
return;
}
const headers = await this._commonHeaders();
headers.set("content-type", "application/json");
headers.set("accept", "application/json, text/event-stream");
const init = {
...this._requestInit,
method: "POST",
headers,
body: JSON.stringify(message),
signal: (_a = this._abortController) === null || _a === void 0 ? void 0 : _a.signal,
};
const response = await fetch(this._url, init);
// Handle session ID received during initialization
const sessionId = response.headers.get("mcp-session-id");
if (sessionId) {
this._sessionId = sessionId;
}
if (!response.ok) {
if (response.status === 401 && this._authProvider) {
const result = await (0, auth_js_1.auth)(this._authProvider, { serverUrl: this._url });
if (result !== "AUTHORIZED") {
throw new auth_js_1.UnauthorizedError();
}
// Purposely _not_ awaited, so we don't call onerror twice
return this.send(message);
}
const text = await response.text().catch(() => null);
throw new Error(`Error POSTing to endpoint (HTTP ${response.status}): ${text}`);
}
// If the response is 202 Accepted, there's no body to process
if (response.status === 202) {
// if the accepted notification is initialized, we start the SSE stream
// if it's supported by the server
if ((0, types_js_1.isInitializedNotification)(message)) {
// Start without a lastEventId since this is a fresh connection
this._startOrAuthSse({ resumptionToken: undefined }).catch(err => { var _a; return (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, err); });
}
return;
}
// Get original message(s) for detecting request IDs
const messages = Array.isArray(message) ? message : [message];
const hasRequests = messages.filter(msg => "method" in msg && "id" in msg && msg.id !== undefined).length > 0;
// Check the response type
const contentType = response.headers.get("content-type");
if (hasRequests) {
if (contentType === null || contentType === void 0 ? void 0 : contentType.includes("text/event-stream")) {
// Handle SSE stream responses for requests
// We use the same handler as standalone streams, which now supports
// reconnection with the last event ID
this._handleSseStream(response.body, { onresumptiontoken });
}
else if (contentType === null || contentType === void 0 ? void 0 : contentType.includes("application/json")) {
// For non-streaming servers, we might get direct JSON responses
const data = await response.json();
const responseMessages = Array.isArray(data)
? data.map(msg => types_js_1.JSONRPCMessageSchema.parse(msg))
: [types_js_1.JSONRPCMessageSchema.parse(data)];
for (const msg of responseMessages) {
(_b = this.onmessage) === null || _b === void 0 ? void 0 : _b.call(this, msg);
}
}
else {
throw new StreamableHTTPError(-1, `Unexpected content type: ${contentType}`);
}
}
}
catch (error) {
(_c = this.onerror) === null || _c === void 0 ? void 0 : _c.call(this, error);
throw error;
}
}
get sessionId() {
return this._sessionId;
}
/**
* Terminates the current session by sending a DELETE request to the server.
*
* Clients that no longer need a particular session
* (e.g., because the user is leaving the client application) SHOULD send an
* HTTP DELETE to the MCP endpoint with the Mcp-Session-Id header to explicitly
* terminate the session.
*
* The server MAY respond with HTTP 405 Method Not Allowed, indicating that
* the server does not allow clients to terminate sessions.
*/
async terminateSession() {
var _a, _b;
if (!this._sessionId) {
return; // No session to terminate
}
try {
const headers = await this._commonHeaders();
const init = {
...this._requestInit,
method: "DELETE",
headers,
signal: (_a = this._abortController) === null || _a === void 0 ? void 0 : _a.signal,
};
const response = await fetch(this._url, init);
// We specifically handle 405 as a valid response according to the spec,
// meaning the server does not support explicit session termination
if (!response.ok && response.status !== 405) {
throw new StreamableHTTPError(response.status, `Failed to terminate session: ${response.statusText}`);
}
this._sessionId = undefined;
}
catch (error) {
(_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error);
throw error;
}
}
}
exports.StreamableHTTPClientTransport = StreamableHTTPClientTransport;
//# sourceMappingURL=streamableHttp.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,17 @@
import { Transport } from "../shared/transport.js";
import { JSONRPCMessage } from "../types.js";
/**
* Client transport for WebSocket: this will connect to a server over the WebSocket protocol.
*/
export declare class WebSocketClientTransport implements Transport {
private _socket?;
private _url;
onclose?: () => void;
onerror?: (error: Error) => void;
onmessage?: (message: JSONRPCMessage) => void;
constructor(url: URL);
start(): Promise<void>;
close(): Promise<void>;
send(message: JSONRPCMessage): Promise<void>;
}
//# sourceMappingURL=websocket.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../../../src/client/websocket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AAInE;;GAEG;AACH,qBAAa,wBAAyB,YAAW,SAAS;IACxD,OAAO,CAAC,OAAO,CAAC,CAAY;IAC5B,OAAO,CAAC,IAAI,CAAM;IAElB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;gBAElC,GAAG,EAAE,GAAG;IAIpB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyChB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;CAW7C"}

View File

@@ -0,0 +1,65 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebSocketClientTransport = void 0;
const types_js_1 = require("../types.js");
const SUBPROTOCOL = "mcp";
/**
* Client transport for WebSocket: this will connect to a server over the WebSocket protocol.
*/
class WebSocketClientTransport {
constructor(url) {
this._url = url;
}
start() {
if (this._socket) {
throw new Error("WebSocketClientTransport already started! If using Client class, note that connect() calls start() automatically.");
}
return new Promise((resolve, reject) => {
this._socket = new WebSocket(this._url, SUBPROTOCOL);
this._socket.onerror = (event) => {
var _a;
const error = "error" in event
? event.error
: new Error(`WebSocket error: ${JSON.stringify(event)}`);
reject(error);
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
};
this._socket.onopen = () => {
resolve();
};
this._socket.onclose = () => {
var _a;
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
};
this._socket.onmessage = (event) => {
var _a, _b;
let message;
try {
message = types_js_1.JSONRPCMessageSchema.parse(JSON.parse(event.data));
}
catch (error) {
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error);
return;
}
(_b = this.onmessage) === null || _b === void 0 ? void 0 : _b.call(this, message);
};
});
}
async close() {
var _a;
(_a = this._socket) === null || _a === void 0 ? void 0 : _a.close();
}
send(message) {
return new Promise((resolve, reject) => {
var _a;
if (!this._socket) {
reject(new Error("Not connected"));
return;
}
(_a = this._socket) === null || _a === void 0 ? void 0 : _a.send(JSON.stringify(message));
resolve();
});
}
}
exports.WebSocketClientTransport = WebSocketClientTransport;
//# sourceMappingURL=websocket.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"websocket.js","sourceRoot":"","sources":["../../../src/client/websocket.ts"],"names":[],"mappings":";;;AACA,0CAAmE;AAEnE,MAAM,WAAW,GAAG,KAAK,CAAC;AAE1B;;GAEG;AACH,MAAa,wBAAwB;IAQnC,YAAY,GAAQ;QAClB,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC;IAClB,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CACb,mHAAmH,CACpH,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,OAAO,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;YAErD,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,CAAC,KAAK,EAAE,EAAE;;gBAC/B,MAAM,KAAK,GACT,OAAO,IAAI,KAAK;oBACd,CAAC,CAAE,KAAK,CAAC,KAAe;oBACxB,CAAC,CAAC,IAAI,KAAK,CAAC,oBAAoB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBAC7D,MAAM,CAAC,KAAK,CAAC,CAAC;gBACd,MAAA,IAAI,CAAC,OAAO,qDAAG,KAAK,CAAC,CAAC;YACxB,CAAC,CAAC;YAEF,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,GAAG,EAAE;gBACzB,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC;YAEF,IAAI,CAAC,OAAO,CAAC,OAAO,GAAG,GAAG,EAAE;;gBAC1B,MAAA,IAAI,CAAC,OAAO,oDAAI,CAAC;YACnB,CAAC,CAAC;YAEF,IAAI,CAAC,OAAO,CAAC,SAAS,GAAG,CAAC,KAAmB,EAAE,EAAE;;gBAC/C,IAAI,OAAuB,CAAC;gBAC5B,IAAI,CAAC;oBACH,OAAO,GAAG,+BAAoB,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC/D,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAA,IAAI,CAAC,OAAO,qDAAG,KAAc,CAAC,CAAC;oBAC/B,OAAO;gBACT,CAAC;gBAED,MAAA,IAAI,CAAC,SAAS,qDAAG,OAAO,CAAC,CAAC;YAC5B,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,KAAK;;QACT,MAAA,IAAI,CAAC,OAAO,0CAAE,KAAK,EAAE,CAAC;IACxB,CAAC;IAED,IAAI,CAAC,OAAuB;QAC1B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;;YACrC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAClB,MAAM,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;gBACnC,OAAO;YACT,CAAC;YAED,MAAA,IAAI,CAAC,OAAO,0CAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;YAC5C,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AApED,4DAoEC"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=multipleClientsParallel.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"multipleClientsParallel.d.ts","sourceRoot":"","sources":["../../../../src/examples/client/multipleClientsParallel.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,134 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const index_js_1 = require("../../client/index.js");
const streamableHttp_js_1 = require("../../client/streamableHttp.js");
const types_js_1 = require("../../types.js");
/**
* Multiple Clients MCP Example
*
* This client demonstrates how to:
* 1. Create multiple MCP clients in parallel
* 2. Each client calls a single tool
* 3. Track notifications from each client independently
*/
// Command line args processing
const args = process.argv.slice(2);
const serverUrl = args[0] || 'http://localhost:3000/mcp';
async function createAndRunClient(config) {
console.log(`[${config.id}] Creating client: ${config.name}`);
const client = new index_js_1.Client({
name: config.name,
version: '1.0.0'
});
const transport = new streamableHttp_js_1.StreamableHTTPClientTransport(new URL(serverUrl));
// Set up client-specific error handler
client.onerror = (error) => {
console.error(`[${config.id}] Client error:`, error);
};
// Set up client-specific notification handler
client.setNotificationHandler(types_js_1.LoggingMessageNotificationSchema, (notification) => {
console.log(`[${config.id}] Notification: ${notification.params.data}`);
});
try {
// Connect to the server
await client.connect(transport);
console.log(`[${config.id}] Connected to MCP server`);
// Call the specified tool
console.log(`[${config.id}] Calling tool: ${config.toolName}`);
const toolRequest = {
method: 'tools/call',
params: {
name: config.toolName,
arguments: {
...config.toolArguments,
// Add client ID to arguments for identification in notifications
caller: config.id
}
}
};
const result = await client.request(toolRequest, types_js_1.CallToolResultSchema);
console.log(`[${config.id}] Tool call completed`);
// Keep the connection open for a bit to receive notifications
await new Promise(resolve => setTimeout(resolve, 5000));
// Disconnect
await transport.close();
console.log(`[${config.id}] Disconnected from MCP server`);
return { id: config.id, result };
}
catch (error) {
console.error(`[${config.id}] Error:`, error);
throw error;
}
}
async function main() {
console.log('MCP Multiple Clients Example');
console.log('============================');
console.log(`Server URL: ${serverUrl}`);
console.log('');
try {
// Define client configurations
const clientConfigs = [
{
id: 'client1',
name: 'basic-client-1',
toolName: 'start-notification-stream',
toolArguments: {
interval: 3, // 1 second between notifications
count: 5 // Send 5 notifications
}
},
{
id: 'client2',
name: 'basic-client-2',
toolName: 'start-notification-stream',
toolArguments: {
interval: 2, // 2 seconds between notifications
count: 3 // Send 3 notifications
}
},
{
id: 'client3',
name: 'basic-client-3',
toolName: 'start-notification-stream',
toolArguments: {
interval: 1, // 0.5 second between notifications
count: 8 // Send 8 notifications
}
}
];
// Start all clients in parallel
console.log(`Starting ${clientConfigs.length} clients in parallel...`);
console.log('');
const clientPromises = clientConfigs.map(config => createAndRunClient(config));
const results = await Promise.all(clientPromises);
// Display results from all clients
console.log('\n=== Final Results ===');
results.forEach(({ id, result }) => {
console.log(`\n[${id}] Tool result:`);
if (Array.isArray(result.content)) {
result.content.forEach((item) => {
if (item.type === 'text' && item.text) {
console.log(` ${item.text}`);
}
else {
console.log(` ${item.type} content:`, item);
}
});
}
else {
console.log(` Unexpected result format:`, result);
}
});
console.log('\n=== All clients completed successfully ===');
}
catch (error) {
console.error('Error running multiple clients:', error);
process.exit(1);
}
}
// Start the example
main().catch((error) => {
console.error('Error running MCP multiple clients example:', error);
process.exit(1);
});
//# sourceMappingURL=multipleClientsParallel.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"multipleClientsParallel.js","sourceRoot":"","sources":["../../../../src/examples/client/multipleClientsParallel.ts"],"names":[],"mappings":";;AAAA,oDAA+C;AAC/C,sEAA+E;AAC/E,6CAKwB;AAExB;;;;;;;GAOG;AAEH,+BAA+B;AAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,SAAS,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,2BAA2B,CAAC;AASzD,KAAK,UAAU,kBAAkB,CAAC,MAAoB;IACpD,OAAO,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,EAAE,sBAAsB,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAE9D,MAAM,MAAM,GAAG,IAAI,iBAAM,CAAC;QACxB,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,IAAI,iDAA6B,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;IAExE,uCAAuC;IACvC,MAAM,CAAC,OAAO,GAAG,CAAC,KAAK,EAAE,EAAE;QACzB,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,EAAE,iBAAiB,EAAE,KAAK,CAAC,CAAC;IACvD,CAAC,CAAC;IAEF,8CAA8C;IAC9C,MAAM,CAAC,sBAAsB,CAAC,2CAAgC,EAAE,CAAC,YAAY,EAAE,EAAE;QAC/E,OAAO,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,EAAE,mBAAmB,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,wBAAwB;QACxB,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,EAAE,2BAA2B,CAAC,CAAC;QAEtD,0BAA0B;QAC1B,OAAO,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,EAAE,mBAAmB,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QAC/D,MAAM,WAAW,GAAoB;YACnC,MAAM,EAAE,YAAY;YACpB,MAAM,EAAE;gBACN,IAAI,EAAE,MAAM,CAAC,QAAQ;gBACrB,SAAS,EAAE;oBACT,GAAG,MAAM,CAAC,aAAa;oBACvB,iEAAiE;oBACjE,MAAM,EAAE,MAAM,CAAC,EAAE;iBAClB;aACF;SACF,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,+BAAoB,CAAC,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,EAAE,uBAAuB,CAAC,CAAC;QAElD,8DAA8D;QAC9D,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;QAExD,aAAa;QACb,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,EAAE,gCAAgC,CAAC,CAAC;QAE3D,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC;IACnC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,EAAE,UAAU,EAAE,KAAK,CAAC,CAAC;QAC9C,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,eAAe,SAAS,EAAE,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,IAAI,CAAC;QACH,+BAA+B;QAC/B,MAAM,aAAa,GAAmB;YACpC;gBACE,EAAE,EAAE,SAAS;gBACb,IAAI,EAAE,gBAAgB;gBACtB,QAAQ,EAAE,2BAA2B;gBACrC,aAAa,EAAE;oBACb,QAAQ,EAAE,CAAC,EAAE,iCAAiC;oBAC9C,KAAK,EAAE,CAAC,CAAK,uBAAuB;iBACrC;aACF;YACD;gBACE,EAAE,EAAE,SAAS;gBACb,IAAI,EAAE,gBAAgB;gBACtB,QAAQ,EAAE,2BAA2B;gBACrC,aAAa,EAAE;oBACb,QAAQ,EAAE,CAAC,EAAE,kCAAkC;oBAC/C,KAAK,EAAE,CAAC,CAAK,uBAAuB;iBACrC;aACF;YACD;gBACE,EAAE,EAAE,SAAS;gBACb,IAAI,EAAE,gBAAgB;gBACtB,QAAQ,EAAE,2BAA2B;gBACrC,aAAa,EAAE;oBACb,QAAQ,EAAE,CAAC,EAAE,mCAAmC;oBAChD,KAAK,EAAE,CAAC,CAAO,uBAAuB;iBACvC;aACF;SACF,CAAC;QAEF,gCAAgC;QAChC,OAAO,CAAC,GAAG,CAAC,YAAY,aAAa,CAAC,MAAM,yBAAyB,CAAC,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAEhB,MAAM,cAAc,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/E,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAElD,mCAAmC;QACnC,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;QACvC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;YACjC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;YACtC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;gBAClC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAqC,EAAE,EAAE;oBAC/D,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;wBACtC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;oBAChC,CAAC;yBAAM,CAAC;wBACN,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,IAAI,WAAW,EAAE,IAAI,CAAC,CAAC;oBAC/C,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,GAAG,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAC;YACrD,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;IAE9D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,KAAK,CAAC,CAAC;QACxD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,oBAAoB;AACpB,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,OAAO,CAAC,KAAK,CAAC,6CAA6C,EAAE,KAAK,CAAC,CAAC;IACpE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=parallelToolCallsClient.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"parallelToolCallsClient.d.ts","sourceRoot":"","sources":["../../../../src/examples/client/parallelToolCallsClient.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,175 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const index_js_1 = require("../../client/index.js");
const streamableHttp_js_1 = require("../../client/streamableHttp.js");
const types_js_1 = require("../../types.js");
/**
* Parallel Tool Calls MCP Client
*
* This client demonstrates how to:
* 1. Start multiple tool calls in parallel
* 2. Track notifications from each tool call using a caller parameter
*/
// Command line args processing
const args = process.argv.slice(2);
const serverUrl = args[0] || 'http://localhost:3000/mcp';
async function main() {
console.log('MCP Parallel Tool Calls Client');
console.log('==============================');
console.log(`Connecting to server at: ${serverUrl}`);
let client;
let transport;
try {
// Create client with streamable HTTP transport
client = new index_js_1.Client({
name: 'parallel-tool-calls-client',
version: '1.0.0'
});
client.onerror = (error) => {
console.error('Client error:', error);
};
// Connect to the server
transport = new streamableHttp_js_1.StreamableHTTPClientTransport(new URL(serverUrl));
await client.connect(transport);
console.log('Successfully connected to MCP server');
// Set up notification handler with caller identification
client.setNotificationHandler(types_js_1.LoggingMessageNotificationSchema, (notification) => {
console.log(`Notification: ${notification.params.data}`);
});
console.log("List tools");
const toolsRequest = await listTools(client);
console.log("Tools: ", toolsRequest);
// 2. Start multiple notification tools in parallel
console.log('\n=== Starting Multiple Notification Streams in Parallel ===');
const toolResults = await startParallelNotificationTools(client);
// Log the results from each tool call
for (const [caller, result] of Object.entries(toolResults)) {
console.log(`\n=== Tool result for ${caller} ===`);
result.content.forEach((item) => {
if (item.type === 'text') {
console.log(` ${item.text}`);
}
else {
console.log(` ${item.type} content:`, item);
}
});
}
// 3. Wait for all notifications (10 seconds)
console.log('\n=== Waiting for all notifications ===');
await new Promise(resolve => setTimeout(resolve, 10000));
// 4. Disconnect
console.log('\n=== Disconnecting ===');
await transport.close();
console.log('Disconnected from MCP server');
}
catch (error) {
console.error('Error running client:', error);
process.exit(1);
}
}
/**
* List available tools on the server
*/
async function listTools(client) {
try {
const toolsRequest = {
method: 'tools/list',
params: {}
};
const toolsResult = await client.request(toolsRequest, types_js_1.ListToolsResultSchema);
console.log('Available tools:');
if (toolsResult.tools.length === 0) {
console.log(' No tools available');
}
else {
for (const tool of toolsResult.tools) {
console.log(` - ${tool.name}: ${tool.description}`);
}
}
}
catch (error) {
console.log(`Tools not supported by this server: ${error}`);
}
}
/**
* Start multiple notification tools in parallel with different configurations
* Each tool call includes a caller parameter to identify its notifications
*/
async function startParallelNotificationTools(client) {
try {
// Define multiple tool calls with different configurations
const toolCalls = [
{
caller: 'fast-notifier',
request: {
method: 'tools/call',
params: {
name: 'start-notification-stream',
arguments: {
interval: 2, // 0.5 second between notifications
count: 10, // Send 10 notifications
caller: 'fast-notifier' // Identify this tool call
}
}
}
},
{
caller: 'slow-notifier',
request: {
method: 'tools/call',
params: {
name: 'start-notification-stream',
arguments: {
interval: 5, // 2 seconds between notifications
count: 5, // Send 5 notifications
caller: 'slow-notifier' // Identify this tool call
}
}
}
},
{
caller: 'burst-notifier',
request: {
method: 'tools/call',
params: {
name: 'start-notification-stream',
arguments: {
interval: 1, // 0.1 second between notifications
count: 3, // Send just 3 notifications
caller: 'burst-notifier' // Identify this tool call
}
}
}
}
];
console.log(`Starting ${toolCalls.length} notification tools in parallel...`);
// Start all tool calls in parallel
const toolPromises = toolCalls.map(({ caller, request }) => {
console.log(`Starting tool call for ${caller}...`);
return client.request(request, types_js_1.CallToolResultSchema)
.then(result => ({ caller, result }))
.catch(error => {
console.error(`Error in tool call for ${caller}:`, error);
throw error;
});
});
// Wait for all tool calls to complete
const results = await Promise.all(toolPromises);
// Organize results by caller
const resultsByTool = {};
results.forEach(({ caller, result }) => {
resultsByTool[caller] = result;
});
return resultsByTool;
}
catch (error) {
console.error(`Error starting parallel notification tools:`, error);
throw error;
}
}
// Start the client
main().catch((error) => {
console.error('Error running MCP client:', error);
process.exit(1);
});
//# sourceMappingURL=parallelToolCallsClient.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"parallelToolCallsClient.js","sourceRoot":"","sources":["../../../../src/examples/client/parallelToolCallsClient.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=simpleStreamableHttp.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"simpleStreamableHttp.d.ts","sourceRoot":"","sources":["../../../../src/examples/client/simpleStreamableHttp.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,448 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const index_js_1 = require("../../client/index.js");
const streamableHttp_js_1 = require("../../client/streamableHttp.js");
const node_readline_1 = require("node:readline");
const types_js_1 = require("../../types.js");
// Create readline interface for user input
const readline = (0, node_readline_1.createInterface)({
input: process.stdin,
output: process.stdout
});
// Track received notifications for debugging resumability
let notificationCount = 0;
// Global client and transport for interactive commands
let client = null;
let transport = null;
let serverUrl = 'http://localhost:3000/mcp';
let notificationsToolLastEventId = undefined;
let sessionId = undefined;
async function main() {
console.log('MCP Interactive Client');
console.log('=====================');
// Connect to server immediately with default settings
await connect();
// Print help and start the command loop
printHelp();
commandLoop();
}
function printHelp() {
console.log('\nAvailable commands:');
console.log(' connect [url] - Connect to MCP server (default: http://localhost:3000/mcp)');
console.log(' disconnect - Disconnect from server');
console.log(' terminate-session - Terminate the current session');
console.log(' reconnect - Reconnect to the server');
console.log(' list-tools - List available tools');
console.log(' call-tool <name> [args] - Call a tool with optional JSON arguments');
console.log(' greet [name] - Call the greet tool');
console.log(' multi-greet [name] - Call the multi-greet tool with notifications');
console.log(' start-notifications [interval] [count] - Start periodic notifications');
console.log(' list-prompts - List available prompts');
console.log(' get-prompt [name] [args] - Get a prompt with optional JSON arguments');
console.log(' list-resources - List available resources');
console.log(' help - Show this help');
console.log(' quit - Exit the program');
}
function commandLoop() {
readline.question('\n> ', async (input) => {
var _a;
const args = input.trim().split(/\s+/);
const command = (_a = args[0]) === null || _a === void 0 ? void 0 : _a.toLowerCase();
try {
switch (command) {
case 'connect':
await connect(args[1]);
break;
case 'disconnect':
await disconnect();
break;
case 'terminate-session':
await terminateSession();
break;
case 'reconnect':
await reconnect();
break;
case 'list-tools':
await listTools();
break;
case 'call-tool':
if (args.length < 2) {
console.log('Usage: call-tool <name> [args]');
}
else {
const toolName = args[1];
let toolArgs = {};
if (args.length > 2) {
try {
toolArgs = JSON.parse(args.slice(2).join(' '));
}
catch (_b) {
console.log('Invalid JSON arguments. Using empty args.');
}
}
await callTool(toolName, toolArgs);
}
break;
case 'greet':
await callGreetTool(args[1] || 'MCP User');
break;
case 'multi-greet':
await callMultiGreetTool(args[1] || 'MCP User');
break;
case 'start-notifications': {
const interval = args[1] ? parseInt(args[1], 10) : 2000;
const count = args[2] ? parseInt(args[2], 10) : 10;
await startNotifications(interval, count);
break;
}
case 'list-prompts':
await listPrompts();
break;
case 'get-prompt':
if (args.length < 2) {
console.log('Usage: get-prompt <name> [args]');
}
else {
const promptName = args[1];
let promptArgs = {};
if (args.length > 2) {
try {
promptArgs = JSON.parse(args.slice(2).join(' '));
}
catch (_c) {
console.log('Invalid JSON arguments. Using empty args.');
}
}
await getPrompt(promptName, promptArgs);
}
break;
case 'list-resources':
await listResources();
break;
case 'help':
printHelp();
break;
case 'quit':
case 'exit':
await cleanup();
return;
default:
if (command) {
console.log(`Unknown command: ${command}`);
}
break;
}
}
catch (error) {
console.error(`Error executing command: ${error}`);
}
// Continue the command loop
commandLoop();
});
}
async function connect(url) {
if (client) {
console.log('Already connected. Disconnect first.');
return;
}
if (url) {
serverUrl = url;
}
console.log(`Connecting to ${serverUrl}...`);
try {
// Create a new client
client = new index_js_1.Client({
name: 'example-client',
version: '1.0.0'
});
client.onerror = (error) => {
console.error('\x1b[31mClient error:', error, '\x1b[0m');
};
transport = new streamableHttp_js_1.StreamableHTTPClientTransport(new URL(serverUrl), {
sessionId: sessionId
});
// Set up notification handlers
client.setNotificationHandler(types_js_1.LoggingMessageNotificationSchema, (notification) => {
notificationCount++;
console.log(`\nNotification #${notificationCount}: ${notification.params.level} - ${notification.params.data}`);
// Re-display the prompt
process.stdout.write('> ');
});
client.setNotificationHandler(types_js_1.ResourceListChangedNotificationSchema, async (_) => {
console.log(`\nResource list changed notification received!`);
try {
if (!client) {
console.log('Client disconnected, cannot fetch resources');
return;
}
const resourcesResult = await client.request({
method: 'resources/list',
params: {}
}, types_js_1.ListResourcesResultSchema);
console.log('Available resources count:', resourcesResult.resources.length);
}
catch (_a) {
console.log('Failed to list resources after change notification');
}
// Re-display the prompt
process.stdout.write('> ');
});
// Connect the client
await client.connect(transport);
sessionId = transport.sessionId;
console.log('Transport created with session ID:', sessionId);
console.log('Connected to MCP server');
}
catch (error) {
console.error('Failed to connect:', error);
client = null;
transport = null;
}
}
async function disconnect() {
if (!client || !transport) {
console.log('Not connected.');
return;
}
try {
await transport.close();
console.log('Disconnected from MCP server');
client = null;
transport = null;
}
catch (error) {
console.error('Error disconnecting:', error);
}
}
async function terminateSession() {
if (!client || !transport) {
console.log('Not connected.');
return;
}
try {
console.log('Terminating session with ID:', transport.sessionId);
await transport.terminateSession();
console.log('Session terminated successfully');
// Check if sessionId was cleared after termination
if (!transport.sessionId) {
console.log('Session ID has been cleared');
sessionId = undefined;
// Also close the transport and clear client objects
await transport.close();
console.log('Transport closed after session termination');
client = null;
transport = null;
}
else {
console.log('Server responded with 405 Method Not Allowed (session termination not supported)');
console.log('Session ID is still active:', transport.sessionId);
}
}
catch (error) {
console.error('Error terminating session:', error);
}
}
async function reconnect() {
if (client) {
await disconnect();
}
await connect();
}
async function listTools() {
if (!client) {
console.log('Not connected to server.');
return;
}
try {
const toolsRequest = {
method: 'tools/list',
params: {}
};
const toolsResult = await client.request(toolsRequest, types_js_1.ListToolsResultSchema);
console.log('Available tools:');
if (toolsResult.tools.length === 0) {
console.log(' No tools available');
}
else {
for (const tool of toolsResult.tools) {
console.log(` - ${tool.name}: ${tool.description}`);
}
}
}
catch (error) {
console.log(`Tools not supported by this server (${error})`);
}
}
async function callTool(name, args) {
if (!client) {
console.log('Not connected to server.');
return;
}
try {
const request = {
method: 'tools/call',
params: {
name,
arguments: args
}
};
console.log(`Calling tool '${name}' with args:`, args);
const onLastEventIdUpdate = (event) => {
notificationsToolLastEventId = event;
};
const result = await client.request(request, types_js_1.CallToolResultSchema, {
resumptionToken: notificationsToolLastEventId, onresumptiontoken: onLastEventIdUpdate
});
console.log('Tool result:');
result.content.forEach(item => {
if (item.type === 'text') {
console.log(` ${item.text}`);
}
else {
console.log(` ${item.type} content:`, item);
}
});
}
catch (error) {
console.log(`Error calling tool ${name}: ${error}`);
}
}
async function callGreetTool(name) {
await callTool('greet', { name });
}
async function callMultiGreetTool(name) {
console.log('Calling multi-greet tool with notifications...');
await callTool('multi-greet', { name });
}
async function startNotifications(interval, count) {
console.log(`Starting notification stream: interval=${interval}ms, count=${count || 'unlimited'}`);
await callTool('start-notification-stream', { interval, count });
}
async function listPrompts() {
if (!client) {
console.log('Not connected to server.');
return;
}
try {
const promptsRequest = {
method: 'prompts/list',
params: {}
};
const promptsResult = await client.request(promptsRequest, types_js_1.ListPromptsResultSchema);
console.log('Available prompts:');
if (promptsResult.prompts.length === 0) {
console.log(' No prompts available');
}
else {
for (const prompt of promptsResult.prompts) {
console.log(` - ${prompt.name}: ${prompt.description}`);
}
}
}
catch (error) {
console.log(`Prompts not supported by this server (${error})`);
}
}
async function getPrompt(name, args) {
if (!client) {
console.log('Not connected to server.');
return;
}
try {
const promptRequest = {
method: 'prompts/get',
params: {
name,
arguments: args
}
};
const promptResult = await client.request(promptRequest, types_js_1.GetPromptResultSchema);
console.log('Prompt template:');
promptResult.messages.forEach((msg, index) => {
console.log(` [${index + 1}] ${msg.role}: ${msg.content.text}`);
});
}
catch (error) {
console.log(`Error getting prompt ${name}: ${error}`);
}
}
async function listResources() {
if (!client) {
console.log('Not connected to server.');
return;
}
try {
const resourcesRequest = {
method: 'resources/list',
params: {}
};
const resourcesResult = await client.request(resourcesRequest, types_js_1.ListResourcesResultSchema);
console.log('Available resources:');
if (resourcesResult.resources.length === 0) {
console.log(' No resources available');
}
else {
for (const resource of resourcesResult.resources) {
console.log(` - ${resource.name}: ${resource.uri}`);
}
}
}
catch (error) {
console.log(`Resources not supported by this server (${error})`);
}
}
async function cleanup() {
if (client && transport) {
try {
// First try to terminate the session gracefully
if (transport.sessionId) {
try {
console.log('Terminating session before exit...');
await transport.terminateSession();
console.log('Session terminated successfully');
}
catch (error) {
console.error('Error terminating session:', error);
}
}
// Then close the transport
await transport.close();
}
catch (error) {
console.error('Error closing transport:', error);
}
}
process.stdin.setRawMode(false);
readline.close();
console.log('\nGoodbye!');
process.exit(0);
}
// Set up raw mode for keyboard input to capture Escape key
process.stdin.setRawMode(true);
process.stdin.on('data', async (data) => {
// Check for Escape key (27)
if (data.length === 1 && data[0] === 27) {
console.log('\nESC key pressed. Disconnecting from server...');
// Abort current operation and disconnect from server
if (client && transport) {
await disconnect();
console.log('Disconnected. Press Enter to continue.');
}
else {
console.log('Not connected to server.');
}
// Re-display the prompt
process.stdout.write('> ');
}
});
// Handle Ctrl+C
process.on('SIGINT', async () => {
console.log('\nReceived SIGINT. Cleaning up...');
await cleanup();
});
// Start the interactive client
main().catch((error) => {
console.error('Error running MCP client:', error);
process.exit(1);
});
//# sourceMappingURL=simpleStreamableHttp.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=streamableHttpWithSseFallbackClient.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"streamableHttpWithSseFallbackClient.d.ts","sourceRoot":"","sources":["../../../../src/examples/client/streamableHttpWithSseFallbackClient.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,168 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const index_js_1 = require("../../client/index.js");
const streamableHttp_js_1 = require("../../client/streamableHttp.js");
const sse_js_1 = require("../../client/sse.js");
const types_js_1 = require("../../types.js");
/**
* Simplified Backwards Compatible MCP Client
*
* This client demonstrates backward compatibility with both:
* 1. Modern servers using Streamable HTTP transport (protocol version 2025-03-26)
* 2. Older servers using HTTP+SSE transport (protocol version 2024-11-05)
*
* Following the MCP specification for backwards compatibility:
* - Attempts to POST an initialize request to the server URL first (modern transport)
* - If that fails with 4xx status, falls back to GET request for SSE stream (older transport)
*/
// Command line args processing
const args = process.argv.slice(2);
const serverUrl = args[0] || 'http://localhost:3000/mcp';
async function main() {
console.log('MCP Backwards Compatible Client');
console.log('===============================');
console.log(`Connecting to server at: ${serverUrl}`);
let client;
let transport;
try {
// Try connecting with automatic transport detection
const connection = await connectWithBackwardsCompatibility(serverUrl);
client = connection.client;
transport = connection.transport;
// Set up notification handler
client.setNotificationHandler(types_js_1.LoggingMessageNotificationSchema, (notification) => {
console.log(`Notification: ${notification.params.level} - ${notification.params.data}`);
});
// DEMO WORKFLOW:
// 1. List available tools
console.log('\n=== Listing Available Tools ===');
await listTools(client);
// 2. Call the notification tool
console.log('\n=== Starting Notification Stream ===');
await startNotificationTool(client);
// 3. Wait for all notifications (5 seconds)
console.log('\n=== Waiting for all notifications ===');
await new Promise(resolve => setTimeout(resolve, 5000));
// 4. Disconnect
console.log('\n=== Disconnecting ===');
await transport.close();
console.log('Disconnected from MCP server');
}
catch (error) {
console.error('Error running client:', error);
process.exit(1);
}
}
/**
* Connect to an MCP server with backwards compatibility
* Following the spec for client backward compatibility
*/
async function connectWithBackwardsCompatibility(url) {
console.log('1. Trying Streamable HTTP transport first...');
// Step 1: Try Streamable HTTP transport first
const client = new index_js_1.Client({
name: 'backwards-compatible-client',
version: '1.0.0'
});
client.onerror = (error) => {
console.error('Client error:', error);
};
const baseUrl = new URL(url);
try {
// Create modern transport
const streamableTransport = new streamableHttp_js_1.StreamableHTTPClientTransport(baseUrl);
await client.connect(streamableTransport);
console.log('Successfully connected using modern Streamable HTTP transport.');
return {
client,
transport: streamableTransport,
transportType: 'streamable-http'
};
}
catch (error) {
// Step 2: If transport fails, try the older SSE transport
console.log(`StreamableHttp transport connection failed: ${error}`);
console.log('2. Falling back to deprecated HTTP+SSE transport...');
try {
// Create SSE transport pointing to /sse endpoint
const sseTransport = new sse_js_1.SSEClientTransport(baseUrl);
const sseClient = new index_js_1.Client({
name: 'backwards-compatible-client',
version: '1.0.0'
});
await sseClient.connect(sseTransport);
console.log('Successfully connected using deprecated HTTP+SSE transport.');
return {
client: sseClient,
transport: sseTransport,
transportType: 'sse'
};
}
catch (sseError) {
console.error(`Failed to connect with either transport method:\n1. Streamable HTTP error: ${error}\n2. SSE error: ${sseError}`);
throw new Error('Could not connect to server with any available transport');
}
}
}
/**
* List available tools on the server
*/
async function listTools(client) {
try {
const toolsRequest = {
method: 'tools/list',
params: {}
};
const toolsResult = await client.request(toolsRequest, types_js_1.ListToolsResultSchema);
console.log('Available tools:');
if (toolsResult.tools.length === 0) {
console.log(' No tools available');
}
else {
for (const tool of toolsResult.tools) {
console.log(` - ${tool.name}: ${tool.description}`);
}
}
}
catch (error) {
console.log(`Tools not supported by this server: ${error}`);
}
}
/**
* Start a notification stream by calling the notification tool
*/
async function startNotificationTool(client) {
try {
// Call the notification tool using reasonable defaults
const request = {
method: 'tools/call',
params: {
name: 'start-notification-stream',
arguments: {
interval: 1000, // 1 second between notifications
count: 5 // Send 5 notifications
}
}
};
console.log('Calling notification tool...');
const result = await client.request(request, types_js_1.CallToolResultSchema);
console.log('Tool result:');
result.content.forEach(item => {
if (item.type === 'text') {
console.log(` ${item.text}`);
}
else {
console.log(` ${item.type} content:`, item);
}
});
}
catch (error) {
console.log(`Error calling notification tool: ${error}`);
}
}
// Start the client
main().catch((error) => {
console.error('Error running MCP client:', error);
process.exit(1);
});
//# sourceMappingURL=streamableHttpWithSseFallbackClient.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"streamableHttpWithSseFallbackClient.js","sourceRoot":"","sources":["../../../../src/examples/client/streamableHttpWithSseFallbackClient.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=jsonResponseStreamableHttp.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"jsonResponseStreamableHttp.d.ts","sourceRoot":"","sources":["../../../../src/examples/server/jsonResponseStreamableHttp.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,142 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const node_crypto_1 = require("node:crypto");
const mcp_js_1 = require("../../server/mcp.js");
const streamableHttp_js_1 = require("../../server/streamableHttp.js");
const zod_1 = require("zod");
const types_js_1 = require("../../types.js");
// Create an MCP server with implementation details
const getServer = () => {
const server = new mcp_js_1.McpServer({
name: 'json-response-streamable-http-server',
version: '1.0.0',
}, {
capabilities: {
logging: {},
}
});
// Register a simple tool that returns a greeting
server.tool('greet', 'A simple greeting tool', {
name: zod_1.z.string().describe('Name to greet'),
}, async ({ name }) => {
return {
content: [
{
type: 'text',
text: `Hello, ${name}!`,
},
],
};
});
// Register a tool that sends multiple greetings with notifications
server.tool('multi-greet', 'A tool that sends different greetings with delays between them', {
name: zod_1.z.string().describe('Name to greet'),
}, async ({ name }, { sendNotification }) => {
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
await sendNotification({
method: "notifications/message",
params: { level: "debug", data: `Starting multi-greet for ${name}` }
});
await sleep(1000); // Wait 1 second before first greeting
await sendNotification({
method: "notifications/message",
params: { level: "info", data: `Sending first greeting to ${name}` }
});
await sleep(1000); // Wait another second before second greeting
await sendNotification({
method: "notifications/message",
params: { level: "info", data: `Sending second greeting to ${name}` }
});
return {
content: [
{
type: 'text',
text: `Good morning, ${name}!`,
}
],
};
});
return server;
};
const app = (0, express_1.default)();
app.use(express_1.default.json());
// Map to store transports by session ID
const transports = {};
app.post('/mcp', async (req, res) => {
console.log('Received MCP request:', req.body);
try {
// Check for existing session ID
const sessionId = req.headers['mcp-session-id'];
let transport;
if (sessionId && transports[sessionId]) {
// Reuse existing transport
transport = transports[sessionId];
}
else if (!sessionId && (0, types_js_1.isInitializeRequest)(req.body)) {
// New initialization request - use JSON response mode
transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
sessionIdGenerator: () => (0, node_crypto_1.randomUUID)(),
enableJsonResponse: true, // Enable JSON response mode
onsessioninitialized: (sessionId) => {
// Store the transport by session ID when session is initialized
// This avoids race conditions where requests might come in before the session is stored
console.log(`Session initialized with ID: ${sessionId}`);
transports[sessionId] = transport;
}
});
// Connect the transport to the MCP server BEFORE handling the request
const server = getServer();
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
return; // Already handled
}
else {
// Invalid request - no session ID or not initialization request
res.status(400).json({
jsonrpc: '2.0',
error: {
code: -32000,
message: 'Bad Request: No valid session ID provided',
},
id: null,
});
return;
}
// Handle the request with existing transport - no need to reconnect
await transport.handleRequest(req, res, req.body);
}
catch (error) {
console.error('Error handling MCP request:', error);
if (!res.headersSent) {
res.status(500).json({
jsonrpc: '2.0',
error: {
code: -32603,
message: 'Internal server error',
},
id: null,
});
}
}
});
// Handle GET requests for SSE streams according to spec
app.get('/mcp', async (req, res) => {
// Since this is a very simple example, we don't support GET requests for this server
// The spec requires returning 405 Method Not Allowed in this case
res.status(405).set('Allow', 'POST').send('Method Not Allowed');
});
// Start the server
const PORT = 3000;
app.listen(PORT, () => {
console.log(`MCP Streamable HTTP Server listening on port ${PORT}`);
});
// Handle server shutdown
process.on('SIGINT', async () => {
console.log('Shutting down server...');
process.exit(0);
});
//# sourceMappingURL=jsonResponseStreamableHttp.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"jsonResponseStreamableHttp.js","sourceRoot":"","sources":["../../../../src/examples/server/jsonResponseStreamableHttp.ts"],"names":[],"mappings":";;;;;AAAA,sDAAqD;AACrD,6CAAyC;AACzC,gDAAgD;AAChD,sEAA+E;AAC/E,6BAAwB;AACxB,6CAAqE;AAGrE,mDAAmD;AACnD,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,MAAM,GAAG,IAAI,kBAAS,CAAC;QAC3B,IAAI,EAAE,sCAAsC;QAC5C,OAAO,EAAE,OAAO;KACjB,EAAE;QACD,YAAY,EAAE;YACZ,OAAO,EAAE,EAAE;SACZ;KACF,CAAC,CAAC;IAEH,iDAAiD;IACjD,MAAM,CAAC,IAAI,CACT,OAAO,EACP,wBAAwB,EACxB;QACE,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;KAC3C,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,EAA2B,EAAE;QAC1C,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,UAAU,IAAI,GAAG;iBACxB;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,mEAAmE;IACnE,MAAM,CAAC,IAAI,CACT,aAAa,EACb,gEAAgE,EAChE;QACE,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;KAC3C,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,gBAAgB,EAAE,EAA2B,EAAE;QAChE,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;QAE9E,MAAM,gBAAgB,CAAC;YACrB,MAAM,EAAE,uBAAuB;YAC/B,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,4BAA4B,IAAI,EAAE,EAAE;SACrE,CAAC,CAAC;QAEH,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,sCAAsC;QAEzD,MAAM,gBAAgB,CAAC;YACrB,MAAM,EAAE,uBAAuB;YAC/B,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,6BAA6B,IAAI,EAAE,EAAE;SACrE,CAAC,CAAC;QAEH,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,6CAA6C;QAEhE,MAAM,gBAAgB,CAAC;YACrB,MAAM,EAAE,uBAAuB;YAC/B,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,8BAA8B,IAAI,EAAE,EAAE;SACtE,CAAC,CAAC;QAEH,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,iBAAiB,IAAI,GAAG;iBAC/B;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC,CAAA;AAED,MAAM,GAAG,GAAG,IAAA,iBAAO,GAAE,CAAC;AACtB,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AAExB,wCAAwC;AACxC,MAAM,UAAU,GAA2D,EAAE,CAAC;AAE9E,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IACrD,OAAO,CAAC,GAAG,CAAC,uBAAuB,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/C,IAAI,CAAC;QACH,gCAAgC;QAChC,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAuB,CAAC;QACtE,IAAI,SAAwC,CAAC;QAE7C,IAAI,SAAS,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACvC,2BAA2B;YAC3B,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;QACpC,CAAC;aAAM,IAAI,CAAC,SAAS,IAAI,IAAA,8BAAmB,EAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACvD,sDAAsD;YACtD,SAAS,GAAG,IAAI,iDAA6B,CAAC;gBAC5C,kBAAkB,EAAE,GAAG,EAAE,CAAC,IAAA,wBAAU,GAAE;gBACtC,kBAAkB,EAAE,IAAI,EAAE,4BAA4B;gBACtD,oBAAoB,EAAE,CAAC,SAAS,EAAE,EAAE;oBAClC,gEAAgE;oBAChE,wFAAwF;oBACxF,OAAO,CAAC,GAAG,CAAC,gCAAgC,SAAS,EAAE,CAAC,CAAC;oBACzD,UAAU,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC;gBACpC,CAAC;aACF,CAAC,CAAC;YAEH,sEAAsE;YACtE,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;YAC3B,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAChC,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;YAClD,OAAO,CAAC,kBAAkB;QAC5B,CAAC;aAAM,CAAC;YACN,gEAAgE;YAChE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE;oBACL,IAAI,EAAE,CAAC,KAAK;oBACZ,OAAO,EAAE,2CAA2C;iBACrD;gBACD,EAAE,EAAE,IAAI;aACT,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,oEAAoE;QACpE,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;QACpD,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;YACrB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE;oBACL,IAAI,EAAE,CAAC,KAAK;oBACZ,OAAO,EAAE,uBAAuB;iBACjC;gBACD,EAAE,EAAE,IAAI;aACT,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,wDAAwD;AACxD,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IACpD,qFAAqF;IACrF,kEAAkE;IAClE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;AAClE,CAAC,CAAC,CAAC;AAEH,mBAAmB;AACnB,MAAM,IAAI,GAAG,IAAI,CAAC;AAClB,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;IACpB,OAAO,CAAC,GAAG,CAAC,gDAAgD,IAAI,EAAE,CAAC,CAAC;AACtE,CAAC,CAAC,CAAC;AAEH,yBAAyB;AACzB,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;IAC9B,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=simpleSseServer.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"simpleSseServer.d.ts","sourceRoot":"","sources":["../../../../src/examples/server/simpleSseServer.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,148 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const mcp_js_1 = require("../../server/mcp.js");
const sse_js_1 = require("../../server/sse.js");
const zod_1 = require("zod");
/**
* This example server demonstrates the deprecated HTTP+SSE transport
* (protocol version 2024-11-05). It mainly used for testing backward compatible clients.
*
* The server exposes two endpoints:
* - /mcp: For establishing the SSE stream (GET)
* - /messages: For receiving client messages (POST)
*
*/
// Create an MCP server instance
const getServer = () => {
const server = new mcp_js_1.McpServer({
name: 'simple-sse-server',
version: '1.0.0',
}, { capabilities: { logging: {} } });
server.tool('start-notification-stream', 'Starts sending periodic notifications', {
interval: zod_1.z.number().describe('Interval in milliseconds between notifications').default(1000),
count: zod_1.z.number().describe('Number of notifications to send').default(10),
}, async ({ interval, count }, { sendNotification }) => {
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
let counter = 0;
// Send the initial notification
await sendNotification({
method: "notifications/message",
params: {
level: "info",
data: `Starting notification stream with ${count} messages every ${interval}ms`
}
});
// Send periodic notifications
while (counter < count) {
counter++;
await sleep(interval);
try {
await sendNotification({
method: "notifications/message",
params: {
level: "info",
data: `Notification #${counter} at ${new Date().toISOString()}`
}
});
}
catch (error) {
console.error("Error sending notification:", error);
}
}
return {
content: [
{
type: 'text',
text: `Completed sending ${count} notifications every ${interval}ms`,
}
],
};
});
return server;
};
const app = (0, express_1.default)();
app.use(express_1.default.json());
// Store transports by session ID
const transports = {};
// SSE endpoint for establishing the stream
app.get('/mcp', async (req, res) => {
console.log('Received GET request to /sse (establishing SSE stream)');
try {
// Create a new SSE transport for the client
// The endpoint for POST messages is '/messages'
const transport = new sse_js_1.SSEServerTransport('/messages', res);
// Store the transport by session ID
const sessionId = transport.sessionId;
transports[sessionId] = transport;
// Set up onclose handler to clean up transport when closed
transport.onclose = () => {
console.log(`SSE transport closed for session ${sessionId}`);
delete transports[sessionId];
};
// Connect the transport to the MCP server
const server = getServer();
await server.connect(transport);
console.log(`Established SSE stream with session ID: ${sessionId}`);
}
catch (error) {
console.error('Error establishing SSE stream:', error);
if (!res.headersSent) {
res.status(500).send('Error establishing SSE stream');
}
}
});
// Messages endpoint for receiving client JSON-RPC requests
app.post('/messages', async (req, res) => {
console.log('Received POST request to /messages');
// Extract session ID from URL query parameter
// In the SSE protocol, this is added by the client based on the endpoint event
const sessionId = req.query.sessionId;
if (!sessionId) {
console.error('No session ID provided in request URL');
res.status(400).send('Missing sessionId parameter');
return;
}
const transport = transports[sessionId];
if (!transport) {
console.error(`No active transport found for session ID: ${sessionId}`);
res.status(404).send('Session not found');
return;
}
try {
// Handle the POST message with the transport
await transport.handlePostMessage(req, res, req.body);
}
catch (error) {
console.error('Error handling request:', error);
if (!res.headersSent) {
res.status(500).send('Error handling request');
}
}
});
// Start the server
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Simple SSE Server (deprecated protocol version 2024-11-05) listening on port ${PORT}`);
});
// Handle server shutdown
process.on('SIGINT', async () => {
console.log('Shutting down server...');
// Close all active transports to properly clean up resources
for (const sessionId in transports) {
try {
console.log(`Closing transport for session ${sessionId}`);
await transports[sessionId].close();
delete transports[sessionId];
}
catch (error) {
console.error(`Error closing transport for session ${sessionId}:`, error);
}
}
console.log('Server shutdown complete');
process.exit(0);
});
//# sourceMappingURL=simpleSseServer.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"simpleSseServer.js","sourceRoot":"","sources":["../../../../src/examples/server/simpleSseServer.ts"],"names":[],"mappings":";;;;;AAAA,sDAAqD;AACrD,gDAAgD;AAChD,gDAAyD;AACzD,6BAAwB;AAGxB;;;;;;;;GAQG;AAEH,gCAAgC;AAChC,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,MAAM,GAAG,IAAI,kBAAS,CAAC;QAC3B,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,OAAO;KACjB,EAAE,EAAE,YAAY,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAEtC,MAAM,CAAC,IAAI,CACT,2BAA2B,EAC3B,uCAAuC,EACvC;QACE,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gDAAgD,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;QAC7F,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iCAAiC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;KAC1E,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,EAAE,gBAAgB,EAAE,EAA2B,EAAE;QAC3E,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;QAC9E,IAAI,OAAO,GAAG,CAAC,CAAC;QAEhB,gCAAgC;QAChC,MAAM,gBAAgB,CAAC;YACrB,MAAM,EAAE,uBAAuB;YAC/B,MAAM,EAAE;gBACN,KAAK,EAAE,MAAM;gBACb,IAAI,EAAE,qCAAqC,KAAK,mBAAmB,QAAQ,IAAI;aAChF;SACF,CAAC,CAAC;QAEH,8BAA8B;QAC9B,OAAO,OAAO,GAAG,KAAK,EAAE,CAAC;YACvB,OAAO,EAAE,CAAC;YACV,MAAM,KAAK,CAAC,QAAQ,CAAC,CAAC;YAEtB,IAAI,CAAC;gBACH,MAAM,gBAAgB,CAAC;oBACrB,MAAM,EAAE,uBAAuB;oBAC/B,MAAM,EAAE;wBACN,KAAK,EAAE,MAAM;wBACb,IAAI,EAAE,iBAAiB,OAAO,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE;qBAChE;iBACF,CAAC,CAAC;YACL,CAAC;YACD,OAAO,KAAK,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;YACtD,CAAC;QACH,CAAC;QAED,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,qBAAqB,KAAK,wBAAwB,QAAQ,IAAI;iBACrE;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,GAAG,GAAG,IAAA,iBAAO,GAAE,CAAC;AACtB,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AAExB,iCAAiC;AACjC,MAAM,UAAU,GAAuC,EAAE,CAAC;AAE1D,2CAA2C;AAC3C,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IACpD,OAAO,CAAC,GAAG,CAAC,wDAAwD,CAAC,CAAC;IAEtE,IAAI,CAAC;QACH,4CAA4C;QAC5C,gDAAgD;QAChD,MAAM,SAAS,GAAG,IAAI,2BAAkB,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;QAE3D,oCAAoC;QACpC,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC;QACtC,UAAU,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC;QAElC,2DAA2D;QAC3D,SAAS,CAAC,OAAO,GAAG,GAAG,EAAE;YACvB,OAAO,CAAC,GAAG,CAAC,oCAAoC,SAAS,EAAE,CAAC,CAAC;YAC7D,OAAO,UAAU,CAAC,SAAS,CAAC,CAAC;QAC/B,CAAC,CAAC;QAEF,0CAA0C;QAC1C,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEhC,OAAO,CAAC,GAAG,CAAC,2CAA2C,SAAS,EAAE,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,KAAK,CAAC,CAAC;QACvD,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;YACrB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,2DAA2D;AAC3D,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IAC1D,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IAElD,8CAA8C;IAC9C,+EAA+E;IAC/E,MAAM,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC,SAA+B,CAAC;IAE5D,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;QACvD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QACpD,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IACxC,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,6CAA6C,SAAS,EAAE,CAAC,CAAC;QACxE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAC1C,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,6CAA6C;QAC7C,MAAM,SAAS,CAAC,iBAAiB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IACxD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;QAChD,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;YACrB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,mBAAmB;AACnB,MAAM,IAAI,GAAG,IAAI,CAAC;AAClB,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;IACpB,OAAO,CAAC,GAAG,CAAC,gFAAgF,IAAI,EAAE,CAAC,CAAC;AACtG,CAAC,CAAC,CAAC;AAEH,yBAAyB;AACzB,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;IAC9B,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IAEvC,6DAA6D;IAC7D,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,IAAI,CAAC;YACH,OAAO,CAAC,GAAG,CAAC,iCAAiC,SAAS,EAAE,CAAC,CAAC;YAC1D,MAAM,UAAU,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,CAAC;YACpC,OAAO,UAAU,CAAC,SAAS,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,uCAAuC,SAAS,GAAG,EAAE,KAAK,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC;IACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=simpleStatelessStreamableHttp.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"simpleStatelessStreamableHttp.d.ts","sourceRoot":"","sources":["../../../../src/examples/server/simpleStatelessStreamableHttp.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,140 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const mcp_js_1 = require("../../server/mcp.js");
const streamableHttp_js_1 = require("../../server/streamableHttp.js");
const zod_1 = require("zod");
const getServer = () => {
// Create an MCP server with implementation details
const server = new mcp_js_1.McpServer({
name: 'stateless-streamable-http-server',
version: '1.0.0',
}, { capabilities: { logging: {} } });
// Register a simple prompt
server.prompt('greeting-template', 'A simple greeting prompt template', {
name: zod_1.z.string().describe('Name to include in greeting'),
}, async ({ name }) => {
return {
messages: [
{
role: 'user',
content: {
type: 'text',
text: `Please greet ${name} in a friendly manner.`,
},
},
],
};
});
// Register a tool specifically for testing resumability
server.tool('start-notification-stream', 'Starts sending periodic notifications for testing resumability', {
interval: zod_1.z.number().describe('Interval in milliseconds between notifications').default(100),
count: zod_1.z.number().describe('Number of notifications to send (0 for 100)').default(10),
}, async ({ interval, count }, { sendNotification }) => {
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
let counter = 0;
while (count === 0 || counter < count) {
counter++;
try {
await sendNotification({
method: "notifications/message",
params: {
level: "info",
data: `Periodic notification #${counter} at ${new Date().toISOString()}`
}
});
}
catch (error) {
console.error("Error sending notification:", error);
}
// Wait for the specified interval
await sleep(interval);
}
return {
content: [
{
type: 'text',
text: `Started sending periodic notifications every ${interval}ms`,
}
],
};
});
// Create a simple resource at a fixed URI
server.resource('greeting-resource', 'https://example.com/greetings/default', { mimeType: 'text/plain' }, async () => {
return {
contents: [
{
uri: 'https://example.com/greetings/default',
text: 'Hello, world!',
},
],
};
});
return server;
};
const app = (0, express_1.default)();
app.use(express_1.default.json());
app.post('/mcp', async (req, res) => {
const server = getServer();
try {
const transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
res.on('close', () => {
console.log('Request closed');
transport.close();
server.close();
});
}
catch (error) {
console.error('Error handling MCP request:', error);
if (!res.headersSent) {
res.status(500).json({
jsonrpc: '2.0',
error: {
code: -32603,
message: 'Internal server error',
},
id: null,
});
}
}
});
app.get('/mcp', async (req, res) => {
console.log('Received GET MCP request');
res.writeHead(405).end(JSON.stringify({
jsonrpc: "2.0",
error: {
code: -32000,
message: "Method not allowed."
},
id: null
}));
});
app.delete('/mcp', async (req, res) => {
console.log('Received DELETE MCP request');
res.writeHead(405).end(JSON.stringify({
jsonrpc: "2.0",
error: {
code: -32000,
message: "Method not allowed."
},
id: null
}));
});
// Start the server
const PORT = 3000;
app.listen(PORT, () => {
console.log(`MCP Stateless Streamable HTTP Server listening on port ${PORT}`);
});
// Handle server shutdown
process.on('SIGINT', async () => {
console.log('Shutting down server...');
process.exit(0);
});
//# sourceMappingURL=simpleStatelessStreamableHttp.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"simpleStatelessStreamableHttp.js","sourceRoot":"","sources":["../../../../src/examples/server/simpleStatelessStreamableHttp.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=simpleStreamableHttp.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"simpleStreamableHttp.d.ts","sourceRoot":"","sources":["../../../../src/examples/server/simpleStreamableHttp.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,257 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const node_crypto_1 = require("node:crypto");
const zod_1 = require("zod");
const mcp_js_1 = require("../../server/mcp.js");
const streamableHttp_js_1 = require("../../server/streamableHttp.js");
const types_js_1 = require("../../types.js");
const inMemoryEventStore_js_1 = require("../shared/inMemoryEventStore.js");
// Create an MCP server with implementation details
const getServer = () => {
const server = new mcp_js_1.McpServer({
name: 'simple-streamable-http-server',
version: '1.0.0',
}, { capabilities: { logging: {} } });
// Register a simple tool that returns a greeting
server.tool('greet', 'A simple greeting tool', {
name: zod_1.z.string().describe('Name to greet'),
}, async ({ name }) => {
return {
content: [
{
type: 'text',
text: `Hello, ${name}!`,
},
],
};
});
// Register a tool that sends multiple greetings with notifications (with annotations)
server.tool('multi-greet', 'A tool that sends different greetings with delays between them', {
name: zod_1.z.string().describe('Name to greet'),
}, {
title: 'Multiple Greeting Tool',
readOnlyHint: true,
openWorldHint: false
}, async ({ name }, { sendNotification }) => {
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
await sendNotification({
method: "notifications/message",
params: { level: "debug", data: `Starting multi-greet for ${name}` }
});
await sleep(1000); // Wait 1 second before first greeting
await sendNotification({
method: "notifications/message",
params: { level: "info", data: `Sending first greeting to ${name}` }
});
await sleep(1000); // Wait another second before second greeting
await sendNotification({
method: "notifications/message",
params: { level: "info", data: `Sending second greeting to ${name}` }
});
return {
content: [
{
type: 'text',
text: `Good morning, ${name}!`,
}
],
};
});
// Register a simple prompt
server.prompt('greeting-template', 'A simple greeting prompt template', {
name: zod_1.z.string().describe('Name to include in greeting'),
}, async ({ name }) => {
return {
messages: [
{
role: 'user',
content: {
type: 'text',
text: `Please greet ${name} in a friendly manner.`,
},
},
],
};
});
// Register a tool specifically for testing resumability
server.tool('start-notification-stream', 'Starts sending periodic notifications for testing resumability', {
interval: zod_1.z.number().describe('Interval in milliseconds between notifications').default(100),
count: zod_1.z.number().describe('Number of notifications to send (0 for 100)').default(50),
}, async ({ interval, count }, { sendNotification }) => {
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
let counter = 0;
while (count === 0 || counter < count) {
counter++;
try {
await sendNotification({
method: "notifications/message",
params: {
level: "info",
data: `Periodic notification #${counter} at ${new Date().toISOString()}`
}
});
}
catch (error) {
console.error("Error sending notification:", error);
}
// Wait for the specified interval
await sleep(interval);
}
return {
content: [
{
type: 'text',
text: `Started sending periodic notifications every ${interval}ms`,
}
],
};
});
// Create a simple resource at a fixed URI
server.resource('greeting-resource', 'https://example.com/greetings/default', { mimeType: 'text/plain' }, async () => {
return {
contents: [
{
uri: 'https://example.com/greetings/default',
text: 'Hello, world!',
},
],
};
});
return server;
};
const app = (0, express_1.default)();
app.use(express_1.default.json());
// Map to store transports by session ID
const transports = {};
app.post('/mcp', async (req, res) => {
console.log('Received MCP request:', req.body);
try {
// Check for existing session ID
const sessionId = req.headers['mcp-session-id'];
let transport;
if (sessionId && transports[sessionId]) {
// Reuse existing transport
transport = transports[sessionId];
}
else if (!sessionId && (0, types_js_1.isInitializeRequest)(req.body)) {
// New initialization request
const eventStore = new inMemoryEventStore_js_1.InMemoryEventStore();
transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
sessionIdGenerator: () => (0, node_crypto_1.randomUUID)(),
eventStore, // Enable resumability
onsessioninitialized: (sessionId) => {
// Store the transport by session ID when session is initialized
// This avoids race conditions where requests might come in before the session is stored
console.log(`Session initialized with ID: ${sessionId}`);
transports[sessionId] = transport;
}
});
// Set up onclose handler to clean up transport when closed
transport.onclose = () => {
const sid = transport.sessionId;
if (sid && transports[sid]) {
console.log(`Transport closed for session ${sid}, removing from transports map`);
delete transports[sid];
}
};
// Connect the transport to the MCP server BEFORE handling the request
// so responses can flow back through the same transport
const server = getServer();
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
return; // Already handled
}
else {
// Invalid request - no session ID or not initialization request
res.status(400).json({
jsonrpc: '2.0',
error: {
code: -32000,
message: 'Bad Request: No valid session ID provided',
},
id: null,
});
return;
}
// Handle the request with existing transport - no need to reconnect
// The existing transport is already connected to the server
await transport.handleRequest(req, res, req.body);
}
catch (error) {
console.error('Error handling MCP request:', error);
if (!res.headersSent) {
res.status(500).json({
jsonrpc: '2.0',
error: {
code: -32603,
message: 'Internal server error',
},
id: null,
});
}
}
});
// Handle GET requests for SSE streams (using built-in support from StreamableHTTP)
app.get('/mcp', async (req, res) => {
const sessionId = req.headers['mcp-session-id'];
if (!sessionId || !transports[sessionId]) {
res.status(400).send('Invalid or missing session ID');
return;
}
// Check for Last-Event-ID header for resumability
const lastEventId = req.headers['last-event-id'];
if (lastEventId) {
console.log(`Client reconnecting with Last-Event-ID: ${lastEventId}`);
}
else {
console.log(`Establishing new SSE stream for session ${sessionId}`);
}
const transport = transports[sessionId];
await transport.handleRequest(req, res);
});
// Handle DELETE requests for session termination (according to MCP spec)
app.delete('/mcp', async (req, res) => {
const sessionId = req.headers['mcp-session-id'];
if (!sessionId || !transports[sessionId]) {
res.status(400).send('Invalid or missing session ID');
return;
}
console.log(`Received session termination request for session ${sessionId}`);
try {
const transport = transports[sessionId];
await transport.handleRequest(req, res);
}
catch (error) {
console.error('Error handling session termination:', error);
if (!res.headersSent) {
res.status(500).send('Error processing session termination');
}
}
});
// Start the server
const PORT = 3000;
app.listen(PORT, () => {
console.log(`MCP Streamable HTTP Server listening on port ${PORT}`);
});
// Handle server shutdown
process.on('SIGINT', async () => {
console.log('Shutting down server...');
// Close all active transports to properly clean up resources
for (const sessionId in transports) {
try {
console.log(`Closing transport for session ${sessionId}`);
await transports[sessionId].close();
delete transports[sessionId];
}
catch (error) {
console.error(`Error closing transport for session ${sessionId}:`, error);
}
}
console.log('Server shutdown complete');
process.exit(0);
});
//# sourceMappingURL=simpleStreamableHttp.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=sseAndStreamableHttpCompatibleServer.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"sseAndStreamableHttpCompatibleServer.d.ts","sourceRoot":"","sources":["../../../../src/examples/server/sseAndStreamableHttpCompatibleServer.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,233 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const node_crypto_1 = require("node:crypto");
const mcp_js_1 = require("../../server/mcp.js");
const streamableHttp_js_1 = require("../../server/streamableHttp.js");
const sse_js_1 = require("../../server/sse.js");
const zod_1 = require("zod");
const types_js_1 = require("../../types.js");
const inMemoryEventStore_js_1 = require("../shared/inMemoryEventStore.js");
/**
* This example server demonstrates backwards compatibility with both:
* 1. The deprecated HTTP+SSE transport (protocol version 2024-11-05)
* 2. The Streamable HTTP transport (protocol version 2025-03-26)
*
* It maintains a single MCP server instance but exposes two transport options:
* - /mcp: The new Streamable HTTP endpoint (supports GET/POST/DELETE)
* - /sse: The deprecated SSE endpoint for older clients (GET to establish stream)
* - /messages: The deprecated POST endpoint for older clients (POST to send messages)
*/
const getServer = () => {
const server = new mcp_js_1.McpServer({
name: 'backwards-compatible-server',
version: '1.0.0',
}, { capabilities: { logging: {} } });
// Register a simple tool that sends notifications over time
server.tool('start-notification-stream', 'Starts sending periodic notifications for testing resumability', {
interval: zod_1.z.number().describe('Interval in milliseconds between notifications').default(100),
count: zod_1.z.number().describe('Number of notifications to send (0 for 100)').default(50),
}, async ({ interval, count }, { sendNotification }) => {
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
let counter = 0;
while (count === 0 || counter < count) {
counter++;
try {
await sendNotification({
method: "notifications/message",
params: {
level: "info",
data: `Periodic notification #${counter} at ${new Date().toISOString()}`
}
});
}
catch (error) {
console.error("Error sending notification:", error);
}
// Wait for the specified interval
await sleep(interval);
}
return {
content: [
{
type: 'text',
text: `Started sending periodic notifications every ${interval}ms`,
}
],
};
});
return server;
};
// Create Express application
const app = (0, express_1.default)();
app.use(express_1.default.json());
// Store transports by session ID
const transports = {};
//=============================================================================
// STREAMABLE HTTP TRANSPORT (PROTOCOL VERSION 2025-03-26)
//=============================================================================
// Handle all MCP Streamable HTTP requests (GET, POST, DELETE) on a single endpoint
app.all('/mcp', async (req, res) => {
console.log(`Received ${req.method} request to /mcp`);
try {
// Check for existing session ID
const sessionId = req.headers['mcp-session-id'];
let transport;
if (sessionId && transports[sessionId]) {
// Check if the transport is of the correct type
const existingTransport = transports[sessionId];
if (existingTransport instanceof streamableHttp_js_1.StreamableHTTPServerTransport) {
// Reuse existing transport
transport = existingTransport;
}
else {
// Transport exists but is not a StreamableHTTPServerTransport (could be SSEServerTransport)
res.status(400).json({
jsonrpc: '2.0',
error: {
code: -32000,
message: 'Bad Request: Session exists but uses a different transport protocol',
},
id: null,
});
return;
}
}
else if (!sessionId && req.method === 'POST' && (0, types_js_1.isInitializeRequest)(req.body)) {
const eventStore = new inMemoryEventStore_js_1.InMemoryEventStore();
transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
sessionIdGenerator: () => (0, node_crypto_1.randomUUID)(),
eventStore, // Enable resumability
onsessioninitialized: (sessionId) => {
// Store the transport by session ID when session is initialized
console.log(`StreamableHTTP session initialized with ID: ${sessionId}`);
transports[sessionId] = transport;
}
});
// Set up onclose handler to clean up transport when closed
transport.onclose = () => {
const sid = transport.sessionId;
if (sid && transports[sid]) {
console.log(`Transport closed for session ${sid}, removing from transports map`);
delete transports[sid];
}
};
// Connect the transport to the MCP server
const server = getServer();
await server.connect(transport);
}
else {
// Invalid request - no session ID or not initialization request
res.status(400).json({
jsonrpc: '2.0',
error: {
code: -32000,
message: 'Bad Request: No valid session ID provided',
},
id: null,
});
return;
}
// Handle the request with the transport
await transport.handleRequest(req, res, req.body);
}
catch (error) {
console.error('Error handling MCP request:', error);
if (!res.headersSent) {
res.status(500).json({
jsonrpc: '2.0',
error: {
code: -32603,
message: 'Internal server error',
},
id: null,
});
}
}
});
//=============================================================================
// DEPRECATED HTTP+SSE TRANSPORT (PROTOCOL VERSION 2024-11-05)
//=============================================================================
app.get('/sse', async (req, res) => {
console.log('Received GET request to /sse (deprecated SSE transport)');
const transport = new sse_js_1.SSEServerTransport('/messages', res);
transports[transport.sessionId] = transport;
res.on("close", () => {
delete transports[transport.sessionId];
});
const server = getServer();
await server.connect(transport);
});
app.post("/messages", async (req, res) => {
const sessionId = req.query.sessionId;
let transport;
const existingTransport = transports[sessionId];
if (existingTransport instanceof sse_js_1.SSEServerTransport) {
// Reuse existing transport
transport = existingTransport;
}
else {
// Transport exists but is not a SSEServerTransport (could be StreamableHTTPServerTransport)
res.status(400).json({
jsonrpc: '2.0',
error: {
code: -32000,
message: 'Bad Request: Session exists but uses a different transport protocol',
},
id: null,
});
return;
}
if (transport) {
await transport.handlePostMessage(req, res, req.body);
}
else {
res.status(400).send('No transport found for sessionId');
}
});
// Start the server
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Backwards compatible MCP server listening on port ${PORT}`);
console.log(`
==============================================
SUPPORTED TRANSPORT OPTIONS:
1. Streamable Http(Protocol version: 2025-03-26)
Endpoint: /mcp
Methods: GET, POST, DELETE
Usage:
- Initialize with POST to /mcp
- Establish SSE stream with GET to /mcp
- Send requests with POST to /mcp
- Terminate session with DELETE to /mcp
2. Http + SSE (Protocol version: 2024-11-05)
Endpoints: /sse (GET) and /messages (POST)
Usage:
- Establish SSE stream with GET to /sse
- Send requests with POST to /messages?sessionId=<id>
==============================================
`);
});
// Handle server shutdown
process.on('SIGINT', async () => {
console.log('Shutting down server...');
// Close all active transports to properly clean up resources
for (const sessionId in transports) {
try {
console.log(`Closing transport for session ${sessionId}`);
await transports[sessionId].close();
delete transports[sessionId];
}
catch (error) {
console.error(`Error closing transport for session ${sessionId}:`, error);
}
}
console.log('Server shutdown complete');
process.exit(0);
});
//# sourceMappingURL=sseAndStreamableHttpCompatibleServer.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=standaloneSseWithGetStreamableHttp.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"standaloneSseWithGetStreamableHttp.d.ts","sourceRoot":"","sources":["../../../../src/examples/server/standaloneSseWithGetStreamableHttp.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,112 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const node_crypto_1 = require("node:crypto");
const mcp_js_1 = require("../../server/mcp.js");
const streamableHttp_js_1 = require("../../server/streamableHttp.js");
const types_js_1 = require("../../types.js");
// Create an MCP server with implementation details
const server = new mcp_js_1.McpServer({
name: 'resource-list-changed-notification-server',
version: '1.0.0',
});
// Store transports by session ID to send notifications
const transports = {};
const addResource = (name, content) => {
const uri = `https://mcp-example.com/dynamic/${encodeURIComponent(name)}`;
server.resource(name, uri, { mimeType: 'text/plain', description: `Dynamic resource: ${name}` }, async () => {
return {
contents: [{ uri, text: content }],
};
});
};
addResource('example-resource', 'Initial content for example-resource');
const resourceChangeInterval = setInterval(() => {
const name = (0, node_crypto_1.randomUUID)();
addResource(name, `Content for ${name}`);
}, 5000); // Change resources every 5 seconds for testing
const app = (0, express_1.default)();
app.use(express_1.default.json());
app.post('/mcp', async (req, res) => {
console.log('Received MCP request:', req.body);
try {
// Check for existing session ID
const sessionId = req.headers['mcp-session-id'];
let transport;
if (sessionId && transports[sessionId]) {
// Reuse existing transport
transport = transports[sessionId];
}
else if (!sessionId && (0, types_js_1.isInitializeRequest)(req.body)) {
// New initialization request
transport = new streamableHttp_js_1.StreamableHTTPServerTransport({
sessionIdGenerator: () => (0, node_crypto_1.randomUUID)(),
onsessioninitialized: (sessionId) => {
// Store the transport by session ID when session is initialized
// This avoids race conditions where requests might come in before the session is stored
console.log(`Session initialized with ID: ${sessionId}`);
transports[sessionId] = transport;
}
});
// Connect the transport to the MCP server
await server.connect(transport);
// Handle the request - the onsessioninitialized callback will store the transport
await transport.handleRequest(req, res, req.body);
return; // Already handled
}
else {
// Invalid request - no session ID or not initialization request
res.status(400).json({
jsonrpc: '2.0',
error: {
code: -32000,
message: 'Bad Request: No valid session ID provided',
},
id: null,
});
return;
}
// Handle the request with existing transport
await transport.handleRequest(req, res, req.body);
}
catch (error) {
console.error('Error handling MCP request:', error);
if (!res.headersSent) {
res.status(500).json({
jsonrpc: '2.0',
error: {
code: -32603,
message: 'Internal server error',
},
id: null,
});
}
}
});
// Handle GET requests for SSE streams (now using built-in support from StreamableHTTP)
app.get('/mcp', async (req, res) => {
const sessionId = req.headers['mcp-session-id'];
if (!sessionId || !transports[sessionId]) {
res.status(400).send('Invalid or missing session ID');
return;
}
console.log(`Establishing SSE stream for session ${sessionId}`);
const transport = transports[sessionId];
await transport.handleRequest(req, res);
});
// Start the server
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
});
// Handle server shutdown
process.on('SIGINT', async () => {
console.log('Shutting down server...');
clearInterval(resourceChangeInterval);
await server.close();
process.exit(0);
});
//# sourceMappingURL=standaloneSseWithGetStreamableHttp.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"standaloneSseWithGetStreamableHttp.js","sourceRoot":"","sources":["../../../../src/examples/server/standaloneSseWithGetStreamableHttp.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,31 @@
import { JSONRPCMessage } from '../../types.js';
import { EventStore } from '../../server/streamableHttp.js';
/**
* Simple in-memory implementation of the EventStore interface for resumability
* This is primarily intended for examples and testing, not for production use
* where a persistent storage solution would be more appropriate.
*/
export declare class InMemoryEventStore implements EventStore {
private events;
/**
* Generates a unique event ID for a given stream ID
*/
private generateEventId;
/**
* Extracts the stream ID from an event ID
*/
private getStreamIdFromEventId;
/**
* Stores an event with a generated event ID
* Implements EventStore.storeEvent
*/
storeEvent(streamId: string, message: JSONRPCMessage): Promise<string>;
/**
* Replays events that occurred after a specific event ID
* Implements EventStore.replayEventsAfter
*/
replayEventsAfter(lastEventId: string, { send }: {
send: (eventId: string, message: JSONRPCMessage) => Promise<void>;
}): Promise<string>;
}
//# sourceMappingURL=inMemoryEventStore.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"inMemoryEventStore.d.ts","sourceRoot":"","sources":["../../../../src/examples/shared/inMemoryEventStore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAE5D;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,UAAU;IACnD,OAAO,CAAC,MAAM,CAAyE;IAEvF;;OAEG;IACH,OAAO,CAAC,eAAe;IAIvB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAK9B;;;OAGG;IACG,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC;IAM5E;;;OAGG;IACG,iBAAiB,CAAC,WAAW,EAAE,MAAM,EACzC,EAAE,IAAI,EAAE,EAAE;QAAE,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;KAAE,GAC9E,OAAO,CAAC,MAAM,CAAC;CAkCnB"}

View File

@@ -0,0 +1,69 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InMemoryEventStore = void 0;
/**
* Simple in-memory implementation of the EventStore interface for resumability
* This is primarily intended for examples and testing, not for production use
* where a persistent storage solution would be more appropriate.
*/
class InMemoryEventStore {
constructor() {
this.events = new Map();
}
/**
* Generates a unique event ID for a given stream ID
*/
generateEventId(streamId) {
return `${streamId}_${Date.now()}_${Math.random().toString(36).substring(2, 10)}`;
}
/**
* Extracts the stream ID from an event ID
*/
getStreamIdFromEventId(eventId) {
const parts = eventId.split('_');
return parts.length > 0 ? parts[0] : '';
}
/**
* Stores an event with a generated event ID
* Implements EventStore.storeEvent
*/
async storeEvent(streamId, message) {
const eventId = this.generateEventId(streamId);
this.events.set(eventId, { streamId, message });
return eventId;
}
/**
* Replays events that occurred after a specific event ID
* Implements EventStore.replayEventsAfter
*/
async replayEventsAfter(lastEventId, { send }) {
if (!lastEventId || !this.events.has(lastEventId)) {
return '';
}
// Extract the stream ID from the event ID
const streamId = this.getStreamIdFromEventId(lastEventId);
if (!streamId) {
return '';
}
let foundLastEvent = false;
// Sort events by eventId for chronological ordering
const sortedEvents = [...this.events.entries()].sort((a, b) => a[0].localeCompare(b[0]));
for (const [eventId, { streamId: eventStreamId, message }] of sortedEvents) {
// Only include events from the same stream
if (eventStreamId !== streamId) {
continue;
}
// Start sending events after we find the lastEventId
if (eventId === lastEventId) {
foundLastEvent = true;
continue;
}
if (foundLastEvent) {
await send(eventId, message);
}
}
return streamId;
}
}
exports.InMemoryEventStore = InMemoryEventStore;
//# sourceMappingURL=inMemoryEventStore.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"inMemoryEventStore.js","sourceRoot":"","sources":["../../../../src/examples/shared/inMemoryEventStore.ts"],"names":[],"mappings":";;;AAGA;;;;GAIG;AACH,MAAa,kBAAkB;IAA/B;QACU,WAAM,GAA+D,IAAI,GAAG,EAAE,CAAC;IAmEzF,CAAC;IAjEC;;OAEG;IACK,eAAe,CAAC,QAAgB;QACtC,OAAO,GAAG,QAAQ,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;IACpF,CAAC;IAED;;OAEG;IACK,sBAAsB,CAAC,OAAe;QAC5C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACjC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1C,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,UAAU,CAAC,QAAgB,EAAE,OAAuB;QACxD,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QAChD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,iBAAiB,CAAC,WAAmB,EACzC,EAAE,IAAI,EAAyE;QAE/E,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC;YAClD,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,0CAA0C;QAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,sBAAsB,CAAC,WAAW,CAAC,CAAC;QAC1D,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,IAAI,cAAc,GAAG,KAAK,CAAC;QAE3B,oDAAoD;QACpD,MAAM,YAAY,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEzF,KAAK,MAAM,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,IAAI,YAAY,EAAE,CAAC;YAC3E,2CAA2C;YAC3C,IAAI,aAAa,KAAK,QAAQ,EAAE,CAAC;gBAC/B,SAAS;YACX,CAAC;YAED,qDAAqD;YACrD,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;gBAC5B,cAAc,GAAG,IAAI,CAAC;gBACtB,SAAS;YACX,CAAC;YAED,IAAI,cAAc,EAAE,CAAC;gBACnB,MAAM,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AApED,gDAoEC"}

View File

@@ -0,0 +1,31 @@
import { Transport } from "./shared/transport.js";
import { JSONRPCMessage, RequestId } from "./types.js";
import { AuthInfo } from "./server/auth/types.js";
/**
* In-memory transport for creating clients and servers that talk to each other within the same process.
*/
export declare class InMemoryTransport implements Transport {
private _otherTransport?;
private _messageQueue;
onclose?: () => void;
onerror?: (error: Error) => void;
onmessage?: (message: JSONRPCMessage, extra?: {
authInfo?: AuthInfo;
}) => void;
sessionId?: string;
/**
* Creates a pair of linked in-memory transports that can communicate with each other. One should be passed to a Client and one to a Server.
*/
static createLinkedPair(): [InMemoryTransport, InMemoryTransport];
start(): Promise<void>;
close(): Promise<void>;
/**
* Sends a message with optional auth info.
* This is useful for testing authentication scenarios.
*/
send(message: JSONRPCMessage, options?: {
relatedRequestId?: RequestId;
authInfo?: AuthInfo;
}): Promise<void>;
}
//# sourceMappingURL=inMemory.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"inMemory.d.ts","sourceRoot":"","sources":["../../src/inMemory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAOlD;;GAEG;AACH,qBAAa,iBAAkB,YAAW,SAAS;IACjD,OAAO,CAAC,eAAe,CAAC,CAAoB;IAC5C,OAAO,CAAC,aAAa,CAAuB;IAE5C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,QAAQ,CAAA;KAAE,KAAK,IAAI,CAAC;IAC/E,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,MAAM,CAAC,gBAAgB,IAAI,CAAC,iBAAiB,EAAE,iBAAiB,CAAC;IAQ3D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B;;;OAGG;IACG,IAAI,CAAC,OAAO,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE;QAAE,gBAAgB,CAAC,EAAE,SAAS,CAAC;QAAC,QAAQ,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAWpH"}

View File

@@ -0,0 +1,53 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InMemoryTransport = void 0;
/**
* In-memory transport for creating clients and servers that talk to each other within the same process.
*/
class InMemoryTransport {
constructor() {
this._messageQueue = [];
}
/**
* Creates a pair of linked in-memory transports that can communicate with each other. One should be passed to a Client and one to a Server.
*/
static createLinkedPair() {
const clientTransport = new InMemoryTransport();
const serverTransport = new InMemoryTransport();
clientTransport._otherTransport = serverTransport;
serverTransport._otherTransport = clientTransport;
return [clientTransport, serverTransport];
}
async start() {
var _a;
// Process any messages that were queued before start was called
while (this._messageQueue.length > 0) {
const queuedMessage = this._messageQueue.shift();
(_a = this.onmessage) === null || _a === void 0 ? void 0 : _a.call(this, queuedMessage.message, queuedMessage.extra);
}
}
async close() {
var _a;
const other = this._otherTransport;
this._otherTransport = undefined;
await (other === null || other === void 0 ? void 0 : other.close());
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
}
/**
* Sends a message with optional auth info.
* This is useful for testing authentication scenarios.
*/
async send(message, options) {
if (!this._otherTransport) {
throw new Error("Not connected");
}
if (this._otherTransport.onmessage) {
this._otherTransport.onmessage(message, { authInfo: options === null || options === void 0 ? void 0 : options.authInfo });
}
else {
this._otherTransport._messageQueue.push({ message, extra: { authInfo: options === null || options === void 0 ? void 0 : options.authInfo } });
}
}
}
exports.InMemoryTransport = InMemoryTransport;
//# sourceMappingURL=inMemory.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"inMemory.js","sourceRoot":"","sources":["../../src/inMemory.ts"],"names":[],"mappings":";;;AASA;;GAEG;AACH,MAAa,iBAAiB;IAA9B;QAEU,kBAAa,GAAoB,EAAE,CAAC;IAgD9C,CAAC;IAzCC;;OAEG;IACH,MAAM,CAAC,gBAAgB;QACrB,MAAM,eAAe,GAAG,IAAI,iBAAiB,EAAE,CAAC;QAChD,MAAM,eAAe,GAAG,IAAI,iBAAiB,EAAE,CAAC;QAChD,eAAe,CAAC,eAAe,GAAG,eAAe,CAAC;QAClD,eAAe,CAAC,eAAe,GAAG,eAAe,CAAC;QAClD,OAAO,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,KAAK;;QACT,gEAAgE;QAChE,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrC,MAAM,aAAa,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,EAAG,CAAC;YAClD,MAAA,IAAI,CAAC,SAAS,qDAAG,aAAa,CAAC,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK;;QACT,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC;QACnC,IAAI,CAAC,eAAe,GAAG,SAAS,CAAC;QACjC,MAAM,CAAA,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,KAAK,EAAE,CAAA,CAAC;QACrB,MAAA,IAAI,CAAC,OAAO,oDAAI,CAAC;IACnB,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI,CAAC,OAAuB,EAAE,OAA+D;QACjG,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;QACnC,CAAC;QAED,IAAI,IAAI,CAAC,eAAe,CAAC,SAAS,EAAE,CAAC;YACnC,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ,EAAE,CAAC,CAAC;QAC3E,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC/F,CAAC;IACH,CAAC;CACF;AAlDD,8CAkDC"}

View File

@@ -0,0 +1 @@
{"type": "commonjs"}

View File

@@ -0,0 +1,19 @@
import { OAuthClientInformationFull } from "../../shared/auth.js";
/**
* Stores information about registered OAuth clients for this server.
*/
export interface OAuthRegisteredClientsStore {
/**
* Returns information about a registered client, based on its ID.
*/
getClient(clientId: string): OAuthClientInformationFull | undefined | Promise<OAuthClientInformationFull | undefined>;
/**
* Registers a new client with the server. The client ID and secret will be automatically generated by the library. A modified version of the client information can be returned to reflect specific values enforced by the server.
*
* NOTE: Implementations should NOT delete expired client secrets in-place. Auth middleware provided by this library will automatically check the `client_secret_expires_at` field and reject requests with expired secrets. Any custom logic for authenticating clients should check the `client_secret_expires_at` field as well.
*
* If unimplemented, dynamic client registration is unsupported.
*/
registerClient?(client: OAuthClientInformationFull): OAuthClientInformationFull | Promise<OAuthClientInformationFull>;
}
//# sourceMappingURL=clients.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"clients.d.ts","sourceRoot":"","sources":["../../../../src/server/auth/clients.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAElE;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;OAEG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,0BAA0B,GAAG,SAAS,GAAG,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC,CAAC;IAEtH;;;;;;OAMG;IACH,cAAc,CAAC,CAAC,MAAM,EAAE,0BAA0B,GAAG,0BAA0B,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAAC;CACvH"}

View File

@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=clients.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"clients.js","sourceRoot":"","sources":["../../../../src/server/auth/clients.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,126 @@
import { OAuthErrorResponse } from "../../shared/auth.js";
/**
* Base class for all OAuth errors
*/
export declare class OAuthError extends Error {
readonly errorCode: string;
readonly errorUri?: string | undefined;
constructor(errorCode: string, message: string, errorUri?: string | undefined);
/**
* Converts the error to a standard OAuth error response object
*/
toResponseObject(): OAuthErrorResponse;
}
/**
* Invalid request error - The request is missing a required parameter,
* includes an invalid parameter value, includes a parameter more than once,
* or is otherwise malformed.
*/
export declare class InvalidRequestError extends OAuthError {
constructor(message: string, errorUri?: string);
}
/**
* Invalid client error - Client authentication failed (e.g., unknown client, no client
* authentication included, or unsupported authentication method).
*/
export declare class InvalidClientError extends OAuthError {
constructor(message: string, errorUri?: string);
}
/**
* Invalid grant error - The provided authorization grant or refresh token is
* invalid, expired, revoked, does not match the redirection URI used in the
* authorization request, or was issued to another client.
*/
export declare class InvalidGrantError extends OAuthError {
constructor(message: string, errorUri?: string);
}
/**
* Unauthorized client error - The authenticated client is not authorized to use
* this authorization grant type.
*/
export declare class UnauthorizedClientError extends OAuthError {
constructor(message: string, errorUri?: string);
}
/**
* Unsupported grant type error - The authorization grant type is not supported
* by the authorization server.
*/
export declare class UnsupportedGrantTypeError extends OAuthError {
constructor(message: string, errorUri?: string);
}
/**
* Invalid scope error - The requested scope is invalid, unknown, malformed, or
* exceeds the scope granted by the resource owner.
*/
export declare class InvalidScopeError extends OAuthError {
constructor(message: string, errorUri?: string);
}
/**
* Access denied error - The resource owner or authorization server denied the request.
*/
export declare class AccessDeniedError extends OAuthError {
constructor(message: string, errorUri?: string);
}
/**
* Server error - The authorization server encountered an unexpected condition
* that prevented it from fulfilling the request.
*/
export declare class ServerError extends OAuthError {
constructor(message: string, errorUri?: string);
}
/**
* Temporarily unavailable error - The authorization server is currently unable to
* handle the request due to a temporary overloading or maintenance of the server.
*/
export declare class TemporarilyUnavailableError extends OAuthError {
constructor(message: string, errorUri?: string);
}
/**
* Unsupported response type error - The authorization server does not support
* obtaining an authorization code using this method.
*/
export declare class UnsupportedResponseTypeError extends OAuthError {
constructor(message: string, errorUri?: string);
}
/**
* Unsupported token type error - The authorization server does not support
* the requested token type.
*/
export declare class UnsupportedTokenTypeError extends OAuthError {
constructor(message: string, errorUri?: string);
}
/**
* Invalid token error - The access token provided is expired, revoked, malformed,
* or invalid for other reasons.
*/
export declare class InvalidTokenError extends OAuthError {
constructor(message: string, errorUri?: string);
}
/**
* Method not allowed error - The HTTP method used is not allowed for this endpoint.
* (Custom, non-standard error)
*/
export declare class MethodNotAllowedError extends OAuthError {
constructor(message: string, errorUri?: string);
}
/**
* Too many requests error - Rate limit exceeded.
* (Custom, non-standard error based on RFC 6585)
*/
export declare class TooManyRequestsError extends OAuthError {
constructor(message: string, errorUri?: string);
}
/**
* Invalid client metadata error - The client metadata is invalid.
* (Custom error for dynamic client registration - RFC 7591)
*/
export declare class InvalidClientMetadataError extends OAuthError {
constructor(message: string, errorUri?: string);
}
/**
* Insufficient scope error - The request requires higher privileges than provided by the access token.
*/
export declare class InsufficientScopeError extends OAuthError {
constructor(message: string, errorUri?: string);
}
//# sourceMappingURL=errors.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../../src/server/auth/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D;;GAEG;AACH,qBAAa,UAAW,SAAQ,KAAK;aAEjB,SAAS,EAAE,MAAM;aAEjB,QAAQ,CAAC,EAAE,MAAM;gBAFjB,SAAS,EAAE,MAAM,EACjC,OAAO,EAAE,MAAM,EACC,QAAQ,CAAC,EAAE,MAAM,YAAA;IAMnC;;OAEG;IACH,gBAAgB,IAAI,kBAAkB;CAYvC;AAED;;;;GAIG;AACH,qBAAa,mBAAoB,SAAQ,UAAU;gBACrC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C;AAED;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,UAAU;gBACpC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C;AAED;;;;GAIG;AACH,qBAAa,iBAAkB,SAAQ,UAAU;gBACnC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C;AAED;;;GAGG;AACH,qBAAa,uBAAwB,SAAQ,UAAU;gBACzC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C;AAED;;;GAGG;AACH,qBAAa,yBAA0B,SAAQ,UAAU;gBAC3C,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C;AAED;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,UAAU;gBACnC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C;AAED;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,UAAU;gBACnC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C;AAED;;;GAGG;AACH,qBAAa,WAAY,SAAQ,UAAU;gBAC7B,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C;AAED;;;GAGG;AACH,qBAAa,2BAA4B,SAAQ,UAAU;gBAC7C,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C;AAED;;;GAGG;AACH,qBAAa,4BAA6B,SAAQ,UAAU;gBAC9C,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C;AAED;;;GAGG;AACH,qBAAa,yBAA0B,SAAQ,UAAU;gBAC3C,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C;AAED;;;GAGG;AACH,qBAAa,iBAAkB,SAAQ,UAAU;gBACnC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C;AAED;;;GAGG;AACH,qBAAa,qBAAsB,SAAQ,UAAU;gBACvC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C;AAED;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,UAAU;gBACtC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C;AAED;;;GAGG;AACH,qBAAa,0BAA2B,SAAQ,UAAU;gBAC5C,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C;AAED;;GAEG;AACH,qBAAa,sBAAuB,SAAQ,UAAU;gBACxC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;CAG/C"}

View File

@@ -0,0 +1,189 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InsufficientScopeError = exports.InvalidClientMetadataError = exports.TooManyRequestsError = exports.MethodNotAllowedError = exports.InvalidTokenError = exports.UnsupportedTokenTypeError = exports.UnsupportedResponseTypeError = exports.TemporarilyUnavailableError = exports.ServerError = exports.AccessDeniedError = exports.InvalidScopeError = exports.UnsupportedGrantTypeError = exports.UnauthorizedClientError = exports.InvalidGrantError = exports.InvalidClientError = exports.InvalidRequestError = exports.OAuthError = void 0;
/**
* Base class for all OAuth errors
*/
class OAuthError extends Error {
constructor(errorCode, message, errorUri) {
super(message);
this.errorCode = errorCode;
this.errorUri = errorUri;
this.name = this.constructor.name;
}
/**
* Converts the error to a standard OAuth error response object
*/
toResponseObject() {
const response = {
error: this.errorCode,
error_description: this.message
};
if (this.errorUri) {
response.error_uri = this.errorUri;
}
return response;
}
}
exports.OAuthError = OAuthError;
/**
* Invalid request error - The request is missing a required parameter,
* includes an invalid parameter value, includes a parameter more than once,
* or is otherwise malformed.
*/
class InvalidRequestError extends OAuthError {
constructor(message, errorUri) {
super("invalid_request", message, errorUri);
}
}
exports.InvalidRequestError = InvalidRequestError;
/**
* Invalid client error - Client authentication failed (e.g., unknown client, no client
* authentication included, or unsupported authentication method).
*/
class InvalidClientError extends OAuthError {
constructor(message, errorUri) {
super("invalid_client", message, errorUri);
}
}
exports.InvalidClientError = InvalidClientError;
/**
* Invalid grant error - The provided authorization grant or refresh token is
* invalid, expired, revoked, does not match the redirection URI used in the
* authorization request, or was issued to another client.
*/
class InvalidGrantError extends OAuthError {
constructor(message, errorUri) {
super("invalid_grant", message, errorUri);
}
}
exports.InvalidGrantError = InvalidGrantError;
/**
* Unauthorized client error - The authenticated client is not authorized to use
* this authorization grant type.
*/
class UnauthorizedClientError extends OAuthError {
constructor(message, errorUri) {
super("unauthorized_client", message, errorUri);
}
}
exports.UnauthorizedClientError = UnauthorizedClientError;
/**
* Unsupported grant type error - The authorization grant type is not supported
* by the authorization server.
*/
class UnsupportedGrantTypeError extends OAuthError {
constructor(message, errorUri) {
super("unsupported_grant_type", message, errorUri);
}
}
exports.UnsupportedGrantTypeError = UnsupportedGrantTypeError;
/**
* Invalid scope error - The requested scope is invalid, unknown, malformed, or
* exceeds the scope granted by the resource owner.
*/
class InvalidScopeError extends OAuthError {
constructor(message, errorUri) {
super("invalid_scope", message, errorUri);
}
}
exports.InvalidScopeError = InvalidScopeError;
/**
* Access denied error - The resource owner or authorization server denied the request.
*/
class AccessDeniedError extends OAuthError {
constructor(message, errorUri) {
super("access_denied", message, errorUri);
}
}
exports.AccessDeniedError = AccessDeniedError;
/**
* Server error - The authorization server encountered an unexpected condition
* that prevented it from fulfilling the request.
*/
class ServerError extends OAuthError {
constructor(message, errorUri) {
super("server_error", message, errorUri);
}
}
exports.ServerError = ServerError;
/**
* Temporarily unavailable error - The authorization server is currently unable to
* handle the request due to a temporary overloading or maintenance of the server.
*/
class TemporarilyUnavailableError extends OAuthError {
constructor(message, errorUri) {
super("temporarily_unavailable", message, errorUri);
}
}
exports.TemporarilyUnavailableError = TemporarilyUnavailableError;
/**
* Unsupported response type error - The authorization server does not support
* obtaining an authorization code using this method.
*/
class UnsupportedResponseTypeError extends OAuthError {
constructor(message, errorUri) {
super("unsupported_response_type", message, errorUri);
}
}
exports.UnsupportedResponseTypeError = UnsupportedResponseTypeError;
/**
* Unsupported token type error - The authorization server does not support
* the requested token type.
*/
class UnsupportedTokenTypeError extends OAuthError {
constructor(message, errorUri) {
super("unsupported_token_type", message, errorUri);
}
}
exports.UnsupportedTokenTypeError = UnsupportedTokenTypeError;
/**
* Invalid token error - The access token provided is expired, revoked, malformed,
* or invalid for other reasons.
*/
class InvalidTokenError extends OAuthError {
constructor(message, errorUri) {
super("invalid_token", message, errorUri);
}
}
exports.InvalidTokenError = InvalidTokenError;
/**
* Method not allowed error - The HTTP method used is not allowed for this endpoint.
* (Custom, non-standard error)
*/
class MethodNotAllowedError extends OAuthError {
constructor(message, errorUri) {
super("method_not_allowed", message, errorUri);
}
}
exports.MethodNotAllowedError = MethodNotAllowedError;
/**
* Too many requests error - Rate limit exceeded.
* (Custom, non-standard error based on RFC 6585)
*/
class TooManyRequestsError extends OAuthError {
constructor(message, errorUri) {
super("too_many_requests", message, errorUri);
}
}
exports.TooManyRequestsError = TooManyRequestsError;
/**
* Invalid client metadata error - The client metadata is invalid.
* (Custom error for dynamic client registration - RFC 7591)
*/
class InvalidClientMetadataError extends OAuthError {
constructor(message, errorUri) {
super("invalid_client_metadata", message, errorUri);
}
}
exports.InvalidClientMetadataError = InvalidClientMetadataError;
/**
* Insufficient scope error - The request requires higher privileges than provided by the access token.
*/
class InsufficientScopeError extends OAuthError {
constructor(message, errorUri) {
super("insufficient_scope", message, errorUri);
}
}
exports.InsufficientScopeError = InsufficientScopeError;
//# sourceMappingURL=errors.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../../src/server/auth/errors.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,13 @@
import { RequestHandler } from "express";
import { OAuthServerProvider } from "../provider.js";
import { Options as RateLimitOptions } from "express-rate-limit";
export type AuthorizationHandlerOptions = {
provider: OAuthServerProvider;
/**
* Rate limiting configuration for the authorization endpoint.
* Set to false to disable rate limiting for this endpoint.
*/
rateLimit?: Partial<RateLimitOptions> | false;
};
export declare function authorizationHandler({ provider, rateLimit: rateLimitConfig }: AuthorizationHandlerOptions): RequestHandler;
//# sourceMappingURL=authorize.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"authorize.d.ts","sourceRoot":"","sources":["../../../../../src/server/auth/handlers/authorize.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAGzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAa,OAAO,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAW5E,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,mBAAmB,CAAC;IAC9B;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,KAAK,CAAC;CAC/C,CAAC;AAiBF,wBAAgB,oBAAoB,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,eAAe,EAAE,EAAE,2BAA2B,GAAG,cAAc,CAmH1H"}

View File

@@ -0,0 +1,149 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.authorizationHandler = authorizationHandler;
const zod_1 = require("zod");
const express_1 = __importDefault(require("express"));
const express_rate_limit_1 = require("express-rate-limit");
const allowedMethods_js_1 = require("../middleware/allowedMethods.js");
const errors_js_1 = require("../errors.js");
// Parameters that must be validated in order to issue redirects.
const ClientAuthorizationParamsSchema = zod_1.z.object({
client_id: zod_1.z.string(),
redirect_uri: zod_1.z.string().optional().refine((value) => value === undefined || URL.canParse(value), { message: "redirect_uri must be a valid URL" }),
});
// Parameters that must be validated for a successful authorization request. Failure can be reported to the redirect URI.
const RequestAuthorizationParamsSchema = zod_1.z.object({
response_type: zod_1.z.literal("code"),
code_challenge: zod_1.z.string(),
code_challenge_method: zod_1.z.literal("S256"),
scope: zod_1.z.string().optional(),
state: zod_1.z.string().optional(),
});
function authorizationHandler({ provider, rateLimit: rateLimitConfig }) {
// Create a router to apply middleware
const router = express_1.default.Router();
router.use((0, allowedMethods_js_1.allowedMethods)(["GET", "POST"]));
router.use(express_1.default.urlencoded({ extended: false }));
// Apply rate limiting unless explicitly disabled
if (rateLimitConfig !== false) {
router.use((0, express_rate_limit_1.rateLimit)({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // 100 requests per windowMs
standardHeaders: true,
legacyHeaders: false,
message: new errors_js_1.TooManyRequestsError('You have exceeded the rate limit for authorization requests').toResponseObject(),
...rateLimitConfig
}));
}
router.all("/", async (req, res) => {
var _a;
res.setHeader('Cache-Control', 'no-store');
// In the authorization flow, errors are split into two categories:
// 1. Pre-redirect errors (direct response with 400)
// 2. Post-redirect errors (redirect with error parameters)
// Phase 1: Validate client_id and redirect_uri. Any errors here must be direct responses.
let client_id, redirect_uri, client;
try {
const result = ClientAuthorizationParamsSchema.safeParse(req.method === 'POST' ? req.body : req.query);
if (!result.success) {
throw new errors_js_1.InvalidRequestError(result.error.message);
}
client_id = result.data.client_id;
redirect_uri = result.data.redirect_uri;
client = await provider.clientsStore.getClient(client_id);
if (!client) {
throw new errors_js_1.InvalidClientError("Invalid client_id");
}
if (redirect_uri !== undefined) {
if (!client.redirect_uris.includes(redirect_uri)) {
throw new errors_js_1.InvalidRequestError("Unregistered redirect_uri");
}
}
else if (client.redirect_uris.length === 1) {
redirect_uri = client.redirect_uris[0];
}
else {
throw new errors_js_1.InvalidRequestError("redirect_uri must be specified when client has multiple registered URIs");
}
}
catch (error) {
// Pre-redirect errors - return direct response
//
// These don't need to be JSON encoded, as they'll be displayed in a user
// agent, but OTOH they all represent exceptional situations (arguably,
// "programmer error"), so presenting a nice HTML page doesn't help the
// user anyway.
if (error instanceof errors_js_1.OAuthError) {
const status = error instanceof errors_js_1.ServerError ? 500 : 400;
res.status(status).json(error.toResponseObject());
}
else {
console.error("Unexpected error looking up client:", error);
const serverError = new errors_js_1.ServerError("Internal Server Error");
res.status(500).json(serverError.toResponseObject());
}
return;
}
// Phase 2: Validate other parameters. Any errors here should go into redirect responses.
let state;
try {
// Parse and validate authorization parameters
const parseResult = RequestAuthorizationParamsSchema.safeParse(req.method === 'POST' ? req.body : req.query);
if (!parseResult.success) {
throw new errors_js_1.InvalidRequestError(parseResult.error.message);
}
const { scope, code_challenge } = parseResult.data;
state = parseResult.data.state;
// Validate scopes
let requestedScopes = [];
if (scope !== undefined) {
requestedScopes = scope.split(" ");
const allowedScopes = new Set((_a = client.scope) === null || _a === void 0 ? void 0 : _a.split(" "));
// Check each requested scope against allowed scopes
for (const scope of requestedScopes) {
if (!allowedScopes.has(scope)) {
throw new errors_js_1.InvalidScopeError(`Client was not registered with scope ${scope}`);
}
}
}
// All validation passed, proceed with authorization
await provider.authorize(client, {
state,
scopes: requestedScopes,
redirectUri: redirect_uri,
codeChallenge: code_challenge,
}, res);
}
catch (error) {
// Post-redirect errors - redirect with error parameters
if (error instanceof errors_js_1.OAuthError) {
res.redirect(302, createErrorRedirect(redirect_uri, error, state));
}
else {
console.error("Unexpected error during authorization:", error);
const serverError = new errors_js_1.ServerError("Internal Server Error");
res.redirect(302, createErrorRedirect(redirect_uri, serverError, state));
}
}
});
return router;
}
/**
* Helper function to create redirect URL with error parameters
*/
function createErrorRedirect(redirectUri, error, state) {
const errorUrl = new URL(redirectUri);
errorUrl.searchParams.set("error", error.errorCode);
errorUrl.searchParams.set("error_description", error.message);
if (error.errorUri) {
errorUrl.searchParams.set("error_uri", error.errorUri);
}
if (state) {
errorUrl.searchParams.set("state", state);
}
return errorUrl.href;
}
//# sourceMappingURL=authorize.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
import { RequestHandler } from "express";
import { OAuthMetadata } from "../../../shared/auth.js";
export declare function metadataHandler(metadata: OAuthMetadata): RequestHandler;
//# sourceMappingURL=metadata.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../../../../src/server/auth/handlers/metadata.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAIxD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,aAAa,GAAG,cAAc,CAavE"}

View File

@@ -0,0 +1,21 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.metadataHandler = metadataHandler;
const express_1 = __importDefault(require("express"));
const cors_1 = __importDefault(require("cors"));
const allowedMethods_js_1 = require("../middleware/allowedMethods.js");
function metadataHandler(metadata) {
// Nested router so we can configure middleware and restrict HTTP method
const router = express_1.default.Router();
// Configure CORS to allow any origin, to make accessible to web-based MCP clients
router.use((0, cors_1.default)());
router.use((0, allowedMethods_js_1.allowedMethods)(['GET']));
router.get("/", (req, res) => {
res.status(200).json(metadata);
});
return router;
}
//# sourceMappingURL=metadata.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../../../src/server/auth/handlers/metadata.ts"],"names":[],"mappings":";;;;;AAKA,0CAaC;AAlBD,sDAAkD;AAElD,gDAAwB;AACxB,uEAAiE;AAEjE,SAAgB,eAAe,CAAC,QAAuB;IACrD,wEAAwE;IACxE,MAAM,MAAM,GAAG,iBAAO,CAAC,MAAM,EAAE,CAAC;IAEhC,kFAAkF;IAClF,MAAM,CAAC,GAAG,CAAC,IAAA,cAAI,GAAE,CAAC,CAAC;IAEnB,MAAM,CAAC,GAAG,CAAC,IAAA,kCAAc,EAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACpC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC3B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}

View File

@@ -0,0 +1,23 @@
import { RequestHandler } from "express";
import { OAuthRegisteredClientsStore } from "../clients.js";
import { Options as RateLimitOptions } from "express-rate-limit";
export type ClientRegistrationHandlerOptions = {
/**
* A store used to save information about dynamically registered OAuth clients.
*/
clientsStore: OAuthRegisteredClientsStore;
/**
* The number of seconds after which to expire issued client secrets, or 0 to prevent expiration of client secrets (not recommended).
*
* If not set, defaults to 30 days.
*/
clientSecretExpirySeconds?: number;
/**
* Rate limiting configuration for the client registration endpoint.
* Set to false to disable rate limiting for this endpoint.
* Registration endpoints are particularly sensitive to abuse and should be rate limited.
*/
rateLimit?: Partial<RateLimitOptions> | false;
};
export declare function clientRegistrationHandler({ clientsStore, clientSecretExpirySeconds, rateLimit: rateLimitConfig }: ClientRegistrationHandlerOptions): RequestHandler;
//# sourceMappingURL=register.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../../../src/server/auth/handlers/register.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAIlD,OAAO,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAa,OAAO,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAS5E,MAAM,MAAM,gCAAgC,GAAG;IAC7C;;OAEG;IACH,YAAY,EAAE,2BAA2B,CAAC;IAE1C;;;;OAIG;IACH,yBAAyB,CAAC,EAAE,MAAM,CAAC;IAEnC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,KAAK,CAAC;CAC/C,CAAC;AAIF,wBAAgB,yBAAyB,CAAC,EACxC,YAAY,EACZ,yBAAgE,EAChE,SAAS,EAAE,eAAe,EAC3B,EAAE,gCAAgC,GAAG,cAAc,CAyEnD"}

View File

@@ -0,0 +1,79 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.clientRegistrationHandler = clientRegistrationHandler;
const express_1 = __importDefault(require("express"));
const auth_js_1 = require("../../../shared/auth.js");
const node_crypto_1 = __importDefault(require("node:crypto"));
const cors_1 = __importDefault(require("cors"));
const express_rate_limit_1 = require("express-rate-limit");
const allowedMethods_js_1 = require("../middleware/allowedMethods.js");
const errors_js_1 = require("../errors.js");
const DEFAULT_CLIENT_SECRET_EXPIRY_SECONDS = 30 * 24 * 60 * 60; // 30 days
function clientRegistrationHandler({ clientsStore, clientSecretExpirySeconds = DEFAULT_CLIENT_SECRET_EXPIRY_SECONDS, rateLimit: rateLimitConfig }) {
if (!clientsStore.registerClient) {
throw new Error("Client registration store does not support registering clients");
}
// Nested router so we can configure middleware and restrict HTTP method
const router = express_1.default.Router();
// Configure CORS to allow any origin, to make accessible to web-based MCP clients
router.use((0, cors_1.default)());
router.use((0, allowedMethods_js_1.allowedMethods)(["POST"]));
router.use(express_1.default.json());
// Apply rate limiting unless explicitly disabled - stricter limits for registration
if (rateLimitConfig !== false) {
router.use((0, express_rate_limit_1.rateLimit)({
windowMs: 60 * 60 * 1000, // 1 hour
max: 20, // 20 requests per hour - stricter as registration is sensitive
standardHeaders: true,
legacyHeaders: false,
message: new errors_js_1.TooManyRequestsError('You have exceeded the rate limit for client registration requests').toResponseObject(),
...rateLimitConfig
}));
}
router.post("/", async (req, res) => {
res.setHeader('Cache-Control', 'no-store');
try {
const parseResult = auth_js_1.OAuthClientMetadataSchema.safeParse(req.body);
if (!parseResult.success) {
throw new errors_js_1.InvalidClientMetadataError(parseResult.error.message);
}
const clientMetadata = parseResult.data;
const isPublicClient = clientMetadata.token_endpoint_auth_method === 'none';
// Generate client credentials
const clientId = node_crypto_1.default.randomUUID();
const clientSecret = isPublicClient
? undefined
: node_crypto_1.default.randomBytes(32).toString('hex');
const clientIdIssuedAt = Math.floor(Date.now() / 1000);
// Calculate client secret expiry time
const clientsDoExpire = clientSecretExpirySeconds > 0;
const secretExpiryTime = clientsDoExpire ? clientIdIssuedAt + clientSecretExpirySeconds : 0;
const clientSecretExpiresAt = isPublicClient ? undefined : secretExpiryTime;
let clientInfo = {
...clientMetadata,
client_id: clientId,
client_secret: clientSecret,
client_id_issued_at: clientIdIssuedAt,
client_secret_expires_at: clientSecretExpiresAt,
};
clientInfo = await clientsStore.registerClient(clientInfo);
res.status(201).json(clientInfo);
}
catch (error) {
if (error instanceof errors_js_1.OAuthError) {
const status = error instanceof errors_js_1.ServerError ? 500 : 400;
res.status(status).json(error.toResponseObject());
}
else {
console.error("Unexpected error registering client:", error);
const serverError = new errors_js_1.ServerError("Internal Server Error");
res.status(500).json(serverError.toResponseObject());
}
}
});
return router;
}
//# sourceMappingURL=register.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../../../../src/server/auth/handlers/register.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,13 @@
import { OAuthServerProvider } from "../provider.js";
import { RequestHandler } from "express";
import { Options as RateLimitOptions } from "express-rate-limit";
export type RevocationHandlerOptions = {
provider: OAuthServerProvider;
/**
* Rate limiting configuration for the token revocation endpoint.
* Set to false to disable rate limiting for this endpoint.
*/
rateLimit?: Partial<RateLimitOptions> | false;
};
export declare function revocationHandler({ provider, rateLimit: rateLimitConfig }: RevocationHandlerOptions): RequestHandler;
//# sourceMappingURL=revoke.d.ts.map

Some files were not shown because too many files have changed in this diff Show More