@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 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
- try {
79
- await (stateful
80
- ? handleStatefulRequest(req, res)
81
- : handleStatelessRequest(req, res));
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
- catch (error) {
84
- log.error('Error handling MCP request:', error);
85
- if (!res.headersSent) {
86
- res.status(500).json({
87
- jsonrpc: '2.0',
88
- error: {
89
- code: -32603,
90
- message: 'Internal server error',
91
- },
92
- id: null,
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 { Span, Tracer } from '@opentelemetry/api';
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.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"