@smithery/sdk 1.1.2 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -74
- package/dist/client/transport.d.ts +9 -0
- package/dist/client/transport.js +12 -0
- package/dist/config.d.ts +9 -2
- package/dist/config.js +10 -2
- package/dist/server/stateful.d.ts +18 -0
- package/dist/server/stateful.js +93 -0
- package/dist/server/stateless.d.ts +17 -0
- package/dist/server/stateless.js +89 -0
- package/package.json +6 -7
- package/dist/index.d.ts +0 -6
- package/dist/index.js +0 -6
- package/dist/multi-client.d.ts +0 -185
- package/dist/multi-client.js +0 -84
- package/dist/transport.d.ts +0 -9
- package/dist/transport.js +0 -12
- package/dist/types.d.ts +0 -30
- package/dist/types.js +0 -7
package/README.md
CHANGED
|
@@ -1,94 +1,53 @@
|
|
|
1
1
|
# Smithery Typescript SDK
|
|
2
2
|
|
|
3
|
+
The SDK provides files for you to easily setup Smithery-compatible MCP servers and clients.
|
|
4
|
+
|
|
3
5
|
## Installation
|
|
4
6
|
|
|
5
7
|
```bash
|
|
6
|
-
npm install @smithery/sdk
|
|
8
|
+
npm install @smithery/sdk @modelcontextprotocol/sdk
|
|
7
9
|
```
|
|
8
10
|
|
|
9
11
|
## Usage
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
npm install @smithery/sdk @modelcontextprotocol/sdk
|
|
15
|
-
```
|
|
13
|
+
### Spawning a Server
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
Here's a minimal example of how to use the SDK to spawn an MCP server.
|
|
18
16
|
|
|
19
17
|
```typescript
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
// Initialize a multi-client connection
|
|
34
|
-
const client = new MultiClient()
|
|
35
|
-
await client.connectAll({
|
|
36
|
-
exa: exaTransport,
|
|
37
|
-
// You can add more connections here...
|
|
38
|
-
})
|
|
18
|
+
import { createStatelessServer } from '@smithery/sdk/server/stateless.js'
|
|
19
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"
|
|
20
|
+
|
|
21
|
+
// Create your MCP server function
|
|
22
|
+
function createMcpServer({ sessionId, config }) {
|
|
23
|
+
// Create and return a server instance
|
|
24
|
+
// https://github.com/modelcontextprotocol/typescript-sdk?tab=readme-ov-file#core-concepts
|
|
25
|
+
const server = new McpServer({
|
|
26
|
+
name: "My App",
|
|
27
|
+
version: "1.0.0"
|
|
28
|
+
})
|
|
39
29
|
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
config: {
|
|
45
|
-
apiKey: process.env.EXA_API_KEY,
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
})
|
|
49
|
-
```
|
|
30
|
+
// ...
|
|
31
|
+
|
|
32
|
+
return server
|
|
33
|
+
}
|
|
50
34
|
|
|
51
|
-
|
|
35
|
+
// Create the stateless server using your MCP server function.
|
|
36
|
+
const { app } = createStatelessServer(createMcpServer)
|
|
52
37
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const openaiResponse = await openai.chat.completions.create({
|
|
58
|
-
model: "gpt-4o-mini",
|
|
59
|
-
messages: [{ role: "user", content: "What AI events are happening in Singapore?" }],
|
|
60
|
-
tools: await openaiAdapter.listTools(),
|
|
38
|
+
// Start the server
|
|
39
|
+
const PORT = process.env.PORT || 8081
|
|
40
|
+
app.listen(PORT, () => {
|
|
41
|
+
console.log(`MCP server running on port ${PORT}`)
|
|
61
42
|
})
|
|
62
|
-
const openaiToolMessages = await openaiAdapter.callTool(openaiResponse)
|
|
63
43
|
```
|
|
64
44
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
{
|
|
70
|
-
role: "user",
|
|
71
|
-
content: "What are some AI events happening in Singapore and how many days until the next one?",
|
|
72
|
-
},
|
|
73
|
-
]
|
|
74
|
-
const adapter = new OpenAIChatAdapter(client)
|
|
75
|
-
let isDone = false
|
|
45
|
+
This example:
|
|
46
|
+
1. Creates a stateless server that handles MCP requests
|
|
47
|
+
2. Defines a function to create MCP server instances for each session
|
|
48
|
+
3. Starts the Express server on the specified port. You must listen on the PORT env var if provided for the deployment to work on Smithery.
|
|
76
49
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
model: "gpt-4o-mini",
|
|
80
|
-
messages,
|
|
81
|
-
tools: await adapter.listTools(),
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
// Handle tool calls
|
|
85
|
-
const toolMessages = await adapter.callTool(response)
|
|
86
|
-
|
|
87
|
-
// Append new messages
|
|
88
|
-
messages.push(response.choices[0].message)
|
|
89
|
-
messages.push(...toolMessages)
|
|
90
|
-
isDone = toolMessages.length === 0
|
|
91
|
-
}
|
|
92
|
-
```
|
|
50
|
+
#### Stateful Server
|
|
51
|
+
Most API integrations are stateless.
|
|
93
52
|
|
|
94
|
-
|
|
53
|
+
However, if your MCP server needs to persist state between calls (i.e., remembering previous interactions in a single chat conversation), you can use the `createStatefulServer` function instead.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a transport to connect to the Smithery server
|
|
4
|
+
* @param baseUrl The URL of the Smithery server (without trailing slash or protocol)
|
|
5
|
+
* @param config Config to pass to the server
|
|
6
|
+
* @param apiKey Optional API key for authentication
|
|
7
|
+
* @returns Transport
|
|
8
|
+
*/
|
|
9
|
+
export declare function createTransport(baseUrl: string, config?: object, apiKey?: string): StreamableHTTPClientTransport;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
2
|
+
import { createSmitheryUrl } from "../config.js";
|
|
3
|
+
/**
|
|
4
|
+
* Creates a transport to connect to the Smithery server
|
|
5
|
+
* @param baseUrl The URL of the Smithery server (without trailing slash or protocol)
|
|
6
|
+
* @param config Config to pass to the server
|
|
7
|
+
* @param apiKey Optional API key for authentication
|
|
8
|
+
* @returns Transport
|
|
9
|
+
*/
|
|
10
|
+
export function createTransport(baseUrl, config, apiKey) {
|
|
11
|
+
return new StreamableHTTPClientTransport(createSmitheryUrl(`${baseUrl}`, config, apiKey));
|
|
12
|
+
}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
import type express from "express";
|
|
1
2
|
/**
|
|
2
|
-
* Creates a URL to connect to the Smithery MCP server
|
|
3
|
+
* Creates a URL to connect to the Smithery MCP server.
|
|
3
4
|
* @param baseUrl The base URL of the Smithery server
|
|
4
5
|
* @param config Optional configuration object
|
|
5
6
|
* @param apiKey API key for authentication. Required if using Smithery.
|
|
6
|
-
* @returns A URL object with properly encoded parameters
|
|
7
|
+
* @returns A URL object with properly encoded parameters. Example: https://server.smithery.ai/{namespace}/mcp?config=BASE64_ENCODED_CONFIG&api_key=API_KEY
|
|
7
8
|
*/
|
|
8
9
|
export declare function createSmitheryUrl(baseUrl: string, config?: object, apiKey?: string): URL;
|
|
10
|
+
/**
|
|
11
|
+
* Parses the config from an express request by checking the query parameter "config".
|
|
12
|
+
* @param req The express request
|
|
13
|
+
* @returns The config
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseExpressRequestConfig(req: express.Request): Record<string, unknown>;
|
package/dist/config.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Creates a URL to connect to the Smithery MCP server
|
|
2
|
+
* Creates a URL to connect to the Smithery MCP server.
|
|
3
3
|
* @param baseUrl The base URL of the Smithery server
|
|
4
4
|
* @param config Optional configuration object
|
|
5
5
|
* @param apiKey API key for authentication. Required if using Smithery.
|
|
6
|
-
* @returns A URL object with properly encoded parameters
|
|
6
|
+
* @returns A URL object with properly encoded parameters. Example: https://server.smithery.ai/{namespace}/mcp?config=BASE64_ENCODED_CONFIG&api_key=API_KEY
|
|
7
7
|
*/
|
|
8
8
|
export function createSmitheryUrl(baseUrl, config, apiKey) {
|
|
9
9
|
const url = new URL(`${baseUrl}/mcp`);
|
|
@@ -18,3 +18,11 @@ export function createSmitheryUrl(baseUrl, config, apiKey) {
|
|
|
18
18
|
}
|
|
19
19
|
return url;
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Parses the config from an express request by checking the query parameter "config".
|
|
23
|
+
* @param req The express request
|
|
24
|
+
* @returns The config
|
|
25
|
+
*/
|
|
26
|
+
export function parseExpressRequestConfig(req) {
|
|
27
|
+
return JSON.parse(Buffer.from(req.query.config, "base64").toString());
|
|
28
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Arguments when we create a new instance of your server
|
|
4
|
+
*/
|
|
5
|
+
export interface CreateServerArg {
|
|
6
|
+
sessionId: string;
|
|
7
|
+
config: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
export type CreateServerFn = (arg: CreateServerArg) => Server;
|
|
10
|
+
/**
|
|
11
|
+
* Creates a stateful server for handling MCP requests.
|
|
12
|
+
* For every new session, we invoke createMcpServer to create a new instance of the server.
|
|
13
|
+
* @param createMcpServer Function to create an MCP server
|
|
14
|
+
* @returns Express app
|
|
15
|
+
*/
|
|
16
|
+
export declare function createStatefulServer(createMcpServer: CreateServerFn): {
|
|
17
|
+
app: import("express-serve-static-core").Express;
|
|
18
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
2
|
+
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
+
import express from "express";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { parseExpressRequestConfig } from "../config.js";
|
|
6
|
+
/**
|
|
7
|
+
* Creates a stateful server for handling MCP requests.
|
|
8
|
+
* For every new session, we invoke createMcpServer to create a new instance of the server.
|
|
9
|
+
* @param createMcpServer Function to create an MCP server
|
|
10
|
+
* @returns Express app
|
|
11
|
+
*/
|
|
12
|
+
export function createStatefulServer(createMcpServer) {
|
|
13
|
+
const app = express();
|
|
14
|
+
app.use(express.json());
|
|
15
|
+
// Map to store transports by session ID
|
|
16
|
+
const transports = {};
|
|
17
|
+
// Handle POST requests for client-to-server communication
|
|
18
|
+
app.post("/mcp", async (req, res) => {
|
|
19
|
+
// Check for existing session ID
|
|
20
|
+
const sessionId = req.headers["mcp-session-id"];
|
|
21
|
+
let transport;
|
|
22
|
+
if (sessionId && transports[sessionId]) {
|
|
23
|
+
// Reuse existing transport
|
|
24
|
+
transport = transports[sessionId];
|
|
25
|
+
}
|
|
26
|
+
else if (!sessionId && isInitializeRequest(req.body)) {
|
|
27
|
+
// New initialization request
|
|
28
|
+
const newSessionId = randomUUID();
|
|
29
|
+
transport = new StreamableHTTPServerTransport({
|
|
30
|
+
sessionIdGenerator: () => newSessionId,
|
|
31
|
+
onsessioninitialized: (sessionId) => {
|
|
32
|
+
// Store the transport by session ID
|
|
33
|
+
transports[sessionId] = transport;
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
// Clean up transport when closed
|
|
37
|
+
transport.onclose = () => {
|
|
38
|
+
if (transport.sessionId) {
|
|
39
|
+
delete transports[transport.sessionId];
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
try {
|
|
43
|
+
const config = parseExpressRequestConfig(req);
|
|
44
|
+
const server = createMcpServer({
|
|
45
|
+
sessionId: newSessionId,
|
|
46
|
+
config,
|
|
47
|
+
});
|
|
48
|
+
// Connect to the MCP server
|
|
49
|
+
await server.connect(transport);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
res.status(400).json({
|
|
53
|
+
jsonrpc: "2.0",
|
|
54
|
+
error: {
|
|
55
|
+
code: -32000,
|
|
56
|
+
message: "Bad Request: Invalid configuration",
|
|
57
|
+
},
|
|
58
|
+
id: null,
|
|
59
|
+
});
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// Invalid request
|
|
65
|
+
res.status(400).json({
|
|
66
|
+
jsonrpc: "2.0",
|
|
67
|
+
error: {
|
|
68
|
+
code: -32000,
|
|
69
|
+
message: "Bad Request: No valid session ID provided",
|
|
70
|
+
},
|
|
71
|
+
id: null,
|
|
72
|
+
});
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
// Handle the request
|
|
76
|
+
await transport.handleRequest(req, res, req.body);
|
|
77
|
+
});
|
|
78
|
+
// Reusable handler for GET and DELETE requests
|
|
79
|
+
const handleSessionRequest = async (req, res) => {
|
|
80
|
+
const sessionId = req.headers["mcp-session-id"];
|
|
81
|
+
if (!sessionId || !transports[sessionId]) {
|
|
82
|
+
res.status(400).send("Invalid or missing session ID");
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const transport = transports[sessionId];
|
|
86
|
+
await transport.handleRequest(req, res);
|
|
87
|
+
};
|
|
88
|
+
// Handle GET requests for server-to-client notifications via SSE
|
|
89
|
+
app.get("/mcp", handleSessionRequest);
|
|
90
|
+
// Handle DELETE requests for session termination
|
|
91
|
+
app.delete("/mcp", handleSessionRequest);
|
|
92
|
+
return { app };
|
|
93
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Arguments when we create a new instance of your server
|
|
4
|
+
*/
|
|
5
|
+
export interface CreateServerArg {
|
|
6
|
+
config: Record<string, unknown>;
|
|
7
|
+
}
|
|
8
|
+
export type CreateServerFn = (arg: CreateServerArg) => Server;
|
|
9
|
+
/**
|
|
10
|
+
* Creates a stateless server for handling MCP requests
|
|
11
|
+
* In stateless mode, each request creates a new server and transport instance
|
|
12
|
+
* @param createMcpServer Function to create an MCP server
|
|
13
|
+
* @returns Express app
|
|
14
|
+
*/
|
|
15
|
+
export declare function createStatelessServer(createMcpServer: CreateServerFn): {
|
|
16
|
+
app: import("express-serve-static-core").Express;
|
|
17
|
+
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
2
|
+
import express from "express";
|
|
3
|
+
import { parseExpressRequestConfig } from "../config.js";
|
|
4
|
+
/**
|
|
5
|
+
* Creates a stateless server for handling MCP requests
|
|
6
|
+
* In stateless mode, each request creates a new server and transport instance
|
|
7
|
+
* @param createMcpServer Function to create an MCP server
|
|
8
|
+
* @returns Express app
|
|
9
|
+
*/
|
|
10
|
+
export function createStatelessServer(createMcpServer) {
|
|
11
|
+
const app = express();
|
|
12
|
+
app.use(express.json());
|
|
13
|
+
app.post("/mcp", async (req, res) => {
|
|
14
|
+
// In stateless mode, create a new instance of transport and server for each request
|
|
15
|
+
// to ensure complete isolation. A single instance would cause request ID collisions
|
|
16
|
+
// when multiple clients connect concurrently.
|
|
17
|
+
try {
|
|
18
|
+
// Parse base64 encoded config from URL query parameter if present
|
|
19
|
+
let config = {};
|
|
20
|
+
if (req.query.config) {
|
|
21
|
+
try {
|
|
22
|
+
config = parseExpressRequestConfig(req);
|
|
23
|
+
}
|
|
24
|
+
catch (configError) {
|
|
25
|
+
res.status(400).json({
|
|
26
|
+
jsonrpc: "2.0",
|
|
27
|
+
error: {
|
|
28
|
+
code: -32000,
|
|
29
|
+
message: "Bad Request: Invalid configuration",
|
|
30
|
+
},
|
|
31
|
+
id: null,
|
|
32
|
+
});
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// Create a new server instance with config
|
|
37
|
+
const server = createMcpServer({ config });
|
|
38
|
+
// Create a new transport instance
|
|
39
|
+
const transport = new StreamableHTTPServerTransport({
|
|
40
|
+
sessionIdGenerator: undefined,
|
|
41
|
+
});
|
|
42
|
+
// Clean up resources when the request ends
|
|
43
|
+
res.on("close", () => {
|
|
44
|
+
transport.close();
|
|
45
|
+
server.close();
|
|
46
|
+
});
|
|
47
|
+
// Connect the server to the transport
|
|
48
|
+
await server.connect(transport);
|
|
49
|
+
// Handle the incoming request
|
|
50
|
+
await transport.handleRequest(req, res, req.body);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
console.error("Error handling MCP request:", error);
|
|
54
|
+
if (!res.headersSent) {
|
|
55
|
+
res.status(500).json({
|
|
56
|
+
jsonrpc: "2.0",
|
|
57
|
+
error: {
|
|
58
|
+
code: -32603,
|
|
59
|
+
message: "Internal server error",
|
|
60
|
+
},
|
|
61
|
+
id: null,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
app.get("/mcp", async (req, res) => {
|
|
67
|
+
console.log("Received GET MCP request");
|
|
68
|
+
res.writeHead(405).end(JSON.stringify({
|
|
69
|
+
jsonrpc: "2.0",
|
|
70
|
+
error: {
|
|
71
|
+
code: -32000,
|
|
72
|
+
message: "Method not allowed in stateless mode",
|
|
73
|
+
},
|
|
74
|
+
id: null,
|
|
75
|
+
}));
|
|
76
|
+
});
|
|
77
|
+
app.delete("/mcp", async (req, res) => {
|
|
78
|
+
console.log("Received DELETE MCP request");
|
|
79
|
+
res.writeHead(405).end(JSON.stringify({
|
|
80
|
+
jsonrpc: "2.0",
|
|
81
|
+
error: {
|
|
82
|
+
code: -32000,
|
|
83
|
+
message: "Method not allowed in stateless mode",
|
|
84
|
+
},
|
|
85
|
+
id: null,
|
|
86
|
+
}));
|
|
87
|
+
});
|
|
88
|
+
return { app };
|
|
89
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@smithery/sdk",
|
|
3
|
-
"version": "1.1
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.2.1",
|
|
4
|
+
"description": "SDK to develop with Smithery",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -19,17 +19,16 @@
|
|
|
19
19
|
"check": "npx @biomejs/biome check --write --unsafe",
|
|
20
20
|
"link": "npm link -ws --include-workspace-root"
|
|
21
21
|
},
|
|
22
|
-
"license": "
|
|
22
|
+
"license": "MIT",
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@anthropic-ai/sdk": "^0.32.1",
|
|
25
|
-
"@
|
|
26
|
-
"
|
|
25
|
+
"@modelcontextprotocol/sdk": "^1.10.2",
|
|
26
|
+
"express": "^5.1.0",
|
|
27
27
|
"openai": "^4.0.0",
|
|
28
28
|
"uuid": "^11.0.3"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@
|
|
32
|
-
"@smithery/mcp-exa": "*",
|
|
31
|
+
"@types/express": "^5.0.1",
|
|
33
32
|
"@types/node": "^20.0.0",
|
|
34
33
|
"@types/uuid": "^9.0.7",
|
|
35
34
|
"dotenv": "^16.4.7",
|
package/dist/index.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { createSmitheryUrl } from "./config.js";
|
|
2
|
-
export { wrapErrorAdapter } from "./integrations/error-adapter.js";
|
|
3
|
-
export { AnthropicChatAdapter } from "./integrations/llm/anthropic.js";
|
|
4
|
-
export { OpenAIChatAdapter } from "./integrations/llm/openai.js";
|
|
5
|
-
export { MultiClient } from "./multi-client.js";
|
|
6
|
-
export { createTransport } from "./transport.js";
|
package/dist/index.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { createSmitheryUrl } from "./config.js";
|
|
2
|
-
export { wrapErrorAdapter } from "./integrations/error-adapter.js";
|
|
3
|
-
export { AnthropicChatAdapter } from "./integrations/llm/anthropic.js";
|
|
4
|
-
export { OpenAIChatAdapter } from "./integrations/llm/openai.js";
|
|
5
|
-
export { MultiClient } from "./multi-client.js";
|
|
6
|
-
export { createTransport } from "./transport.js";
|
package/dist/multi-client.d.ts
DELETED
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
-
import type { RequestOptions } from "@modelcontextprotocol/sdk/shared/protocol.js";
|
|
4
|
-
import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
5
|
-
import { type CallToolRequest, CallToolResultSchema, type CompatibilityCallToolResultSchema, type ListToolsRequest, type Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
-
interface ClientInfo {
|
|
7
|
-
name: string;
|
|
8
|
-
version: string;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* A client that connects to multiple MCPs and provides a unified interface for
|
|
12
|
-
* accessing their tools, treating them as a single MCP.
|
|
13
|
-
*/
|
|
14
|
-
export declare class MultiClient implements Pick<Client, "callTool" | "listTools" | "close"> {
|
|
15
|
-
private client_capabilities;
|
|
16
|
-
clients: Record<string, Client>;
|
|
17
|
-
client_info: ClientInfo;
|
|
18
|
-
constructor(client_info?: ClientInfo, client_capabilities?: {
|
|
19
|
-
capabilities: Record<string, unknown>;
|
|
20
|
-
});
|
|
21
|
-
/**
|
|
22
|
-
* Connects to a collection of transport or servers.
|
|
23
|
-
*/
|
|
24
|
-
connectAll(transports: Record<string, Transport | Server>): Promise<void>;
|
|
25
|
-
/**
|
|
26
|
-
* Maps a tool name to a namespace-specific name to avoid conflicts.
|
|
27
|
-
*/
|
|
28
|
-
toolNameMapper: (namespace: string, tool: Tool) => string;
|
|
29
|
-
toolNameUnmapper: (fullToolName: string) => {
|
|
30
|
-
namespace: string;
|
|
31
|
-
toolName: string;
|
|
32
|
-
};
|
|
33
|
-
/**
|
|
34
|
-
* List all tools available from all MCPs, ensuring each tool is namespaced.
|
|
35
|
-
* @param params - Optional parameters for the request.
|
|
36
|
-
* @param options - Optional options for the request.
|
|
37
|
-
* @returns A promise that resolves to an array of tools.
|
|
38
|
-
*/
|
|
39
|
-
listTools(params?: ListToolsRequest["params"], options?: RequestOptions): Promise<{
|
|
40
|
-
tools: {
|
|
41
|
-
[x: string]: unknown;
|
|
42
|
-
name: string;
|
|
43
|
-
inputSchema: {
|
|
44
|
-
[x: string]: unknown;
|
|
45
|
-
type: "object";
|
|
46
|
-
properties?: {
|
|
47
|
-
[x: string]: unknown;
|
|
48
|
-
} | undefined;
|
|
49
|
-
};
|
|
50
|
-
description?: string | undefined;
|
|
51
|
-
}[];
|
|
52
|
-
}>;
|
|
53
|
-
callTool(params: CallToolRequest["params"], resultSchema?: typeof CallToolResultSchema | typeof CompatibilityCallToolResultSchema, options?: RequestOptions): Promise<import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
|
|
54
|
-
_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">>>;
|
|
55
|
-
}, {
|
|
56
|
-
content: import("zod").ZodArray<import("zod").ZodUnion<[import("zod").ZodObject<{
|
|
57
|
-
type: import("zod").ZodLiteral<"text">;
|
|
58
|
-
text: import("zod").ZodString;
|
|
59
|
-
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
|
|
60
|
-
type: import("zod").ZodLiteral<"text">;
|
|
61
|
-
text: import("zod").ZodString;
|
|
62
|
-
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
|
|
63
|
-
type: import("zod").ZodLiteral<"text">;
|
|
64
|
-
text: import("zod").ZodString;
|
|
65
|
-
}, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<{
|
|
66
|
-
type: import("zod").ZodLiteral<"image">;
|
|
67
|
-
data: import("zod").ZodString;
|
|
68
|
-
mimeType: import("zod").ZodString;
|
|
69
|
-
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
|
|
70
|
-
type: import("zod").ZodLiteral<"image">;
|
|
71
|
-
data: import("zod").ZodString;
|
|
72
|
-
mimeType: import("zod").ZodString;
|
|
73
|
-
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
|
|
74
|
-
type: import("zod").ZodLiteral<"image">;
|
|
75
|
-
data: import("zod").ZodString;
|
|
76
|
-
mimeType: import("zod").ZodString;
|
|
77
|
-
}, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<{
|
|
78
|
-
type: import("zod").ZodLiteral<"resource">;
|
|
79
|
-
resource: import("zod").ZodUnion<[import("zod").ZodObject<import("zod").objectUtil.extendShape<{
|
|
80
|
-
uri: import("zod").ZodString;
|
|
81
|
-
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
82
|
-
}, {
|
|
83
|
-
text: import("zod").ZodString;
|
|
84
|
-
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
|
|
85
|
-
uri: import("zod").ZodString;
|
|
86
|
-
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
87
|
-
}, {
|
|
88
|
-
text: import("zod").ZodString;
|
|
89
|
-
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
|
|
90
|
-
uri: import("zod").ZodString;
|
|
91
|
-
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
92
|
-
}, {
|
|
93
|
-
text: import("zod").ZodString;
|
|
94
|
-
}>, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<import("zod").objectUtil.extendShape<{
|
|
95
|
-
uri: import("zod").ZodString;
|
|
96
|
-
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
97
|
-
}, {
|
|
98
|
-
blob: import("zod").ZodString;
|
|
99
|
-
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
|
|
100
|
-
uri: import("zod").ZodString;
|
|
101
|
-
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
102
|
-
}, {
|
|
103
|
-
blob: import("zod").ZodString;
|
|
104
|
-
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
|
|
105
|
-
uri: import("zod").ZodString;
|
|
106
|
-
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
107
|
-
}, {
|
|
108
|
-
blob: import("zod").ZodString;
|
|
109
|
-
}>, import("zod").ZodTypeAny, "passthrough">>]>;
|
|
110
|
-
}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
|
|
111
|
-
type: import("zod").ZodLiteral<"resource">;
|
|
112
|
-
resource: import("zod").ZodUnion<[import("zod").ZodObject<import("zod").objectUtil.extendShape<{
|
|
113
|
-
uri: import("zod").ZodString;
|
|
114
|
-
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
115
|
-
}, {
|
|
116
|
-
text: import("zod").ZodString;
|
|
117
|
-
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
|
|
118
|
-
uri: import("zod").ZodString;
|
|
119
|
-
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
120
|
-
}, {
|
|
121
|
-
text: import("zod").ZodString;
|
|
122
|
-
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
|
|
123
|
-
uri: import("zod").ZodString;
|
|
124
|
-
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
125
|
-
}, {
|
|
126
|
-
text: import("zod").ZodString;
|
|
127
|
-
}>, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<import("zod").objectUtil.extendShape<{
|
|
128
|
-
uri: import("zod").ZodString;
|
|
129
|
-
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
130
|
-
}, {
|
|
131
|
-
blob: import("zod").ZodString;
|
|
132
|
-
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
|
|
133
|
-
uri: import("zod").ZodString;
|
|
134
|
-
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
135
|
-
}, {
|
|
136
|
-
blob: import("zod").ZodString;
|
|
137
|
-
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
|
|
138
|
-
uri: import("zod").ZodString;
|
|
139
|
-
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
140
|
-
}, {
|
|
141
|
-
blob: import("zod").ZodString;
|
|
142
|
-
}>, import("zod").ZodTypeAny, "passthrough">>]>;
|
|
143
|
-
}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
|
|
144
|
-
type: import("zod").ZodLiteral<"resource">;
|
|
145
|
-
resource: import("zod").ZodUnion<[import("zod").ZodObject<import("zod").objectUtil.extendShape<{
|
|
146
|
-
uri: import("zod").ZodString;
|
|
147
|
-
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
148
|
-
}, {
|
|
149
|
-
text: import("zod").ZodString;
|
|
150
|
-
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
|
|
151
|
-
uri: import("zod").ZodString;
|
|
152
|
-
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
153
|
-
}, {
|
|
154
|
-
text: import("zod").ZodString;
|
|
155
|
-
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
|
|
156
|
-
uri: import("zod").ZodString;
|
|
157
|
-
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
158
|
-
}, {
|
|
159
|
-
text: import("zod").ZodString;
|
|
160
|
-
}>, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodObject<import("zod").objectUtil.extendShape<{
|
|
161
|
-
uri: import("zod").ZodString;
|
|
162
|
-
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
163
|
-
}, {
|
|
164
|
-
blob: import("zod").ZodString;
|
|
165
|
-
}>, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
|
|
166
|
-
uri: import("zod").ZodString;
|
|
167
|
-
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
168
|
-
}, {
|
|
169
|
-
blob: import("zod").ZodString;
|
|
170
|
-
}>, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<import("zod").objectUtil.extendShape<{
|
|
171
|
-
uri: import("zod").ZodString;
|
|
172
|
-
mimeType: import("zod").ZodOptional<import("zod").ZodString>;
|
|
173
|
-
}, {
|
|
174
|
-
blob: import("zod").ZodString;
|
|
175
|
-
}>, import("zod").ZodTypeAny, "passthrough">>]>;
|
|
176
|
-
}, import("zod").ZodTypeAny, "passthrough">>]>, "many">;
|
|
177
|
-
isError: import("zod").ZodOptional<import("zod").ZodDefault<import("zod").ZodBoolean>>;
|
|
178
|
-
}>, import("zod").ZodTypeAny, "passthrough"> | import("zod").objectOutputType<import("zod").objectUtil.extendShape<{
|
|
179
|
-
_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">>>;
|
|
180
|
-
}, {
|
|
181
|
-
toolResult: import("zod").ZodUnknown;
|
|
182
|
-
}>, import("zod").ZodTypeAny, "passthrough">>;
|
|
183
|
-
close(): Promise<void>;
|
|
184
|
-
}
|
|
185
|
-
export {};
|
package/dist/multi-client.js
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
-
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
|
|
3
|
-
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
4
|
-
import { CallToolResultSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
-
/**
|
|
6
|
-
* A client that connects to multiple MCPs and provides a unified interface for
|
|
7
|
-
* accessing their tools, treating them as a single MCP.
|
|
8
|
-
*/
|
|
9
|
-
export class MultiClient {
|
|
10
|
-
constructor(client_info, client_capabilities = {
|
|
11
|
-
capabilities: {},
|
|
12
|
-
}) {
|
|
13
|
-
this.client_capabilities = client_capabilities;
|
|
14
|
-
this.clients = {};
|
|
15
|
-
/**
|
|
16
|
-
* Maps a tool name to a namespace-specific name to avoid conflicts.
|
|
17
|
-
*/
|
|
18
|
-
this.toolNameMapper = (namespace, tool) => {
|
|
19
|
-
return `${namespace}_${tool.name}`;
|
|
20
|
-
};
|
|
21
|
-
this.toolNameUnmapper = (fullToolName) => {
|
|
22
|
-
const namespace = fullToolName.split("_")[0];
|
|
23
|
-
const toolName = fullToolName.split("_").slice(1).join("_");
|
|
24
|
-
return { namespace, toolName };
|
|
25
|
-
};
|
|
26
|
-
this.client_info = client_info || {
|
|
27
|
-
name: "MultiClient",
|
|
28
|
-
version: "1.0.0",
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Connects to a collection of transport or servers.
|
|
33
|
-
*/
|
|
34
|
-
async connectAll(transports) {
|
|
35
|
-
await Promise.all(Object.entries(transports).map(async ([namespace, transport]) => {
|
|
36
|
-
const client = new Client({
|
|
37
|
-
name: this.client_info.name,
|
|
38
|
-
version: "1.0.0",
|
|
39
|
-
}, this.client_capabilities);
|
|
40
|
-
if (transport instanceof Server) {
|
|
41
|
-
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
|
42
|
-
await transport.connect(serverTransport);
|
|
43
|
-
await client.connect(clientTransport);
|
|
44
|
-
}
|
|
45
|
-
else {
|
|
46
|
-
await client.connect(transport);
|
|
47
|
-
}
|
|
48
|
-
this.clients[namespace] = client;
|
|
49
|
-
}));
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* List all tools available from all MCPs, ensuring each tool is namespaced.
|
|
53
|
-
* @param params - Optional parameters for the request.
|
|
54
|
-
* @param options - Optional options for the request.
|
|
55
|
-
* @returns A promise that resolves to an array of tools.
|
|
56
|
-
*/
|
|
57
|
-
async listTools(params, options) {
|
|
58
|
-
const tools = (await Promise.all(Object.entries(this.clients).map(async ([namespace, mcp]) => {
|
|
59
|
-
const capabilities = mcp.getServerCapabilities();
|
|
60
|
-
if (!capabilities?.tools)
|
|
61
|
-
return [];
|
|
62
|
-
const response = await mcp.listTools(params, options);
|
|
63
|
-
return response.tools.map((tool) => ({
|
|
64
|
-
...tool,
|
|
65
|
-
name: this.toolNameMapper(namespace, tool),
|
|
66
|
-
}));
|
|
67
|
-
}))).flat();
|
|
68
|
-
return { tools };
|
|
69
|
-
}
|
|
70
|
-
async callTool(params, resultSchema = CallToolResultSchema, options) {
|
|
71
|
-
const { namespace, toolName } = this.toolNameUnmapper(params.name);
|
|
72
|
-
const mcp = this.clients[namespace];
|
|
73
|
-
if (!mcp) {
|
|
74
|
-
throw new Error(`MCP tool ${namespace} not found`);
|
|
75
|
-
}
|
|
76
|
-
return mcp.callTool({
|
|
77
|
-
name: toolName,
|
|
78
|
-
arguments: params.arguments,
|
|
79
|
-
}, resultSchema, options);
|
|
80
|
-
}
|
|
81
|
-
async close() {
|
|
82
|
-
await Promise.all(Object.values(this.clients).map((mcp) => mcp.close()));
|
|
83
|
-
}
|
|
84
|
-
}
|
package/dist/transport.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { WebSocketClientTransport } from "@modelcontextprotocol/sdk/client/websocket.js";
|
|
2
|
-
/**
|
|
3
|
-
* Creates a transport to connect to the Smithery server
|
|
4
|
-
* @param smitheryServerUrl The URL of the Smithery server (without trailing slash or protocol)
|
|
5
|
-
* @param config Config to pass to the server
|
|
6
|
-
* @param apiKey Optional API key for authentication
|
|
7
|
-
* @returns Transport
|
|
8
|
-
*/
|
|
9
|
-
export declare function createTransport(smitheryServerUrl: string, config?: object, apiKey?: string): WebSocketClientTransport;
|
package/dist/transport.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { WebSocketClientTransport } from "@modelcontextprotocol/sdk/client/websocket.js";
|
|
2
|
-
import { createSmitheryUrl } from "./config.js";
|
|
3
|
-
/**
|
|
4
|
-
* Creates a transport to connect to the Smithery server
|
|
5
|
-
* @param smitheryServerUrl The URL of the Smithery server (without trailing slash or protocol)
|
|
6
|
-
* @param config Config to pass to the server
|
|
7
|
-
* @param apiKey Optional API key for authentication
|
|
8
|
-
* @returns Transport
|
|
9
|
-
*/
|
|
10
|
-
export function createTransport(smitheryServerUrl, config, apiKey) {
|
|
11
|
-
return new WebSocketClientTransport(createSmitheryUrl(`${smitheryServerUrl}/ws`, config, apiKey));
|
|
12
|
-
}
|
package/dist/types.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
export declare const ToolSchema: z.ZodObject<{
|
|
3
|
-
name: z.ZodString;
|
|
4
|
-
description: z.ZodOptional<z.ZodString>;
|
|
5
|
-
inputSchema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
6
|
-
}, "strip", z.ZodTypeAny, {
|
|
7
|
-
name: string;
|
|
8
|
-
inputSchema: Record<string, unknown>;
|
|
9
|
-
description?: string | undefined;
|
|
10
|
-
}, {
|
|
11
|
-
name: string;
|
|
12
|
-
inputSchema: Record<string, unknown>;
|
|
13
|
-
description?: string | undefined;
|
|
14
|
-
}>;
|
|
15
|
-
export declare const ToolsSchema: z.ZodRecord<z.ZodString, z.ZodArray<z.ZodObject<{
|
|
16
|
-
name: z.ZodString;
|
|
17
|
-
description: z.ZodOptional<z.ZodString>;
|
|
18
|
-
inputSchema: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
19
|
-
}, "strip", z.ZodTypeAny, {
|
|
20
|
-
name: string;
|
|
21
|
-
inputSchema: Record<string, unknown>;
|
|
22
|
-
description?: string | undefined;
|
|
23
|
-
}, {
|
|
24
|
-
name: string;
|
|
25
|
-
inputSchema: Record<string, unknown>;
|
|
26
|
-
description?: string | undefined;
|
|
27
|
-
}>, "many">>;
|
|
28
|
-
export interface Tool extends z.infer<typeof ToolSchema> {
|
|
29
|
-
}
|
|
30
|
-
export type Tools = z.infer<typeof ToolsSchema>;
|