import fs from 'node:fs';
import path from 'node:path';
import process from 'node:process';
import { fileURLToPath } from 'node:url';
import { styleText } from 'node:util';
import {
McpServer,
ResourceTemplate,
} from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
type InitializeRequest,
InitializeRequestSchema,
type InitializeResult,
ErrorCode as RpcErrorCode,
SUPPORTED_PROTOCOL_VERSIONS,
} from '@modelcontextprotocol/sdk/types.js';
import { SERVER_INSTRUCTIONS, SERVER_NAME, SERVER_VERSION } from './config.js';
import { logger } from './lib/errors.js';
import { registerPrompts } from './prompts.js';
import { registerPromptTools } from './tools.js';
process.on('warning', (warning) => {
const code = 'code' in warning ? warning.code : undefined;
logger.warn(
{ message: warning.message, code },
`Node.js warning: ${warning.name}`
);
});
type InitializeHandler = (
request: InitializeRequest
) => Promise<InitializeResult>;
type OnRequestHandler = (request: unknown, extra?: unknown) => void;
type OnInitializedHandler = () => void;
const INSTRUCTIONS_RESOURCE_URI = 'internal://instructions';
const INSTRUCTIONS_PATH = path.resolve(
path.dirname(fileURLToPath(import.meta.url)),
'instructions.md'
);
const INSTRUCTIONS_TEXT = fs.readFileSync(INSTRUCTIONS_PATH, 'utf-8');
function registerInstructionsResource(server: McpServer): void {
server.registerResource(
'instructions',
new ResourceTemplate(INSTRUCTIONS_RESOURCE_URI, { list: undefined }),
{ title: 'Agent Instructions', mimeType: 'text/markdown' },
(uri) => ({
contents: [
{
uri: uri.href,
text: INSTRUCTIONS_TEXT,
mimeType: 'text/markdown',
},
],
})
);
}
function enforceStrictProtocolVersion(server: McpServer): void {
const baseInitialize = (
server.server as unknown as { _oninitialize?: InitializeHandler }
)._oninitialize?.bind(server.server);
if (!baseInitialize) {
logger.warn(
'Strict protocol version check unavailable (SDK internals changed). Falling back to SDK default initialize handler.'
);
return;
}
server.server.setRequestHandler(
InitializeRequestSchema,
async (request): Promise<InitializeResult> => {
const { protocolVersion } = request.params;
if (!SUPPORTED_PROTOCOL_VERSIONS.includes(protocolVersion)) {
logger.warn(
{ protocolVersion, supported: SUPPORTED_PROTOCOL_VERSIONS },
'Unsupported protocol version requested; negotiating to latest supported version'
);
}
return await baseInitialize(request);
}
);
}
function enforceInitializeFirst(server: McpServer): void {
const protocol = server.server as unknown as {
_onrequest?: OnRequestHandler;
oninitialized?: OnInitializedHandler;
_transport?: { send: (message: unknown) => Promise<void> };
};
const baseOnRequest = protocol._onrequest?.bind(server.server);
if (!baseOnRequest) {
logger.warn(
'Initialize gating unavailable (SDK internals changed). Proceeding without lifecycle guard.'
);
return;
}
let initialized = false;
const baseOnInitialized = protocol.oninitialized?.bind(server.server);
protocol.oninitialized = (): void => {
initialized = true;
baseOnInitialized?.();
};
protocol._onrequest = (request: unknown, extra?: unknown): void => {
const method =
typeof request === 'object' && request !== null && 'method' in request
? (request as { method?: unknown }).method
: undefined;
if (
!initialized &&
method !== 'initialize' &&
method !== 'ping' &&
method !== 'logging/setLevel'
) {
const hasId =
typeof request === 'object' &&
request !== null &&
Object.prototype.hasOwnProperty.call(request, 'id');
if (hasId) {
const rawId = (request as { id?: unknown }).id;
const responseId =
typeof rawId === 'string' ||
typeof rawId === 'number' ||
rawId === null
? rawId
: null;
const errorResponse = {
jsonrpc: '2.0',
id: responseId,
error: {
code: RpcErrorCode.InvalidRequest,
message: 'Server not initialized',
},
};
protocol._transport?.send(errorResponse).catch((error: unknown) => {
logger.error({ err: error }, 'Failed to send initialize error');
});
}
return;
}
baseOnRequest(request, extra);
};
}
type ToolInputValidator = (
tool: unknown,
args: unknown,
toolName: string
) => Promise<unknown>;
function disableSdkToolInputValidation(server: McpServer): void {
const validationTarget = server as unknown as {
validateToolInput?: ToolInputValidator;
};
if (!validationTarget.validateToolInput) return;
validationTarget.validateToolInput = (_tool, args): Promise<unknown> =>
Promise.resolve(args);
}
function createServer(): McpServer {
const server = new McpServer(
{
name: SERVER_NAME,
version: SERVER_VERSION,
},
{
instructions: SERVER_INSTRUCTIONS,
capabilities: {
logging: {},
resources: {},
tools: { listChanged: false },
prompts: { listChanged: false },
},
}
);
registerInstructionsResource(server);
registerPromptTools(server);
registerPrompts(server);
enforceStrictProtocolVersion(server);
enforceInitializeFirst(server);
// Keep validation in handlers so we can return structured MCP tool errors.
disableSdkToolInputValidation(server);
return server;
}
function isLoggingNegotiated(server: McpServer): boolean {
const protocol = server.server as unknown as {
getClientCapabilities?: () => unknown;
};
if (!protocol.getClientCapabilities) return false;
const caps = protocol.getClientCapabilities();
if (!caps) return false;
const { logging } = caps as { logging?: unknown };
if (typeof logging === 'boolean') return logging;
return true;
}
export async function startServer(): Promise<McpServer> {
const server = createServer();
await server.connect(new StdioServerTransport());
logger.info(
`${styleText('green', SERVER_NAME)} v${styleText('blue', SERVER_VERSION)} started`
);
const protocol = server.server as unknown as { oninitialized?: () => void };
const baseOnInitialized = protocol.oninitialized?.bind(server.server);
protocol.oninitialized = (): void => {
baseOnInitialized?.();
if (!isLoggingNegotiated(server)) return;
server
.sendLoggingMessage({
level: 'info',
logger: SERVER_NAME,
data: { event: 'start', version: SERVER_VERSION },
})
.catch((error: unknown) => {
logger.debug({ err: error }, 'Failed to send MCP log message');
});
};
return server;
}