|
| 1 | +# OpenTelemetry MCP Instrumentation |
| 2 | + |
| 3 | +MCP Python Agent provides observability for MCP client and MCP server. |
| 4 | +This document provides examples of usage and results in the MCP instrumentation. |
| 5 | +For details on usage and installation of LoongSuite and Jaeger, please refer to [LoongSuite Documentation](https://github.com/alibaba/loongsuite-python-agent/blob/main/README.md). |
| 6 | + |
| 7 | +## Installing MCP Instrumentation |
| 8 | + |
| 9 | +```shell |
| 10 | +# Open Telemetry |
| 11 | +pip install opentelemetry-distro opentelemetry-exporter-otlp |
| 12 | +opentelemetry-bootstrap -a install |
| 13 | + |
| 14 | +# mcp |
| 15 | +pip install mcp==1.13.1 |
| 16 | + |
| 17 | +# MCPInstrumentor |
| 18 | +git clone https://github.com/alibaba/loongsuite-python-agent.git |
| 19 | +cd loongsuite-python-agent |
| 20 | +pip install ./instrumentation-genai/opentelemetry-instrumentation-mcp |
| 21 | +``` |
| 22 | + |
| 23 | +## Collect Data |
| 24 | + |
| 25 | +Here's a simple demonstration of MCP instrumentation. The demo uses: |
| 26 | + |
| 27 | +- An [MCP server](examples/simple_server.py) that provides an `add_numbers` tool |
| 28 | +- An [MCP client](examples/simple_client.py) that connects to the server and calls the tool |
| 29 | + |
| 30 | +### Running the Demo |
| 31 | + |
| 32 | +#### Option 1: Using OpenTelemetry |
| 33 | + |
| 34 | +```bash |
| 35 | +export OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true |
| 36 | + |
| 37 | +opentelemetry-instrument \ |
| 38 | +--traces_exporter console \ |
| 39 | +--service_name demo-mcp-client \ |
| 40 | +python examples/simple_client.py |
| 41 | +``` |
| 42 | + |
| 43 | +#### Option 2: Using Loongsuite |
| 44 | + |
| 45 | +```bash |
| 46 | +export OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true |
| 47 | + |
| 48 | +loongsuite-instrument \ |
| 49 | +--traces_exporter console \ |
| 50 | +--service_name demo-mcp-client \ |
| 51 | +python examples/simple_client.py |
| 52 | +``` |
| 53 | + |
| 54 | +### Results |
| 55 | + |
| 56 | +The instrumentation will generate traces showing the MCP operations: |
| 57 | + |
| 58 | +```bash |
| 59 | +Starting MCP Client... |
| 60 | +Connection successful! |
| 61 | +======================================== |
| 62 | +Getting available tools... |
| 63 | +[09/01/25 15:57:53] INFO Processing request of type ListToolsRequest server.py:624 |
| 64 | +Found 1 tools: |
| 65 | + - add_numbers: |
| 66 | + Add two integers together. |
| 67 | + |
| 68 | + Args: |
| 69 | + a: First integer |
| 70 | + b: Second integer |
| 71 | + |
| 72 | + Returns: |
| 73 | + Sum of the two numbers |
| 74 | + |
| 75 | +======================================== |
| 76 | +Calling add_numbers tool... |
| 77 | + INFO Processing request of type CallToolRequest server.py:624 |
| 78 | +Tool call result: |
| 79 | + 42 |
| 80 | +======================================== |
| 81 | +Demo completed! |
| 82 | + |
| 83 | +{ |
| 84 | + "name": "tools/call add_numbers", |
| 85 | + "context": { |
| 86 | + "trace_id": "0xcd90df6933f64384f5311ec1fa626bd1", |
| 87 | + "span_id": "0x287a0dd698d1a078", |
| 88 | + "trace_state": "[]" |
| 89 | + }, |
| 90 | + "kind": "SpanKind.CLIENT", |
| 91 | + "parent_id": "0x7301d09643bee0a9", |
| 92 | + "start_time": "2025-09-02T11:50:45.156324Z", |
| 93 | + "end_time": "2025-09-02T11:50:45.159357Z", |
| 94 | + "status": { |
| 95 | + "status_code": "OK" |
| 96 | + }, |
| 97 | + "attributes": { |
| 98 | + "component.name": "mcp.client", |
| 99 | + "mcp.method.name": "tools/call", |
| 100 | + "rpc.jsonrpc.request_id": "2", |
| 101 | + "mcp.client.version": "2025-06-18", |
| 102 | + "mcp.tool.name": "add_numbers", |
| 103 | + "mcp.parameters": "{\"args\": [], \"kwargs\": {\"name\": \"add_numbers\", \"arguments\": {\"a\": 15, \"b\": 27}}}", |
| 104 | + "network.transport": "stdio", |
| 105 | + "mcp.output.size": "2" |
| 106 | + }, |
| 107 | + "events": [], |
| 108 | + "links": [], |
| 109 | + "resource": { |
| 110 | + "attributes": { |
| 111 | + "telemetry.sdk.language": "python", |
| 112 | + "telemetry.sdk.name": "opentelemetry", |
| 113 | + "telemetry.sdk.version": "1.36.0", |
| 114 | + "service.name": "demo-mcp-client", |
| 115 | + "telemetry.auto.version": "0.57b0" |
| 116 | + }, |
| 117 | + "schema_url": "" |
| 118 | + } |
| 119 | +} |
| 120 | +``` |
| 121 | + |
| 122 | + |
| 123 | +After [setting up jaeger](https://www.jaegertracing.io/docs/1.6/getting-started/) and exporting data to it by following these commands: |
| 124 | + |
| 125 | +```bash |
| 126 | +export OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true |
| 127 | + |
| 128 | +loongsuite-instrument \ |
| 129 | +--exporter_otlp_protocol grpc \ |
| 130 | +--traces_exporter otlp \ |
| 131 | +--exporter_otlp_insecure true \ |
| 132 | +--exporter_otlp_endpoint YOUR-END-POINT \ |
| 133 | +python examples/simple_client.py |
| 134 | +``` |
| 135 | + |
| 136 | +You can see traces on the jaeger UI as follows: |
| 137 | + |
| 138 | + |
| 139 | + |
| 140 | +## References |
| 141 | + |
| 142 | +- [OpenTelemetry Project](https://opentelemetry.io/) |
| 143 | +- [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) |
0 commit comments