fastmcp 1.6.1 → 1.7.0
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 +35 -10
- package/dist/FastMCP.d.ts +38 -8
- package/dist/FastMCP.js +171 -103
- package/dist/FastMCP.js.map +1 -1
- package/jsr.json +1 -1
- package/package.json +5 -4
- package/src/FastMCP.test.ts +127 -13
- package/src/FastMCP.ts +213 -113
- package/src/examples/addition.ts +26 -0
- package/vitest.config.js +9 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# FastMCP
|
|
2
2
|
|
|
3
|
-
A TypeScript framework for building [MCP](https://modelcontextprotocol.io/) servers.
|
|
3
|
+
A TypeScript framework for building [MCP](https://modelcontextprotocol.io/) servers capable of handling client sessions.
|
|
4
4
|
|
|
5
5
|
> [!NOTE]
|
|
6
6
|
> For a Python implementation, see [FastMCP](https://github.com/jlowin/fastmcp).
|
|
@@ -8,13 +8,14 @@ A TypeScript framework for building [MCP](https://modelcontextprotocol.io/) serv
|
|
|
8
8
|
## Features
|
|
9
9
|
|
|
10
10
|
- Simple Tool, Resource, Prompt definition
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
11
|
+
- [Sessions](#sessions)
|
|
12
|
+
- [Image content](#returning-an-image)
|
|
13
|
+
- [Logging](#logging)
|
|
14
|
+
- [Error handling](#errors)
|
|
15
|
+
- [SSE](#sse)
|
|
16
|
+
- [Progress notifications](#progress)
|
|
17
|
+
- [Typed events](#typed-events)
|
|
18
|
+
- CLI for [testing](#test-with-mcp-cli) and [debugging](#inspect-with-mcp-inspector)
|
|
18
19
|
|
|
19
20
|
## Installation
|
|
20
21
|
|
|
@@ -371,7 +372,7 @@ async load() {
|
|
|
371
372
|
|
|
372
373
|
[Prompts](https://modelcontextprotocol.io/docs/concepts/prompts) enable servers to define reusable prompt templates and workflows that clients can easily surface to users and LLMs. They provide a powerful way to standardize and share common LLM interactions.
|
|
373
374
|
|
|
374
|
-
```
|
|
375
|
+
```ts
|
|
375
376
|
server.addPrompt({
|
|
376
377
|
name: "git-commit",
|
|
377
378
|
description: "Generate a Git commit message",
|
|
@@ -388,6 +389,30 @@ server.addPrompt({
|
|
|
388
389
|
});
|
|
389
390
|
```
|
|
390
391
|
|
|
392
|
+
### Sessions
|
|
393
|
+
|
|
394
|
+
The `session` object is an instance of `FastMCPSession` and it describes active client sessions.
|
|
395
|
+
|
|
396
|
+
```ts
|
|
397
|
+
server.sessions;
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
We allocate a new server instance for each client connection to enable 1:1 communication between a client and the server.
|
|
401
|
+
|
|
402
|
+
### Typed events
|
|
403
|
+
|
|
404
|
+
You can listen to events emitted by the server using the `on` method:
|
|
405
|
+
|
|
406
|
+
```ts
|
|
407
|
+
server.on("connect", (event) => {
|
|
408
|
+
console.log("Client connected:", event.session);
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
server.on("disconnect", (event) => {
|
|
412
|
+
console.log("Client disconnected:", event.session);
|
|
413
|
+
});
|
|
414
|
+
```
|
|
415
|
+
|
|
391
416
|
## Running Your Server
|
|
392
417
|
|
|
393
418
|
### Test with `mcp-cli`
|
|
@@ -414,7 +439,7 @@ npx fastmcp inspect server.ts
|
|
|
414
439
|
> [!NOTE]
|
|
415
440
|
> If you've developed a server using FastMCP, please [submit a PR](https://github.com/punkpeye/fastmcp) to showcase it here!
|
|
416
441
|
|
|
417
|
-
|
|
442
|
+
- https://github.com/apinetwork/piapi-mcp-server
|
|
418
443
|
|
|
419
444
|
## Acknowledgements
|
|
420
445
|
|
package/dist/FastMCP.d.ts
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
1
2
|
import { z } from 'zod';
|
|
3
|
+
import { StrictEventEmitter } from 'strict-event-emitter-types';
|
|
4
|
+
import { EventEmitter } from 'events';
|
|
5
|
+
import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
|
|
2
6
|
|
|
7
|
+
type SSEServer = {
|
|
8
|
+
close: () => Promise<void>;
|
|
9
|
+
};
|
|
10
|
+
type FastMCPEvents = {
|
|
11
|
+
connect: (event: {
|
|
12
|
+
session: FastMCPSession;
|
|
13
|
+
}) => void;
|
|
14
|
+
disconnect: (event: {
|
|
15
|
+
session: FastMCPSession;
|
|
16
|
+
}) => void;
|
|
17
|
+
};
|
|
3
18
|
/**
|
|
4
19
|
* Generates an image content object from a URL, file path, or buffer.
|
|
5
20
|
*/
|
|
@@ -100,19 +115,34 @@ type ServerOptions = {
|
|
|
100
115
|
version: `${number}.${number}.${number}`;
|
|
101
116
|
};
|
|
102
117
|
type LoggingLevel = "debug" | "info" | "notice" | "warning" | "error" | "critical" | "alert" | "emergency";
|
|
103
|
-
declare class
|
|
118
|
+
declare class FastMCPSession {
|
|
104
119
|
#private;
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
120
|
+
constructor({ name, version, tools, resources, prompts, }: {
|
|
121
|
+
name: string;
|
|
122
|
+
version: string;
|
|
123
|
+
tools: Tool[];
|
|
124
|
+
resources: Resource[];
|
|
125
|
+
prompts: Prompt[];
|
|
126
|
+
});
|
|
127
|
+
get server(): Server;
|
|
128
|
+
connect(transport: Transport): void;
|
|
108
129
|
private setupErrorHandling;
|
|
109
|
-
/**
|
|
110
|
-
* Returns the current logging level.
|
|
111
|
-
*/
|
|
112
130
|
get loggingLevel(): LoggingLevel;
|
|
131
|
+
private setupLoggingHandlers;
|
|
113
132
|
private setupToolHandlers;
|
|
114
133
|
private setupResourceHandlers;
|
|
115
134
|
private setupPromptHandlers;
|
|
135
|
+
}
|
|
136
|
+
declare const FastMCPEventEmitterBase: {
|
|
137
|
+
new (): StrictEventEmitter<EventEmitter, FastMCPEvents>;
|
|
138
|
+
};
|
|
139
|
+
declare class FastMCPEventEmitter extends FastMCPEventEmitterBase {
|
|
140
|
+
}
|
|
141
|
+
declare class FastMCP extends FastMCPEventEmitter {
|
|
142
|
+
#private;
|
|
143
|
+
options: ServerOptions;
|
|
144
|
+
constructor(options: ServerOptions);
|
|
145
|
+
get sessions(): FastMCPSession[];
|
|
116
146
|
/**
|
|
117
147
|
* Adds a tool to the server.
|
|
118
148
|
*/
|
|
@@ -143,4 +173,4 @@ declare class FastMCP {
|
|
|
143
173
|
stop(): Promise<void>;
|
|
144
174
|
}
|
|
145
175
|
|
|
146
|
-
export { FastMCP, UserError, imageContent };
|
|
176
|
+
export { FastMCP, FastMCPSession, type SSEServer, UserError, imageContent };
|
package/dist/FastMCP.js
CHANGED
|
@@ -16,6 +16,7 @@ import { zodToJsonSchema } from "zod-to-json-schema";
|
|
|
16
16
|
import { z } from "zod";
|
|
17
17
|
import { readFile } from "fs/promises";
|
|
18
18
|
import { fileTypeFromBuffer } from "file-type";
|
|
19
|
+
import { EventEmitter } from "events";
|
|
19
20
|
import { startSSEServer } from "mcp-proxy";
|
|
20
21
|
var imageContent = async (input) => {
|
|
21
22
|
let rawData;
|
|
@@ -84,55 +85,67 @@ var ContentResultZodSchema = z.object({
|
|
|
84
85
|
content: ContentZodSchema.array(),
|
|
85
86
|
isError: z.boolean().optional()
|
|
86
87
|
}).strict();
|
|
87
|
-
var
|
|
88
|
-
|
|
89
|
-
this.options = options;
|
|
90
|
-
this.#options = options;
|
|
91
|
-
this.#tools = [];
|
|
92
|
-
this.#resources = [];
|
|
93
|
-
this.#prompts = [];
|
|
94
|
-
}
|
|
95
|
-
#tools;
|
|
96
|
-
#resources;
|
|
97
|
-
#prompts;
|
|
98
|
-
#server = null;
|
|
99
|
-
#options;
|
|
88
|
+
var FastMCPSession = class {
|
|
89
|
+
#capabilities = {};
|
|
100
90
|
#loggingLevel = "info";
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
91
|
+
#server;
|
|
92
|
+
constructor({
|
|
93
|
+
name,
|
|
94
|
+
version,
|
|
95
|
+
tools,
|
|
96
|
+
resources,
|
|
97
|
+
prompts
|
|
98
|
+
}) {
|
|
99
|
+
if (tools.length) {
|
|
100
|
+
this.#capabilities.tools = {};
|
|
105
101
|
}
|
|
106
|
-
if (
|
|
107
|
-
this.
|
|
102
|
+
if (resources.length) {
|
|
103
|
+
this.#capabilities.resources = {};
|
|
108
104
|
}
|
|
109
|
-
if (
|
|
110
|
-
this.
|
|
105
|
+
if (prompts.length) {
|
|
106
|
+
this.#capabilities.prompts = {};
|
|
111
107
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
108
|
+
this.#capabilities.logging = {};
|
|
109
|
+
this.#server = new Server(
|
|
110
|
+
{ name, version },
|
|
111
|
+
{ capabilities: this.#capabilities }
|
|
112
|
+
);
|
|
113
|
+
this.setupErrorHandling();
|
|
114
|
+
this.setupLoggingHandlers();
|
|
115
|
+
if (tools.length) {
|
|
116
|
+
this.setupToolHandlers(tools);
|
|
117
|
+
}
|
|
118
|
+
if (resources.length) {
|
|
119
|
+
this.setupResourceHandlers(resources);
|
|
120
|
+
}
|
|
121
|
+
if (prompts.length) {
|
|
122
|
+
this.setupPromptHandlers(prompts);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
get server() {
|
|
126
|
+
return this.#server;
|
|
127
|
+
}
|
|
128
|
+
connect(transport) {
|
|
129
|
+
this.#server.connect(transport);
|
|
116
130
|
}
|
|
117
|
-
setupErrorHandling(
|
|
118
|
-
server.onerror = (error) => {
|
|
131
|
+
setupErrorHandling() {
|
|
132
|
+
this.#server.onerror = (error) => {
|
|
119
133
|
console.error("[MCP Error]", error);
|
|
120
134
|
};
|
|
121
|
-
process.on("SIGINT", async () => {
|
|
122
|
-
await server.close();
|
|
123
|
-
process.exit(0);
|
|
124
|
-
});
|
|
125
135
|
}
|
|
126
|
-
/**
|
|
127
|
-
* Returns the current logging level.
|
|
128
|
-
*/
|
|
129
136
|
get loggingLevel() {
|
|
130
137
|
return this.#loggingLevel;
|
|
131
138
|
}
|
|
132
|
-
|
|
133
|
-
server.setRequestHandler(
|
|
139
|
+
setupLoggingHandlers() {
|
|
140
|
+
this.#server.setRequestHandler(SetLevelRequestSchema, (request) => {
|
|
141
|
+
this.#loggingLevel = request.params.level;
|
|
142
|
+
return {};
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
setupToolHandlers(tools) {
|
|
146
|
+
this.#server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
134
147
|
return {
|
|
135
|
-
tools:
|
|
148
|
+
tools: tools.map((tool) => {
|
|
136
149
|
return {
|
|
137
150
|
name: tool.name,
|
|
138
151
|
description: tool.description,
|
|
@@ -141,10 +154,8 @@ var FastMCP = class {
|
|
|
141
154
|
})
|
|
142
155
|
};
|
|
143
156
|
});
|
|
144
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
145
|
-
const tool =
|
|
146
|
-
(tool2) => tool2.name === request.params.name
|
|
147
|
-
);
|
|
157
|
+
this.#server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
158
|
+
const tool = tools.find((tool2) => tool2.name === request.params.name);
|
|
148
159
|
if (!tool) {
|
|
149
160
|
throw new McpError(
|
|
150
161
|
ErrorCode.MethodNotFound,
|
|
@@ -166,7 +177,7 @@ var FastMCP = class {
|
|
|
166
177
|
let result;
|
|
167
178
|
try {
|
|
168
179
|
const reportProgress = async (progress) => {
|
|
169
|
-
await server.notification({
|
|
180
|
+
await this.#server.notification({
|
|
170
181
|
method: "notifications/progress",
|
|
171
182
|
params: {
|
|
172
183
|
...progress,
|
|
@@ -176,7 +187,7 @@ var FastMCP = class {
|
|
|
176
187
|
};
|
|
177
188
|
const log = {
|
|
178
189
|
debug: (message, context) => {
|
|
179
|
-
server.sendLoggingMessage({
|
|
190
|
+
this.#server.sendLoggingMessage({
|
|
180
191
|
level: "debug",
|
|
181
192
|
data: {
|
|
182
193
|
message,
|
|
@@ -185,7 +196,7 @@ var FastMCP = class {
|
|
|
185
196
|
});
|
|
186
197
|
},
|
|
187
198
|
error: (message, context) => {
|
|
188
|
-
server.sendLoggingMessage({
|
|
199
|
+
this.#server.sendLoggingMessage({
|
|
189
200
|
level: "error",
|
|
190
201
|
data: {
|
|
191
202
|
message,
|
|
@@ -194,7 +205,7 @@ var FastMCP = class {
|
|
|
194
205
|
});
|
|
195
206
|
},
|
|
196
207
|
info: (message, context) => {
|
|
197
|
-
server.sendLoggingMessage({
|
|
208
|
+
this.#server.sendLoggingMessage({
|
|
198
209
|
level: "info",
|
|
199
210
|
data: {
|
|
200
211
|
message,
|
|
@@ -203,7 +214,7 @@ var FastMCP = class {
|
|
|
203
214
|
});
|
|
204
215
|
},
|
|
205
216
|
warn: (message, context) => {
|
|
206
|
-
server.sendLoggingMessage({
|
|
217
|
+
this.#server.sendLoggingMessage({
|
|
207
218
|
level: "warning",
|
|
208
219
|
data: {
|
|
209
220
|
message,
|
|
@@ -242,10 +253,10 @@ var FastMCP = class {
|
|
|
242
253
|
return result;
|
|
243
254
|
});
|
|
244
255
|
}
|
|
245
|
-
setupResourceHandlers(
|
|
246
|
-
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
256
|
+
setupResourceHandlers(resources) {
|
|
257
|
+
this.#server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
247
258
|
return {
|
|
248
|
-
resources:
|
|
259
|
+
resources: resources.map((resource) => {
|
|
249
260
|
return {
|
|
250
261
|
uri: resource.uri,
|
|
251
262
|
name: resource.name,
|
|
@@ -254,43 +265,46 @@ var FastMCP = class {
|
|
|
254
265
|
})
|
|
255
266
|
};
|
|
256
267
|
});
|
|
257
|
-
server.setRequestHandler(
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
throw new McpError(
|
|
263
|
-
ErrorCode.MethodNotFound,
|
|
264
|
-
`Unknown resource: ${request.params.uri}`
|
|
265
|
-
);
|
|
266
|
-
}
|
|
267
|
-
let result;
|
|
268
|
-
try {
|
|
269
|
-
result = await resource.load();
|
|
270
|
-
} catch (error) {
|
|
271
|
-
throw new McpError(
|
|
272
|
-
ErrorCode.InternalError,
|
|
273
|
-
`Error reading resource: ${error}`,
|
|
274
|
-
{
|
|
275
|
-
uri: resource.uri
|
|
276
|
-
}
|
|
268
|
+
this.#server.setRequestHandler(
|
|
269
|
+
ReadResourceRequestSchema,
|
|
270
|
+
async (request) => {
|
|
271
|
+
const resource = resources.find(
|
|
272
|
+
(resource2) => resource2.uri === request.params.uri
|
|
277
273
|
);
|
|
274
|
+
if (!resource) {
|
|
275
|
+
throw new McpError(
|
|
276
|
+
ErrorCode.MethodNotFound,
|
|
277
|
+
`Unknown resource: ${request.params.uri}`
|
|
278
|
+
);
|
|
279
|
+
}
|
|
280
|
+
let result;
|
|
281
|
+
try {
|
|
282
|
+
result = await resource.load();
|
|
283
|
+
} catch (error) {
|
|
284
|
+
throw new McpError(
|
|
285
|
+
ErrorCode.InternalError,
|
|
286
|
+
`Error reading resource: ${error}`,
|
|
287
|
+
{
|
|
288
|
+
uri: resource.uri
|
|
289
|
+
}
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
return {
|
|
293
|
+
contents: [
|
|
294
|
+
{
|
|
295
|
+
uri: resource.uri,
|
|
296
|
+
mimeType: resource.mimeType,
|
|
297
|
+
...result
|
|
298
|
+
}
|
|
299
|
+
]
|
|
300
|
+
};
|
|
278
301
|
}
|
|
279
|
-
|
|
280
|
-
contents: [
|
|
281
|
-
{
|
|
282
|
-
uri: resource.uri,
|
|
283
|
-
mimeType: resource.mimeType,
|
|
284
|
-
...result
|
|
285
|
-
}
|
|
286
|
-
]
|
|
287
|
-
};
|
|
288
|
-
});
|
|
302
|
+
);
|
|
289
303
|
}
|
|
290
|
-
setupPromptHandlers(
|
|
291
|
-
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
304
|
+
setupPromptHandlers(prompts) {
|
|
305
|
+
this.#server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
292
306
|
return {
|
|
293
|
-
prompts:
|
|
307
|
+
prompts: prompts.map((prompt) => {
|
|
294
308
|
return {
|
|
295
309
|
name: prompt.name,
|
|
296
310
|
description: prompt.description,
|
|
@@ -299,8 +313,8 @@ var FastMCP = class {
|
|
|
299
313
|
})
|
|
300
314
|
};
|
|
301
315
|
});
|
|
302
|
-
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
303
|
-
const prompt =
|
|
316
|
+
this.#server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
317
|
+
const prompt = prompts.find(
|
|
304
318
|
(prompt2) => prompt2.name === request.params.name
|
|
305
319
|
);
|
|
306
320
|
if (!prompt) {
|
|
@@ -340,6 +354,25 @@ var FastMCP = class {
|
|
|
340
354
|
};
|
|
341
355
|
});
|
|
342
356
|
}
|
|
357
|
+
};
|
|
358
|
+
var FastMCPEventEmitterBase = EventEmitter;
|
|
359
|
+
var FastMCPEventEmitter = class extends FastMCPEventEmitterBase {
|
|
360
|
+
};
|
|
361
|
+
var FastMCP = class extends FastMCPEventEmitter {
|
|
362
|
+
constructor(options) {
|
|
363
|
+
super();
|
|
364
|
+
this.options = options;
|
|
365
|
+
this.#options = options;
|
|
366
|
+
}
|
|
367
|
+
#options;
|
|
368
|
+
#prompts = [];
|
|
369
|
+
#resources = [];
|
|
370
|
+
#sessions = [];
|
|
371
|
+
#sseServer = null;
|
|
372
|
+
#tools = [];
|
|
373
|
+
get sessions() {
|
|
374
|
+
return this.#sessions;
|
|
375
|
+
}
|
|
343
376
|
/**
|
|
344
377
|
* Adds a tool to the server.
|
|
345
378
|
*/
|
|
@@ -358,39 +391,73 @@ var FastMCP = class {
|
|
|
358
391
|
addPrompt(prompt) {
|
|
359
392
|
this.#prompts.push(prompt);
|
|
360
393
|
}
|
|
361
|
-
#sseServer = null;
|
|
362
394
|
/**
|
|
363
395
|
* Starts the server.
|
|
364
396
|
*/
|
|
365
397
|
async start(options = {
|
|
366
398
|
transportType: "stdio"
|
|
367
399
|
}) {
|
|
368
|
-
const capabilities = {};
|
|
369
|
-
if (this.#tools.length) {
|
|
370
|
-
capabilities.tools = {};
|
|
371
|
-
}
|
|
372
|
-
if (this.#resources.length) {
|
|
373
|
-
capabilities.resources = {};
|
|
374
|
-
}
|
|
375
|
-
if (this.#prompts.length) {
|
|
376
|
-
capabilities.prompts = {};
|
|
377
|
-
}
|
|
378
|
-
capabilities.logging = {};
|
|
379
|
-
this.#server = new Server(
|
|
380
|
-
{ name: this.#options.name, version: this.#options.version },
|
|
381
|
-
{ capabilities }
|
|
382
|
-
);
|
|
383
|
-
this.setupHandlers(this.#server);
|
|
384
400
|
if (options.transportType === "stdio") {
|
|
385
401
|
const transport = new StdioServerTransport();
|
|
386
|
-
|
|
402
|
+
const session = new FastMCPSession({
|
|
403
|
+
name: this.#options.name,
|
|
404
|
+
version: this.#options.version,
|
|
405
|
+
tools: this.#tools,
|
|
406
|
+
resources: this.#resources,
|
|
407
|
+
prompts: this.#prompts
|
|
408
|
+
});
|
|
409
|
+
await session.connect(transport);
|
|
410
|
+
this.#sessions.push(session);
|
|
411
|
+
this.emit("connect", {
|
|
412
|
+
session
|
|
413
|
+
});
|
|
387
414
|
console.error(`server is running on stdio`);
|
|
388
415
|
} else if (options.transportType === "sse") {
|
|
389
416
|
this.#sseServer = await startSSEServer({
|
|
390
417
|
endpoint: options.sse.endpoint,
|
|
391
418
|
port: options.sse.port,
|
|
392
|
-
|
|
419
|
+
createServer: async () => {
|
|
420
|
+
const session = new FastMCPSession({
|
|
421
|
+
name: this.#options.name,
|
|
422
|
+
version: this.#options.version,
|
|
423
|
+
tools: this.#tools,
|
|
424
|
+
resources: this.#resources,
|
|
425
|
+
prompts: this.#prompts
|
|
426
|
+
});
|
|
427
|
+
this.#sessions.push(session);
|
|
428
|
+
return session.server;
|
|
429
|
+
},
|
|
430
|
+
onClose: (server) => {
|
|
431
|
+
const session = this.#sessions.find(
|
|
432
|
+
(session2) => session2.server === server
|
|
433
|
+
);
|
|
434
|
+
if (!session) {
|
|
435
|
+
throw new UnexpectedStateError("Server not found");
|
|
436
|
+
}
|
|
437
|
+
this.#sessions = this.#sessions.filter(
|
|
438
|
+
(maybeOurSession) => maybeOurSession !== session
|
|
439
|
+
);
|
|
440
|
+
this.emit("disconnect", {
|
|
441
|
+
session
|
|
442
|
+
});
|
|
443
|
+
},
|
|
444
|
+
onConnect: async (server) => {
|
|
445
|
+
const session = this.#sessions.find(
|
|
446
|
+
(session2) => session2.server === server
|
|
447
|
+
);
|
|
448
|
+
if (!session) {
|
|
449
|
+
throw new UnexpectedStateError("Server not found");
|
|
450
|
+
}
|
|
451
|
+
setTimeout(() => {
|
|
452
|
+
this.emit("connect", {
|
|
453
|
+
session
|
|
454
|
+
});
|
|
455
|
+
}, 100);
|
|
456
|
+
}
|
|
393
457
|
});
|
|
458
|
+
console.error(
|
|
459
|
+
`server is running on SSE at http://localhost:${options.sse.port}${options.sse.endpoint}`
|
|
460
|
+
);
|
|
394
461
|
} else {
|
|
395
462
|
throw new Error("Invalid transport type");
|
|
396
463
|
}
|
|
@@ -406,6 +473,7 @@ var FastMCP = class {
|
|
|
406
473
|
};
|
|
407
474
|
export {
|
|
408
475
|
FastMCP,
|
|
476
|
+
FastMCPSession,
|
|
409
477
|
UserError,
|
|
410
478
|
imageContent
|
|
411
479
|
};
|
package/dist/FastMCP.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/FastMCP.ts"],"sourcesContent":["import { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ErrorCode,\n GetPromptRequestSchema,\n ListPromptsRequestSchema,\n ListResourcesRequestSchema,\n ListToolsRequestSchema,\n McpError,\n ReadResourceRequestSchema,\n ServerCapabilities,\n SetLevelRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { zodToJsonSchema } from \"zod-to-json-schema\";\nimport { z } from \"zod\";\nimport { readFile } from \"fs/promises\";\nimport { fileTypeFromBuffer } from \"file-type\";\nimport { startSSEServer, type SSEServer } from \"mcp-proxy\";\n\n/**\n * Generates an image content object from a URL, file path, or buffer.\n */\nexport const imageContent = async (\n input: { url: string } | { path: string } | { buffer: Buffer },\n): Promise<ImageContent> => {\n let rawData: Buffer;\n\n if (\"url\" in input) {\n const response = await fetch(input.url);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch image from URL: ${response.statusText}`);\n }\n\n rawData = Buffer.from(await response.arrayBuffer());\n } else if (\"path\" in input) {\n rawData = await readFile(input.path);\n } else if (\"buffer\" in input) {\n rawData = input.buffer;\n } else {\n throw new Error(\n \"Invalid input: Provide a valid 'url', 'path', or 'buffer'\",\n );\n }\n\n const mimeType = await fileTypeFromBuffer(rawData);\n\n const base64Data = rawData.toString(\"base64\");\n\n return {\n type: \"image\",\n data: base64Data,\n mimeType: mimeType?.mime ?? \"image/png\",\n } as const;\n};\n\nabstract class FastMCPError extends Error {\n public constructor(message?: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\ntype Extra = unknown;\n\ntype Extras = Record<string, Extra>;\n\nclass UnexpectedStateError extends FastMCPError {\n public extras?: Extras;\n\n public constructor(message: string, extras?: Extras) {\n super(message);\n this.name = new.target.name;\n this.extras = extras;\n }\n}\n\n/**\n * An error that is meant to be surfaced to the user.\n */\nexport class UserError extends UnexpectedStateError {}\n\ntype ToolParameters = z.ZodTypeAny;\n\ntype Literal = boolean | null | number | string | undefined;\n\ntype SerializableValue =\n | Literal\n | SerializableValue[]\n | { [key: string]: SerializableValue };\n\ntype Progress = {\n /**\n * The progress thus far. This should increase every time progress is made, even if the total is unknown.\n */\n progress: number;\n /**\n * Total number of items to process (or total progress required), if known.\n */\n total?: number;\n};\n\ntype Context = {\n reportProgress: (progress: Progress) => Promise<void>;\n log: {\n debug: (message: string, data?: SerializableValue) => void;\n error: (message: string, data?: SerializableValue) => void;\n info: (message: string, data?: SerializableValue) => void;\n warn: (message: string, data?: SerializableValue) => void;\n };\n};\n\ntype TextContent = {\n type: \"text\";\n text: string;\n};\n\nconst TextContentZodSchema = z\n .object({\n type: z.literal(\"text\"),\n /**\n * The text content of the message.\n */\n text: z.string(),\n })\n .strict() satisfies z.ZodType<TextContent>;\n\ntype ImageContent = {\n type: \"image\";\n data: string;\n mimeType: string;\n};\n\nconst ImageContentZodSchema = z\n .object({\n type: z.literal(\"image\"),\n /**\n * The base64-encoded image data.\n */\n data: z.string().base64(),\n /**\n * The MIME type of the image. Different providers may support different image types.\n */\n mimeType: z.string(),\n })\n .strict() satisfies z.ZodType<ImageContent>;\n\ntype Content = TextContent | ImageContent;\n\nconst ContentZodSchema = z.discriminatedUnion(\"type\", [\n TextContentZodSchema,\n ImageContentZodSchema,\n]) satisfies z.ZodType<Content>;\n\ntype ContentResult = {\n content: Content[];\n isError?: boolean;\n};\n\nconst ContentResultZodSchema = z\n .object({\n content: ContentZodSchema.array(),\n isError: z.boolean().optional(),\n })\n .strict() satisfies z.ZodType<ContentResult>;\n\ntype Tool<Params extends ToolParameters = ToolParameters> = {\n name: string;\n description?: string;\n parameters?: Params;\n execute: (\n args: z.infer<Params>,\n context: Context,\n ) => Promise<string | ContentResult | TextContent | ImageContent>;\n};\n\ntype Resource = {\n uri: string;\n name: string;\n description?: string;\n mimeType?: string;\n load: () => Promise<{ text: string } | { blob: string }>;\n};\n\ntype PromptArgument = Readonly<{\n name: string;\n description?: string;\n required?: boolean;\n}>;\n\ntype ArgumentsToObject<T extends PromptArgument[]> = {\n [K in T[number][\"name\"]]: Extract<\n T[number],\n { name: K }\n >[\"required\"] extends true\n ? string\n : string | undefined;\n};\n\ntype Prompt<\n Arguments extends PromptArgument[] = PromptArgument[],\n Args = ArgumentsToObject<Arguments>,\n> = {\n name: string;\n description?: string;\n arguments?: Arguments;\n load: (args: Args) => Promise<string>;\n};\n\ntype ServerOptions = {\n name: string;\n version: `${number}.${number}.${number}`;\n};\n\ntype LoggingLevel =\n | \"debug\"\n | \"info\"\n | \"notice\"\n | \"warning\"\n | \"error\"\n | \"critical\"\n | \"alert\"\n | \"emergency\";\n\nexport class FastMCP {\n #tools: Tool[];\n #resources: Resource[];\n #prompts: Prompt[];\n #server: Server | null = null;\n #options: ServerOptions;\n #loggingLevel: LoggingLevel = \"info\";\n\n constructor(public options: ServerOptions) {\n this.#options = options;\n this.#tools = [];\n this.#resources = [];\n this.#prompts = [];\n }\n\n private setupHandlers(server: Server) {\n this.setupErrorHandling(server);\n\n if (this.#tools.length) {\n this.setupToolHandlers(server);\n }\n\n if (this.#resources.length) {\n this.setupResourceHandlers(server);\n }\n\n if (this.#prompts.length) {\n this.setupPromptHandlers(server);\n }\n\n server.setRequestHandler(SetLevelRequestSchema, (request) => {\n this.#loggingLevel = request.params.level;\n\n return {};\n });\n }\n\n private setupErrorHandling(server: Server) {\n server.onerror = (error) => {\n console.error(\"[MCP Error]\", error);\n };\n\n process.on(\"SIGINT\", async () => {\n await server.close();\n process.exit(0);\n });\n }\n\n /**\n * Returns the current logging level.\n */\n public get loggingLevel(): LoggingLevel {\n return this.#loggingLevel;\n }\n\n private setupToolHandlers(server: Server) {\n server.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: this.#tools.map((tool) => {\n return {\n name: tool.name,\n description: tool.description,\n inputSchema: tool.parameters\n ? zodToJsonSchema(tool.parameters)\n : undefined,\n };\n }),\n };\n });\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const tool = this.#tools.find(\n (tool) => tool.name === request.params.name,\n );\n\n if (!tool) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown tool: ${request.params.name}`,\n );\n }\n\n let args: any = undefined;\n\n if (tool.parameters) {\n const parsed = tool.parameters.safeParse(request.params.arguments);\n\n if (!parsed.success) {\n throw new McpError(\n ErrorCode.InvalidRequest,\n `Invalid ${request.params.name} arguments`,\n );\n }\n\n args = parsed.data;\n }\n\n const progressToken = request.params?._meta?.progressToken;\n\n let result: ContentResult;\n\n try {\n const reportProgress = async (progress: Progress) => {\n await server.notification({\n method: \"notifications/progress\",\n params: {\n ...progress,\n progressToken,\n },\n });\n };\n\n const log = {\n debug: (message: string, context?: SerializableValue) => {\n server.sendLoggingMessage({\n level: \"debug\",\n data: {\n message,\n context,\n },\n });\n },\n error: (message: string, context?: SerializableValue) => {\n server.sendLoggingMessage({\n level: \"error\",\n data: {\n message,\n context,\n },\n });\n },\n info: (message: string, context?: SerializableValue) => {\n server.sendLoggingMessage({\n level: \"info\",\n data: {\n message,\n context,\n },\n });\n },\n warn: (message: string, context?: SerializableValue) => {\n server.sendLoggingMessage({\n level: \"warning\",\n data: {\n message,\n context,\n },\n });\n },\n };\n\n const maybeStringResult = await tool.execute(args, {\n reportProgress,\n log,\n });\n\n if (typeof maybeStringResult === \"string\") {\n result = ContentResultZodSchema.parse({\n content: [{ type: \"text\", text: maybeStringResult }],\n });\n } else if (\"type\" in maybeStringResult) {\n result = ContentResultZodSchema.parse({\n content: [maybeStringResult],\n });\n } else {\n result = ContentResultZodSchema.parse(maybeStringResult);\n }\n } catch (error) {\n if (error instanceof UserError) {\n return {\n content: [{ type: \"text\", text: error.message }],\n isError: true,\n };\n }\n\n return {\n content: [{ type: \"text\", text: `Error: ${error}` }],\n isError: true,\n };\n }\n\n return result;\n });\n }\n\n private setupResourceHandlers(server: Server) {\n server.setRequestHandler(ListResourcesRequestSchema, async () => {\n return {\n resources: this.#resources.map((resource) => {\n return {\n uri: resource.uri,\n name: resource.name,\n mimeType: resource.mimeType,\n };\n }),\n };\n });\n\n server.setRequestHandler(ReadResourceRequestSchema, async (request) => {\n const resource = this.#resources.find(\n (resource) => resource.uri === request.params.uri,\n );\n\n if (!resource) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown resource: ${request.params.uri}`,\n );\n }\n\n let result: Awaited<ReturnType<Resource[\"load\"]>>;\n\n try {\n result = await resource.load();\n } catch (error) {\n throw new McpError(\n ErrorCode.InternalError,\n `Error reading resource: ${error}`,\n {\n uri: resource.uri,\n },\n );\n }\n\n return {\n contents: [\n {\n uri: resource.uri,\n mimeType: resource.mimeType,\n ...result,\n },\n ],\n };\n });\n }\n\n private setupPromptHandlers(server: Server) {\n server.setRequestHandler(ListPromptsRequestSchema, async () => {\n return {\n prompts: this.#prompts.map((prompt) => {\n return {\n name: prompt.name,\n description: prompt.description,\n arguments: prompt.arguments,\n };\n }),\n };\n });\n\n server.setRequestHandler(GetPromptRequestSchema, async (request) => {\n const prompt = this.#prompts.find(\n (prompt) => prompt.name === request.params.name,\n );\n\n if (!prompt) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown prompt: ${request.params.name}`,\n );\n }\n\n const args = request.params.arguments;\n\n if (prompt.arguments) {\n for (const arg of prompt.arguments) {\n if (arg.required && !(args && arg.name in args)) {\n throw new McpError(\n ErrorCode.InvalidRequest,\n `Missing required argument: ${arg.name}`,\n );\n }\n }\n }\n\n let result: Awaited<ReturnType<Prompt[\"load\"]>>;\n\n try {\n result = await prompt.load(args as Record<string, string | undefined>);\n } catch (error) {\n throw new McpError(\n ErrorCode.InternalError,\n `Error loading prompt: ${error}`,\n );\n }\n\n return {\n description: prompt.description,\n messages: [\n {\n role: \"user\",\n content: { type: \"text\", text: result },\n },\n ],\n };\n });\n }\n\n /**\n * Adds a tool to the server.\n */\n public addTool<Params extends ToolParameters>(tool: Tool<Params>) {\n this.#tools.push(tool as unknown as Tool);\n }\n\n /**\n * Adds a resource to the server.\n */\n public addResource(resource: Resource) {\n this.#resources.push(resource);\n }\n\n /**\n * Adds a prompt to the server.\n */\n public addPrompt<const Args extends PromptArgument[]>(prompt: Prompt<Args>) {\n this.#prompts.push(prompt);\n }\n\n #sseServer: SSEServer | null = null;\n\n /**\n * Starts the server.\n */\n public async start(\n options:\n | { transportType: \"stdio\" }\n | {\n transportType: \"sse\";\n sse: { endpoint: `/${string}`; port: number };\n } = {\n transportType: \"stdio\",\n },\n ) {\n const capabilities: ServerCapabilities = {};\n\n if (this.#tools.length) {\n capabilities.tools = {};\n }\n\n if (this.#resources.length) {\n capabilities.resources = {};\n }\n\n if (this.#prompts.length) {\n capabilities.prompts = {};\n }\n\n capabilities.logging = {};\n\n this.#server = new Server(\n { name: this.#options.name, version: this.#options.version },\n { capabilities },\n );\n\n this.setupHandlers(this.#server);\n\n if (options.transportType === \"stdio\") {\n const transport = new StdioServerTransport();\n\n await this.#server.connect(transport);\n\n console.error(`server is running on stdio`);\n } else if (options.transportType === \"sse\") {\n this.#sseServer = await startSSEServer({\n endpoint: options.sse.endpoint as `/${string}`,\n port: options.sse.port,\n server: this.#server,\n });\n } else {\n throw new Error(\"Invalid transport type\");\n }\n }\n\n /**\n * Stops the server.\n */\n public async stop() {\n if (this.#sseServer) {\n this.#sseServer.close();\n }\n }\n}\n"],"mappings":";AAAA,SAAS,cAAc;AACvB,SAAS,4BAA4B;AACrC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,OACK;AACP,SAAS,uBAAuB;AAChC,SAAS,SAAS;AAClB,SAAS,gBAAgB;AACzB,SAAS,0BAA0B;AACnC,SAAS,sBAAsC;AAKxC,IAAM,eAAe,OAC1B,UAC0B;AAC1B,MAAI;AAEJ,MAAI,SAAS,OAAO;AAClB,UAAM,WAAW,MAAM,MAAM,MAAM,GAAG;AAEtC,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,mCAAmC,SAAS,UAAU,EAAE;AAAA,IAC1E;AAEA,cAAU,OAAO,KAAK,MAAM,SAAS,YAAY,CAAC;AAAA,EACpD,WAAW,UAAU,OAAO;AAC1B,cAAU,MAAM,SAAS,MAAM,IAAI;AAAA,EACrC,WAAW,YAAY,OAAO;AAC5B,cAAU,MAAM;AAAA,EAClB,OAAO;AACL,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW,MAAM,mBAAmB,OAAO;AAEjD,QAAM,aAAa,QAAQ,SAAS,QAAQ;AAE5C,SAAO;AAAA,IACL,MAAM;AAAA,IACN,MAAM;AAAA,IACN,UAAU,UAAU,QAAQ;AAAA,EAC9B;AACF;AAEA,IAAe,eAAf,cAAoC,MAAM;AAAA,EACjC,YAAY,SAAkB;AACnC,UAAM,OAAO;AACb,SAAK,OAAO,WAAW;AAAA,EACzB;AACF;AAMA,IAAM,uBAAN,cAAmC,aAAa;AAAA,EACvC;AAAA,EAEA,YAAY,SAAiB,QAAiB;AACnD,UAAM,OAAO;AACb,SAAK,OAAO,WAAW;AACvB,SAAK,SAAS;AAAA,EAChB;AACF;AAKO,IAAM,YAAN,cAAwB,qBAAqB;AAAC;AAqCrD,IAAM,uBAAuB,EAC1B,OAAO;AAAA,EACN,MAAM,EAAE,QAAQ,MAAM;AAAA;AAAA;AAAA;AAAA,EAItB,MAAM,EAAE,OAAO;AACjB,CAAC,EACA,OAAO;AAQV,IAAM,wBAAwB,EAC3B,OAAO;AAAA,EACN,MAAM,EAAE,QAAQ,OAAO;AAAA;AAAA;AAAA;AAAA,EAIvB,MAAM,EAAE,OAAO,EAAE,OAAO;AAAA;AAAA;AAAA;AAAA,EAIxB,UAAU,EAAE,OAAO;AACrB,CAAC,EACA,OAAO;AAIV,IAAM,mBAAmB,EAAE,mBAAmB,QAAQ;AAAA,EACpD;AAAA,EACA;AACF,CAAC;AAOD,IAAM,yBAAyB,EAC5B,OAAO;AAAA,EACN,SAAS,iBAAiB,MAAM;AAAA,EAChC,SAAS,EAAE,QAAQ,EAAE,SAAS;AAChC,CAAC,EACA,OAAO;AA4DH,IAAM,UAAN,MAAc;AAAA,EAQnB,YAAmB,SAAwB;AAAxB;AACjB,SAAK,WAAW;AAChB,SAAK,SAAS,CAAC;AACf,SAAK,aAAa,CAAC;AACnB,SAAK,WAAW,CAAC;AAAA,EACnB;AAAA,EAZA;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAyB;AAAA,EACzB;AAAA,EACA,gBAA8B;AAAA,EAStB,cAAc,QAAgB;AACpC,SAAK,mBAAmB,MAAM;AAE9B,QAAI,KAAK,OAAO,QAAQ;AACtB,WAAK,kBAAkB,MAAM;AAAA,IAC/B;AAEA,QAAI,KAAK,WAAW,QAAQ;AAC1B,WAAK,sBAAsB,MAAM;AAAA,IACnC;AAEA,QAAI,KAAK,SAAS,QAAQ;AACxB,WAAK,oBAAoB,MAAM;AAAA,IACjC;AAEA,WAAO,kBAAkB,uBAAuB,CAAC,YAAY;AAC3D,WAAK,gBAAgB,QAAQ,OAAO;AAEpC,aAAO,CAAC;AAAA,IACV,CAAC;AAAA,EACH;AAAA,EAEQ,mBAAmB,QAAgB;AACzC,WAAO,UAAU,CAAC,UAAU;AAC1B,cAAQ,MAAM,eAAe,KAAK;AAAA,IACpC;AAEA,YAAQ,GAAG,UAAU,YAAY;AAC/B,YAAM,OAAO,MAAM;AACnB,cAAQ,KAAK,CAAC;AAAA,IAChB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,IAAW,eAA6B;AACtC,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,kBAAkB,QAAgB;AACxC,WAAO,kBAAkB,wBAAwB,YAAY;AAC3D,aAAO;AAAA,QACL,OAAO,KAAK,OAAO,IAAI,CAAC,SAAS;AAC/B,iBAAO;AAAA,YACL,MAAM,KAAK;AAAA,YACX,aAAa,KAAK;AAAA,YAClB,aAAa,KAAK,aACd,gBAAgB,KAAK,UAAU,IAC/B;AAAA,UACN;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAED,WAAO,kBAAkB,uBAAuB,OAAO,YAAY;AACjE,YAAM,OAAO,KAAK,OAAO;AAAA,QACvB,CAACA,UAASA,MAAK,SAAS,QAAQ,OAAO;AAAA,MACzC;AAEA,UAAI,CAAC,MAAM;AACT,cAAM,IAAI;AAAA,UACR,UAAU;AAAA,UACV,iBAAiB,QAAQ,OAAO,IAAI;AAAA,QACtC;AAAA,MACF;AAEA,UAAI,OAAY;AAEhB,UAAI,KAAK,YAAY;AACnB,cAAM,SAAS,KAAK,WAAW,UAAU,QAAQ,OAAO,SAAS;AAEjE,YAAI,CAAC,OAAO,SAAS;AACnB,gBAAM,IAAI;AAAA,YACR,UAAU;AAAA,YACV,WAAW,QAAQ,OAAO,IAAI;AAAA,UAChC;AAAA,QACF;AAEA,eAAO,OAAO;AAAA,MAChB;AAEA,YAAM,gBAAgB,QAAQ,QAAQ,OAAO;AAE7C,UAAI;AAEJ,UAAI;AACF,cAAM,iBAAiB,OAAO,aAAuB;AACnD,gBAAM,OAAO,aAAa;AAAA,YACxB,QAAQ;AAAA,YACR,QAAQ;AAAA,cACN,GAAG;AAAA,cACH;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAEA,cAAM,MAAM;AAAA,UACV,OAAO,CAAC,SAAiB,YAAgC;AACvD,mBAAO,mBAAmB;AAAA,cACxB,OAAO;AAAA,cACP,MAAM;AAAA,gBACJ;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,UACA,OAAO,CAAC,SAAiB,YAAgC;AACvD,mBAAO,mBAAmB;AAAA,cACxB,OAAO;AAAA,cACP,MAAM;AAAA,gBACJ;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,UACA,MAAM,CAAC,SAAiB,YAAgC;AACtD,mBAAO,mBAAmB;AAAA,cACxB,OAAO;AAAA,cACP,MAAM;AAAA,gBACJ;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,UACA,MAAM,CAAC,SAAiB,YAAgC;AACtD,mBAAO,mBAAmB;AAAA,cACxB,OAAO;AAAA,cACP,MAAM;AAAA,gBACJ;AAAA,gBACA;AAAA,cACF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAEA,cAAM,oBAAoB,MAAM,KAAK,QAAQ,MAAM;AAAA,UACjD;AAAA,UACA;AAAA,QACF,CAAC;AAED,YAAI,OAAO,sBAAsB,UAAU;AACzC,mBAAS,uBAAuB,MAAM;AAAA,YACpC,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,kBAAkB,CAAC;AAAA,UACrD,CAAC;AAAA,QACH,WAAW,UAAU,mBAAmB;AACtC,mBAAS,uBAAuB,MAAM;AAAA,YACpC,SAAS,CAAC,iBAAiB;AAAA,UAC7B,CAAC;AAAA,QACH,OAAO;AACL,mBAAS,uBAAuB,MAAM,iBAAiB;AAAA,QACzD;AAAA,MACF,SAAS,OAAO;AACd,YAAI,iBAAiB,WAAW;AAC9B,iBAAO;AAAA,YACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,MAAM,QAAQ,CAAC;AAAA,YAC/C,SAAS;AAAA,UACX;AAAA,QACF;AAEA,eAAO;AAAA,UACL,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,UAAU,KAAK,GAAG,CAAC;AAAA,UACnD,SAAS;AAAA,QACX;AAAA,MACF;AAEA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA,EAEQ,sBAAsB,QAAgB;AAC5C,WAAO,kBAAkB,4BAA4B,YAAY;AAC/D,aAAO;AAAA,QACL,WAAW,KAAK,WAAW,IAAI,CAAC,aAAa;AAC3C,iBAAO;AAAA,YACL,KAAK,SAAS;AAAA,YACd,MAAM,SAAS;AAAA,YACf,UAAU,SAAS;AAAA,UACrB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAED,WAAO,kBAAkB,2BAA2B,OAAO,YAAY;AACrE,YAAM,WAAW,KAAK,WAAW;AAAA,QAC/B,CAACC,cAAaA,UAAS,QAAQ,QAAQ,OAAO;AAAA,MAChD;AAEA,UAAI,CAAC,UAAU;AACb,cAAM,IAAI;AAAA,UACR,UAAU;AAAA,UACV,qBAAqB,QAAQ,OAAO,GAAG;AAAA,QACzC;AAAA,MACF;AAEA,UAAI;AAEJ,UAAI;AACF,iBAAS,MAAM,SAAS,KAAK;AAAA,MAC/B,SAAS,OAAO;AACd,cAAM,IAAI;AAAA,UACR,UAAU;AAAA,UACV,2BAA2B,KAAK;AAAA,UAChC;AAAA,YACE,KAAK,SAAS;AAAA,UAChB;AAAA,QACF;AAAA,MACF;AAEA,aAAO;AAAA,QACL,UAAU;AAAA,UACR;AAAA,YACE,KAAK,SAAS;AAAA,YACd,UAAU,SAAS;AAAA,YACnB,GAAG;AAAA,UACL;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEQ,oBAAoB,QAAgB;AAC1C,WAAO,kBAAkB,0BAA0B,YAAY;AAC7D,aAAO;AAAA,QACL,SAAS,KAAK,SAAS,IAAI,CAAC,WAAW;AACrC,iBAAO;AAAA,YACL,MAAM,OAAO;AAAA,YACb,aAAa,OAAO;AAAA,YACpB,WAAW,OAAO;AAAA,UACpB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AAED,WAAO,kBAAkB,wBAAwB,OAAO,YAAY;AAClE,YAAM,SAAS,KAAK,SAAS;AAAA,QAC3B,CAACC,YAAWA,QAAO,SAAS,QAAQ,OAAO;AAAA,MAC7C;AAEA,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI;AAAA,UACR,UAAU;AAAA,UACV,mBAAmB,QAAQ,OAAO,IAAI;AAAA,QACxC;AAAA,MACF;AAEA,YAAM,OAAO,QAAQ,OAAO;AAE5B,UAAI,OAAO,WAAW;AACpB,mBAAW,OAAO,OAAO,WAAW;AAClC,cAAI,IAAI,YAAY,EAAE,QAAQ,IAAI,QAAQ,OAAO;AAC/C,kBAAM,IAAI;AAAA,cACR,UAAU;AAAA,cACV,8BAA8B,IAAI,IAAI;AAAA,YACxC;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,UAAI;AAEJ,UAAI;AACF,iBAAS,MAAM,OAAO,KAAK,IAA0C;AAAA,MACvE,SAAS,OAAO;AACd,cAAM,IAAI;AAAA,UACR,UAAU;AAAA,UACV,yBAAyB,KAAK;AAAA,QAChC;AAAA,MACF;AAEA,aAAO;AAAA,QACL,aAAa,OAAO;AAAA,QACpB,UAAU;AAAA,UACR;AAAA,YACE,MAAM;AAAA,YACN,SAAS,EAAE,MAAM,QAAQ,MAAM,OAAO;AAAA,UACxC;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKO,QAAuC,MAAoB;AAChE,SAAK,OAAO,KAAK,IAAuB;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKO,YAAY,UAAoB;AACrC,SAAK,WAAW,KAAK,QAAQ;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKO,UAA+C,QAAsB;AAC1E,SAAK,SAAS,KAAK,MAAM;AAAA,EAC3B;AAAA,EAEA,aAA+B;AAAA;AAAA;AAAA;AAAA,EAK/B,MAAa,MACX,UAKQ;AAAA,IACN,eAAe;AAAA,EACjB,GACA;AACA,UAAM,eAAmC,CAAC;AAE1C,QAAI,KAAK,OAAO,QAAQ;AACtB,mBAAa,QAAQ,CAAC;AAAA,IACxB;AAEA,QAAI,KAAK,WAAW,QAAQ;AAC1B,mBAAa,YAAY,CAAC;AAAA,IAC5B;AAEA,QAAI,KAAK,SAAS,QAAQ;AACxB,mBAAa,UAAU,CAAC;AAAA,IAC1B;AAEA,iBAAa,UAAU,CAAC;AAExB,SAAK,UAAU,IAAI;AAAA,MACjB,EAAE,MAAM,KAAK,SAAS,MAAM,SAAS,KAAK,SAAS,QAAQ;AAAA,MAC3D,EAAE,aAAa;AAAA,IACjB;AAEA,SAAK,cAAc,KAAK,OAAO;AAE/B,QAAI,QAAQ,kBAAkB,SAAS;AACrC,YAAM,YAAY,IAAI,qBAAqB;AAE3C,YAAM,KAAK,QAAQ,QAAQ,SAAS;AAEpC,cAAQ,MAAM,4BAA4B;AAAA,IAC5C,WAAW,QAAQ,kBAAkB,OAAO;AAC1C,WAAK,aAAa,MAAM,eAAe;AAAA,QACrC,UAAU,QAAQ,IAAI;AAAA,QACtB,MAAM,QAAQ,IAAI;AAAA,QAClB,QAAQ,KAAK;AAAA,MACf,CAAC;AAAA,IACH,OAAO;AACL,YAAM,IAAI,MAAM,wBAAwB;AAAA,IAC1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAa,OAAO;AAClB,QAAI,KAAK,YAAY;AACnB,WAAK,WAAW,MAAM;AAAA,IACxB;AAAA,EACF;AACF;","names":["tool","resource","prompt"]}
|
|
1
|
+
{"version":3,"sources":["../src/FastMCP.ts"],"sourcesContent":["import { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ErrorCode,\n GetPromptRequestSchema,\n ListPromptsRequestSchema,\n ListResourcesRequestSchema,\n ListToolsRequestSchema,\n McpError,\n ReadResourceRequestSchema,\n ServerCapabilities,\n SetLevelRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { zodToJsonSchema } from \"zod-to-json-schema\";\nimport { z } from \"zod\";\nimport { readFile } from \"fs/promises\";\nimport { fileTypeFromBuffer } from \"file-type\";\nimport { StrictEventEmitter } from \"strict-event-emitter-types\";\nimport { EventEmitter } from \"events\";\nimport { startSSEServer } from \"mcp-proxy\";\nimport { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\n\nexport type SSEServer = {\n close: () => Promise<void>;\n};\n\ntype FastMCPEvents = {\n connect: (event: { session: FastMCPSession }) => void;\n disconnect: (event: { session: FastMCPSession }) => void;\n};\n\n/**\n * Generates an image content object from a URL, file path, or buffer.\n */\nexport const imageContent = async (\n input: { url: string } | { path: string } | { buffer: Buffer },\n): Promise<ImageContent> => {\n let rawData: Buffer;\n\n if (\"url\" in input) {\n const response = await fetch(input.url);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch image from URL: ${response.statusText}`);\n }\n\n rawData = Buffer.from(await response.arrayBuffer());\n } else if (\"path\" in input) {\n rawData = await readFile(input.path);\n } else if (\"buffer\" in input) {\n rawData = input.buffer;\n } else {\n throw new Error(\n \"Invalid input: Provide a valid 'url', 'path', or 'buffer'\",\n );\n }\n\n const mimeType = await fileTypeFromBuffer(rawData);\n\n const base64Data = rawData.toString(\"base64\");\n\n return {\n type: \"image\",\n data: base64Data,\n mimeType: mimeType?.mime ?? \"image/png\",\n } as const;\n};\n\nabstract class FastMCPError extends Error {\n public constructor(message?: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\ntype Extra = unknown;\n\ntype Extras = Record<string, Extra>;\n\nclass UnexpectedStateError extends FastMCPError {\n public extras?: Extras;\n\n public constructor(message: string, extras?: Extras) {\n super(message);\n this.name = new.target.name;\n this.extras = extras;\n }\n}\n\n/**\n * An error that is meant to be surfaced to the user.\n */\nexport class UserError extends UnexpectedStateError {}\n\ntype ToolParameters = z.ZodTypeAny;\n\ntype Literal = boolean | null | number | string | undefined;\n\ntype SerializableValue =\n | Literal\n | SerializableValue[]\n | { [key: string]: SerializableValue };\n\ntype Progress = {\n /**\n * The progress thus far. This should increase every time progress is made, even if the total is unknown.\n */\n progress: number;\n /**\n * Total number of items to process (or total progress required), if known.\n */\n total?: number;\n};\n\ntype Context = {\n reportProgress: (progress: Progress) => Promise<void>;\n log: {\n debug: (message: string, data?: SerializableValue) => void;\n error: (message: string, data?: SerializableValue) => void;\n info: (message: string, data?: SerializableValue) => void;\n warn: (message: string, data?: SerializableValue) => void;\n };\n};\n\ntype TextContent = {\n type: \"text\";\n text: string;\n};\n\nconst TextContentZodSchema = z\n .object({\n type: z.literal(\"text\"),\n /**\n * The text content of the message.\n */\n text: z.string(),\n })\n .strict() satisfies z.ZodType<TextContent>;\n\ntype ImageContent = {\n type: \"image\";\n data: string;\n mimeType: string;\n};\n\nconst ImageContentZodSchema = z\n .object({\n type: z.literal(\"image\"),\n /**\n * The base64-encoded image data.\n */\n data: z.string().base64(),\n /**\n * The MIME type of the image. Different providers may support different image types.\n */\n mimeType: z.string(),\n })\n .strict() satisfies z.ZodType<ImageContent>;\n\ntype Content = TextContent | ImageContent;\n\nconst ContentZodSchema = z.discriminatedUnion(\"type\", [\n TextContentZodSchema,\n ImageContentZodSchema,\n]) satisfies z.ZodType<Content>;\n\ntype ContentResult = {\n content: Content[];\n isError?: boolean;\n};\n\nconst ContentResultZodSchema = z\n .object({\n content: ContentZodSchema.array(),\n isError: z.boolean().optional(),\n })\n .strict() satisfies z.ZodType<ContentResult>;\n\ntype Tool<Params extends ToolParameters = ToolParameters> = {\n name: string;\n description?: string;\n parameters?: Params;\n execute: (\n args: z.infer<Params>,\n context: Context,\n ) => Promise<string | ContentResult | TextContent | ImageContent>;\n};\n\ntype Resource = {\n uri: string;\n name: string;\n description?: string;\n mimeType?: string;\n load: () => Promise<{ text: string } | { blob: string }>;\n};\n\ntype PromptArgument = Readonly<{\n name: string;\n description?: string;\n required?: boolean;\n}>;\n\ntype ArgumentsToObject<T extends PromptArgument[]> = {\n [K in T[number][\"name\"]]: Extract<\n T[number],\n { name: K }\n >[\"required\"] extends true\n ? string\n : string | undefined;\n};\n\ntype Prompt<\n Arguments extends PromptArgument[] = PromptArgument[],\n Args = ArgumentsToObject<Arguments>,\n> = {\n name: string;\n description?: string;\n arguments?: Arguments;\n load: (args: Args) => Promise<string>;\n};\n\ntype ServerOptions = {\n name: string;\n version: `${number}.${number}.${number}`;\n};\n\ntype LoggingLevel =\n | \"debug\"\n | \"info\"\n | \"notice\"\n | \"warning\"\n | \"error\"\n | \"critical\"\n | \"alert\"\n | \"emergency\";\n\nexport class FastMCPSession {\n #capabilities: ServerCapabilities = {};\n #loggingLevel: LoggingLevel = \"info\";\n #server: Server;\n\n constructor({\n name,\n version,\n tools,\n resources,\n prompts,\n }: {\n name: string;\n version: string;\n tools: Tool[];\n resources: Resource[];\n prompts: Prompt[];\n }) {\n if (tools.length) {\n this.#capabilities.tools = {};\n }\n\n if (resources.length) {\n this.#capabilities.resources = {};\n }\n\n if (prompts.length) {\n this.#capabilities.prompts = {};\n }\n\n this.#capabilities.logging = {};\n\n this.#server = new Server(\n { name: name, version: version },\n { capabilities: this.#capabilities },\n );\n\n this.setupErrorHandling();\n this.setupLoggingHandlers();\n\n if (tools.length) {\n this.setupToolHandlers(tools);\n }\n\n if (resources.length) {\n this.setupResourceHandlers(resources);\n }\n\n if (prompts.length) {\n this.setupPromptHandlers(prompts);\n }\n }\n\n public get server(): Server {\n return this.#server;\n }\n\n public connect(transport: Transport) {\n this.#server.connect(transport);\n }\n\n private setupErrorHandling() {\n this.#server.onerror = (error) => {\n console.error(\"[MCP Error]\", error);\n };\n }\n\n public get loggingLevel(): LoggingLevel {\n return this.#loggingLevel;\n }\n\n private setupLoggingHandlers() {\n this.#server.setRequestHandler(SetLevelRequestSchema, (request) => {\n this.#loggingLevel = request.params.level;\n\n return {};\n });\n }\n\n private setupToolHandlers(tools: Tool[]) {\n this.#server.setRequestHandler(ListToolsRequestSchema, async () => {\n return {\n tools: tools.map((tool) => {\n return {\n name: tool.name,\n description: tool.description,\n inputSchema: tool.parameters\n ? zodToJsonSchema(tool.parameters)\n : undefined,\n };\n }),\n };\n });\n\n this.#server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const tool = tools.find((tool) => tool.name === request.params.name);\n\n if (!tool) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown tool: ${request.params.name}`,\n );\n }\n\n let args: any = undefined;\n\n if (tool.parameters) {\n const parsed = tool.parameters.safeParse(request.params.arguments);\n\n if (!parsed.success) {\n throw new McpError(\n ErrorCode.InvalidRequest,\n `Invalid ${request.params.name} arguments`,\n );\n }\n\n args = parsed.data;\n }\n\n const progressToken = request.params?._meta?.progressToken;\n\n let result: ContentResult;\n\n try {\n const reportProgress = async (progress: Progress) => {\n await this.#server.notification({\n method: \"notifications/progress\",\n params: {\n ...progress,\n progressToken,\n },\n });\n };\n\n const log = {\n debug: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n level: \"debug\",\n data: {\n message,\n context,\n },\n });\n },\n error: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n level: \"error\",\n data: {\n message,\n context,\n },\n });\n },\n info: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n level: \"info\",\n data: {\n message,\n context,\n },\n });\n },\n warn: (message: string, context?: SerializableValue) => {\n this.#server.sendLoggingMessage({\n level: \"warning\",\n data: {\n message,\n context,\n },\n });\n },\n };\n\n const maybeStringResult = await tool.execute(args, {\n reportProgress,\n log,\n });\n\n if (typeof maybeStringResult === \"string\") {\n result = ContentResultZodSchema.parse({\n content: [{ type: \"text\", text: maybeStringResult }],\n });\n } else if (\"type\" in maybeStringResult) {\n result = ContentResultZodSchema.parse({\n content: [maybeStringResult],\n });\n } else {\n result = ContentResultZodSchema.parse(maybeStringResult);\n }\n } catch (error) {\n if (error instanceof UserError) {\n return {\n content: [{ type: \"text\", text: error.message }],\n isError: true,\n };\n }\n\n return {\n content: [{ type: \"text\", text: `Error: ${error}` }],\n isError: true,\n };\n }\n\n return result;\n });\n }\n\n private setupResourceHandlers(resources: Resource[]) {\n this.#server.setRequestHandler(ListResourcesRequestSchema, async () => {\n return {\n resources: resources.map((resource) => {\n return {\n uri: resource.uri,\n name: resource.name,\n mimeType: resource.mimeType,\n };\n }),\n };\n });\n\n this.#server.setRequestHandler(\n ReadResourceRequestSchema,\n async (request) => {\n const resource = resources.find(\n (resource) => resource.uri === request.params.uri,\n );\n\n if (!resource) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown resource: ${request.params.uri}`,\n );\n }\n\n let result: Awaited<ReturnType<Resource[\"load\"]>>;\n\n try {\n result = await resource.load();\n } catch (error) {\n throw new McpError(\n ErrorCode.InternalError,\n `Error reading resource: ${error}`,\n {\n uri: resource.uri,\n },\n );\n }\n\n return {\n contents: [\n {\n uri: resource.uri,\n mimeType: resource.mimeType,\n ...result,\n },\n ],\n };\n },\n );\n }\n\n private setupPromptHandlers(prompts: Prompt[]) {\n this.#server.setRequestHandler(ListPromptsRequestSchema, async () => {\n return {\n prompts: prompts.map((prompt) => {\n return {\n name: prompt.name,\n description: prompt.description,\n arguments: prompt.arguments,\n };\n }),\n };\n });\n\n this.#server.setRequestHandler(GetPromptRequestSchema, async (request) => {\n const prompt = prompts.find(\n (prompt) => prompt.name === request.params.name,\n );\n\n if (!prompt) {\n throw new McpError(\n ErrorCode.MethodNotFound,\n `Unknown prompt: ${request.params.name}`,\n );\n }\n\n const args = request.params.arguments;\n\n if (prompt.arguments) {\n for (const arg of prompt.arguments) {\n if (arg.required && !(args && arg.name in args)) {\n throw new McpError(\n ErrorCode.InvalidRequest,\n `Missing required argument: ${arg.name}`,\n );\n }\n }\n }\n\n let result: Awaited<ReturnType<Prompt[\"load\"]>>;\n\n try {\n result = await prompt.load(args as Record<string, string | undefined>);\n } catch (error) {\n throw new McpError(\n ErrorCode.InternalError,\n `Error loading prompt: ${error}`,\n );\n }\n\n return {\n description: prompt.description,\n messages: [\n {\n role: \"user\",\n content: { type: \"text\", text: result },\n },\n ],\n };\n });\n }\n}\n\nconst FastMCPEventEmitterBase: {\n new (): StrictEventEmitter<EventEmitter, FastMCPEvents>;\n} = EventEmitter;\n\nclass FastMCPEventEmitter extends FastMCPEventEmitterBase {}\n\nexport class FastMCP extends FastMCPEventEmitter {\n #options: ServerOptions;\n #prompts: Prompt[] = [];\n #resources: Resource[] = [];\n #sessions: FastMCPSession[] = [];\n #sseServer: SSEServer | null = null;\n #tools: Tool[] = [];\n\n constructor(public options: ServerOptions) {\n super();\n\n this.#options = options;\n }\n\n public get sessions(): FastMCPSession[] {\n return this.#sessions;\n }\n\n /**\n * Adds a tool to the server.\n */\n public addTool<Params extends ToolParameters>(tool: Tool<Params>) {\n this.#tools.push(tool as unknown as Tool);\n }\n\n /**\n * Adds a resource to the server.\n */\n public addResource(resource: Resource) {\n this.#resources.push(resource);\n }\n\n /**\n * Adds a prompt to the server.\n */\n public addPrompt<const Args extends PromptArgument[]>(prompt: Prompt<Args>) {\n this.#prompts.push(prompt);\n }\n\n /**\n * Starts the server.\n */\n public async start(\n options:\n | { transportType: \"stdio\" }\n | {\n transportType: \"sse\";\n sse: { endpoint: `/${string}`; port: number };\n } = {\n transportType: \"stdio\",\n },\n ) {\n if (options.transportType === \"stdio\") {\n const transport = new StdioServerTransport();\n\n const session = new FastMCPSession({\n name: this.#options.name,\n version: this.#options.version,\n tools: this.#tools,\n resources: this.#resources,\n prompts: this.#prompts,\n });\n\n await session.connect(transport);\n\n this.#sessions.push(session);\n\n this.emit(\"connect\", {\n session,\n });\n\n console.error(`server is running on stdio`);\n } else if (options.transportType === \"sse\") {\n this.#sseServer = await startSSEServer({\n endpoint: options.sse.endpoint as `/${string}`,\n port: options.sse.port,\n createServer: async () => {\n const session = new FastMCPSession({\n name: this.#options.name,\n version: this.#options.version,\n tools: this.#tools,\n resources: this.#resources,\n prompts: this.#prompts,\n });\n\n this.#sessions.push(session);\n\n return session.server;\n },\n onClose: (server) => {\n const session = this.#sessions.find(\n (session) => session.server === server,\n );\n\n if (!session) {\n throw new UnexpectedStateError(\"Server not found\");\n }\n\n this.#sessions = this.#sessions.filter(\n (maybeOurSession) => maybeOurSession !== session,\n );\n\n this.emit(\"disconnect\", {\n session,\n });\n },\n onConnect: async (server) => {\n const session = this.#sessions.find(\n (session) => session.server === server,\n );\n\n if (!session) {\n throw new UnexpectedStateError(\"Server not found\");\n }\n\n // TODO investigate where is the race condition\n setTimeout(() => {\n this.emit(\"connect\", {\n session,\n });\n }, 100);\n },\n });\n\n console.error(\n `server is running on SSE at http://localhost:${options.sse.port}${options.sse.endpoint}`,\n );\n } else {\n throw new Error(\"Invalid transport type\");\n }\n }\n\n /**\n * Stops the server.\n */\n public async stop() {\n if (this.#sseServer) {\n this.#sseServer.close();\n }\n }\n}\n"],"mappings":"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","names":["tool","resource","prompt","session"]}
|