Skip to content

util-genai | Add MCPInvocation type for MCP span#105

Open
etserend wants to merge 1 commit into
open-telemetry:mainfrom
etserend:add-mcp-invocation-type
Open

util-genai | Add MCPInvocation type for MCP span#105
etserend wants to merge 1 commit into
open-telemetry:mainfrom
etserend:add-mcp-invocation-type

Conversation

@etserend
Copy link
Copy Markdown
Contributor

@etserend etserend commented Jun 1, 2026

Description

Add MCPInvocation type and TelemetryHandler.mcp() factory method to support MCP (Model Context Protocol) span tracking in the shared util-genai package.

A single MCPInvocation class handles both client and server spans via an is_client flag, per the MCP semantic conventions.

Key behaviors:

  • Span name: {mcp.method.name} {target} (target = tool_name or prompt_name)
  • SpanKind: CLIENT or SERVER based on is_client
  • gen_ai.operation.name = "execute_tool" only for tools/call
  • All semconv attributes: mcp.method.name, mcp.session.id, mcp.protocol.version, mcp.resource.uri, jsonrpc.request.id, network/server/client attributes
  • Opt-in content capture for gen_ai.tool.call.arguments / gen_ai.tool.call.result

Metrics support is deferred to a follow-up PR.

Fixes #94

Type of change

  • New feature (non-breaking change which adds functionality)

How has this been tested?

  • 50 new unit tests in test_handler_mcp.py covering span creation, attributes, context manager usage, sampling, CLIENT/SERVER kinds, error handling, and content capture
  • Full test suite passes (313 tests)
  • Type check passes (pyright, 0 errors)
  • Lint passes (ruff)

Checklist

See CONTRIBUTING.md
for the style guide, changelog guidance, and more.

  • Followed the style guidelines of this project
  • Changelog updated if the change requires an entry
  • Unit tests added

@etserend etserend force-pushed the add-mcp-invocation-type branch 2 times, most recently from 71d8cbd to 549a1b6 Compare June 1, 2026 21:33
def test_span_name_with_tool_name(self) -> None:
self.handler.mcp("tools/call", tool_name="get_weather").stop()
self.assertEqual(
self._get_finished_spans()[0].name, "tools/call get_weather"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test locks in the wrong behavior if the name should be "execute_tool get_weather"

Comment thread util/opentelemetry-util-genai/src/opentelemetry/util/genai/_mcp_invocation.py Outdated
Comment thread util/opentelemetry-util-genai/src/opentelemetry/util/genai/_mcp_invocation.py Outdated
@etserend etserend force-pushed the add-mcp-invocation-type branch from 549a1b6 to 80828b2 Compare June 1, 2026 23:30
@etserend etserend marked this pull request as ready for review June 2, 2026 15:31
@etserend etserend requested a review from a team as a code owner June 2, 2026 15:31
Copilot AI review requested due to automatic review settings June 2, 2026 15:31
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR adds first-class support for emitting spans/metrics for Model Context Protocol (MCP) operations by introducing an MCPInvocation type and a TelemetryHandler.mcp() factory, along with a dedicated test suite and changelog entry.

Changes:

  • Added TelemetryHandler.mcp() factory method returning a new MCPInvocation.
  • Implemented MCPInvocation to set MCP, JSON-RPC, network, tool/prompt, and error attributes and record metrics.
  • Added comprehensive tests validating span naming, attributes, context-manager behavior, error handling, and sampler attribute capture.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
util/opentelemetry-util-genai/tests/test_handler_mcp.py New tests covering MCP span creation, attributes, context manager semantics, errors, and sampling attributes.
util/opentelemetry-util-genai/src/opentelemetry/util/genai/invocation.py Exports MCPInvocation from the public invocation module.
util/opentelemetry-util-genai/src/opentelemetry/util/genai/handler.py Adds TelemetryHandler.mcp() factory to create and start MCP spans.
util/opentelemetry-util-genai/src/opentelemetry/util/genai/_mcp_invocation.py Implements MCPInvocation and MCP-specific semantic attribute handling.
util/opentelemetry-util-genai/.changelog/105.added Changelog entry for MCP support.

Comment on lines +321 to +331
def should_sample(
self,
parent_context,
trace_id,
name,
kind=None,
attributes=None,
links=None,
):
captured.update(attributes or {})
return SamplingResult(Decision.RECORD_AND_SAMPLE, attributes)
Comment on lines +61 to +65
_operation_name = (
GenAI.GenAiOperationNameValues.EXECUTE_TOOL.value
if mcp_method_name == "tools/call"
else ""
)
Comment on lines +100 to +113
def _get_base_attributes(self) -> dict[str, Any]:
attrs: dict[str, Any] = {
_MCP_METHOD_NAME: self.mcp_method_name,
}
if self._operation_name:
attrs[GenAI.GEN_AI_OPERATION_NAME] = self._operation_name

optional: tuple[tuple[str, Any], ...] = (
(GenAI.GEN_AI_TOOL_NAME, self.tool_name),
(GenAI.GEN_AI_PROMPT_NAME, self.prompt_name),
)
optional += self._network_endpoint_attrs()
attrs.update({k: v for k, v in optional if v is not None})
return attrs
@etserend etserend force-pushed the add-mcp-invocation-type branch from 80828b2 to db21883 Compare June 2, 2026 15:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

opentelemetry-util-genai: add MCP invocation types and TelemetryHandler support

3 participants