@tigerdata/mcp-boilerplate 0.1.8 → 0.2.0
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/logger.js +5 -3
- package/dist/mcpServer.js +47 -37
- package/package.json +8 -8
package/dist/logger.js
CHANGED
|
@@ -2,9 +2,11 @@ import { logs, SeverityNumber } from '@opentelemetry/api-logs';
|
|
|
2
2
|
const name = process.env.OTEL_SERVICE_NAME || 'mcp-app';
|
|
3
3
|
const logger = logs.getLogger(name);
|
|
4
4
|
// Helper functions to replace console.log
|
|
5
|
+
// We use console.error for all levels so that messages are written to stderr
|
|
6
|
+
// and not stdout, which would interfere with the stdio MCP transport.
|
|
5
7
|
export const log = {
|
|
6
8
|
debug: (...args) => {
|
|
7
|
-
console.
|
|
9
|
+
console.error(...args);
|
|
8
10
|
const [body, attributes] = args;
|
|
9
11
|
logger.emit({
|
|
10
12
|
severityText: 'DEBUG',
|
|
@@ -18,7 +20,7 @@ export const log = {
|
|
|
18
20
|
});
|
|
19
21
|
},
|
|
20
22
|
info: (...args) => {
|
|
21
|
-
console.
|
|
23
|
+
console.error(...args);
|
|
22
24
|
const [body, attributes] = args;
|
|
23
25
|
logger.emit({
|
|
24
26
|
severityText: 'INFO',
|
|
@@ -32,7 +34,7 @@ export const log = {
|
|
|
32
34
|
});
|
|
33
35
|
},
|
|
34
36
|
warn: (...args) => {
|
|
35
|
-
console.
|
|
37
|
+
console.error(...args);
|
|
36
38
|
const [body, attributes] = args;
|
|
37
39
|
logger.emit({
|
|
38
40
|
severityText: 'WARN',
|
package/dist/mcpServer.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
-
import { SpanStatusCode, trace } from '@opentelemetry/api';
|
|
2
|
+
import { SpanStatusCode, trace, context as otelContext, propagation, SpanKind, } from '@opentelemetry/api';
|
|
3
3
|
import { log } from './logger.js';
|
|
4
4
|
const name = process.env.OTEL_SERVICE_NAME;
|
|
5
5
|
const tracer = trace.getTracer(name ? `${name}.mcpServer` : 'mcpServer');
|
|
@@ -39,44 +39,54 @@ export const mcpServerFactory = ({ name, version = '1.0.0', context, apiFactorie
|
|
|
39
39
|
// make sense.
|
|
40
40
|
title: tool.config.title,
|
|
41
41
|
},
|
|
42
|
-
}, async (args
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
content: [
|
|
51
|
-
{
|
|
52
|
-
type: 'text',
|
|
53
|
-
text,
|
|
54
|
-
},
|
|
55
|
-
],
|
|
56
|
-
structuredContent: result,
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
catch (error) {
|
|
60
|
-
log.error('Error invoking tool:', error);
|
|
61
|
-
span.recordException(error);
|
|
62
|
-
span.setStatus({
|
|
63
|
-
code: SpanStatusCode.ERROR,
|
|
64
|
-
message: error.message,
|
|
42
|
+
}, async (args, extra) => {
|
|
43
|
+
let traceContext = otelContext.active();
|
|
44
|
+
if (extra?._meta?.traceparent) {
|
|
45
|
+
// Some MCP clients (e.g. pydantic) pass the parent trace context
|
|
46
|
+
traceContext = propagation.extract(traceContext, {
|
|
47
|
+
traceparent: extra._meta.traceparent,
|
|
48
|
+
tracestate: extra._meta.tracestate,
|
|
65
49
|
});
|
|
66
|
-
return {
|
|
67
|
-
content: [
|
|
68
|
-
{
|
|
69
|
-
type: 'text',
|
|
70
|
-
text: `Error: ${error.message || 'Unknown error'}`,
|
|
71
|
-
},
|
|
72
|
-
],
|
|
73
|
-
isError: true,
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
finally {
|
|
77
|
-
span.end();
|
|
78
50
|
}
|
|
79
|
-
|
|
51
|
+
return tracer.startActiveSpan(`mcp.tool.${tool.name}`, { kind: SpanKind.SERVER }, traceContext, async (span) => {
|
|
52
|
+
span.setAttribute('mcp.tool.args', JSON.stringify(args));
|
|
53
|
+
try {
|
|
54
|
+
const result = await tool.fn(args);
|
|
55
|
+
const text = JSON.stringify(result);
|
|
56
|
+
span.setAttribute('mcp.tool.responseBytes', text.length);
|
|
57
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
58
|
+
return {
|
|
59
|
+
content: [
|
|
60
|
+
{
|
|
61
|
+
type: 'text',
|
|
62
|
+
text,
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
structuredContent: result,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
log.error('Error invoking tool:', error);
|
|
70
|
+
span.recordException(error);
|
|
71
|
+
span.setStatus({
|
|
72
|
+
code: SpanStatusCode.ERROR,
|
|
73
|
+
message: error.message,
|
|
74
|
+
});
|
|
75
|
+
return {
|
|
76
|
+
content: [
|
|
77
|
+
{
|
|
78
|
+
type: 'text',
|
|
79
|
+
text: `Error: ${error.message || 'Unknown error'}`,
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
isError: true,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
span.end();
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
});
|
|
80
90
|
}
|
|
81
91
|
for (const factory of promptFactories) {
|
|
82
92
|
const prompt = factory(context);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tigerdata/mcp-boilerplate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "MCP boilerplate code for Node.js",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "TigerData",
|
|
@@ -29,14 +29,14 @@
|
|
|
29
29
|
"lint:fix": "eslint --fix"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
32
|
+
"@modelcontextprotocol/sdk": "^1.20.1",
|
|
33
33
|
"@opentelemetry/api": "^1.9.0",
|
|
34
|
-
"@opentelemetry/auto-instrumentations-node": "^0.
|
|
35
|
-
"@opentelemetry/exporter-trace-otlp-grpc": "^0.
|
|
36
|
-
"@opentelemetry/instrumentation-http": "^0.
|
|
37
|
-
"@opentelemetry/sdk-metrics": "^2.0
|
|
38
|
-
"@opentelemetry/sdk-node": "^0.
|
|
39
|
-
"@opentelemetry/sdk-trace-node": "^2.0
|
|
34
|
+
"@opentelemetry/auto-instrumentations-node": "^0.66.0",
|
|
35
|
+
"@opentelemetry/exporter-trace-otlp-grpc": "^0.207.0",
|
|
36
|
+
"@opentelemetry/instrumentation-http": "^0.207.0",
|
|
37
|
+
"@opentelemetry/sdk-metrics": "^2.2.0",
|
|
38
|
+
"@opentelemetry/sdk-node": "^0.207.0",
|
|
39
|
+
"@opentelemetry/sdk-trace-node": "^2.2.0",
|
|
40
40
|
"express": "^5.1.0",
|
|
41
41
|
"raw-body": "^3.0.1",
|
|
42
42
|
"zod": "^3.23.8"
|