diff --git a/src/common/atlas/openapi.d.ts b/src/common/atlas/openapi.d.ts index 890c45c7..a204436b 100644 --- a/src/common/atlas/openapi.d.ts +++ b/src/common/atlas/openapi.d.ts @@ -1735,6 +1735,11 @@ export interface components { * @example 32b6e34b3d91647abb20e7b8 */ readonly roleId?: string; + /** + * @description Provision status of the service account. + * @enum {string} + */ + readonly status?: "IN_PROGRESS" | "COMPLETE" | "FAILED" | "NOT_INITIATED"; } & { /** * @description discriminator enum property added by openapi-typescript diff --git a/src/common/logger.ts b/src/common/logger.ts index 0add105c..8e5994f3 100644 --- a/src/common/logger.ts +++ b/src/common/logger.ts @@ -244,18 +244,32 @@ export class DiskLogger extends LoggerBase<{ initialized: [] }> { } export class McpLogger extends LoggerBase { + private shouldLogFunction?: (level: LogLevel) => boolean; + public constructor(private readonly server: McpServer) { super(); } protected readonly type: LoggerType = "mcp"; + /** + * Sets the function to check if a log level should be sent + */ + public setShouldLogFunction(shouldLog: (level: LogLevel) => boolean): void { + this.shouldLogFunction = shouldLog; + } + protected logCore(level: LogLevel, payload: LogPayload): void { // Only log if the server is connected if (!this.server?.isConnected()) { return; } + // Check if this log level should be sent + if (this.shouldLogFunction && !this.shouldLogFunction(level)) { + return; + } + void this.server.server.sendLoggingMessage({ level, data: `[${payload.context}]: ${payload.message}`, diff --git a/src/server.ts b/src/server.ts index bf41b26d..2791a234 100644 --- a/src/server.ts +++ b/src/server.ts @@ -12,17 +12,20 @@ import { type ServerCommand } from "./telemetry/types.js"; import { CallToolRequestSchema, CallToolResult, + SetLevelRequestSchema, SubscribeRequestSchema, UnsubscribeRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; import assert from "assert"; import { ToolBase } from "./tools/tool.js"; +import { LogLevel, McpLogger } from "./common/logger.js"; export interface ServerOptions { session: Session; userConfig: UserConfig; mcpServer: McpServer; telemetry: Telemetry; + mcpLogger?: McpLogger; } export class Server { @@ -33,13 +36,21 @@ export class Server { public readonly tools: ToolBase[] = []; private readonly startTime: number; private readonly subscriptions = new Set(); + private minimumLogLevel: LogLevel = "info"; + private readonly mcpLogger?: McpLogger; - constructor({ session, mcpServer, userConfig, telemetry }: ServerOptions) { + constructor({ session, mcpServer, userConfig, telemetry, mcpLogger }: ServerOptions) { this.startTime = Date.now(); this.session = session; this.telemetry = telemetry; this.mcpServer = mcpServer; this.userConfig = userConfig; + this.mcpLogger = mcpLogger; + + // Set up log level filtering for MCP logger + if (this.mcpLogger) { + this.mcpLogger.setShouldLogFunction((level: LogLevel) => this.shouldLog(level)); + } } async connect(transport: Transport): Promise { @@ -96,6 +107,16 @@ export class Server { return {}; }); + this.mcpServer.server.setRequestHandler(SetLevelRequestSchema, ({ params }) => { + this.minimumLogLevel = params.level; + this.session.logger.debug({ + id: LogId.serverInitialized, + context: "logging", + message: `Log level set to: ${params.level}`, + }); + return {}; + }); + this.mcpServer.server.oninitialized = (): void => { this.session.setAgentRunner(this.mcpServer.server.getClientVersion()); @@ -137,6 +158,18 @@ export class Server { } } + /** + * Checks if a log level meets the minimum threshold for logging + * @param level - The log level to check + * @returns true if the level should be logged, false otherwise + */ + public shouldLog(level: LogLevel): boolean { + const levels: LogLevel[] = ["debug", "info", "notice", "warning", "error", "critical", "alert", "emergency"]; + const currentIndex = levels.indexOf(this.minimumLogLevel); + const levelIndex = levels.indexOf(level); + return levelIndex >= currentIndex; + } + /** * Emits a server event * @param command - The server command (e.g., "start", "stop", "register", "deregister") diff --git a/src/transports/base.ts b/src/transports/base.ts index 22a000cc..f669a9f3 100644 --- a/src/transports/base.ts +++ b/src/transports/base.ts @@ -37,8 +37,10 @@ export abstract class TransportRunnerBase { }); const loggers = [this.logger]; + let mcpLogger: McpLogger | undefined; if (userConfig.loggers.includes("mcp")) { - loggers.push(new McpLogger(mcpServer)); + mcpLogger = new McpLogger(mcpServer); + loggers.push(mcpLogger); } const logger = new CompositeLogger(...loggers); @@ -61,6 +63,7 @@ export abstract class TransportRunnerBase { session, telemetry, userConfig, + mcpLogger, }); }