fastmcp 3.13.0 → 3.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/dist/FastMCP.d.ts +15 -2
- package/dist/FastMCP.js +28 -21
- package/dist/FastMCP.js.map +1 -1
- package/jsr.json +1 -1
- package/package.json +17 -17
- package/src/FastMCP.ts +42 -21
- package/src/examples/custom-logger.ts +201 -0
package/README.md
CHANGED
|
@@ -696,6 +696,44 @@ server.addTool({
|
|
|
696
696
|
});
|
|
697
697
|
```
|
|
698
698
|
|
|
699
|
+
#### Custom Logger
|
|
700
|
+
|
|
701
|
+
FastMCP allows you to provide a custom logger implementation to control how the server logs messages. This is useful for integrating with existing logging infrastructure or customizing log formatting.
|
|
702
|
+
|
|
703
|
+
```ts
|
|
704
|
+
import { FastMCP, Logger } from "fastmcp";
|
|
705
|
+
|
|
706
|
+
class CustomLogger implements Logger {
|
|
707
|
+
debug(...args: unknown[]): void {
|
|
708
|
+
console.log("[DEBUG]", new Date().toISOString(), ...args);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
error(...args: unknown[]): void {
|
|
712
|
+
console.error("[ERROR]", new Date().toISOString(), ...args);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
info(...args: unknown[]): void {
|
|
716
|
+
console.info("[INFO]", new Date().toISOString(), ...args);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
log(...args: unknown[]): void {
|
|
720
|
+
console.log("[LOG]", new Date().toISOString(), ...args);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
warn(...args: unknown[]): void {
|
|
724
|
+
console.warn("[WARN]", new Date().toISOString(), ...args);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
const server = new FastMCP({
|
|
729
|
+
name: "My Server",
|
|
730
|
+
version: "1.0.0",
|
|
731
|
+
logger: new CustomLogger(),
|
|
732
|
+
});
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
See `src/examples/custom-logger.ts` for examples with Winston, Pino, and file-based logging.
|
|
736
|
+
|
|
699
737
|
#### Logging
|
|
700
738
|
|
|
701
739
|
Tools can log messages to the client using the `log` object in the context object:
|
|
@@ -1713,6 +1751,7 @@ Refer to this [issue](https://github.com/punkpeye/fastmcp/issues/25#issuecomment
|
|
|
1713
1751
|
- [cswkim/discogs-mcp-server](https://github.com/cswkim/discogs-mcp-server) - connects to the Discogs API for interacting with your music collection
|
|
1714
1752
|
- [Panzer-Jack/feuse-mcp](https://github.com/Panzer-Jack/feuse-mcp) - Frontend Useful MCP Tools - Essential utilities for web developers to automate API integration and code generation
|
|
1715
1753
|
- [sunra-ai/sunra-clients](https://github.com/sunra-ai/sunra-clients/tree/main/mcp-server) - Sunra.ai is a generative media platform built for developers, providing high-performance AI model inference capabilities.
|
|
1754
|
+
- [foxtrottwist/shortcuts-mcp](https://github.com/foxtrottwist/shortcuts-mcp) - connects Claude to macOS Shortcuts for system automation, app integration, and interactive workflows
|
|
1716
1755
|
|
|
1717
1756
|
## Acknowledgements
|
|
1718
1757
|
|
package/dist/FastMCP.d.ts
CHANGED
|
@@ -10,6 +10,13 @@ import http from 'http';
|
|
|
10
10
|
import { StrictEventEmitter } from 'strict-event-emitter-types';
|
|
11
11
|
import { z } from 'zod';
|
|
12
12
|
|
|
13
|
+
interface Logger {
|
|
14
|
+
debug(...args: unknown[]): void;
|
|
15
|
+
error(...args: unknown[]): void;
|
|
16
|
+
info(...args: unknown[]): void;
|
|
17
|
+
log(...args: unknown[]): void;
|
|
18
|
+
warn(...args: unknown[]): void;
|
|
19
|
+
}
|
|
13
20
|
type SSEServer = {
|
|
14
21
|
close: () => Promise<void>;
|
|
15
22
|
};
|
|
@@ -247,6 +254,11 @@ type ServerOptions<T extends FastMCPSessionAuth> = {
|
|
|
247
254
|
status?: number;
|
|
248
255
|
};
|
|
249
256
|
instructions?: string;
|
|
257
|
+
/**
|
|
258
|
+
* Custom logger instance. If not provided, defaults to console.
|
|
259
|
+
* Use this to integrate with your own logging system.
|
|
260
|
+
*/
|
|
261
|
+
logger?: Logger;
|
|
250
262
|
name: string;
|
|
251
263
|
/**
|
|
252
264
|
* Configuration for OAuth well-known discovery endpoints that can be exposed
|
|
@@ -534,9 +546,10 @@ declare class FastMCPSession<T extends FastMCPSessionAuth = FastMCPSessionAuth>
|
|
|
534
546
|
get loggingLevel(): LoggingLevel;
|
|
535
547
|
get roots(): Root[];
|
|
536
548
|
get server(): Server;
|
|
537
|
-
constructor({ auth, instructions, name, ping, prompts, resources, resourcesTemplates, roots, tools, transportType, utils, version, }: {
|
|
549
|
+
constructor({ auth, instructions, logger, name, ping, prompts, resources, resourcesTemplates, roots, tools, transportType, utils, version, }: {
|
|
538
550
|
auth?: T;
|
|
539
551
|
instructions?: string;
|
|
552
|
+
logger: Logger;
|
|
540
553
|
name: string;
|
|
541
554
|
ping?: ServerOptions<T>["ping"];
|
|
542
555
|
prompts: Prompt<T>[];
|
|
@@ -616,4 +629,4 @@ declare class FastMCP<T extends FastMCPSessionAuth = FastMCPSessionAuth> extends
|
|
|
616
629
|
stop(): Promise<void>;
|
|
617
630
|
}
|
|
618
631
|
|
|
619
|
-
export { type AudioContent, type Content, type ContentResult, type Context, FastMCP, type FastMCPEvents, FastMCPSession, type FastMCPSessionEvents, type ImageContent, type InputPrompt, type InputPromptArgument, type LoggingLevel, type Progress, type Prompt, type PromptArgument, type Resource, type ResourceContent, type ResourceResult, type ResourceTemplate, type ResourceTemplateArgument, type SSEServer, type SerializableValue, type ServerOptions, type TextContent, type Tool, type ToolParameters, UnexpectedStateError, UserError, audioContent, imageContent };
|
|
632
|
+
export { type AudioContent, type Content, type ContentResult, type Context, FastMCP, type FastMCPEvents, FastMCPSession, type FastMCPSessionEvents, type ImageContent, type InputPrompt, type InputPromptArgument, type Logger, type LoggingLevel, type Progress, type Prompt, type PromptArgument, type Resource, type ResourceContent, type ResourceResult, type ResourceTemplate, type ResourceTemplateArgument, type SSEServer, type SerializableValue, type ServerOptions, type TextContent, type Tool, type ToolParameters, UnexpectedStateError, UserError, audioContent, imageContent };
|
package/dist/FastMCP.js
CHANGED
|
@@ -237,6 +237,7 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
|
|
|
237
237
|
#capabilities = {};
|
|
238
238
|
#clientCapabilities;
|
|
239
239
|
#connectionState = "connecting";
|
|
240
|
+
#logger;
|
|
240
241
|
#loggingLevel = "info";
|
|
241
242
|
#needsEventLoopFlush = false;
|
|
242
243
|
#pingConfig;
|
|
@@ -251,6 +252,7 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
|
|
|
251
252
|
constructor({
|
|
252
253
|
auth,
|
|
253
254
|
instructions,
|
|
255
|
+
logger,
|
|
254
256
|
name,
|
|
255
257
|
ping,
|
|
256
258
|
prompts,
|
|
@@ -264,6 +266,7 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
|
|
|
264
266
|
}) {
|
|
265
267
|
super();
|
|
266
268
|
this.#auth = auth;
|
|
269
|
+
this.#logger = logger;
|
|
267
270
|
this.#pingConfig = ping;
|
|
268
271
|
this.#rootsConfig = roots;
|
|
269
272
|
this.#needsEventLoopFlush = transportType === "httpStream";
|
|
@@ -316,7 +319,7 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
|
|
|
316
319
|
try {
|
|
317
320
|
await this.#server.close();
|
|
318
321
|
} catch (error) {
|
|
319
|
-
|
|
322
|
+
this.#logger.error("[FastMCP error]", "could not close server", error);
|
|
320
323
|
}
|
|
321
324
|
}
|
|
322
325
|
async connect(transport) {
|
|
@@ -338,7 +341,7 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
|
|
|
338
341
|
await delay(retryDelay);
|
|
339
342
|
}
|
|
340
343
|
if (!this.#clientCapabilities) {
|
|
341
|
-
|
|
344
|
+
this.#logger.warn(
|
|
342
345
|
`[FastMCP warning] could not infer client capabilities after ${maxAttempts} attempts. Connection may be unstable.`
|
|
343
346
|
);
|
|
344
347
|
}
|
|
@@ -348,11 +351,11 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
|
|
|
348
351
|
this.#roots = roots?.roots || [];
|
|
349
352
|
} catch (e) {
|
|
350
353
|
if (e instanceof McpError && e.code === ErrorCode.MethodNotFound) {
|
|
351
|
-
|
|
354
|
+
this.#logger.debug(
|
|
352
355
|
"[FastMCP debug] listRoots method not supported by client"
|
|
353
356
|
);
|
|
354
357
|
} else {
|
|
355
|
-
|
|
358
|
+
this.#logger.error(
|
|
356
359
|
`[FastMCP error] received error listing roots.
|
|
357
360
|
|
|
358
361
|
${e instanceof Error ? e.stack : JSON.stringify(e)}`
|
|
@@ -369,17 +372,17 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
|
|
|
369
372
|
} catch {
|
|
370
373
|
const logLevel = pingConfig.logLevel;
|
|
371
374
|
if (logLevel === "debug") {
|
|
372
|
-
|
|
375
|
+
this.#logger.debug("[FastMCP debug] server ping failed");
|
|
373
376
|
} else if (logLevel === "warning") {
|
|
374
|
-
|
|
377
|
+
this.#logger.warn(
|
|
375
378
|
"[FastMCP warning] server is not responding to ping"
|
|
376
379
|
);
|
|
377
380
|
} else if (logLevel === "error") {
|
|
378
|
-
|
|
381
|
+
this.#logger.error(
|
|
379
382
|
"[FastMCP error] server is not responding to ping"
|
|
380
383
|
);
|
|
381
384
|
} else {
|
|
382
|
-
|
|
385
|
+
this.#logger.info("[FastMCP info] server ping failed");
|
|
383
386
|
}
|
|
384
387
|
}
|
|
385
388
|
}, pingConfig.intervalMs);
|
|
@@ -565,7 +568,7 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
|
|
|
565
568
|
}
|
|
566
569
|
setupErrorHandling() {
|
|
567
570
|
this.#server.onerror = (error) => {
|
|
568
|
-
|
|
571
|
+
this.#logger.error("[FastMCP error]", error);
|
|
569
572
|
};
|
|
570
573
|
}
|
|
571
574
|
setupLoggingHandlers() {
|
|
@@ -731,7 +734,7 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
|
|
|
731
734
|
}
|
|
732
735
|
setupRootsHandlers() {
|
|
733
736
|
if (this.#rootsConfig?.enabled === false) {
|
|
734
|
-
|
|
737
|
+
this.#logger.debug(
|
|
735
738
|
"[FastMCP debug] roots capability explicitly disabled via config"
|
|
736
739
|
);
|
|
737
740
|
return;
|
|
@@ -747,11 +750,11 @@ ${e instanceof Error ? e.stack : JSON.stringify(e)}`
|
|
|
747
750
|
});
|
|
748
751
|
}).catch((error) => {
|
|
749
752
|
if (error instanceof McpError && error.code === ErrorCode.MethodNotFound) {
|
|
750
|
-
|
|
753
|
+
this.#logger.debug(
|
|
751
754
|
"[FastMCP debug] listRoots method not supported by client"
|
|
752
755
|
);
|
|
753
756
|
} else {
|
|
754
|
-
|
|
757
|
+
this.#logger.error(
|
|
755
758
|
`[FastMCP error] received error listing roots.
|
|
756
759
|
|
|
757
760
|
${error instanceof Error ? error.stack : JSON.stringify(error)}`
|
|
@@ -761,7 +764,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
|
|
|
761
764
|
}
|
|
762
765
|
);
|
|
763
766
|
} else {
|
|
764
|
-
|
|
767
|
+
this.#logger.debug(
|
|
765
768
|
"[FastMCP debug] roots capability not available, not setting up notification handler"
|
|
766
769
|
);
|
|
767
770
|
}
|
|
@@ -827,7 +830,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
|
|
|
827
830
|
await new Promise((resolve) => setImmediate(resolve));
|
|
828
831
|
}
|
|
829
832
|
} catch (progressError) {
|
|
830
|
-
|
|
833
|
+
this.#logger.warn(
|
|
831
834
|
`[FastMCP warning] Failed to report progress for tool '${request.params.name}':`,
|
|
832
835
|
progressError instanceof Error ? progressError.message : String(progressError)
|
|
833
836
|
);
|
|
@@ -885,7 +888,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
|
|
|
885
888
|
await new Promise((resolve) => setImmediate(resolve));
|
|
886
889
|
}
|
|
887
890
|
} catch (streamError) {
|
|
888
|
-
|
|
891
|
+
this.#logger.warn(
|
|
889
892
|
`[FastMCP warning] Failed to stream content for tool '${request.params.name}':`,
|
|
890
893
|
streamError instanceof Error ? streamError.message : String(streamError)
|
|
891
894
|
);
|
|
@@ -968,12 +971,14 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
968
971
|
this.options = options;
|
|
969
972
|
this.#options = options;
|
|
970
973
|
this.#authenticate = options.authenticate;
|
|
974
|
+
this.#logger = options.logger || console;
|
|
971
975
|
}
|
|
972
976
|
get sessions() {
|
|
973
977
|
return this.#sessions;
|
|
974
978
|
}
|
|
975
979
|
#authenticate;
|
|
976
980
|
#httpStreamServer = null;
|
|
981
|
+
#logger;
|
|
977
982
|
#options;
|
|
978
983
|
#prompts = [];
|
|
979
984
|
#resources = [];
|
|
@@ -1073,6 +1078,7 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
1073
1078
|
const transport = new StdioServerTransport();
|
|
1074
1079
|
const session = new FastMCPSession({
|
|
1075
1080
|
instructions: this.#options.instructions,
|
|
1081
|
+
logger: this.#logger,
|
|
1076
1082
|
name: this.#options.name,
|
|
1077
1083
|
ping: this.#options.ping,
|
|
1078
1084
|
prompts: this.#prompts,
|
|
@@ -1092,7 +1098,7 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
1092
1098
|
} else if (config.transportType === "httpStream") {
|
|
1093
1099
|
const httpConfig = config.httpStream;
|
|
1094
1100
|
if (httpConfig.stateless) {
|
|
1095
|
-
|
|
1101
|
+
this.#logger.info(
|
|
1096
1102
|
`[FastMCP info] Starting server in stateless mode on HTTP Stream at http://localhost:${httpConfig.port}${httpConfig.endpoint}`
|
|
1097
1103
|
);
|
|
1098
1104
|
this.#httpStreamServer = await startHTTPServer({
|
|
@@ -1109,7 +1115,7 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
1109
1115
|
onClose: async () => {
|
|
1110
1116
|
},
|
|
1111
1117
|
onConnect: async () => {
|
|
1112
|
-
|
|
1118
|
+
this.#logger.debug(
|
|
1113
1119
|
`[FastMCP debug] Stateless HTTP Stream request handled`
|
|
1114
1120
|
);
|
|
1115
1121
|
},
|
|
@@ -1138,7 +1144,7 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
1138
1144
|
},
|
|
1139
1145
|
onConnect: async (session) => {
|
|
1140
1146
|
this.#sessions.push(session);
|
|
1141
|
-
|
|
1147
|
+
this.#logger.info(`[FastMCP info] HTTP Stream session established`);
|
|
1142
1148
|
this.emit("connect", {
|
|
1143
1149
|
session
|
|
1144
1150
|
});
|
|
@@ -1149,10 +1155,10 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
1149
1155
|
port: httpConfig.port,
|
|
1150
1156
|
streamEndpoint: httpConfig.endpoint
|
|
1151
1157
|
});
|
|
1152
|
-
|
|
1158
|
+
this.#logger.info(
|
|
1153
1159
|
`[FastMCP info] server is running on HTTP Stream at http://localhost:${httpConfig.port}${httpConfig.endpoint}`
|
|
1154
1160
|
);
|
|
1155
|
-
|
|
1161
|
+
this.#logger.info(
|
|
1156
1162
|
`[FastMCP info] Transport type: httpStream (Streamable HTTP, not SSE)`
|
|
1157
1163
|
);
|
|
1158
1164
|
}
|
|
@@ -1178,6 +1184,7 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
1178
1184
|
) : this.#tools;
|
|
1179
1185
|
return new FastMCPSession({
|
|
1180
1186
|
auth,
|
|
1187
|
+
logger: this.#logger,
|
|
1181
1188
|
name: this.#options.name,
|
|
1182
1189
|
ping: this.#options.ping,
|
|
1183
1190
|
prompts: this.#prompts,
|
|
@@ -1235,7 +1242,7 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
1235
1242
|
return;
|
|
1236
1243
|
}
|
|
1237
1244
|
} catch (error) {
|
|
1238
|
-
|
|
1245
|
+
this.#logger.error("[FastMCP error] health endpoint error", error);
|
|
1239
1246
|
}
|
|
1240
1247
|
}
|
|
1241
1248
|
const oauthConfig = this.#options.oauth;
|