@cardor/heimdall-mcp 0.1.0 → 0.1.2
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/dist/{chunk-VOBMDW4J.js → chunk-7VRCO72I.js} +54 -12
- package/dist/chunk-7VRCO72I.js.map +1 -0
- package/dist/cli.js +54 -13
- package/dist/cli.js.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +13 -4
- package/dist/chunk-VOBMDW4J.js.map +0 -1
|
@@ -226,10 +226,11 @@ var TelemetryCollector = class {
|
|
|
226
226
|
if (input.request.method === "tools/call" && toolName) {
|
|
227
227
|
this.metrics.record(toolName, input.status, input.durationMs);
|
|
228
228
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
229
|
+
const meta = { traceId: span.traceId, spanId: span.spanId };
|
|
230
|
+
if (input.status === "error" && input.response.error) {
|
|
231
|
+
meta["error"] = input.response.error;
|
|
232
|
+
}
|
|
233
|
+
this.log.debug(`${span.name} [${input.status}] ${input.durationMs}ms`, meta);
|
|
233
234
|
try {
|
|
234
235
|
await this.store.save(span);
|
|
235
236
|
} catch (err) {
|
|
@@ -362,17 +363,58 @@ var HttpOutbound = class {
|
|
|
362
363
|
async send(message) {
|
|
363
364
|
await fetch(this.url, {
|
|
364
365
|
method: "POST",
|
|
365
|
-
headers: {
|
|
366
|
+
headers: {
|
|
367
|
+
"Content-Type": "application/json",
|
|
368
|
+
"Accept": "application/json, text/event-stream"
|
|
369
|
+
},
|
|
366
370
|
body: JSON.stringify(message)
|
|
367
371
|
});
|
|
368
372
|
}
|
|
369
373
|
async sendAndWait(message) {
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
374
|
+
let res;
|
|
375
|
+
try {
|
|
376
|
+
res = await fetch(this.url, {
|
|
377
|
+
method: "POST",
|
|
378
|
+
headers: {
|
|
379
|
+
"Content-Type": "application/json",
|
|
380
|
+
"Accept": "application/json, text/event-stream"
|
|
381
|
+
},
|
|
382
|
+
body: JSON.stringify(message)
|
|
383
|
+
});
|
|
384
|
+
} catch (err) {
|
|
385
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
386
|
+
process.stderr.write(`[heimdall-mcp] fetch failed \u2192 ${this.url}: ${detail}
|
|
387
|
+
`);
|
|
388
|
+
return {
|
|
389
|
+
jsonrpc: "2.0",
|
|
390
|
+
id: message.id ?? null,
|
|
391
|
+
error: { code: -32603, message: `HTTP fetch failed: ${detail}` }
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
const rawText = await res.text();
|
|
395
|
+
if (!res.ok) {
|
|
396
|
+
process.stderr.write(
|
|
397
|
+
`[heimdall-mcp] target returned HTTP ${res.status} \u2192 ${this.url}
|
|
398
|
+
[heimdall-mcp] response body: ${rawText.slice(0, 500)}
|
|
399
|
+
`
|
|
400
|
+
);
|
|
401
|
+
return {
|
|
402
|
+
jsonrpc: "2.0",
|
|
403
|
+
id: message.id ?? null,
|
|
404
|
+
error: { code: -32603, message: `Target HTTP ${res.status}: ${rawText.slice(0, 200)}` }
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
try {
|
|
408
|
+
return JSON.parse(rawText);
|
|
409
|
+
} catch {
|
|
410
|
+
process.stderr.write(`[heimdall-mcp] target returned non-JSON: ${rawText.slice(0, 500)}
|
|
411
|
+
`);
|
|
412
|
+
return {
|
|
413
|
+
jsonrpc: "2.0",
|
|
414
|
+
id: message.id ?? null,
|
|
415
|
+
error: { code: -32603, message: `Target returned non-JSON: ${rawText.slice(0, 200)}` }
|
|
416
|
+
};
|
|
417
|
+
}
|
|
376
418
|
}
|
|
377
419
|
onMessage(_handler) {
|
|
378
420
|
}
|
|
@@ -657,4 +699,4 @@ export {
|
|
|
657
699
|
McpProxy,
|
|
658
700
|
ProxyBuilder
|
|
659
701
|
};
|
|
660
|
-
//# sourceMappingURL=chunk-
|
|
702
|
+
//# sourceMappingURL=chunk-7VRCO72I.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/proxy/McpProxy.ts","../src/interceptor/ForwardInterceptor.ts","../src/interceptor/InterceptorPipeline.ts","../src/interceptor/TelemetryInterceptor.ts","../src/telemetry/LogEmitter.ts","../src/telemetry/McpSpanBuilder.ts","../src/telemetry/MetricsRecorder.ts","../src/telemetry/TelemetryCollector.ts","../src/proxy/ProxyBuilder.ts","../src/store/StoreResolver.ts","../src/transport/HttpInbound.ts","../src/transport/HttpOutbound.ts","../src/transport/SseInbound.ts","../src/transport/SseOutbound.ts","../src/transport/StdioInbound.ts","../src/transport/StdioOutbound.ts","../src/transport/TransportFactory.ts"],"sourcesContent":["import { EventEmitter } from 'node:events'\n\nimport { ForwardInterceptor } from '@/interceptor/ForwardInterceptor'\nimport { InterceptorPipeline } from '@/interceptor/InterceptorPipeline'\nimport { TelemetryInterceptor } from '@/interceptor/TelemetryInterceptor'\nimport { TelemetryCollector } from '@/telemetry/TelemetryCollector'\n\nimport type { TraceStore } from '@/store/TraceStore'\nimport type { HttpOutbound } from '@/transport/HttpOutbound'\nimport type { McpTransport } from '@/transport/McpTransport'\nimport type { SseOutbound } from '@/transport/SseOutbound'\nimport type { StdioOutbound } from '@/transport/StdioOutbound'\n\nexport class McpProxy extends EventEmitter {\n private pipeline: InterceptorPipeline\n\n constructor(\n private inbound: McpTransport,\n private outbound: StdioOutbound | HttpOutbound | SseOutbound,\n store: TraceStore,\n ) {\n super()\n const collector = new TelemetryCollector(store)\n this.pipeline = new InterceptorPipeline()\n this.pipeline.use(new TelemetryInterceptor(collector))\n this.pipeline.use(new ForwardInterceptor(outbound))\n }\n\n addInterceptor(interceptor: Parameters<InterceptorPipeline['use']>[0]): this {\n // insert before ForwardInterceptor (last item) — not possible post-construction\n // so this is a pre-build concern; McpProxy accepts a custom pipeline instead\n this.pipeline.use(interceptor)\n return this\n }\n\n async start(): Promise<void> {\n this.inbound.onMessage(async (msg) => {\n try {\n return await this.pipeline.run(msg)\n } catch (err) {\n this.emit('error', err)\n return {\n jsonrpc: '2.0' as const,\n id: msg.id,\n error: { code: -32603, message: String(err) },\n }\n }\n })\n }\n\n async stop(): Promise<void> {\n await this.inbound.close()\n await this.outbound.close()\n }\n}\n","import type { Interceptor, InterceptorContext } from './Interceptor'\nimport type { HttpOutbound } from '@/transport/HttpOutbound'\nimport type { SseOutbound } from '@/transport/SseOutbound'\nimport type { StdioOutbound } from '@/transport/StdioOutbound'\nimport type { JsonRpcMessage } from '@/types'\n\ntype ForwardableOutbound = StdioOutbound | HttpOutbound | SseOutbound\n\nexport class ForwardInterceptor implements Interceptor {\n readonly name = 'ForwardInterceptor'\n\n constructor(private outbound: ForwardableOutbound) {}\n\n async intercept(\n request: JsonRpcMessage,\n _context: InterceptorContext,\n _next: () => Promise<JsonRpcMessage>\n ): Promise<JsonRpcMessage> {\n return this.outbound.sendAndWait(request)\n }\n}\n","import { randomBytes } from 'node:crypto'\n\nimport type { Interceptor, InterceptorContext } from './Interceptor'\nimport type { JsonRpcMessage } from '@/types'\n\nexport class InterceptorPipeline {\n private interceptors: Interceptor[] = []\n\n use(interceptor: Interceptor): this {\n this.interceptors.push(interceptor)\n return this\n }\n\n async run(request: JsonRpcMessage): Promise<JsonRpcMessage> {\n const context: InterceptorContext = {\n startedAt: new Date(),\n traceId: randomBytes(16).toString('hex'),\n spanId: randomBytes(8).toString('hex'),\n metadata: {},\n }\n\n let index = 0\n const next = async (): Promise<JsonRpcMessage> => {\n const interceptor = this.interceptors[index++]\n if (!interceptor) throw new Error('Pipeline ended without ForwardInterceptor')\n return interceptor.intercept(request, context, next)\n }\n\n return next()\n }\n}\n","import type { Interceptor, InterceptorContext } from './Interceptor'\nimport type { TelemetryCollector } from '@/telemetry/TelemetryCollector'\nimport type { JsonRpcMessage } from '@/types'\n\nexport class TelemetryInterceptor implements Interceptor {\n readonly name = 'TelemetryInterceptor'\n\n constructor(private collector: TelemetryCollector) {}\n\n async intercept(\n request: JsonRpcMessage,\n context: InterceptorContext,\n next: () => Promise<JsonRpcMessage>\n ): Promise<JsonRpcMessage> {\n context.startedAt = new Date()\n\n let response: JsonRpcMessage\n let status: 'ok' | 'error' = 'ok'\n\n try {\n response = await next()\n if (response.error) status = 'error'\n } catch (err) {\n status = 'error'\n response = {\n jsonrpc: '2.0',\n id: request.id,\n error: { code: -32603, message: String(err) },\n }\n }\n\n const endedAt = new Date()\n const durationMs = endedAt.getTime() - context.startedAt.getTime()\n\n await this.collector.record({\n traceId: context.traceId,\n spanId: context.spanId,\n request,\n response,\n status,\n startedAt: context.startedAt,\n endedAt,\n durationMs,\n })\n\n return response\n }\n}\n","import pc from 'picocolors'\n\ntype LogLevel = 'info' | 'warn' | 'error' | 'debug'\n\nexport class LogEmitter {\n private enabled: boolean\n\n constructor(enabled = true) {\n this.enabled = enabled\n }\n\n info(message: string, meta?: Record<string, unknown>): void {\n this.emit('info', message, meta)\n }\n\n warn(message: string, meta?: Record<string, unknown>): void {\n this.emit('warn', message, meta)\n }\n\n error(message: string, meta?: Record<string, unknown>): void {\n this.emit('error', message, meta)\n }\n\n debug(message: string, meta?: Record<string, unknown>): void {\n this.emit('debug', message, meta)\n }\n\n private emit(level: LogLevel, message: string, meta?: Record<string, unknown>): void {\n if (!this.enabled) return\n const ts = new Date().toISOString()\n const prefix = {\n info: pc.blue('[info]'),\n warn: pc.yellow('[warn]'),\n error: pc.red('[error]'),\n debug: pc.gray('[debug]'),\n }[level]\n const metaStr = meta ? ' ' + JSON.stringify(meta) : ''\n process.stderr.write(`${ts} ${prefix} ${message}${metaStr}\\n`)\n }\n}\n","import { randomBytes } from 'node:crypto'\n\nimport type { JsonRpcMessage, McpSpan, SpanStatus } from '@/types'\n\nexport interface SpanInput {\n traceId: string\n spanId: string\n request: JsonRpcMessage\n response: JsonRpcMessage\n status: SpanStatus\n startedAt: Date\n endedAt: Date\n durationMs: number\n}\n\nconst METHOD_TO_SPAN_NAME: Record<string, string> = {\n initialize: 'mcp.initialize',\n 'tools/list': 'mcp.tools.list',\n 'tools/call': 'mcp.tool.call',\n 'resources/read': 'mcp.resource.read',\n 'resources/list': 'mcp.resources.list',\n 'prompts/get': 'mcp.prompt.get',\n 'prompts/list': 'mcp.prompts.list',\n shutdown: 'mcp.shutdown',\n}\n\nexport class McpSpanBuilder {\n build(input: SpanInput): McpSpan {\n const method = input.request.method ?? 'unknown'\n const spanName = METHOD_TO_SPAN_NAME[method] ?? `mcp.${method}`\n const params = input.request.params as Record<string, unknown> | undefined\n const result = input.response.result as Record<string, unknown> | undefined\n\n const attributes = this.buildAttributes(method, params, result, input)\n const events = this.buildEvents(method, params, result)\n\n return {\n id: `${input.traceId}-${input.spanId}`,\n traceId: input.traceId,\n spanId: input.spanId,\n name: spanName,\n status: input.status,\n startedAt: input.startedAt,\n endedAt: input.endedAt,\n durationMs: input.durationMs,\n attributes,\n events,\n }\n }\n\n private buildAttributes(\n method: string,\n params: Record<string, unknown> | undefined,\n result: Record<string, unknown> | undefined,\n input: SpanInput\n ): Record<string, unknown> {\n const base: Record<string, unknown> = {\n 'gen_ai.operation.name': method,\n 'mcp.duration_ms': input.durationMs,\n }\n\n if (method === 'tools/call') {\n const name = (params as { name?: string } | undefined)?.name\n base['gen_ai.tool.name'] = name\n base['gen_ai.tool.call.id'] = randomBytes(8).toString('hex')\n }\n\n if (method === 'tools/list') {\n const tools = (result as { tools?: unknown[] } | undefined)?.tools\n base['mcp.tools_count'] = Array.isArray(tools) ? tools.length : 0\n }\n\n if (method === 'resources/read') {\n base['url.full'] = (params as { uri?: string } | undefined)?.uri\n }\n\n if (method === 'prompts/get') {\n base['mcp.prompt_name'] = (params as { name?: string } | undefined)?.name\n }\n\n if (method === 'initialize') {\n const p = params as { clientInfo?: { version?: string }; capabilities?: unknown } | undefined\n const r = result as { serverInfo?: { version?: string }; capabilities?: unknown } | undefined\n base['mcp.client_version'] = p?.clientInfo?.version\n base['mcp.server_version'] = r?.serverInfo?.version\n base['mcp.client_capabilities'] = JSON.stringify(p?.capabilities ?? {})\n base['mcp.server_capabilities'] = JSON.stringify(r?.capabilities ?? {})\n }\n\n return base\n }\n\n private buildEvents(\n method: string,\n params: Record<string, unknown> | undefined,\n result: Record<string, unknown> | undefined\n ) {\n const events = []\n\n if (method === 'tools/call') {\n events.push({ name: 'tool.input', timestamp: new Date(), attributes: { body: JSON.stringify(params) } })\n if (result) events.push({ name: 'tool.output', timestamp: new Date(), attributes: { body: JSON.stringify(result) } })\n }\n\n if (method === 'tools/list' && result) {\n events.push({ name: 'tools.list', timestamp: new Date(), attributes: { tools: JSON.stringify((result as { tools?: unknown }).tools ?? []) } })\n }\n\n if (method === 'prompts/get' && result) {\n events.push({ name: 'prompt.rendered', timestamp: new Date(), attributes: { body: JSON.stringify(result) } })\n }\n\n return events\n }\n}\n","import type { SpanStatus } from '@/types'\n\nexport interface ToolMetrics {\n callCount: number\n errorCount: number\n totalDurationMs: number\n}\n\nexport class MetricsRecorder {\n private metrics = new Map<string, ToolMetrics>()\n\n record(toolName: string, status: SpanStatus, durationMs: number): void {\n const existing = this.metrics.get(toolName) ?? { callCount: 0, errorCount: 0, totalDurationMs: 0 }\n existing.callCount++\n if (status === 'error') existing.errorCount++\n existing.totalDurationMs += durationMs\n this.metrics.set(toolName, existing)\n }\n\n getAll(): Map<string, ToolMetrics & { avgDurationMs: number }> {\n const result = new Map<string, ToolMetrics & { avgDurationMs: number }>()\n for (const [name, m] of this.metrics) {\n result.set(name, {\n ...m,\n avgDurationMs: m.callCount > 0 ? m.totalDurationMs / m.callCount : 0,\n })\n }\n return result\n }\n}\n","import { LogEmitter } from './LogEmitter'\nimport { McpSpanBuilder } from './McpSpanBuilder'\nimport { MetricsRecorder } from './MetricsRecorder'\n\nimport type { SpanInput } from './McpSpanBuilder'\nimport type { TraceStore } from '@/store/TraceStore'\n\nexport type { SpanInput }\n\nexport class TelemetryCollector {\n private spanBuilder = new McpSpanBuilder()\n private metrics = new MetricsRecorder()\n private log = new LogEmitter()\n\n constructor(private store: TraceStore) {}\n\n async record(input: SpanInput): Promise<void> {\n const span = this.spanBuilder.build(input)\n\n const toolName = (input.request.params as { name?: string } | undefined)?.name\n if (input.request.method === 'tools/call' && toolName) {\n this.metrics.record(toolName, input.status, input.durationMs)\n }\n\n const meta: Record<string, unknown> = { traceId: span.traceId, spanId: span.spanId }\n if (input.status === 'error' && input.response.error) {\n meta['error'] = input.response.error\n }\n this.log.debug(`${span.name} [${input.status}] ${input.durationMs}ms`, meta)\n\n try {\n await this.store.save(span)\n } catch (err) {\n this.log.error('Failed to save span', { err: String(err) })\n }\n }\n\n getMetrics() {\n return this.metrics.getAll()\n }\n}\n","import * as v from 'valibot'\n\nimport { StoreResolver } from '@/store/StoreResolver'\nimport { TransportFactory } from '@/transport/TransportFactory'\n\nimport { McpProxy } from './McpProxy'\n\nimport type { InboundConfig, OutboundConfig } from '@/types'\n\nconst InboundSchema = v.object({\n transport: v.picklist(['stdio', 'http', 'sse']),\n port: v.optional(v.number()),\n host: v.optional(v.string()),\n})\n\nconst OutboundSchema = v.object({\n transport: v.picklist(['stdio', 'http', 'sse']),\n url: v.optional(v.string()),\n command: v.optional(v.string()),\n args: v.optional(v.array(v.string())),\n})\n\nexport class ProxyBuilder {\n private _inbound?: InboundConfig\n private _outbound?: OutboundConfig\n private _store?: string\n\n static create(): ProxyBuilder {\n return new ProxyBuilder()\n }\n\n inbound(config: InboundConfig): this {\n this._inbound = v.parse(InboundSchema, config)\n return this\n }\n\n outbound(config: OutboundConfig): this {\n this._outbound = v.parse(OutboundSchema, config)\n return this\n }\n\n store(connectionString: string): this {\n this._store = connectionString\n return this\n }\n\n async build(): Promise<McpProxy> {\n if (!this._inbound) throw new Error('ProxyBuilder: inbound config is required')\n if (!this._outbound) throw new Error('ProxyBuilder: outbound config is required')\n if (!this._store) throw new Error('ProxyBuilder: store connection string is required')\n\n const inbound = TransportFactory.createInbound(this._inbound)\n const outbound = TransportFactory.createOutbound(this._outbound)\n const store = await StoreResolver.resolve(this._store)\n\n return new McpProxy(\n inbound,\n outbound as ConstructorParameters<typeof McpProxy>[1],\n store,\n )\n }\n}\n","import { homedir } from 'node:os'\n\nimport type { TraceStore } from './TraceStore'\n\ninterface InitableStore extends TraceStore {\n init(): Promise<void>\n}\n\nfunction toLibsqlUrl(connectionString: string): string {\n // Already a file: or :memory: URL — pass through\n if (connectionString.startsWith('file:') || connectionString === ':memory:') {\n return connectionString\n }\n // Strip sqlite:// scheme and expand ~ so @libsql/client gets a valid file: URL\n const raw = connectionString.replace(/^sqlite:\\/\\//, '')\n const expanded = raw.startsWith('~/') ? homedir() + raw.slice(1) : raw\n return `file:${expanded}`\n}\n\nexport class StoreResolver {\n static async resolve(connectionString: string): Promise<TraceStore> {\n let store: InitableStore\n\n if (connectionString.startsWith('sqlite://') || connectionString.startsWith('file:') || connectionString === ':memory:') {\n const { SqliteStore } = await import('./SqliteStore')\n store = new SqliteStore(toLibsqlUrl(connectionString))\n } else if (connectionString.startsWith('postgres://') || connectionString.startsWith('postgresql://')) {\n const { PostgresStore } = await import('./PostgresStore')\n store = new PostgresStore(connectionString)\n } else if (connectionString.startsWith('mysql://')) {\n const { MySqlStore } = await import('./MySqlStore')\n store = new MySqlStore(connectionString)\n } else {\n throw new Error(`Unsupported store connection string: \"${connectionString}\". Expected sqlite://, postgres://, or mysql://`)\n }\n\n await store.init()\n return store\n }\n}\n","import { createServer } from 'node:http'\n\nimport type { McpTransport } from './McpTransport'\nimport type { JsonRpcMessage } from '@/types'\n\nexport class HttpInbound implements McpTransport {\n private handler?: (msg: JsonRpcMessage) => Promise<JsonRpcMessage>\n private server\n\n constructor(private port: number, private host = '0.0.0.0') {\n this.server = createServer(async (req, res) => {\n if (req.method !== 'POST') {\n res.writeHead(405).end()\n return\n }\n const chunks: Buffer[] = []\n for await (const chunk of req) chunks.push(chunk as Buffer)\n const body = Buffer.concat(chunks).toString()\n\n try {\n const msg = JSON.parse(body) as JsonRpcMessage\n const response = this.handler ? await this.handler(msg) : { jsonrpc: '2.0' as const, id: msg.id, result: null }\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(response))\n } catch {\n res.writeHead(400).end()\n }\n })\n }\n\n async send(_message: JsonRpcMessage): Promise<void> {\n // HTTP inbound is request/response — responses go through the handler return value\n }\n\n onMessage(handler: (msg: JsonRpcMessage) => Promise<JsonRpcMessage>): void {\n this.handler = handler\n this.server.listen(this.port, this.host)\n }\n\n async close(): Promise<void> {\n await new Promise<void>((resolve, reject) =>\n this.server.close((err) => (err ? reject(err) : resolve()))\n )\n }\n}\n","import type { McpTransport } from './McpTransport'\nimport type { JsonRpcMessage } from '@/types'\n\nexport class HttpOutbound implements McpTransport {\n constructor(private url: string) {}\n\n async send(message: JsonRpcMessage): Promise<void> {\n await fetch(this.url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json, text/event-stream',\n },\n body: JSON.stringify(message),\n })\n }\n\n async sendAndWait(message: JsonRpcMessage): Promise<JsonRpcMessage> {\n let res: Response\n try {\n res = await fetch(this.url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json, text/event-stream',\n },\n body: JSON.stringify(message),\n })\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err)\n process.stderr.write(`[heimdall-mcp] fetch failed → ${this.url}: ${detail}\\n`)\n return {\n jsonrpc: '2.0',\n id: message.id ?? null,\n error: { code: -32603, message: `HTTP fetch failed: ${detail}` },\n }\n }\n\n const rawText = await res.text()\n\n if (!res.ok) {\n process.stderr.write(\n `[heimdall-mcp] target returned HTTP ${res.status} → ${this.url}\\n` +\n `[heimdall-mcp] response body: ${rawText.slice(0, 500)}\\n`\n )\n return {\n jsonrpc: '2.0',\n id: message.id ?? null,\n error: { code: -32603, message: `Target HTTP ${res.status}: ${rawText.slice(0, 200)}` },\n }\n }\n\n try {\n return JSON.parse(rawText) as JsonRpcMessage\n } catch {\n process.stderr.write(`[heimdall-mcp] target returned non-JSON: ${rawText.slice(0, 500)}\\n`)\n return {\n jsonrpc: '2.0',\n id: message.id ?? null,\n error: { code: -32603, message: `Target returned non-JSON: ${rawText.slice(0, 200)}` },\n }\n }\n }\n\n onMessage(_handler: (msg: JsonRpcMessage) => Promise<JsonRpcMessage>): void {}\n\n async close(): Promise<void> {}\n}\n","import { createServer } from 'node:http'\n\nimport type { McpTransport } from './McpTransport'\nimport type { JsonRpcMessage } from '@/types'\nimport type { ServerResponse } from 'node:http'\n\nexport class SseInbound implements McpTransport {\n private handler?: (msg: JsonRpcMessage) => Promise<JsonRpcMessage>\n private server\n private clients = new Set<ServerResponse>()\n\n constructor(private port: number, private host = '0.0.0.0') {\n this.server = createServer(async (req, res) => {\n if (req.url === '/sse' && req.method === 'GET') {\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n })\n this.clients.add(res)\n req.on('close', () => this.clients.delete(res))\n return\n }\n\n if (req.method === 'POST') {\n const chunks: Buffer[] = []\n for await (const chunk of req) chunks.push(chunk as Buffer)\n try {\n const msg = JSON.parse(Buffer.concat(chunks).toString()) as JsonRpcMessage\n const response = this.handler ? await this.handler(msg) : { jsonrpc: '2.0' as const, id: msg.id, result: null }\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(response))\n } catch {\n res.writeHead(400).end()\n }\n return\n }\n\n res.writeHead(404).end()\n })\n }\n\n async send(message: JsonRpcMessage): Promise<void> {\n const data = `data: ${JSON.stringify(message)}\\n\\n`\n for (const client of this.clients) client.write(data)\n }\n\n onMessage(handler: (msg: JsonRpcMessage) => Promise<JsonRpcMessage>): void {\n this.handler = handler\n this.server.listen(this.port, this.host)\n }\n\n async close(): Promise<void> {\n for (const client of this.clients) client.end()\n await new Promise<void>((resolve, reject) =>\n this.server.close((err) => (err ? reject(err) : resolve()))\n )\n }\n}\n","import type { McpTransport } from './McpTransport'\nimport type { JsonRpcMessage } from '@/types'\n\nexport class SseOutbound implements McpTransport {\n private eventSource?: EventSource\n private pending = new Map<string | number, (msg: JsonRpcMessage) => void>()\n\n constructor(private url: string) {}\n\n private ensureConnected() {\n if (this.eventSource) return\n // Node 22 has built-in EventSource\n this.eventSource = new EventSource(`${this.url}/sse`)\n this.eventSource.onmessage = (e) => {\n try {\n const msg = JSON.parse(e.data) as JsonRpcMessage\n const id = msg.id\n if (id != null) {\n const resolve = this.pending.get(id)\n if (resolve) {\n this.pending.delete(id)\n resolve(msg)\n }\n }\n } catch {\n // ignore\n }\n }\n }\n\n async send(message: JsonRpcMessage): Promise<void> {\n await fetch(this.url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(message),\n })\n }\n\n async sendAndWait(message: JsonRpcMessage): Promise<JsonRpcMessage> {\n this.ensureConnected()\n return new Promise((resolve, reject) => {\n const id = message.id\n if (id == null) {\n this.send(message).catch(reject)\n resolve({ jsonrpc: '2.0', id: null })\n return\n }\n this.pending.set(id, resolve)\n this.send(message).catch((err) => {\n this.pending.delete(id)\n reject(err)\n })\n })\n }\n\n onMessage(_handler: (msg: JsonRpcMessage) => Promise<JsonRpcMessage>): void {}\n\n async close(): Promise<void> {\n this.eventSource?.close()\n }\n}\n","import { createInterface } from 'node:readline'\n\nimport type { McpTransport } from './McpTransport'\nimport type { JsonRpcMessage } from '@/types'\n\nexport class StdioInbound implements McpTransport {\n private handler?: (msg: JsonRpcMessage) => Promise<JsonRpcMessage>\n\n async send(message: JsonRpcMessage): Promise<void> {\n process.stdout.write(JSON.stringify(message) + '\\n')\n }\n\n onMessage(handler: (msg: JsonRpcMessage) => Promise<JsonRpcMessage>): void {\n this.handler = handler\n const rl = createInterface({ input: process.stdin, terminal: false })\n\n rl.on('line', async (line) => {\n const trimmed = line.trim()\n if (!trimmed) return\n try {\n const msg = JSON.parse(trimmed) as JsonRpcMessage\n if (this.handler) {\n const response = await this.handler(msg)\n await this.send(response)\n }\n } catch {\n // malformed JSON — ignore\n }\n })\n }\n\n async close(): Promise<void> {\n process.stdin.destroy()\n }\n}\n","import { spawn } from 'node:child_process'\nimport { createInterface } from 'node:readline'\n\nimport type { McpTransport } from './McpTransport'\nimport type { JsonRpcMessage } from '@/types'\n\nexport class StdioOutbound implements McpTransport {\n private proc\n private pending = new Map<string | number, (msg: JsonRpcMessage) => void>()\n\n constructor(command: string, args: string[] = []) {\n this.proc = spawn(command, args, {\n stdio: ['pipe', 'pipe', 'inherit'],\n })\n\n const rl = createInterface({ input: this.proc.stdout!, terminal: false })\n rl.on('line', (line) => {\n const trimmed = line.trim()\n if (!trimmed) return\n try {\n const msg = JSON.parse(trimmed) as JsonRpcMessage\n const id = msg.id\n if (id != null) {\n const resolve = this.pending.get(id)\n if (resolve) {\n this.pending.delete(id)\n resolve(msg)\n }\n }\n } catch {\n // ignore\n }\n })\n }\n\n async send(message: JsonRpcMessage): Promise<void> {\n return new Promise((resolve, reject) => {\n this.proc.stdin!.write(JSON.stringify(message) + '\\n', (err) => {\n if (err) reject(err)\n else resolve()\n })\n })\n }\n\n async sendAndWait(message: JsonRpcMessage): Promise<JsonRpcMessage> {\n return new Promise((resolve, reject) => {\n const id = message.id\n if (id == null) {\n this.send(message).catch(reject)\n // notifications have no response — return empty ack\n resolve({ jsonrpc: '2.0', id: null })\n return\n }\n this.pending.set(id, resolve)\n this.send(message).catch((err) => {\n this.pending.delete(id)\n reject(err)\n })\n })\n }\n\n // McpTransport.onMessage is not used for outbound — responses come via sendAndWait\n onMessage(_handler: (msg: JsonRpcMessage) => Promise<JsonRpcMessage>): void {}\n\n async close(): Promise<void> {\n this.proc.stdin!.end()\n await new Promise<void>((resolve) => this.proc.on('close', resolve))\n }\n}\n","import { HttpInbound } from './HttpInbound'\nimport { HttpOutbound } from './HttpOutbound'\nimport { SseInbound } from './SseInbound'\nimport { SseOutbound } from './SseOutbound'\nimport { StdioInbound } from './StdioInbound'\nimport { StdioOutbound } from './StdioOutbound'\n\nimport type { McpTransport } from './McpTransport'\nimport type { InboundConfig, OutboundConfig } from '@/types'\n\nexport class TransportFactory {\n static createInbound(config: InboundConfig): McpTransport {\n switch (config.transport) {\n case 'stdio':\n return new StdioInbound()\n case 'http':\n return new HttpInbound(config.port ?? 3000, config.host)\n case 'sse':\n return new SseInbound(config.port ?? 3000, config.host)\n }\n }\n\n static createOutbound(config: OutboundConfig): McpTransport {\n switch (config.transport) {\n case 'stdio':\n if (!config.command) throw new Error('outbound stdio requires a command')\n return new StdioOutbound(config.command, config.args)\n case 'http':\n if (!config.url) throw new Error('outbound http requires a url')\n return new HttpOutbound(config.url)\n case 'sse':\n if (!config.url) throw new Error('outbound sse requires a url')\n return new SseOutbound(config.url)\n }\n }\n}\n"],"mappings":"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","names":["randomBytes","createServer","createInterface"]}
|
package/dist/cli.js
CHANGED
|
@@ -1,42 +1,83 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ProxyBuilder
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-7VRCO72I.js";
|
|
4
4
|
|
|
5
5
|
// src/cli.ts
|
|
6
6
|
import { Command } from "commander";
|
|
7
7
|
import pc from "picocolors";
|
|
8
|
+
function log(msg, ...args) {
|
|
9
|
+
process.stderr.write(`[heimdall-mcp] ${msg} ${args.map((a) => JSON.stringify(a)).join(" ")}
|
|
10
|
+
`);
|
|
11
|
+
}
|
|
8
12
|
var program = new Command();
|
|
9
13
|
program.name("heimdall-mcp").description("Transparent MCP proxy with tracing and configurable storage").version("0.1.0");
|
|
10
|
-
program.command("start", { isDefault: true }).description("Start the proxy (default command)").option("--store <url>", "Storage connection string (sqlite://, postgres://, mysql://)").option("--target <url>", "Target server URL for http/sse outbound").option("--in <transport>", "Inbound transport: stdio | http | sse", "stdio").option("--in-port <port>", "Port for inbound http/sse", parseInt).option("--out <transport>", "Outbound transport: stdio | http | sse", "stdio").option("--out-port <port>", "Port for outbound http/sse", parseInt).allowUnknownOption(true).action(async (opts
|
|
11
|
-
const
|
|
14
|
+
program.command("start", { isDefault: true }).description("Start the proxy (default command)").option("--store <url>", "Storage connection string (sqlite://, postgres://, mysql://)").option("--target <url>", "Target server URL for http/sse outbound").option("--in <transport>", "Inbound transport: stdio | http | sse", "stdio").option("--in-port <port>", "Port for inbound http/sse", parseInt).option("--out <transport>", "Outbound transport: stdio | http | sse", "stdio").option("--out-port <port>", "Port for outbound http/sse", parseInt).option("--debug", "Write verbose logs to stderr").allowUnknownOption(true).action(async (opts) => {
|
|
15
|
+
const debug = Boolean(opts.debug);
|
|
16
|
+
const dashDashIdx = process.argv.indexOf("--");
|
|
17
|
+
const subArgs = dashDashIdx >= 0 ? process.argv.slice(dashDashIdx + 1) : [];
|
|
18
|
+
const [subCommand, ...subCommandArgs] = subArgs;
|
|
19
|
+
if (debug) {
|
|
20
|
+
log("starting with config", {
|
|
21
|
+
store: opts.store,
|
|
22
|
+
inTransport: opts.in,
|
|
23
|
+
outTransport: opts.out,
|
|
24
|
+
target: opts.target ?? null,
|
|
25
|
+
subCommand: subCommand ?? null,
|
|
26
|
+
subCommandArgs
|
|
27
|
+
});
|
|
28
|
+
}
|
|
12
29
|
if (!opts.store) {
|
|
13
|
-
|
|
30
|
+
process.stderr.write(pc.red("Error: --store is required\n"));
|
|
14
31
|
process.exit(1);
|
|
15
32
|
}
|
|
16
33
|
const inTransport = opts.in;
|
|
17
34
|
const outTransport = opts.out;
|
|
18
|
-
const separatorIdx = rawArgs.indexOf("--");
|
|
19
|
-
const subArgs = separatorIdx >= 0 ? rawArgs.slice(separatorIdx + 1) : [];
|
|
20
|
-
const [subCommand, ...subCommandArgs] = subArgs;
|
|
21
35
|
const builder = ProxyBuilder.create().inbound({ transport: inTransport, port: opts.inPort }).store(opts.store);
|
|
22
36
|
if (outTransport === "stdio") {
|
|
23
37
|
if (!subCommand) {
|
|
24
|
-
|
|
38
|
+
process.stderr.write(pc.red("Error: stdio outbound requires a command after --\n"));
|
|
39
|
+
process.stderr.write(` Received process.argv: ${JSON.stringify(process.argv)}
|
|
40
|
+
`);
|
|
25
41
|
process.exit(1);
|
|
26
42
|
}
|
|
27
43
|
builder.outbound({ transport: "stdio", command: subCommand, args: subCommandArgs });
|
|
28
44
|
} else {
|
|
29
45
|
if (!opts.target) {
|
|
30
|
-
|
|
46
|
+
process.stderr.write(pc.red("Error: http/sse outbound requires --target <url>\n"));
|
|
31
47
|
process.exit(1);
|
|
32
48
|
}
|
|
33
49
|
builder.outbound({ transport: outTransport, url: opts.target });
|
|
34
50
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
51
|
+
let proxy;
|
|
52
|
+
try {
|
|
53
|
+
proxy = await builder.build();
|
|
54
|
+
} catch (err) {
|
|
55
|
+
process.stderr.write(pc.red(`Error building proxy: ${err}
|
|
56
|
+
`));
|
|
57
|
+
if (debug && err instanceof Error) process.stderr.write(err.stack + "\n");
|
|
58
|
+
process.exit(1);
|
|
59
|
+
}
|
|
60
|
+
if (debug) log("proxy built, starting...");
|
|
61
|
+
process.on("SIGINT", () => {
|
|
62
|
+
if (debug) log("SIGINT received, stopping");
|
|
63
|
+
proxy.stop().then(() => process.exit(0));
|
|
64
|
+
});
|
|
65
|
+
process.on("SIGTERM", () => {
|
|
66
|
+
if (debug) log("SIGTERM received, stopping");
|
|
67
|
+
proxy.stop().then(() => process.exit(0));
|
|
68
|
+
});
|
|
69
|
+
process.on("uncaughtException", (err) => {
|
|
70
|
+
process.stderr.write(pc.red(`[heimdall-mcp] uncaught: ${err}
|
|
71
|
+
`));
|
|
72
|
+
if (debug) process.stderr.write(err.stack + "\n");
|
|
73
|
+
});
|
|
74
|
+
proxy.on("error", (err) => {
|
|
75
|
+
process.stderr.write(pc.red(`[heimdall-mcp] proxy error: ${err}
|
|
76
|
+
`));
|
|
77
|
+
if (debug && err instanceof Error) process.stderr.write(err.stack + "\n");
|
|
78
|
+
});
|
|
39
79
|
await proxy.start();
|
|
80
|
+
if (debug) log("proxy running");
|
|
40
81
|
});
|
|
41
82
|
program.parse();
|
|
42
83
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { Command } from 'commander'\nimport pc from 'picocolors'\n\nimport { ProxyBuilder } from '@/proxy/ProxyBuilder'\n\nconst program = new Command()\n\nprogram\n .name('heimdall-mcp')\n .description('Transparent MCP proxy with tracing and configurable storage')\n .version('0.1.0')\n\nprogram\n .command('start', { isDefault: true })\n .description('Start the proxy (default command)')\n .option('--store <url>',
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { Command } from 'commander'\nimport pc from 'picocolors'\n\nimport { ProxyBuilder } from '@/proxy/ProxyBuilder'\n\nfunction log(msg: string, ...args: unknown[]) {\n process.stderr.write(`[heimdall-mcp] ${msg} ${args.map((a) => JSON.stringify(a)).join(' ')}\\n`)\n}\n\nconst program = new Command()\n\nprogram\n .name('heimdall-mcp')\n .description('Transparent MCP proxy with tracing and configurable storage')\n .version('0.1.0')\n\nprogram\n .command('start', { isDefault: true })\n .description('Start the proxy (default command)')\n .option('--store <url>', 'Storage connection string (sqlite://, postgres://, mysql://)')\n .option('--target <url>', 'Target server URL for http/sse outbound')\n .option('--in <transport>', 'Inbound transport: stdio | http | sse', 'stdio')\n .option('--in-port <port>', 'Port for inbound http/sse', parseInt)\n .option('--out <transport>', 'Outbound transport: stdio | http | sse', 'stdio')\n .option('--out-port <port>', 'Port for outbound http/sse', parseInt)\n .option('--debug', 'Write verbose logs to stderr')\n .allowUnknownOption(true)\n .action(async (opts) => {\n const debug = Boolean(opts.debug)\n\n // Commander may strip '--' from cmd.args — parse process.argv directly to be safe\n const dashDashIdx = process.argv.indexOf('--')\n const subArgs = dashDashIdx >= 0 ? process.argv.slice(dashDashIdx + 1) : []\n const [subCommand, ...subCommandArgs] = subArgs\n\n if (debug) {\n log('starting with config', {\n store: opts.store,\n inTransport: opts.in,\n outTransport: opts.out,\n target: opts.target ?? null,\n subCommand: subCommand ?? null,\n subCommandArgs,\n })\n }\n\n if (!opts.store) {\n process.stderr.write(pc.red('Error: --store is required\\n'))\n process.exit(1)\n }\n\n const inTransport = opts.in as 'stdio' | 'http' | 'sse'\n const outTransport = opts.out as 'stdio' | 'http' | 'sse'\n\n const builder = ProxyBuilder.create()\n .inbound({ transport: inTransport, port: opts.inPort })\n .store(opts.store)\n\n if (outTransport === 'stdio') {\n if (!subCommand) {\n process.stderr.write(pc.red('Error: stdio outbound requires a command after --\\n'))\n process.stderr.write(` Received process.argv: ${JSON.stringify(process.argv)}\\n`)\n process.exit(1)\n }\n builder.outbound({ transport: 'stdio', command: subCommand, args: subCommandArgs })\n } else {\n if (!opts.target) {\n process.stderr.write(pc.red('Error: http/sse outbound requires --target <url>\\n'))\n process.exit(1)\n }\n builder.outbound({ transport: outTransport, url: opts.target })\n }\n\n let proxy\n try {\n proxy = await builder.build()\n } catch (err) {\n process.stderr.write(pc.red(`Error building proxy: ${err}\\n`))\n if (debug && err instanceof Error) process.stderr.write(err.stack + '\\n')\n process.exit(1)\n }\n\n if (debug) log('proxy built, starting...')\n\n process.on('SIGINT', () => { if (debug) log('SIGINT received, stopping'); proxy.stop().then(() => process.exit(0)) })\n process.on('SIGTERM', () => { if (debug) log('SIGTERM received, stopping'); proxy.stop().then(() => process.exit(0)) })\n\n process.on('uncaughtException', (err) => {\n process.stderr.write(pc.red(`[heimdall-mcp] uncaught: ${err}\\n`))\n if (debug) process.stderr.write(err.stack + '\\n')\n })\n\n proxy.on('error', (err) => {\n process.stderr.write(pc.red(`[heimdall-mcp] proxy error: ${err}\\n`))\n if (debug && err instanceof Error) process.stderr.write(err.stack + '\\n')\n })\n\n await proxy.start()\n if (debug) log('proxy running')\n })\n\nprogram.parse()\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cardor/heimdall-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Transparent MCP proxy with OpenTelemetry tracing and configurable storage",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -14,7 +14,10 @@
|
|
|
14
14
|
"bin": {
|
|
15
15
|
"heimdall-mcp": "./bin/heimdall-mcp.js"
|
|
16
16
|
},
|
|
17
|
-
"files": [
|
|
17
|
+
"files": [
|
|
18
|
+
"bin",
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
18
21
|
"scripts": {
|
|
19
22
|
"build": "tsup",
|
|
20
23
|
"dev": "tsup --watch",
|
|
@@ -23,7 +26,13 @@
|
|
|
23
26
|
"prepublishOnly": "npm run build && npm test",
|
|
24
27
|
"prepare": "husky"
|
|
25
28
|
},
|
|
26
|
-
"keywords": [
|
|
29
|
+
"keywords": [
|
|
30
|
+
"mcp",
|
|
31
|
+
"proxy",
|
|
32
|
+
"opentelemetry",
|
|
33
|
+
"tracing",
|
|
34
|
+
"observability"
|
|
35
|
+
],
|
|
27
36
|
"author": "",
|
|
28
37
|
"license": "MIT",
|
|
29
38
|
"dependencies": {
|
|
@@ -50,4 +59,4 @@
|
|
|
50
59
|
"engines": {
|
|
51
60
|
"node": ">=22.5.0"
|
|
52
61
|
}
|
|
53
|
-
}
|
|
62
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/proxy/McpProxy.ts","../src/interceptor/ForwardInterceptor.ts","../src/interceptor/InterceptorPipeline.ts","../src/interceptor/TelemetryInterceptor.ts","../src/telemetry/LogEmitter.ts","../src/telemetry/McpSpanBuilder.ts","../src/telemetry/MetricsRecorder.ts","../src/telemetry/TelemetryCollector.ts","../src/proxy/ProxyBuilder.ts","../src/store/StoreResolver.ts","../src/transport/HttpInbound.ts","../src/transport/HttpOutbound.ts","../src/transport/SseInbound.ts","../src/transport/SseOutbound.ts","../src/transport/StdioInbound.ts","../src/transport/StdioOutbound.ts","../src/transport/TransportFactory.ts"],"sourcesContent":["import { EventEmitter } from 'node:events'\n\nimport { ForwardInterceptor } from '@/interceptor/ForwardInterceptor'\nimport { InterceptorPipeline } from '@/interceptor/InterceptorPipeline'\nimport { TelemetryInterceptor } from '@/interceptor/TelemetryInterceptor'\nimport { TelemetryCollector } from '@/telemetry/TelemetryCollector'\n\nimport type { TraceStore } from '@/store/TraceStore'\nimport type { HttpOutbound } from '@/transport/HttpOutbound'\nimport type { McpTransport } from '@/transport/McpTransport'\nimport type { SseOutbound } from '@/transport/SseOutbound'\nimport type { StdioOutbound } from '@/transport/StdioOutbound'\n\nexport class McpProxy extends EventEmitter {\n private pipeline: InterceptorPipeline\n\n constructor(\n private inbound: McpTransport,\n private outbound: StdioOutbound | HttpOutbound | SseOutbound,\n store: TraceStore,\n ) {\n super()\n const collector = new TelemetryCollector(store)\n this.pipeline = new InterceptorPipeline()\n this.pipeline.use(new TelemetryInterceptor(collector))\n this.pipeline.use(new ForwardInterceptor(outbound))\n }\n\n addInterceptor(interceptor: Parameters<InterceptorPipeline['use']>[0]): this {\n // insert before ForwardInterceptor (last item) — not possible post-construction\n // so this is a pre-build concern; McpProxy accepts a custom pipeline instead\n this.pipeline.use(interceptor)\n return this\n }\n\n async start(): Promise<void> {\n this.inbound.onMessage(async (msg) => {\n try {\n return await this.pipeline.run(msg)\n } catch (err) {\n this.emit('error', err)\n return {\n jsonrpc: '2.0' as const,\n id: msg.id,\n error: { code: -32603, message: String(err) },\n }\n }\n })\n }\n\n async stop(): Promise<void> {\n await this.inbound.close()\n await this.outbound.close()\n }\n}\n","import type { Interceptor, InterceptorContext } from './Interceptor'\nimport type { HttpOutbound } from '@/transport/HttpOutbound'\nimport type { SseOutbound } from '@/transport/SseOutbound'\nimport type { StdioOutbound } from '@/transport/StdioOutbound'\nimport type { JsonRpcMessage } from '@/types'\n\ntype ForwardableOutbound = StdioOutbound | HttpOutbound | SseOutbound\n\nexport class ForwardInterceptor implements Interceptor {\n readonly name = 'ForwardInterceptor'\n\n constructor(private outbound: ForwardableOutbound) {}\n\n async intercept(\n request: JsonRpcMessage,\n _context: InterceptorContext,\n _next: () => Promise<JsonRpcMessage>\n ): Promise<JsonRpcMessage> {\n return this.outbound.sendAndWait(request)\n }\n}\n","import { randomBytes } from 'node:crypto'\n\nimport type { Interceptor, InterceptorContext } from './Interceptor'\nimport type { JsonRpcMessage } from '@/types'\n\nexport class InterceptorPipeline {\n private interceptors: Interceptor[] = []\n\n use(interceptor: Interceptor): this {\n this.interceptors.push(interceptor)\n return this\n }\n\n async run(request: JsonRpcMessage): Promise<JsonRpcMessage> {\n const context: InterceptorContext = {\n startedAt: new Date(),\n traceId: randomBytes(16).toString('hex'),\n spanId: randomBytes(8).toString('hex'),\n metadata: {},\n }\n\n let index = 0\n const next = async (): Promise<JsonRpcMessage> => {\n const interceptor = this.interceptors[index++]\n if (!interceptor) throw new Error('Pipeline ended without ForwardInterceptor')\n return interceptor.intercept(request, context, next)\n }\n\n return next()\n }\n}\n","import type { Interceptor, InterceptorContext } from './Interceptor'\nimport type { TelemetryCollector } from '@/telemetry/TelemetryCollector'\nimport type { JsonRpcMessage } from '@/types'\n\nexport class TelemetryInterceptor implements Interceptor {\n readonly name = 'TelemetryInterceptor'\n\n constructor(private collector: TelemetryCollector) {}\n\n async intercept(\n request: JsonRpcMessage,\n context: InterceptorContext,\n next: () => Promise<JsonRpcMessage>\n ): Promise<JsonRpcMessage> {\n context.startedAt = new Date()\n\n let response: JsonRpcMessage\n let status: 'ok' | 'error' = 'ok'\n\n try {\n response = await next()\n if (response.error) status = 'error'\n } catch (err) {\n status = 'error'\n response = {\n jsonrpc: '2.0',\n id: request.id,\n error: { code: -32603, message: String(err) },\n }\n }\n\n const endedAt = new Date()\n const durationMs = endedAt.getTime() - context.startedAt.getTime()\n\n await this.collector.record({\n traceId: context.traceId,\n spanId: context.spanId,\n request,\n response,\n status,\n startedAt: context.startedAt,\n endedAt,\n durationMs,\n })\n\n return response\n }\n}\n","import pc from 'picocolors'\n\ntype LogLevel = 'info' | 'warn' | 'error' | 'debug'\n\nexport class LogEmitter {\n private enabled: boolean\n\n constructor(enabled = true) {\n this.enabled = enabled\n }\n\n info(message: string, meta?: Record<string, unknown>): void {\n this.emit('info', message, meta)\n }\n\n warn(message: string, meta?: Record<string, unknown>): void {\n this.emit('warn', message, meta)\n }\n\n error(message: string, meta?: Record<string, unknown>): void {\n this.emit('error', message, meta)\n }\n\n debug(message: string, meta?: Record<string, unknown>): void {\n this.emit('debug', message, meta)\n }\n\n private emit(level: LogLevel, message: string, meta?: Record<string, unknown>): void {\n if (!this.enabled) return\n const ts = new Date().toISOString()\n const prefix = {\n info: pc.blue('[info]'),\n warn: pc.yellow('[warn]'),\n error: pc.red('[error]'),\n debug: pc.gray('[debug]'),\n }[level]\n const metaStr = meta ? ' ' + JSON.stringify(meta) : ''\n process.stderr.write(`${ts} ${prefix} ${message}${metaStr}\\n`)\n }\n}\n","import { randomBytes } from 'node:crypto'\n\nimport type { JsonRpcMessage, McpSpan, SpanStatus } from '@/types'\n\nexport interface SpanInput {\n traceId: string\n spanId: string\n request: JsonRpcMessage\n response: JsonRpcMessage\n status: SpanStatus\n startedAt: Date\n endedAt: Date\n durationMs: number\n}\n\nconst METHOD_TO_SPAN_NAME: Record<string, string> = {\n initialize: 'mcp.initialize',\n 'tools/list': 'mcp.tools.list',\n 'tools/call': 'mcp.tool.call',\n 'resources/read': 'mcp.resource.read',\n 'resources/list': 'mcp.resources.list',\n 'prompts/get': 'mcp.prompt.get',\n 'prompts/list': 'mcp.prompts.list',\n shutdown: 'mcp.shutdown',\n}\n\nexport class McpSpanBuilder {\n build(input: SpanInput): McpSpan {\n const method = input.request.method ?? 'unknown'\n const spanName = METHOD_TO_SPAN_NAME[method] ?? `mcp.${method}`\n const params = input.request.params as Record<string, unknown> | undefined\n const result = input.response.result as Record<string, unknown> | undefined\n\n const attributes = this.buildAttributes(method, params, result, input)\n const events = this.buildEvents(method, params, result)\n\n return {\n id: `${input.traceId}-${input.spanId}`,\n traceId: input.traceId,\n spanId: input.spanId,\n name: spanName,\n status: input.status,\n startedAt: input.startedAt,\n endedAt: input.endedAt,\n durationMs: input.durationMs,\n attributes,\n events,\n }\n }\n\n private buildAttributes(\n method: string,\n params: Record<string, unknown> | undefined,\n result: Record<string, unknown> | undefined,\n input: SpanInput\n ): Record<string, unknown> {\n const base: Record<string, unknown> = {\n 'gen_ai.operation.name': method,\n 'mcp.duration_ms': input.durationMs,\n }\n\n if (method === 'tools/call') {\n const name = (params as { name?: string } | undefined)?.name\n base['gen_ai.tool.name'] = name\n base['gen_ai.tool.call.id'] = randomBytes(8).toString('hex')\n }\n\n if (method === 'tools/list') {\n const tools = (result as { tools?: unknown[] } | undefined)?.tools\n base['mcp.tools_count'] = Array.isArray(tools) ? tools.length : 0\n }\n\n if (method === 'resources/read') {\n base['url.full'] = (params as { uri?: string } | undefined)?.uri\n }\n\n if (method === 'prompts/get') {\n base['mcp.prompt_name'] = (params as { name?: string } | undefined)?.name\n }\n\n if (method === 'initialize') {\n const p = params as { clientInfo?: { version?: string }; capabilities?: unknown } | undefined\n const r = result as { serverInfo?: { version?: string }; capabilities?: unknown } | undefined\n base['mcp.client_version'] = p?.clientInfo?.version\n base['mcp.server_version'] = r?.serverInfo?.version\n base['mcp.client_capabilities'] = JSON.stringify(p?.capabilities ?? {})\n base['mcp.server_capabilities'] = JSON.stringify(r?.capabilities ?? {})\n }\n\n return base\n }\n\n private buildEvents(\n method: string,\n params: Record<string, unknown> | undefined,\n result: Record<string, unknown> | undefined\n ) {\n const events = []\n\n if (method === 'tools/call') {\n events.push({ name: 'tool.input', timestamp: new Date(), attributes: { body: JSON.stringify(params) } })\n if (result) events.push({ name: 'tool.output', timestamp: new Date(), attributes: { body: JSON.stringify(result) } })\n }\n\n if (method === 'tools/list' && result) {\n events.push({ name: 'tools.list', timestamp: new Date(), attributes: { tools: JSON.stringify((result as { tools?: unknown }).tools ?? []) } })\n }\n\n if (method === 'prompts/get' && result) {\n events.push({ name: 'prompt.rendered', timestamp: new Date(), attributes: { body: JSON.stringify(result) } })\n }\n\n return events\n }\n}\n","import type { SpanStatus } from '@/types'\n\nexport interface ToolMetrics {\n callCount: number\n errorCount: number\n totalDurationMs: number\n}\n\nexport class MetricsRecorder {\n private metrics = new Map<string, ToolMetrics>()\n\n record(toolName: string, status: SpanStatus, durationMs: number): void {\n const existing = this.metrics.get(toolName) ?? { callCount: 0, errorCount: 0, totalDurationMs: 0 }\n existing.callCount++\n if (status === 'error') existing.errorCount++\n existing.totalDurationMs += durationMs\n this.metrics.set(toolName, existing)\n }\n\n getAll(): Map<string, ToolMetrics & { avgDurationMs: number }> {\n const result = new Map<string, ToolMetrics & { avgDurationMs: number }>()\n for (const [name, m] of this.metrics) {\n result.set(name, {\n ...m,\n avgDurationMs: m.callCount > 0 ? m.totalDurationMs / m.callCount : 0,\n })\n }\n return result\n }\n}\n","import { LogEmitter } from './LogEmitter'\nimport { McpSpanBuilder } from './McpSpanBuilder'\nimport { MetricsRecorder } from './MetricsRecorder'\n\nimport type { SpanInput } from './McpSpanBuilder'\nimport type { TraceStore } from '@/store/TraceStore'\n\nexport type { SpanInput }\n\nexport class TelemetryCollector {\n private spanBuilder = new McpSpanBuilder()\n private metrics = new MetricsRecorder()\n private log = new LogEmitter()\n\n constructor(private store: TraceStore) {}\n\n async record(input: SpanInput): Promise<void> {\n const span = this.spanBuilder.build(input)\n\n const toolName = (input.request.params as { name?: string } | undefined)?.name\n if (input.request.method === 'tools/call' && toolName) {\n this.metrics.record(toolName, input.status, input.durationMs)\n }\n\n this.log.debug(`${span.name} [${input.status}] ${input.durationMs}ms`, {\n traceId: span.traceId,\n spanId: span.spanId,\n })\n\n try {\n await this.store.save(span)\n } catch (err) {\n this.log.error('Failed to save span', { err: String(err) })\n }\n }\n\n getMetrics() {\n return this.metrics.getAll()\n }\n}\n","import * as v from 'valibot'\n\nimport { StoreResolver } from '@/store/StoreResolver'\nimport { TransportFactory } from '@/transport/TransportFactory'\n\nimport { McpProxy } from './McpProxy'\n\nimport type { InboundConfig, OutboundConfig } from '@/types'\n\nconst InboundSchema = v.object({\n transport: v.picklist(['stdio', 'http', 'sse']),\n port: v.optional(v.number()),\n host: v.optional(v.string()),\n})\n\nconst OutboundSchema = v.object({\n transport: v.picklist(['stdio', 'http', 'sse']),\n url: v.optional(v.string()),\n command: v.optional(v.string()),\n args: v.optional(v.array(v.string())),\n})\n\nexport class ProxyBuilder {\n private _inbound?: InboundConfig\n private _outbound?: OutboundConfig\n private _store?: string\n\n static create(): ProxyBuilder {\n return new ProxyBuilder()\n }\n\n inbound(config: InboundConfig): this {\n this._inbound = v.parse(InboundSchema, config)\n return this\n }\n\n outbound(config: OutboundConfig): this {\n this._outbound = v.parse(OutboundSchema, config)\n return this\n }\n\n store(connectionString: string): this {\n this._store = connectionString\n return this\n }\n\n async build(): Promise<McpProxy> {\n if (!this._inbound) throw new Error('ProxyBuilder: inbound config is required')\n if (!this._outbound) throw new Error('ProxyBuilder: outbound config is required')\n if (!this._store) throw new Error('ProxyBuilder: store connection string is required')\n\n const inbound = TransportFactory.createInbound(this._inbound)\n const outbound = TransportFactory.createOutbound(this._outbound)\n const store = await StoreResolver.resolve(this._store)\n\n return new McpProxy(\n inbound,\n outbound as ConstructorParameters<typeof McpProxy>[1],\n store,\n )\n }\n}\n","import { homedir } from 'node:os'\n\nimport type { TraceStore } from './TraceStore'\n\ninterface InitableStore extends TraceStore {\n init(): Promise<void>\n}\n\nfunction toLibsqlUrl(connectionString: string): string {\n // Already a file: or :memory: URL — pass through\n if (connectionString.startsWith('file:') || connectionString === ':memory:') {\n return connectionString\n }\n // Strip sqlite:// scheme and expand ~ so @libsql/client gets a valid file: URL\n const raw = connectionString.replace(/^sqlite:\\/\\//, '')\n const expanded = raw.startsWith('~/') ? homedir() + raw.slice(1) : raw\n return `file:${expanded}`\n}\n\nexport class StoreResolver {\n static async resolve(connectionString: string): Promise<TraceStore> {\n let store: InitableStore\n\n if (connectionString.startsWith('sqlite://') || connectionString.startsWith('file:') || connectionString === ':memory:') {\n const { SqliteStore } = await import('./SqliteStore')\n store = new SqliteStore(toLibsqlUrl(connectionString))\n } else if (connectionString.startsWith('postgres://') || connectionString.startsWith('postgresql://')) {\n const { PostgresStore } = await import('./PostgresStore')\n store = new PostgresStore(connectionString)\n } else if (connectionString.startsWith('mysql://')) {\n const { MySqlStore } = await import('./MySqlStore')\n store = new MySqlStore(connectionString)\n } else {\n throw new Error(`Unsupported store connection string: \"${connectionString}\". Expected sqlite://, postgres://, or mysql://`)\n }\n\n await store.init()\n return store\n }\n}\n","import { createServer } from 'node:http'\n\nimport type { McpTransport } from './McpTransport'\nimport type { JsonRpcMessage } from '@/types'\n\nexport class HttpInbound implements McpTransport {\n private handler?: (msg: JsonRpcMessage) => Promise<JsonRpcMessage>\n private server\n\n constructor(private port: number, private host = '0.0.0.0') {\n this.server = createServer(async (req, res) => {\n if (req.method !== 'POST') {\n res.writeHead(405).end()\n return\n }\n const chunks: Buffer[] = []\n for await (const chunk of req) chunks.push(chunk as Buffer)\n const body = Buffer.concat(chunks).toString()\n\n try {\n const msg = JSON.parse(body) as JsonRpcMessage\n const response = this.handler ? await this.handler(msg) : { jsonrpc: '2.0' as const, id: msg.id, result: null }\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(response))\n } catch {\n res.writeHead(400).end()\n }\n })\n }\n\n async send(_message: JsonRpcMessage): Promise<void> {\n // HTTP inbound is request/response — responses go through the handler return value\n }\n\n onMessage(handler: (msg: JsonRpcMessage) => Promise<JsonRpcMessage>): void {\n this.handler = handler\n this.server.listen(this.port, this.host)\n }\n\n async close(): Promise<void> {\n await new Promise<void>((resolve, reject) =>\n this.server.close((err) => (err ? reject(err) : resolve()))\n )\n }\n}\n","import type { McpTransport } from './McpTransport'\nimport type { JsonRpcMessage } from '@/types'\n\nexport class HttpOutbound implements McpTransport {\n constructor(private url: string) {}\n\n async send(message: JsonRpcMessage): Promise<void> {\n await fetch(this.url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(message),\n })\n }\n\n async sendAndWait(message: JsonRpcMessage): Promise<JsonRpcMessage> {\n const res = await fetch(this.url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(message),\n })\n return res.json() as Promise<JsonRpcMessage>\n }\n\n onMessage(_handler: (msg: JsonRpcMessage) => Promise<JsonRpcMessage>): void {}\n\n async close(): Promise<void> {}\n}\n","import { createServer } from 'node:http'\n\nimport type { McpTransport } from './McpTransport'\nimport type { JsonRpcMessage } from '@/types'\nimport type { ServerResponse } from 'node:http'\n\nexport class SseInbound implements McpTransport {\n private handler?: (msg: JsonRpcMessage) => Promise<JsonRpcMessage>\n private server\n private clients = new Set<ServerResponse>()\n\n constructor(private port: number, private host = '0.0.0.0') {\n this.server = createServer(async (req, res) => {\n if (req.url === '/sse' && req.method === 'GET') {\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n })\n this.clients.add(res)\n req.on('close', () => this.clients.delete(res))\n return\n }\n\n if (req.method === 'POST') {\n const chunks: Buffer[] = []\n for await (const chunk of req) chunks.push(chunk as Buffer)\n try {\n const msg = JSON.parse(Buffer.concat(chunks).toString()) as JsonRpcMessage\n const response = this.handler ? await this.handler(msg) : { jsonrpc: '2.0' as const, id: msg.id, result: null }\n res.writeHead(200, { 'Content-Type': 'application/json' })\n res.end(JSON.stringify(response))\n } catch {\n res.writeHead(400).end()\n }\n return\n }\n\n res.writeHead(404).end()\n })\n }\n\n async send(message: JsonRpcMessage): Promise<void> {\n const data = `data: ${JSON.stringify(message)}\\n\\n`\n for (const client of this.clients) client.write(data)\n }\n\n onMessage(handler: (msg: JsonRpcMessage) => Promise<JsonRpcMessage>): void {\n this.handler = handler\n this.server.listen(this.port, this.host)\n }\n\n async close(): Promise<void> {\n for (const client of this.clients) client.end()\n await new Promise<void>((resolve, reject) =>\n this.server.close((err) => (err ? reject(err) : resolve()))\n )\n }\n}\n","import type { McpTransport } from './McpTransport'\nimport type { JsonRpcMessage } from '@/types'\n\nexport class SseOutbound implements McpTransport {\n private eventSource?: EventSource\n private pending = new Map<string | number, (msg: JsonRpcMessage) => void>()\n\n constructor(private url: string) {}\n\n private ensureConnected() {\n if (this.eventSource) return\n // Node 22 has built-in EventSource\n this.eventSource = new EventSource(`${this.url}/sse`)\n this.eventSource.onmessage = (e) => {\n try {\n const msg = JSON.parse(e.data) as JsonRpcMessage\n const id = msg.id\n if (id != null) {\n const resolve = this.pending.get(id)\n if (resolve) {\n this.pending.delete(id)\n resolve(msg)\n }\n }\n } catch {\n // ignore\n }\n }\n }\n\n async send(message: JsonRpcMessage): Promise<void> {\n await fetch(this.url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(message),\n })\n }\n\n async sendAndWait(message: JsonRpcMessage): Promise<JsonRpcMessage> {\n this.ensureConnected()\n return new Promise((resolve, reject) => {\n const id = message.id\n if (id == null) {\n this.send(message).catch(reject)\n resolve({ jsonrpc: '2.0', id: null })\n return\n }\n this.pending.set(id, resolve)\n this.send(message).catch((err) => {\n this.pending.delete(id)\n reject(err)\n })\n })\n }\n\n onMessage(_handler: (msg: JsonRpcMessage) => Promise<JsonRpcMessage>): void {}\n\n async close(): Promise<void> {\n this.eventSource?.close()\n }\n}\n","import { createInterface } from 'node:readline'\n\nimport type { McpTransport } from './McpTransport'\nimport type { JsonRpcMessage } from '@/types'\n\nexport class StdioInbound implements McpTransport {\n private handler?: (msg: JsonRpcMessage) => Promise<JsonRpcMessage>\n\n async send(message: JsonRpcMessage): Promise<void> {\n process.stdout.write(JSON.stringify(message) + '\\n')\n }\n\n onMessage(handler: (msg: JsonRpcMessage) => Promise<JsonRpcMessage>): void {\n this.handler = handler\n const rl = createInterface({ input: process.stdin, terminal: false })\n\n rl.on('line', async (line) => {\n const trimmed = line.trim()\n if (!trimmed) return\n try {\n const msg = JSON.parse(trimmed) as JsonRpcMessage\n if (this.handler) {\n const response = await this.handler(msg)\n await this.send(response)\n }\n } catch {\n // malformed JSON — ignore\n }\n })\n }\n\n async close(): Promise<void> {\n process.stdin.destroy()\n }\n}\n","import { spawn } from 'node:child_process'\nimport { createInterface } from 'node:readline'\n\nimport type { McpTransport } from './McpTransport'\nimport type { JsonRpcMessage } from '@/types'\n\nexport class StdioOutbound implements McpTransport {\n private proc\n private pending = new Map<string | number, (msg: JsonRpcMessage) => void>()\n\n constructor(command: string, args: string[] = []) {\n this.proc = spawn(command, args, {\n stdio: ['pipe', 'pipe', 'inherit'],\n })\n\n const rl = createInterface({ input: this.proc.stdout!, terminal: false })\n rl.on('line', (line) => {\n const trimmed = line.trim()\n if (!trimmed) return\n try {\n const msg = JSON.parse(trimmed) as JsonRpcMessage\n const id = msg.id\n if (id != null) {\n const resolve = this.pending.get(id)\n if (resolve) {\n this.pending.delete(id)\n resolve(msg)\n }\n }\n } catch {\n // ignore\n }\n })\n }\n\n async send(message: JsonRpcMessage): Promise<void> {\n return new Promise((resolve, reject) => {\n this.proc.stdin!.write(JSON.stringify(message) + '\\n', (err) => {\n if (err) reject(err)\n else resolve()\n })\n })\n }\n\n async sendAndWait(message: JsonRpcMessage): Promise<JsonRpcMessage> {\n return new Promise((resolve, reject) => {\n const id = message.id\n if (id == null) {\n this.send(message).catch(reject)\n // notifications have no response — return empty ack\n resolve({ jsonrpc: '2.0', id: null })\n return\n }\n this.pending.set(id, resolve)\n this.send(message).catch((err) => {\n this.pending.delete(id)\n reject(err)\n })\n })\n }\n\n // McpTransport.onMessage is not used for outbound — responses come via sendAndWait\n onMessage(_handler: (msg: JsonRpcMessage) => Promise<JsonRpcMessage>): void {}\n\n async close(): Promise<void> {\n this.proc.stdin!.end()\n await new Promise<void>((resolve) => this.proc.on('close', resolve))\n }\n}\n","import { HttpInbound } from './HttpInbound'\nimport { HttpOutbound } from './HttpOutbound'\nimport { SseInbound } from './SseInbound'\nimport { SseOutbound } from './SseOutbound'\nimport { StdioInbound } from './StdioInbound'\nimport { StdioOutbound } from './StdioOutbound'\n\nimport type { McpTransport } from './McpTransport'\nimport type { InboundConfig, OutboundConfig } from '@/types'\n\nexport class TransportFactory {\n static createInbound(config: InboundConfig): McpTransport {\n switch (config.transport) {\n case 'stdio':\n return new StdioInbound()\n case 'http':\n return new HttpInbound(config.port ?? 3000, config.host)\n case 'sse':\n return new SseInbound(config.port ?? 3000, config.host)\n }\n }\n\n static createOutbound(config: OutboundConfig): McpTransport {\n switch (config.transport) {\n case 'stdio':\n if (!config.command) throw new Error('outbound stdio requires a command')\n return new StdioOutbound(config.command, config.args)\n case 'http':\n if (!config.url) throw new Error('outbound http requires a url')\n return new HttpOutbound(config.url)\n case 'sse':\n if (!config.url) throw new Error('outbound sse requires a url')\n return new SseOutbound(config.url)\n }\n }\n}\n"],"mappings":"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","names":["randomBytes","createServer","createInterface"]}
|