Admin c41d242667
Some checks failed
CI / verify (push) Has been cancelled
CI / print-rust (push) Has been cancelled
feat(api): serve Keycloak-protected read-only FieldLens MCP telemetry
2026-09-27 00:09:43 +00:00

48 lines
2.1 KiB
TypeScript

import type { Request, Response } from 'express'
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'
import { z } from 'zod/v4'
import { config } from './config.js'
import { pool } from './db.js'
import { log } from './log.js'
export function captureLimit(value: number) {
return Number.isFinite(value) ? Math.max(1, Math.min(200, Math.trunc(value))) : 50
}
export function createFieldLensMcpServer() {
const server = new McpServer({ name: 'fieldlens', version: '1.0.0' })
server.registerTool('list_print_captures', {
description: 'Read recent FieldLens printer capture diagnostics for the authorized tenant. No print document or barcode values are included.',
inputSchema: { limit: z.number().int().min(1).max(200).optional() },
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false },
}, async ({ limit }) => {
const result = await pool.query(`
SELECT id, device_id AS "deviceId", source, stream_format AS "streamFormat",
byte_count AS "byteCount", barcode_count AS "barcodeCount", forwarded,
failure_kind AS "failureKind", app_version AS "appVersion",
captured_at AS "capturedAt", received_at AS "receivedAt"
FROM print_capture_diagnostics WHERE tenant_id = $1
ORDER BY captured_at DESC LIMIT $2
`, [config.tenantId, captureLimit(limit ?? 50)])
return { content: [{ type: 'text', text: JSON.stringify({ captures: result.rows }) }] }
})
return server
}
export async function handleMcpRequest(req: Request, res: Response) {
const server = createFieldLensMcpServer()
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined, enableJsonResponse: true })
res.once('close', () => {
void transport.close()
void server.close()
})
try {
await server.connect(transport)
await transport.handleRequest(req, res, req.body)
} catch {
log('error', 'mcp_request_failed')
if (!res.headersSent) res.status(500).json({ jsonrpc: '2.0', error: { code: -32603, message: 'Internal server error' }, id: null })
}
}