openllmetry-js icon indicating copy to clipboard operation
openllmetry-js copied to clipboard

instrumentation for @modelcontextprotocol/sdk

Open narengogi opened this issue 6 months ago • 4 comments

Credit where it's due, The mcp server in the sample app is from the following repository: https://github.com/modelcontextprotocol/servers

  • [ ] I've not been able to get auto-instumentation to work for the Classes I'm instrumenting, I've verified the path to the exports, but the otel package is not picking them up for patching, this would require users to manually instrument thus
  
  const mcpInstrumentation = new McpInstrumentation();
  mcpInstrumentation.manuallyInstrument(sse);
  
  const consoleExporter = new ConsoleSpanExporter();
  const provider = new NodeTracerProvider({
    spanProcessors: [new SimpleSpanProcessor(consoleExporter)]
  });
  provider.register();

  registerInstrumentations({
    instrumentations: [mcpInstrumentation],
  });
  • [X] Have to patch the send method on both stdio and sse clients, currently I'm only instrumenting the onmessage method, which receives messages from the server
  • [ ] Not keen on how useful instrumenting the server module would be. I've seen some discussion from @fali007 mentioning how attaching meta to the messages can help with distributed tracing, this is something I have to look into https://github.com/modelcontextprotocol/python-sdk/issues/421
  • [x] Have to write tests
  • [x] Add sample apps

[!IMPORTANT] Adds OpenTelemetry instrumentation for MCP with manual instrumentation for SSE and stdio clients, and integrates it into the Traceloop SDK.

  • Instrumentation:
    • Adds @traceloop/instrumentation-mcp package for OpenTelemetry instrumentation of MCP.
    • Implements McpInstrumentation class in instrumentation.ts for manual instrumentation of sse and stdio clients.
    • Adds manuallyInstrument() method to handle onmessage method wrapping for both clients.
  • Semantic Attributes:
    • Adds MCP-related attributes to SpanAttributes in SemanticAttributes.ts.
  • SDK Integration:
    • Updates traceloop-sdk to include @traceloop/instrumentation-mcp in package.json.
    • Modifies initialize-options.interface.ts to support MCP modules.
    • Updates index.ts in tracing to initialize and configure McpInstrumentation.
  • Configuration:
    • Adds rollup.config.js for building the new package.
    • Updates package.json scripts and dependencies for the new package.

This description was created by Ellipsis for e40868557a4e3d857bee281d7dc67361b6d5a629. You can customize this summary. It will automatically update as commits are pushed.

narengogi avatar May 31 '25 18:05 narengogi

Hey @narengogi - look at the langchain instrumentation - there are some tricks to instrument sub modules

nirga avatar May 31 '25 23:05 nirga

Hey @nirga !

  1. Is there a problem with any of the keys of this span? I'm unable to see these spans in the Traceloop dashboard, however I've confirmed that the spans are exported by using an instance of ConsoleSpanExporter
{
  resource: {
    attributes: {
      'service.name': undefined,
      'telemetry.sdk.language': 'nodejs',
      'telemetry.sdk.name': 'opentelemetry',
      'telemetry.sdk.version': '1.29.0',
      'process.pid': 1349940,
      'process.executable.name': 'node',
      'process.executable.path': '/home/naren/.nvm/versions/node/v20.17.0/bin/node',
      'process.command_args': [
        '/home/naren/.nvm/versions/node/v20.17.0/bin/node',
        '/home/naren/Code/traceloop/mcp-server-test/src/sse-client.js'
      ],
      'process.runtime.version': '20.17.0',
      'process.runtime.name': 'nodejs',
      'process.runtime.description': 'Node.js',
      'process.command': '/home/naren/Code/traceloop/mcp-server-test/src/sse-client.js',
      'process.owner': 'naren',
      'host.name': 'arch-linux',
      'host.arch': 'amd64',
      'host.id': 'd8ee4a281760asdasd'
    }
  },
  instrumentationScope: undefined,
  traceId: '800e70e3d9419c8a42097436d3a03091',
  parentSpanContext: undefined,
  traceState: undefined,
  name: 'mcp.client.response',
  id: 'eda193391c63afaf',
  kind: 2,
  timestamp: 1749072849426000,
  duration: 5335.81,
  attributes: { 'mcp.request.method': 'notifications/initialized' },
  status: { code: 0 },
  events: [],
  links: []
}
  1. W.R.T auto-instrumentation, I've tried a few combinations including providing the full qualified path to the modules in the final node_modules build, none of which seem to work I've tried
  • import * as sse from '@modelcontextprotocol/sdk/client/sse.js';
  • import * as sse from '@modelcontextprotocol/sdk/client/sse';
  • import * as sse from '@modelcontextprotocol/sdk/client/sse.js'; I'll take a look at this again

narengogi avatar Jun 04 '25 21:06 narengogi

Added tests and a sample app!

narengogi avatar Jun 04 '25 22:06 narengogi

@narengogi can you try running the python sample app and compare the span attributes? they should be the same. In traceloop dashboard, try clicking on the word "Traces" (the title) and then choosing "Spans" from the menu that opens. I re-run CI - looks like it's failing

nirga avatar Jun 09 '25 01:06 nirga