fastmcp 1.22.4 → 1.23.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/src/FastMCP.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
2
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
3
4
  import {
4
5
  AudioContent,
5
6
  CallToolRequestSchema,
@@ -20,21 +21,18 @@ import {
20
21
  SetLevelRequestSchema,
21
22
  } from "@modelcontextprotocol/sdk/types.js";
22
23
  import { StandardSchemaV1 } from "@standard-schema/spec";
23
- import { toJsonSchema } from "xsschema";
24
- import { z } from "zod";
25
- import { setTimeout as delay } from "timers/promises";
26
- import { readFile } from "fs/promises";
27
- import { fileTypeFromBuffer } from "file-type";
28
- import { StrictEventEmitter } from "strict-event-emitter-types";
29
24
  import { EventEmitter } from "events";
25
+ import { fileTypeFromBuffer } from "file-type";
26
+ import { readFile } from "fs/promises";
30
27
  import Fuse from "fuse.js";
28
+ import http from "http";
31
29
  import { startSSEServer } from "mcp-proxy";
32
- import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
30
+ import { StrictEventEmitter } from "strict-event-emitter-types";
31
+ import { setTimeout as delay } from "timers/promises";
32
+ import { fetch } from "undici";
33
33
  import parseURITemplate from "uri-templates";
34
- import http from "http";
35
- import {
36
- fetch
37
- } from "undici";
34
+ import { toJsonSchema } from "xsschema";
35
+ import { z } from "zod";
38
36
 
39
37
  export type SSEServer = {
40
38
  close: () => Promise<void>;
@@ -46,15 +44,15 @@ type FastMCPEvents<T extends FastMCPSessionAuth> = {
46
44
  };
47
45
 
48
46
  type FastMCPSessionEvents = {
49
- rootsChanged: (event: { roots: Root[] }) => void;
50
47
  error: (event: { error: Error }) => void;
48
+ rootsChanged: (event: { roots: Root[] }) => void;
51
49
  };
52
50
 
53
51
  /**
54
52
  * Generates an image content object from a URL, file path, or buffer.
55
53
  */
56
54
  export const imageContent = async (
57
- input: { url: string } | { path: string } | { buffer: Buffer },
55
+ input: { buffer: Buffer } | { path: string } | { url: string },
58
56
  ): Promise<ImageContent> => {
59
57
  let rawData: Buffer;
60
58
 
@@ -81,13 +79,15 @@ export const imageContent = async (
81
79
  const base64Data = rawData.toString("base64");
82
80
 
83
81
  return {
84
- type: "image",
85
82
  data: base64Data,
86
83
  mimeType: mimeType?.mime ?? "image/png",
84
+ type: "image",
87
85
  } as const;
88
86
  };
89
87
 
90
- export const audioContent = async (input: { url: string } | { path: string } | { buffer: Buffer }): Promise<AudioContent> => {
88
+ export const audioContent = async (
89
+ input: { buffer: Buffer } | { path: string } | { url: string },
90
+ ): Promise<AudioContent> => {
91
91
  let rawData: Buffer;
92
92
 
93
93
  if ("url" in input) {
@@ -103,7 +103,9 @@ export const audioContent = async (input: { url: string } | { path: string } | {
103
103
  } else if ("buffer" in input) {
104
104
  rawData = input.buffer;
105
105
  } else {
106
- throw new Error("Invalid input: Provide a valid 'url', 'path', or 'buffer'");
106
+ throw new Error(
107
+ "Invalid input: Provide a valid 'url', 'path', or 'buffer'",
108
+ );
107
109
  }
108
110
 
109
111
  const mimeType = await fileTypeFromBuffer(rawData);
@@ -111,47 +113,29 @@ export const audioContent = async (input: { url: string } | { path: string } | {
111
113
  const base64Data = rawData.toString("base64");
112
114
 
113
115
  return {
114
- type: "audio",
115
116
  data: base64Data,
116
117
  mimeType: mimeType?.mime ?? "audio/mpeg",
118
+ type: "audio",
117
119
  } as const;
118
120
  };
119
121
 
120
- abstract class FastMCPError extends Error {
121
- public constructor(message?: string) {
122
- super(message);
123
- this.name = new.target.name;
124
- }
125
- }
122
+ type Context<T extends FastMCPSessionAuth> = {
123
+ log: {
124
+ debug: (message: string, data?: SerializableValue) => void;
125
+ error: (message: string, data?: SerializableValue) => void;
126
+ info: (message: string, data?: SerializableValue) => void;
127
+ warn: (message: string, data?: SerializableValue) => void;
128
+ };
129
+ reportProgress: (progress: Progress) => Promise<void>;
130
+ session: T | undefined;
131
+ };
126
132
 
127
133
  type Extra = unknown;
128
134
 
129
135
  type Extras = Record<string, Extra>;
130
136
 
131
- export class UnexpectedStateError extends FastMCPError {
132
- public extras?: Extras;
133
-
134
- public constructor(message: string, extras?: Extras) {
135
- super(message);
136
- this.name = new.target.name;
137
- this.extras = extras;
138
- }
139
- }
140
-
141
- /**
142
- * An error that is meant to be surfaced to the user.
143
- */
144
- export class UserError extends UnexpectedStateError {}
145
-
146
- type ToolParameters = StandardSchemaV1;
147
-
148
137
  type Literal = boolean | null | number | string | undefined;
149
138
 
150
- type SerializableValue =
151
- | Literal
152
- | SerializableValue[]
153
- | { [key: string]: SerializableValue };
154
-
155
139
  type Progress = {
156
140
  /**
157
141
  * The progress thus far. This should increase every time progress is made, even if the total is unknown.
@@ -163,41 +147,58 @@ type Progress = {
163
147
  total?: number;
164
148
  };
165
149
 
166
- type Context<T extends FastMCPSessionAuth> = {
167
- session: T | undefined;
168
- reportProgress: (progress: Progress) => Promise<void>;
169
- log: {
170
- debug: (message: string, data?: SerializableValue) => void;
171
- error: (message: string, data?: SerializableValue) => void;
172
- info: (message: string, data?: SerializableValue) => void;
173
- warn: (message: string, data?: SerializableValue) => void;
174
- };
175
- };
150
+ type SerializableValue =
151
+ | { [key: string]: SerializableValue }
152
+ | Literal
153
+ | SerializableValue[];
176
154
 
177
155
  type TextContent = {
178
- type: "text";
179
156
  text: string;
157
+ type: "text";
180
158
  };
181
159
 
160
+ type ToolParameters = StandardSchemaV1;
161
+
162
+ abstract class FastMCPError extends Error {
163
+ public constructor(message?: string) {
164
+ super(message);
165
+ this.name = new.target.name;
166
+ }
167
+ }
168
+
169
+ export class UnexpectedStateError extends FastMCPError {
170
+ public extras?: Extras;
171
+
172
+ public constructor(message: string, extras?: Extras) {
173
+ super(message);
174
+ this.name = new.target.name;
175
+ this.extras = extras;
176
+ }
177
+ }
178
+
179
+ /**
180
+ * An error that is meant to be surfaced to the user.
181
+ */
182
+ export class UserError extends UnexpectedStateError {}
183
+
182
184
  const TextContentZodSchema = z
183
185
  .object({
184
- type: z.literal("text"),
185
186
  /**
186
187
  * The text content of the message.
187
188
  */
188
189
  text: z.string(),
190
+ type: z.literal("text"),
189
191
  })
190
192
  .strict() satisfies z.ZodType<TextContent>;
191
193
 
192
194
  type ImageContent = {
193
- type: "image";
194
195
  data: string;
195
196
  mimeType: string;
197
+ type: "image";
196
198
  };
197
199
 
198
200
  const ImageContentZodSchema = z
199
201
  .object({
200
- type: z.literal("image"),
201
202
  /**
202
203
  * The base64-encoded image data.
203
204
  */
@@ -206,10 +207,11 @@ const ImageContentZodSchema = z
206
207
  * The MIME type of the image. Different providers may support different image types.
207
208
  */
208
209
  mimeType: z.string(),
210
+ type: z.literal("image"),
209
211
  })
210
212
  .strict() satisfies z.ZodType<ImageContent>;
211
213
 
212
- type Content = TextContent | ImageContent;
214
+ type Content = ImageContent | TextContent;
213
215
 
214
216
  const ContentZodSchema = z.discriminatedUnion("type", [
215
217
  TextContentZodSchema,
@@ -229,9 +231,9 @@ const ContentResultZodSchema = z
229
231
  .strict() satisfies z.ZodType<ContentResult>;
230
232
 
231
233
  type Completion = {
232
- values: string[];
233
- total?: number;
234
234
  hasMore?: boolean;
235
+ total?: number;
236
+ values: string[];
235
237
  };
236
238
 
237
239
  /**
@@ -239,97 +241,85 @@ type Completion = {
239
241
  */
240
242
  const CompletionZodSchema = z.object({
241
243
  /**
242
- * An array of completion values. Must not exceed 100 items.
244
+ * Indicates whether there are additional completion options beyond those provided in the current response, even if the exact total is unknown.
243
245
  */
244
- values: z.array(z.string()).max(100),
246
+ hasMore: z.optional(z.boolean()),
245
247
  /**
246
248
  * The total number of completion options available. This can exceed the number of values actually sent in the response.
247
249
  */
248
250
  total: z.optional(z.number().int()),
249
251
  /**
250
- * Indicates whether there are additional completion options beyond those provided in the current response, even if the exact total is unknown.
252
+ * An array of completion values. Must not exceed 100 items.
251
253
  */
252
- hasMore: z.optional(z.boolean()),
254
+ values: z.array(z.string()).max(100),
253
255
  }) satisfies z.ZodType<Completion>;
254
256
 
255
- type Tool<T extends FastMCPSessionAuth, Params extends ToolParameters = ToolParameters> = {
256
- name: string;
257
+ type ArgumentValueCompleter = (value: string) => Promise<Completion>;
258
+
259
+ type InputPrompt<
260
+ Arguments extends InputPromptArgument[] = InputPromptArgument[],
261
+ Args = PromptArgumentsToObject<Arguments>,
262
+ > = {
263
+ arguments?: InputPromptArgument[];
257
264
  description?: string;
258
- parameters?: Params;
259
- execute: (
260
- args: StandardSchemaV1.InferOutput<Params>,
261
- context: Context<T>,
262
- ) => Promise<string | ContentResult | TextContent | ImageContent | AudioContent>;
265
+ load: (args: Args) => Promise<string>;
266
+ name: string;
263
267
  };
264
268
 
265
- type ResourceResult =
266
- | {
267
- text: string;
268
- }
269
- | {
270
- blob: string;
271
- };
272
-
273
- type InputResourceTemplateArgument = Readonly<{
274
- name: string;
275
- description?: string;
269
+ type InputPromptArgument = Readonly<{
276
270
  complete?: ArgumentValueCompleter;
277
- }>;
278
-
279
- type ResourceTemplateArgument = Readonly<{
280
- name: string;
281
271
  description?: string;
282
- complete?: ArgumentValueCompleter;
272
+ enum?: string[];
273
+ name: string;
274
+ required?: boolean;
283
275
  }>;
284
276
 
285
- type ResourceTemplate<
277
+ type InputResourceTemplate<
286
278
  Arguments extends ResourceTemplateArgument[] = ResourceTemplateArgument[],
287
279
  > = {
288
- uriTemplate: string;
289
- name: string;
290
- description?: string;
291
- mimeType?: string;
292
280
  arguments: Arguments;
293
- complete?: (name: string, value: string) => Promise<Completion>;
281
+ description?: string;
294
282
  load: (
295
283
  args: ResourceTemplateArgumentsToObject<Arguments>,
296
284
  ) => Promise<ResourceResult>;
285
+ mimeType?: string;
286
+ name: string;
287
+ uriTemplate: string;
297
288
  };
298
289
 
299
- type ResourceTemplateArgumentsToObject<T extends { name: string }[]> = {
300
- [K in T[number]["name"]]: string;
301
- };
290
+ type InputResourceTemplateArgument = Readonly<{
291
+ complete?: ArgumentValueCompleter;
292
+ description?: string;
293
+ name: string;
294
+ }>;
302
295
 
303
- type InputResourceTemplate<
304
- Arguments extends ResourceTemplateArgument[] = ResourceTemplateArgument[],
296
+ type LoggingLevel =
297
+ | "alert"
298
+ | "critical"
299
+ | "debug"
300
+ | "emergency"
301
+ | "error"
302
+ | "info"
303
+ | "notice"
304
+ | "warning";
305
+
306
+ type Prompt<
307
+ Arguments extends PromptArgument[] = PromptArgument[],
308
+ Args = PromptArgumentsToObject<Arguments>,
305
309
  > = {
306
- uriTemplate: string;
307
- name: string;
310
+ arguments?: PromptArgument[];
311
+ complete?: (name: string, value: string) => Promise<Completion>;
308
312
  description?: string;
309
- mimeType?: string;
310
- arguments: Arguments;
311
- load: (
312
- args: ResourceTemplateArgumentsToObject<Arguments>,
313
- ) => Promise<ResourceResult>;
314
- };
315
-
316
- type Resource = {
317
- uri: string;
313
+ load: (args: Args) => Promise<string>;
318
314
  name: string;
319
- description?: string;
320
- mimeType?: string;
321
- load: () => Promise<ResourceResult | ResourceResult[]>;
322
- complete?: (name: string, value: string) => Promise<Completion>;
323
315
  };
324
316
 
325
- type ArgumentValueCompleter = (value: string) => Promise<Completion>;
326
-
327
- type InputPromptArgument = Readonly<{
328
- name: string;
329
- description?: string;
330
- required?: boolean;
317
+ type PromptArgument = Readonly<{
331
318
  complete?: ArgumentValueCompleter;
319
+ description?: string;
332
320
  enum?: string[];
321
+ name: string;
322
+ required?: boolean;
333
323
  }>;
334
324
 
335
325
  type PromptArgumentsToObject<T extends { name: string; required?: boolean }[]> =
@@ -342,93 +332,171 @@ type PromptArgumentsToObject<T extends { name: string; required?: boolean }[]> =
342
332
  : string | undefined;
343
333
  };
344
334
 
345
- type InputPrompt<
346
- Arguments extends InputPromptArgument[] = InputPromptArgument[],
347
- Args = PromptArgumentsToObject<Arguments>,
348
- > = {
349
- name: string;
335
+ type Resource = {
336
+ complete?: (name: string, value: string) => Promise<Completion>;
350
337
  description?: string;
351
- arguments?: InputPromptArgument[];
352
- load: (args: Args) => Promise<string>;
338
+ load: () => Promise<ResourceResult | ResourceResult[]>;
339
+ mimeType?: string;
340
+ name: string;
341
+ uri: string;
353
342
  };
354
343
 
355
- type PromptArgument = Readonly<{
356
- name: string;
357
- description?: string;
358
- required?: boolean;
359
- complete?: ArgumentValueCompleter;
360
- enum?: string[];
361
- }>;
344
+ type ResourceResult =
345
+ | {
346
+ blob: string;
347
+ }
348
+ | {
349
+ text: string;
350
+ };
362
351
 
363
- type Prompt<
364
- Arguments extends PromptArgument[] = PromptArgument[],
365
- Args = PromptArgumentsToObject<Arguments>,
352
+ type ResourceTemplate<
353
+ Arguments extends ResourceTemplateArgument[] = ResourceTemplateArgument[],
366
354
  > = {
367
- arguments?: PromptArgument[];
355
+ arguments: Arguments;
368
356
  complete?: (name: string, value: string) => Promise<Completion>;
369
357
  description?: string;
370
- load: (args: Args) => Promise<string>;
358
+ load: (
359
+ args: ResourceTemplateArgumentsToObject<Arguments>,
360
+ ) => Promise<ResourceResult>;
361
+ mimeType?: string;
371
362
  name: string;
363
+ uriTemplate: string;
372
364
  };
373
365
 
374
- type ServerOptions<T extends FastMCPSessionAuth> = {
366
+ type ResourceTemplateArgument = Readonly<{
367
+ complete?: ArgumentValueCompleter;
368
+ description?: string;
375
369
  name: string;
376
- version: `${number}.${number}.${number}`;
370
+ }>;
371
+
372
+ type ResourceTemplateArgumentsToObject<T extends { name: string }[]> = {
373
+ [K in T[number]["name"]]: string;
374
+ };
375
+
376
+ type ServerOptions<T extends FastMCPSessionAuth> = {
377
377
  authenticate?: Authenticate<T>;
378
+ instructions?: string;
379
+ name: string;
380
+ version: `${number}.${number}.${number}`;
378
381
  };
379
382
 
380
- type LoggingLevel =
381
- | "debug"
382
- | "info"
383
- | "notice"
384
- | "warning"
385
- | "error"
386
- | "critical"
387
- | "alert"
388
- | "emergency";
383
+ type Tool<
384
+ T extends FastMCPSessionAuth,
385
+ Params extends ToolParameters = ToolParameters,
386
+ > = {
387
+ annotations?: ToolAnnotations;
388
+ description?: string;
389
+ execute: (
390
+ args: StandardSchemaV1.InferOutput<Params>,
391
+ context: Context<T>,
392
+ ) => Promise<
393
+ AudioContent | ContentResult | ImageContent | string | TextContent
394
+ >;
395
+ name: string;
396
+ parameters?: Params;
397
+ };
398
+
399
+ /**
400
+ * Tool annotations as defined in MCP Specification (2025-03-26)
401
+ * These provide hints about a tool's behavior.
402
+ */
403
+ type ToolAnnotations = {
404
+ /**
405
+ * If true, the tool may perform destructive updates
406
+ * Only meaningful when readOnlyHint is false
407
+ * @default true
408
+ */
409
+ destructiveHint?: boolean;
410
+
411
+ /**
412
+ * If true, calling the tool repeatedly with the same arguments has no additional effect
413
+ * Only meaningful when readOnlyHint is false
414
+ * @default false
415
+ */
416
+ idempotentHint?: boolean;
417
+
418
+ /**
419
+ * If true, the tool may interact with an "open world" of external entities
420
+ * @default true
421
+ */
422
+ openWorldHint?: boolean;
423
+
424
+ /**
425
+ * If true, indicates the tool does not modify its environment
426
+ * @default false
427
+ */
428
+ readOnlyHint?: boolean;
429
+
430
+ /**
431
+ * A human-readable title for the tool, useful for UI display
432
+ */
433
+ title?: string;
434
+ };
389
435
 
390
436
  const FastMCPSessionEventEmitterBase: {
391
437
  new (): StrictEventEmitter<EventEmitter, FastMCPSessionEvents>;
392
438
  } = EventEmitter;
393
439
 
394
- class FastMCPSessionEventEmitter extends FastMCPSessionEventEmitterBase {}
440
+ type FastMCPSessionAuth = Record<string, unknown> | undefined;
395
441
 
396
442
  type SamplingResponse = {
443
+ content: AudioContent | ImageContent | TextContent;
397
444
  model: string;
398
- stopReason?: "endTurn" | "stopSequence" | "maxTokens" | string;
399
- role: "user" | "assistant";
400
- content: TextContent | ImageContent | AudioContent;
445
+ role: "assistant" | "user";
446
+ stopReason?: "endTurn" | "maxTokens" | "stopSequence" | string;
401
447
  };
402
448
 
403
- type FastMCPSessionAuth = Record<string, unknown> | undefined;
449
+ class FastMCPSessionEventEmitter extends FastMCPSessionEventEmitterBase {}
404
450
 
405
- export class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth> extends FastMCPSessionEventEmitter {
451
+ export class FastMCPSession<
452
+ T extends FastMCPSessionAuth = FastMCPSessionAuth,
453
+ > extends FastMCPSessionEventEmitter {
454
+ public get clientCapabilities(): ClientCapabilities | null {
455
+ return this.#clientCapabilities ?? null;
456
+ }
457
+ public get loggingLevel(): LoggingLevel {
458
+ return this.#loggingLevel;
459
+ }
460
+ public get roots(): Root[] {
461
+ return this.#roots;
462
+ }
463
+ public get server(): Server {
464
+ return this.#server;
465
+ }
466
+ #auth: T | undefined;
406
467
  #capabilities: ServerCapabilities = {};
407
468
  #clientCapabilities?: ClientCapabilities;
408
469
  #loggingLevel: LoggingLevel = "info";
470
+ #pingInterval: null | ReturnType<typeof setInterval> = null;
471
+
409
472
  #prompts: Prompt[] = [];
473
+
410
474
  #resources: Resource[] = [];
475
+
411
476
  #resourceTemplates: ResourceTemplate[] = [];
477
+
412
478
  #roots: Root[] = [];
479
+
413
480
  #server: Server;
414
- #auth: T | undefined;
415
481
 
416
482
  constructor({
417
483
  auth,
484
+ instructions,
418
485
  name,
419
- version,
420
- tools,
486
+ prompts,
421
487
  resources,
422
488
  resourcesTemplates,
423
- prompts,
489
+ tools,
490
+ version,
424
491
  }: {
425
492
  auth?: T;
493
+ instructions?: string;
426
494
  name: string;
427
- version: string;
428
- tools: Tool<T>[];
495
+ prompts: Prompt[];
429
496
  resources: Resource[];
430
497
  resourcesTemplates: InputResourceTemplate[];
431
- prompts: Prompt[];
498
+ tools: Tool<T>[];
499
+ version: string;
432
500
  }) {
433
501
  super();
434
502
 
@@ -454,7 +522,7 @@ export class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth> e
454
522
 
455
523
  this.#server = new Server(
456
524
  { name: name, version: version },
457
- { capabilities: this.#capabilities },
525
+ { capabilities: this.#capabilities, instructions: instructions },
458
526
  );
459
527
 
460
528
  this.setupErrorHandling();
@@ -487,33 +555,72 @@ export class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth> e
487
555
  }
488
556
  }
489
557
 
490
- private addResource(inputResource: Resource) {
491
- this.#resources.push(inputResource);
558
+ public async close() {
559
+ if (this.#pingInterval) {
560
+ clearInterval(this.#pingInterval);
561
+ }
562
+
563
+ try {
564
+ await this.#server.close();
565
+ } catch (error) {
566
+ console.error("[FastMCP error]", "could not close server", error);
567
+ }
492
568
  }
493
569
 
494
- private addResourceTemplate(inputResourceTemplate: InputResourceTemplate) {
495
- const completers: Record<string, ArgumentValueCompleter> = {};
570
+ public async connect(transport: Transport) {
571
+ if (this.#server.transport) {
572
+ throw new UnexpectedStateError("Server is already connected");
573
+ }
496
574
 
497
- for (const argument of inputResourceTemplate.arguments ?? []) {
498
- if (argument.complete) {
499
- completers[argument.name] = argument.complete;
575
+ await this.#server.connect(transport);
576
+
577
+ let attempt = 0;
578
+
579
+ while (attempt++ < 10) {
580
+ const capabilities = await this.#server.getClientCapabilities();
581
+
582
+ if (capabilities) {
583
+ this.#clientCapabilities = capabilities;
584
+
585
+ break;
500
586
  }
587
+
588
+ await delay(100);
501
589
  }
502
590
 
503
- const resourceTemplate = {
504
- ...inputResourceTemplate,
505
- complete: async (name: string, value: string) => {
506
- if (completers[name]) {
507
- return await completers[name](value);
508
- }
591
+ if (!this.#clientCapabilities) {
592
+ console.warn("[FastMCP warning] could not infer client capabilities");
593
+ }
509
594
 
510
- return {
511
- values: [],
512
- };
513
- },
514
- };
595
+ if (this.#clientCapabilities?.roots?.listChanged) {
596
+ try {
597
+ const roots = await this.#server.listRoots();
598
+ this.#roots = roots.roots;
599
+ } catch (e) {
600
+ console.error(
601
+ `[FastMCP error] received error listing roots.\n\n${e instanceof Error ? e.stack : JSON.stringify(e)}`,
602
+ );
603
+ }
604
+ }
515
605
 
516
- this.#resourceTemplates.push(resourceTemplate);
606
+ if (this.#clientCapabilities) {
607
+ this.#pingInterval = setInterval(async () => {
608
+ try {
609
+ await this.#server.ping();
610
+ } catch {
611
+ // The reason we are not emitting an error here is because some clients
612
+ // seem to not respond to the ping request, and we don't want to crash the server,
613
+ // e.g., https://github.com/punkpeye/fastmcp/issues/38.
614
+ console.warn("[FastMCP warning] server is not responding to ping");
615
+ }
616
+ }, 1000);
617
+ }
618
+ }
619
+
620
+ public async requestSampling(
621
+ message: z.infer<typeof CreateMessageRequestSchema>["params"],
622
+ ): Promise<SamplingResponse> {
623
+ return this.#server.createMessage(message);
517
624
  }
518
625
 
519
626
  private addPrompt(inputPrompt: InputPrompt) {
@@ -545,8 +652,8 @@ export class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth> e
545
652
  const result = fuse.search(value);
546
653
 
547
654
  return {
548
- values: result.map((item) => item.item),
549
655
  total: result.length,
656
+ values: result.map((item) => item.item),
550
657
  };
551
658
  }
552
659
 
@@ -559,94 +666,33 @@ export class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth> e
559
666
  this.#prompts.push(prompt);
560
667
  }
561
668
 
562
- public get clientCapabilities(): ClientCapabilities | null {
563
- return this.#clientCapabilities ?? null;
564
- }
565
-
566
- public get server(): Server {
567
- return this.#server;
568
- }
569
-
570
- #pingInterval: ReturnType<typeof setInterval> | null = null;
571
-
572
- public async requestSampling(
573
- message: z.infer<typeof CreateMessageRequestSchema>["params"],
574
- ): Promise<SamplingResponse> {
575
- return this.#server.createMessage(message);
669
+ private addResource(inputResource: Resource) {
670
+ this.#resources.push(inputResource);
576
671
  }
577
672
 
578
- public async connect(transport: Transport) {
579
- if (this.#server.transport) {
580
- throw new UnexpectedStateError("Server is already connected");
581
- }
582
-
583
- await this.#server.connect(transport);
584
-
585
- let attempt = 0;
586
-
587
- while (attempt++ < 10) {
588
- const capabilities = await this.#server.getClientCapabilities();
589
-
590
- if (capabilities) {
591
- this.#clientCapabilities = capabilities;
592
-
593
- break;
594
- }
595
-
596
- await delay(100);
597
- }
598
-
599
- if (!this.#clientCapabilities) {
600
- console.warn('[FastMCP warning] could not infer client capabilities')
601
- }
673
+ private addResourceTemplate(inputResourceTemplate: InputResourceTemplate) {
674
+ const completers: Record<string, ArgumentValueCompleter> = {};
602
675
 
603
- if (this.#clientCapabilities?.roots?.listChanged) {
604
- try {
605
- const roots = await this.#server.listRoots();
606
- this.#roots = roots.roots;
607
- } catch(e) {
608
- console.error(`[FastMCP error] received error listing roots.\n\n${e instanceof Error ? e.stack : JSON.stringify(e)}`)
676
+ for (const argument of inputResourceTemplate.arguments ?? []) {
677
+ if (argument.complete) {
678
+ completers[argument.name] = argument.complete;
609
679
  }
610
680
  }
611
681
 
612
- if (this.#clientCapabilities) {
613
- this.#pingInterval = setInterval(async () => {
614
- try {
615
- await this.#server.ping();
616
- } catch {
617
- // The reason we are not emitting an error here is because some clients
618
- // seem to not respond to the ping request, and we don't want to crash the server,
619
- // e.g., https://github.com/punkpeye/fastmcp/issues/38.
620
- console.warn("[FastMCP warning] server is not responding to ping")
682
+ const resourceTemplate = {
683
+ ...inputResourceTemplate,
684
+ complete: async (name: string, value: string) => {
685
+ if (completers[name]) {
686
+ return await completers[name](value);
621
687
  }
622
- }, 1000);
623
- }
624
- }
625
688
 
626
- public get roots(): Root[] {
627
- return this.#roots;
628
- }
629
-
630
- public async close() {
631
- if (this.#pingInterval) {
632
- clearInterval(this.#pingInterval);
633
- }
634
-
635
- try {
636
- await this.#server.close();
637
- } catch (error) {
638
- console.error("[FastMCP error]", "could not close server", error);
639
- }
640
- }
641
-
642
- private setupErrorHandling() {
643
- this.#server.onerror = (error) => {
644
- console.error("[FastMCP error]", error);
689
+ return {
690
+ values: [],
691
+ };
692
+ },
645
693
  };
646
- }
647
694
 
648
- public get loggingLevel(): LoggingLevel {
649
- return this.#loggingLevel;
695
+ this.#resourceTemplates.push(resourceTemplate);
650
696
  }
651
697
 
652
698
  private setupCompleteHandlers() {
@@ -722,19 +768,10 @@ export class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth> e
722
768
  });
723
769
  }
724
770
 
725
- private setupRootsHandlers() {
726
- this.#server.setNotificationHandler(
727
- RootsListChangedNotificationSchema,
728
- () => {
729
- this.#server.listRoots().then((roots) => {
730
- this.#roots = roots.roots;
731
-
732
- this.emit("rootsChanged", {
733
- roots: roots.roots,
734
- });
735
- });
736
- },
737
- );
771
+ private setupErrorHandling() {
772
+ this.#server.onerror = (error) => {
773
+ console.error("[FastMCP error]", error);
774
+ };
738
775
  }
739
776
 
740
777
  private setupLoggingHandlers() {
@@ -745,134 +782,63 @@ export class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth> e
745
782
  });
746
783
  }
747
784
 
748
- private setupToolHandlers(tools: Tool<T>[]) {
749
- this.#server.setRequestHandler(ListToolsRequestSchema, async () => {
785
+ private setupPromptHandlers(prompts: Prompt[]) {
786
+ this.#server.setRequestHandler(ListPromptsRequestSchema, async () => {
750
787
  return {
751
- tools: await Promise.all(tools.map(async (tool) => {
788
+ prompts: prompts.map((prompt) => {
752
789
  return {
753
- name: tool.name,
754
- description: tool.description,
755
- inputSchema: tool.parameters
756
- ? await toJsonSchema(tool.parameters)
757
- : undefined,
790
+ arguments: prompt.arguments,
791
+ complete: prompt.complete,
792
+ description: prompt.description,
793
+ name: prompt.name,
758
794
  };
759
- })),
795
+ }),
760
796
  };
761
797
  });
762
798
 
763
- this.#server.setRequestHandler(CallToolRequestSchema, async (request) => {
764
- const tool = tools.find((tool) => tool.name === request.params.name);
799
+ this.#server.setRequestHandler(GetPromptRequestSchema, async (request) => {
800
+ const prompt = prompts.find(
801
+ (prompt) => prompt.name === request.params.name,
802
+ );
765
803
 
766
- if (!tool) {
804
+ if (!prompt) {
767
805
  throw new McpError(
768
806
  ErrorCode.MethodNotFound,
769
- `Unknown tool: ${request.params.name}`,
770
- );
771
- }
772
-
773
- let args: any = undefined;
774
-
775
- if (tool.parameters) {
776
- const parsed = await tool.parameters["~standard"].validate(
777
- request.params.arguments
807
+ `Unknown prompt: ${request.params.name}`,
778
808
  );
809
+ }
779
810
 
780
- if (parsed.issues) {
781
- throw new McpError(
782
- ErrorCode.InvalidParams,
783
- `Invalid ${request.params.name} parameters`,
784
- );
785
- }
786
-
787
- args = parsed.value;
788
- }
789
-
790
- const progressToken = request.params?._meta?.progressToken;
791
-
792
- let result: ContentResult;
793
-
794
- try {
795
- const reportProgress = async (progress: Progress) => {
796
- await this.#server.notification({
797
- method: "notifications/progress",
798
- params: {
799
- ...progress,
800
- progressToken,
801
- },
802
- });
803
- };
804
-
805
- const log = {
806
- debug: (message: string, context?: SerializableValue) => {
807
- this.#server.sendLoggingMessage({
808
- level: "debug",
809
- data: {
810
- message,
811
- context,
812
- },
813
- });
814
- },
815
- error: (message: string, context?: SerializableValue) => {
816
- this.#server.sendLoggingMessage({
817
- level: "error",
818
- data: {
819
- message,
820
- context,
821
- },
822
- });
823
- },
824
- info: (message: string, context?: SerializableValue) => {
825
- this.#server.sendLoggingMessage({
826
- level: "info",
827
- data: {
828
- message,
829
- context,
830
- },
831
- });
832
- },
833
- warn: (message: string, context?: SerializableValue) => {
834
- this.#server.sendLoggingMessage({
835
- level: "warning",
836
- data: {
837
- message,
838
- context,
839
- },
840
- });
841
- },
842
- };
843
-
844
- const maybeStringResult = await tool.execute(args, {
845
- reportProgress,
846
- log,
847
- session: this.#auth,
848
- });
811
+ const args = request.params.arguments;
849
812
 
850
- if (typeof maybeStringResult === "string") {
851
- result = ContentResultZodSchema.parse({
852
- content: [{ type: "text", text: maybeStringResult }],
853
- });
854
- } else if ("type" in maybeStringResult) {
855
- result = ContentResultZodSchema.parse({
856
- content: [maybeStringResult],
857
- });
858
- } else {
859
- result = ContentResultZodSchema.parse(maybeStringResult);
860
- }
861
- } catch (error) {
862
- if (error instanceof UserError) {
863
- return {
864
- content: [{ type: "text", text: error.message }],
865
- isError: true,
866
- };
813
+ for (const arg of prompt.arguments ?? []) {
814
+ if (arg.required && !(args && arg.name in args)) {
815
+ throw new McpError(
816
+ ErrorCode.InvalidRequest,
817
+ `Missing required argument: ${arg.name}`,
818
+ );
867
819
  }
820
+ }
868
821
 
869
- return {
870
- content: [{ type: "text", text: `Error: ${error}` }],
871
- isError: true,
872
- };
822
+ let result: Awaited<ReturnType<Prompt["load"]>>;
823
+
824
+ try {
825
+ result = await prompt.load(args as Record<string, string | undefined>);
826
+ } catch (error) {
827
+ throw new McpError(
828
+ ErrorCode.InternalError,
829
+ `Error loading prompt: ${error}`,
830
+ );
873
831
  }
874
832
 
875
- return result;
833
+ return {
834
+ description: prompt.description,
835
+ messages: [
836
+ {
837
+ content: { text: result, type: "text" },
838
+ role: "user",
839
+ },
840
+ ],
841
+ };
876
842
  });
877
843
  }
878
844
 
@@ -881,9 +847,9 @@ export class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth> e
881
847
  return {
882
848
  resources: resources.map((resource) => {
883
849
  return {
884
- uri: resource.uri,
885
- name: resource.name,
886
850
  mimeType: resource.mimeType,
851
+ name: resource.name,
852
+ uri: resource.uri,
887
853
  };
888
854
  }),
889
855
  };
@@ -917,9 +883,9 @@ export class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth> e
917
883
  return {
918
884
  contents: [
919
885
  {
920
- uri: uri,
921
886
  mimeType: resourceTemplate.mimeType,
922
887
  name: resourceTemplate.name,
888
+ uri: uri,
923
889
  ...result,
924
890
  },
925
891
  ],
@@ -953,9 +919,9 @@ export class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth> e
953
919
  if (Array.isArray(maybeArrayResult)) {
954
920
  return {
955
921
  contents: maybeArrayResult.map((result) => ({
956
- uri: resource.uri,
957
922
  mimeType: resource.mimeType,
958
923
  name: resource.name,
924
+ uri: resource.uri,
959
925
  ...result,
960
926
  })),
961
927
  };
@@ -963,9 +929,9 @@ export class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth> e
963
929
  return {
964
930
  contents: [
965
931
  {
966
- uri: resource.uri,
967
932
  mimeType: resource.mimeType,
968
933
  name: resource.name,
934
+ uri: resource.uri,
969
935
  ...maybeArrayResult,
970
936
  },
971
937
  ],
@@ -996,63 +962,152 @@ export class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth> e
996
962
  );
997
963
  }
998
964
 
999
- private setupPromptHandlers(prompts: Prompt[]) {
1000
- this.#server.setRequestHandler(ListPromptsRequestSchema, async () => {
965
+ private setupRootsHandlers() {
966
+ this.#server.setNotificationHandler(
967
+ RootsListChangedNotificationSchema,
968
+ () => {
969
+ this.#server.listRoots().then((roots) => {
970
+ this.#roots = roots.roots;
971
+
972
+ this.emit("rootsChanged", {
973
+ roots: roots.roots,
974
+ });
975
+ });
976
+ },
977
+ );
978
+ }
979
+
980
+ private setupToolHandlers(tools: Tool<T>[]) {
981
+ this.#server.setRequestHandler(ListToolsRequestSchema, async () => {
1001
982
  return {
1002
- prompts: prompts.map((prompt) => {
1003
- return {
1004
- name: prompt.name,
1005
- description: prompt.description,
1006
- arguments: prompt.arguments,
1007
- complete: prompt.complete,
1008
- };
1009
- }),
983
+ tools: await Promise.all(
984
+ tools.map(async (tool) => {
985
+ return {
986
+ annotations: tool.annotations,
987
+ description: tool.description,
988
+ inputSchema: tool.parameters
989
+ ? await toJsonSchema(tool.parameters)
990
+ : undefined,
991
+ name: tool.name,
992
+ };
993
+ }),
994
+ ),
1010
995
  };
1011
996
  });
1012
997
 
1013
- this.#server.setRequestHandler(GetPromptRequestSchema, async (request) => {
1014
- const prompt = prompts.find(
1015
- (prompt) => prompt.name === request.params.name,
1016
- );
998
+ this.#server.setRequestHandler(CallToolRequestSchema, async (request) => {
999
+ const tool = tools.find((tool) => tool.name === request.params.name);
1017
1000
 
1018
- if (!prompt) {
1001
+ if (!tool) {
1019
1002
  throw new McpError(
1020
1003
  ErrorCode.MethodNotFound,
1021
- `Unknown prompt: ${request.params.name}`,
1004
+ `Unknown tool: ${request.params.name}`,
1022
1005
  );
1023
1006
  }
1024
1007
 
1025
- const args = request.params.arguments;
1008
+ let args: unknown = undefined;
1026
1009
 
1027
- for (const arg of prompt.arguments ?? []) {
1028
- if (arg.required && !(args && arg.name in args)) {
1010
+ if (tool.parameters) {
1011
+ const parsed = await tool.parameters["~standard"].validate(
1012
+ request.params.arguments,
1013
+ );
1014
+
1015
+ if (parsed.issues) {
1029
1016
  throw new McpError(
1030
- ErrorCode.InvalidRequest,
1031
- `Missing required argument: ${arg.name}`,
1017
+ ErrorCode.InvalidParams,
1018
+ `Invalid ${request.params.name} parameters`,
1032
1019
  );
1033
1020
  }
1021
+
1022
+ args = parsed.value;
1034
1023
  }
1035
1024
 
1036
- let result: Awaited<ReturnType<Prompt["load"]>>;
1025
+ const progressToken = request.params?._meta?.progressToken;
1026
+
1027
+ let result: ContentResult;
1037
1028
 
1038
1029
  try {
1039
- result = await prompt.load(args as Record<string, string | undefined>);
1030
+ const reportProgress = async (progress: Progress) => {
1031
+ await this.#server.notification({
1032
+ method: "notifications/progress",
1033
+ params: {
1034
+ ...progress,
1035
+ progressToken,
1036
+ },
1037
+ });
1038
+ };
1039
+
1040
+ const log = {
1041
+ debug: (message: string, context?: SerializableValue) => {
1042
+ this.#server.sendLoggingMessage({
1043
+ data: {
1044
+ context,
1045
+ message,
1046
+ },
1047
+ level: "debug",
1048
+ });
1049
+ },
1050
+ error: (message: string, context?: SerializableValue) => {
1051
+ this.#server.sendLoggingMessage({
1052
+ data: {
1053
+ context,
1054
+ message,
1055
+ },
1056
+ level: "error",
1057
+ });
1058
+ },
1059
+ info: (message: string, context?: SerializableValue) => {
1060
+ this.#server.sendLoggingMessage({
1061
+ data: {
1062
+ context,
1063
+ message,
1064
+ },
1065
+ level: "info",
1066
+ });
1067
+ },
1068
+ warn: (message: string, context?: SerializableValue) => {
1069
+ this.#server.sendLoggingMessage({
1070
+ data: {
1071
+ context,
1072
+ message,
1073
+ },
1074
+ level: "warning",
1075
+ });
1076
+ },
1077
+ };
1078
+
1079
+ const maybeStringResult = await tool.execute(args, {
1080
+ log,
1081
+ reportProgress,
1082
+ session: this.#auth,
1083
+ });
1084
+
1085
+ if (typeof maybeStringResult === "string") {
1086
+ result = ContentResultZodSchema.parse({
1087
+ content: [{ text: maybeStringResult, type: "text" }],
1088
+ });
1089
+ } else if ("type" in maybeStringResult) {
1090
+ result = ContentResultZodSchema.parse({
1091
+ content: [maybeStringResult],
1092
+ });
1093
+ } else {
1094
+ result = ContentResultZodSchema.parse(maybeStringResult);
1095
+ }
1040
1096
  } catch (error) {
1041
- throw new McpError(
1042
- ErrorCode.InternalError,
1043
- `Error loading prompt: ${error}`,
1044
- );
1097
+ if (error instanceof UserError) {
1098
+ return {
1099
+ content: [{ text: error.message, type: "text" }],
1100
+ isError: true,
1101
+ };
1102
+ }
1103
+
1104
+ return {
1105
+ content: [{ text: `Error: ${error}`, type: "text" }],
1106
+ isError: true,
1107
+ };
1045
1108
  }
1046
1109
 
1047
- return {
1048
- description: prompt.description,
1049
- messages: [
1050
- {
1051
- role: "user",
1052
- content: { type: "text", text: result },
1053
- },
1054
- ],
1055
- };
1110
+ return result;
1056
1111
  });
1057
1112
  }
1058
1113
  }
@@ -1061,19 +1116,25 @@ const FastMCPEventEmitterBase: {
1061
1116
  new (): StrictEventEmitter<EventEmitter, FastMCPEvents<FastMCPSessionAuth>>;
1062
1117
  } = EventEmitter;
1063
1118
 
1064
- class FastMCPEventEmitter extends FastMCPEventEmitterBase {}
1065
-
1066
1119
  type Authenticate<T> = (request: http.IncomingMessage) => Promise<T>;
1067
1120
 
1068
- export class FastMCP<T extends Record<string, unknown> | undefined = undefined> extends FastMCPEventEmitter {
1121
+ class FastMCPEventEmitter extends FastMCPEventEmitterBase {}
1122
+
1123
+ export class FastMCP<
1124
+ T extends Record<string, unknown> | undefined = undefined,
1125
+ > extends FastMCPEventEmitter {
1126
+ public get sessions(): FastMCPSession<T>[] {
1127
+ return this.#sessions;
1128
+ }
1129
+ #authenticate: Authenticate<T> | undefined;
1069
1130
  #options: ServerOptions<T>;
1070
1131
  #prompts: InputPrompt[] = [];
1071
1132
  #resources: Resource[] = [];
1072
1133
  #resourcesTemplates: InputResourceTemplate[] = [];
1073
1134
  #sessions: FastMCPSession<T>[] = [];
1074
- #sseServer: SSEServer | null = null;
1135
+ #sseServer: null | SSEServer = null;
1136
+
1075
1137
  #tools: Tool<T>[] = [];
1076
- #authenticate: Authenticate<T> | undefined;
1077
1138
 
1078
1139
  constructor(public options: ServerOptions<T>) {
1079
1140
  super();
@@ -1082,15 +1143,13 @@ export class FastMCP<T extends Record<string, unknown> | undefined = undefined>
1082
1143
  this.#authenticate = options.authenticate;
1083
1144
  }
1084
1145
 
1085
- public get sessions(): FastMCPSession<T>[] {
1086
- return this.#sessions;
1087
- }
1088
-
1089
1146
  /**
1090
- * Adds a tool to the server.
1147
+ * Adds a prompt to the server.
1091
1148
  */
1092
- public addTool<Params extends ToolParameters>(tool: Tool<T, Params>) {
1093
- this.#tools.push(tool as unknown as Tool<T>);
1149
+ public addPrompt<const Args extends InputPromptArgument[]>(
1150
+ prompt: InputPrompt<Args>,
1151
+ ) {
1152
+ this.#prompts.push(prompt);
1094
1153
  }
1095
1154
 
1096
1155
  /**
@@ -1110,12 +1169,10 @@ export class FastMCP<T extends Record<string, unknown> | undefined = undefined>
1110
1169
  }
1111
1170
 
1112
1171
  /**
1113
- * Adds a prompt to the server.
1172
+ * Adds a tool to the server.
1114
1173
  */
1115
- public addPrompt<const Args extends InputPromptArgument[]>(
1116
- prompt: InputPrompt<Args>,
1117
- ) {
1118
- this.#prompts.push(prompt);
1174
+ public addTool<Params extends ToolParameters>(tool: Tool<T, Params>) {
1175
+ this.#tools.push(tool as unknown as Tool<T>);
1119
1176
  }
1120
1177
 
1121
1178
  /**
@@ -1123,11 +1180,11 @@ export class FastMCP<T extends Record<string, unknown> | undefined = undefined>
1123
1180
  */
1124
1181
  public async start(
1125
1182
  options:
1126
- | { transportType: "stdio" }
1127
1183
  | {
1128
- transportType: "sse";
1129
1184
  sse: { endpoint: `/${string}`; port: number };
1130
- } = {
1185
+ transportType: "sse";
1186
+ }
1187
+ | { transportType: "stdio" } = {
1131
1188
  transportType: "stdio",
1132
1189
  },
1133
1190
  ) {
@@ -1135,12 +1192,13 @@ export class FastMCP<T extends Record<string, unknown> | undefined = undefined>
1135
1192
  const transport = new StdioServerTransport();
1136
1193
 
1137
1194
  const session = new FastMCPSession<T>({
1195
+ instructions: this.#options.instructions,
1138
1196
  name: this.#options.name,
1139
- version: this.#options.version,
1140
- tools: this.#tools,
1197
+ prompts: this.#prompts,
1141
1198
  resources: this.#resources,
1142
1199
  resourcesTemplates: this.#resourcesTemplates,
1143
- prompts: this.#prompts,
1200
+ tools: this.#tools,
1201
+ version: this.#options.version,
1144
1202
  });
1145
1203
 
1146
1204
  await session.connect(transport);
@@ -1150,11 +1208,8 @@ export class FastMCP<T extends Record<string, unknown> | undefined = undefined>
1150
1208
  this.emit("connect", {
1151
1209
  session,
1152
1210
  });
1153
-
1154
1211
  } else if (options.transportType === "sse") {
1155
1212
  this.#sseServer = await startSSEServer<FastMCPSession<T>>({
1156
- endpoint: options.sse.endpoint as `/${string}`,
1157
- port: options.sse.port,
1158
1213
  createServer: async (request) => {
1159
1214
  let auth: T | undefined;
1160
1215
 
@@ -1165,13 +1220,14 @@ export class FastMCP<T extends Record<string, unknown> | undefined = undefined>
1165
1220
  return new FastMCPSession<T>({
1166
1221
  auth,
1167
1222
  name: this.#options.name,
1168
- version: this.#options.version,
1169
- tools: this.#tools,
1223
+ prompts: this.#prompts,
1170
1224
  resources: this.#resources,
1171
1225
  resourcesTemplates: this.#resourcesTemplates,
1172
- prompts: this.#prompts,
1226
+ tools: this.#tools,
1227
+ version: this.#options.version,
1173
1228
  });
1174
1229
  },
1230
+ endpoint: options.sse.endpoint as `/${string}`,
1175
1231
  onClose: (session) => {
1176
1232
  this.emit("disconnect", {
1177
1233
  session,
@@ -1184,6 +1240,7 @@ export class FastMCP<T extends Record<string, unknown> | undefined = undefined>
1184
1240
  session,
1185
1241
  });
1186
1242
  },
1243
+ port: options.sse.port,
1187
1244
  });
1188
1245
 
1189
1246
  console.info(
@@ -1206,11 +1263,11 @@ export class FastMCP<T extends Record<string, unknown> | undefined = undefined>
1206
1263
 
1207
1264
  export type { Context };
1208
1265
  export type { Tool, ToolParameters };
1209
- export type { Content, TextContent, ImageContent, ContentResult };
1266
+ export type { Content, ContentResult, ImageContent, TextContent };
1210
1267
  export type { Progress, SerializableValue };
1211
1268
  export type { Resource, ResourceResult };
1212
1269
  export type { ResourceTemplate, ResourceTemplateArgument };
1213
1270
  export type { Prompt, PromptArgument };
1214
1271
  export type { InputPrompt, InputPromptArgument };
1215
- export type { ServerOptions, LoggingLevel };
1272
+ export type { LoggingLevel, ServerOptions };
1216
1273
  export type { FastMCPEvents, FastMCPSessionEvents };