@tigerdata/mcp-boilerplate 0.3.0 → 0.4.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/dist/http/mcp.js +38 -15
- package/dist/tracing.d.ts +1 -1
- package/dist/tracing.js +6 -0
- package/package.json +2 -1
package/dist/http/mcp.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js';
|
|
2
2
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
3
|
+
import { trace, context as otelContext, propagation, SpanKind, SpanStatusCode, } from '@opentelemetry/api';
|
|
4
|
+
import { ATTR_HTTP_RESPONSE_STATUS_CODE } from '@opentelemetry/semantic-conventions';
|
|
3
5
|
import { Router } from 'express';
|
|
4
6
|
import { randomUUID } from 'node:crypto';
|
|
5
7
|
import getRawBody from 'raw-body';
|
|
6
8
|
import { log } from '../logger.js';
|
|
9
|
+
const name = process.env.OTEL_SERVICE_NAME;
|
|
10
|
+
const tracer = trace.getTracer(name ? `${name}.router.mcp` : 'router.mcp');
|
|
7
11
|
export const mcpRouterFactory = (context, createServer, { name, stateful = true, } = {}) => {
|
|
8
12
|
const router = Router();
|
|
9
13
|
const transports = new Map();
|
|
@@ -75,24 +79,43 @@ export const mcpRouterFactory = (context, createServer, { name, stateful = true,
|
|
|
75
79
|
await transport.handleRequest(req, res, body);
|
|
76
80
|
};
|
|
77
81
|
router.post('/', async (req, res) => {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
let traceContext = otelContext.active();
|
|
83
|
+
if (req.headers.traceparent) {
|
|
84
|
+
// Some MCP clients (e.g. pydantic) pass the parent trace context
|
|
85
|
+
traceContext = propagation.extract(traceContext, {
|
|
86
|
+
traceparent: req.headers.traceparent,
|
|
87
|
+
});
|
|
82
88
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
89
|
+
await tracer.startActiveSpan('mcp.http.post', { kind: SpanKind.SERVER }, traceContext, async (span) => {
|
|
90
|
+
try {
|
|
91
|
+
await (stateful
|
|
92
|
+
? handleStatefulRequest(req, res)
|
|
93
|
+
: handleStatelessRequest(req, res));
|
|
94
|
+
span.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE, res.statusCode);
|
|
95
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
log.error('Error handling MCP request:', error);
|
|
99
|
+
span.recordException(error);
|
|
100
|
+
span.setStatus({
|
|
101
|
+
code: SpanStatusCode.ERROR,
|
|
102
|
+
message: error.message,
|
|
93
103
|
});
|
|
104
|
+
if (!res.headersSent) {
|
|
105
|
+
res.status(500).json({
|
|
106
|
+
jsonrpc: '2.0',
|
|
107
|
+
error: {
|
|
108
|
+
code: -32603,
|
|
109
|
+
message: 'Internal server error',
|
|
110
|
+
},
|
|
111
|
+
id: null,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
94
114
|
}
|
|
95
|
-
|
|
115
|
+
finally {
|
|
116
|
+
span.end();
|
|
117
|
+
}
|
|
118
|
+
});
|
|
96
119
|
});
|
|
97
120
|
// Reusable handler for GET and DELETE requests
|
|
98
121
|
const handleSessionRequest = async (req, res) => {
|
package/dist/tracing.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Span, type Tracer } from '@opentelemetry/api';
|
|
2
2
|
import type { GenerateTextResult, ModelMessage } from 'ai';
|
|
3
3
|
export declare const withSpan: <T>(tracer: Tracer, name: string, fn: (span: Span) => Promise<T>) => Promise<T>;
|
|
4
4
|
export declare const addAiResultToSpan: (span: Span, aiResult: GenerateTextResult<any, unknown>, inputMessages: ModelMessage[]) => void;
|
package/dist/tracing.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SpanStatusCode } from '@opentelemetry/api';
|
|
1
2
|
import { log } from './logger.js';
|
|
2
3
|
export const withSpan = async (tracer, name, fn) => {
|
|
3
4
|
return tracer.startActiveSpan(name, async (span) => {
|
|
@@ -6,6 +7,11 @@ export const withSpan = async (tracer, name, fn) => {
|
|
|
6
7
|
}
|
|
7
8
|
catch (error) {
|
|
8
9
|
log.error(`Error in span ${name}`, error);
|
|
10
|
+
span.recordException(error);
|
|
11
|
+
span.setStatus({
|
|
12
|
+
code: SpanStatusCode.ERROR,
|
|
13
|
+
message: error.message,
|
|
14
|
+
});
|
|
9
15
|
throw error;
|
|
10
16
|
}
|
|
11
17
|
finally {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tigerdata/mcp-boilerplate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "MCP boilerplate code for Node.js",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "TigerData",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"@opentelemetry/sdk-metrics": "^2.2.0",
|
|
42
42
|
"@opentelemetry/sdk-node": "^0.207.0",
|
|
43
43
|
"@opentelemetry/sdk-trace-node": "^2.2.0",
|
|
44
|
+
"@opentelemetry/semantic-conventions": "^1.37.0",
|
|
44
45
|
"express": "^5.1.0",
|
|
45
46
|
"raw-body": "^3.0.1",
|
|
46
47
|
"zod": "^3.23.8"
|