Skip to content

feat(server): canonical gen_ai.*/mcp.* attributes on MCP tool spans (RFC0038.7) - #623

Merged
jensholdgaard merged 4 commits into
mainfrom
rfc0038-mcp-genai-attrs
Jul 24, 2026
Merged

feat(server): canonical gen_ai.*/mcp.* attributes on MCP tool spans (RFC0038.7)#623
jensholdgaard merged 4 commits into
mainfrom
rfc0038-mcp-genai-attrs

Conversation

@jensholdgaard

@jensholdgaard jensholdgaard commented Jul 24, 2026

Copy link
Copy Markdown
Owner

What

RFC0038.7 — the MCP execute_tool tool spans now carry the canonical OTel
GenAI/MCP semantic-convention attributes, the agent-observability payload:

Attribute Value
gen_ai.operation.name execute_tool
gen_ai.tool.name the invoked tool (query_logs / list_templates / template_drift)
mcp.method.name tools/call
mcp.session.id the caller's session, from the forwarded mcp-session-id header

So Ourios's agent-facing tool calls interoperate with GenAI-aware backends, and
an agent's calls within one session correlate — the agent-observability thesis.

Why it isn't a one-line registry dependency

These attributes moved out of core semantic-conventions to the separate
semantic-conventions-genai
repo. In our pinned dependency (semconv v1.42.0) they survive only as
deprecated "Moved to …" stubs, which weaver registry live-check reports as
hard violations. Two facts (both verified with the local weaver 0.23.0) rule
out simply pinning the genai registry:

  • weaver does not support multiple dependencies — a manifest with two
    dependencies entries panics: not yet implemented: Multiple dependencies is not supported yet.
  • semconv v1.42.0 still ships model/gen-ai/ + model/mcp/, so a second
    dependency would define the same group ids twice (the genai repo's own
    manifest works around this only via a build-time filtered copy of upstream).

Approach: emit + narrowly exempt

The live-check CI job now gates on a filtered violation count that exempts
only the genai-relocation deprecated advisory for the gen_ai.*/mcp.*
namespaces — every other violation (including any other deprecation on those
keys, or any non-conformant attribute) still fails the gate. #622 tracks
collapsing this into a single genai dependency once upstream deletes its v1.42
copies (then it's a one-line swap and the exemption is deleted).

Driving an MCP tools/call through live-check (the job now enables MCP and
performs a handshake) also surfaces rmcp's own internal instrumentation —
bare session_id/peer_info/notification fields on its events. That
non-semconv transport noise is muted at the source in ourios-telemetry's
guarded_env_filter (rmcp=off), alongside the export-stack loop guard; our
own execute_tool span (target ourios_server::mcp) is unaffected.

§3 invariant / hazard note

No pillar or on-disk invariant touched. This is the OTel traces signal (RFC
0038) gaining span attributes. Per the project's OTel-alignment rule, every name
here was confirmed against the OpenTelemetry MCP: the gen_ai.*/mcp.* keys are
the canonical (relocated) OTel names, and execute_tool is the GenAI
well-known gen_ai.operation.name value; no collision with a differently-meant
semconv name.

Verification

  • cargo fmt --all --check, cargo clippy --all-targets --all-features -D warnings, cargo test -p ourios-server -p ourios-telemetry, mdbook build
    all green.
  • End-to-end live-check reproduced locally: real ourios-server + weaver registry live-check with an MCP tools/call driven → the execute_tool span
    carries all four attributes and non-exempt violations = 0 (the only
    remaining 4 are the sanctioned gen_ai/mcp "moved" deprecations the gate
    exempts).
  • Unit test rfc0038_1_mcp_span asserts the four attributes (incl. the session
    id) on the emitted span.

Refs #622.

Summary by CodeRabbit

  • New Features

    • Added richer MCP tool telemetry, including session identifiers and standardized GenAI/MCP attributes.
    • Added live validation for MCP template-listing telemetry and semantic-convention compliance.
  • Bug Fixes

    • Improved CI checks to detect unexpected telemetry violations while allowing a specific deprecated advisory.
  • Documentation

    • Updated self-tracing acceptance criteria and testing guidance for MCP telemetry.
    • Clarified telemetry logging safeguards and third-party logging suppression.

…RFC0038.7)

The MCP `execute_tool` spans now carry the canonical OTel GenAI/MCP
semantic-convention attributes — `gen_ai.operation.name = execute_tool`,
`gen_ai.tool.name`, `mcp.method.name = tools/call`, and `mcp.session.id`
(recorded from the forwarded `mcp-session-id` header) — so Ourios's
agent-facing tool calls interoperate with GenAI-aware backends and an
agent's calls within a session correlate.

These attributes moved out of core semantic-conventions to the separate
semantic-conventions-genai repo; in our pinned semconv v1.42.0 dependency
they survive only as deprecated "Moved to …" stubs, which `weaver
registry live-check` reports as violations. weaver cannot take a second
registry dependency ("Multiple dependencies is not supported yet"), and
v1.42.0 still ships the gen-ai/mcp model, so a second dependency would
also collide on group ids. The live-check job therefore gates on a
filtered violation count that exempts only the genai-relocation
deprecation for the gen_ai.*/mcp.* namespaces; every other violation
(including any other deprecation on those keys) still fails. #622 tracks
collapsing this into a single genai dependency once upstream deletes its
v1.42 copies.

Driving an MCP tools/call through live-check also surfaces rmcp's own
internal instrumentation (bare session_id/peer_info/notification fields
on its events) — non-semconv transport noise, not Ourios signal. That is
muted at the source in `ourios-telemetry`'s guarded_env_filter
(`rmcp=off`), alongside the export-stack loop guard; the `execute_tool`
span (target `ourios_server::mcp`) is unaffected.

Verified end-to-end locally: real server + weaver live-check with an MCP
call driven → non-exempt violations = 0.

Refs #622.

Signed-off-by: Jens Holdgaard Pedersen <Jens@holdgaard.org>
@jensholdgaard
jensholdgaard requested a review from Copilot July 24, 2026 17:54
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jensholdgaard, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 42 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a2d87f5c-32f0-4b61-989f-4c49c896315b

📥 Commits

Reviewing files that changed from the base of the PR and between 725be94 and 5c62e38.

📒 Files selected for processing (2)
  • .github/workflows/ci.yml
  • docs/rfcs/0038-self-tracing.md
📝 Walkthrough

Walkthrough

MCP tool tracing now records session identifiers and canonical GenAI/MCP attributes. The RFC and integration test define the span contract, while CI exercises MCP calls and validates Weaver’s JSON report with a narrow relocation-deprecation exemption.

Changes

MCP telemetry validation

Layer / File(s) Summary
MCP span metadata and coverage
crates/ourios-server/src/mcp.rs, crates/ourios-server/tests/*, crates/ourios-telemetry/src/lib.rs
MCP tool spans record mcp.session.id and GenAI/MCP metadata; the integration test validates the attributes, and rmcp logging is muted.
Live-check MCP exercise and gating
.github/workflows/ci.yml
CI enables MCP, calls list_templates, validates the Weaver JSON report, filters the sanctioned relocation advisory, and requires a clean server exit.
RFC acceptance criteria
docs/rfcs/0038-self-tracing.md
RFC0038 documents the MCP span contract, RFC0038.7, and filtered live-check behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CI
  participant MCPClient
  participant ourios-server
  participant Weaver
  CI->>ourios-server: Start with MCP enabled
  MCPClient->>ourios-server: Initialize session and call list_templates
  ourios-server-->>Weaver: Emit MCP execute-tool telemetry
  Weaver-->>CI: Write live-check JSON report
  CI->>CI: Filter sanctioned advisory and evaluate violations
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: canonical GenAI/MCP attributes on MCP tool spans.
Description check ✅ Passed Provides the change summary, related refs, and verification details, so it is mostly complete despite not matching the template headings exactly.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rfc0038-mcp-genai-attrs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/ci.yml (1)

393-465: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Make MCP emission a required live-check assertion.

The || true fallbacks let the MCP handshake or tools/call fail while the HTTP query still supplies telemetry entities. With no emitted GenAI/MCP attributes, unexpected=0 and CI passes—so this gate does not enforce RFC0038.7. Fail on a missing session or either MCP request failure, and require the report to contain the sanctioned relocation findings for all four expected attributes before excluding them.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 393 - 465, Make the MCP live-check
mandatory by removing the best-effort fallbacks around mcp_session creation,
notifications/initialized, and tools/call, failing when the session is missing
or either request fails. Extend report validation before calculating unexpected
so the Weaver report contains the sanctioned relocation findings for all four
expected gen_ai/mcp attributes; fail if any are absent. Preserve the existing
exemption only after this completeness check.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/ci.yml:
- Around line 393-465: Make the MCP live-check mandatory by removing the
best-effort fallbacks around mcp_session creation, notifications/initialized,
and tools/call, failing when the session is missing or either request fails.
Extend report validation before calculating unexpected so the Weaver report
contains the sanctioned relocation findings for all four expected gen_ai/mcp
attributes; fail if any are absent. Preserve the existing exemption only after
this completeness check.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 86c35577-a607-46c1-92aa-312209a44436

📥 Commits

Reviewing files that changed from the base of the PR and between a214f5e and 725be94.

📒 Files selected for processing (5)
  • .github/workflows/ci.yml
  • crates/ourios-server/src/mcp.rs
  • crates/ourios-server/tests/rfc0038_1_mcp_span.rs
  • crates/ourios-telemetry/src/lib.rs
  • docs/rfcs/0038-self-tracing.md

Copilot AI left a comment

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.

Pull request overview

Updates Ourios’s MCP tool-execution tracing to emit the canonical OpenTelemetry GenAI/MCP semantic-convention attributes (RFC0038.7), and adjusts the semconv live-check CI gate to narrowly exempt the upstream “moved to semantic-conventions-genai” deprecations while still failing on any other drift.

Changes:

  • Add gen_ai.* and mcp.* attributes (including mcp.session.id from mcp-session-id) to execute_tool {tool} spans for all MCP tools.
  • Silence rmcp’s internal, non-semconv instrumentation from exported telemetry via guarded_env_filter.
  • Extend the CI live-check job to enable MCP, drive a tools/call, and gate on a filtered violation count that only exempts the GenAI relocation deprecations.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
docs/rfcs/0038-self-tracing.md Documents RFC0038.7: canonical GenAI/MCP attributes on tool spans and the narrow live-check exemption.
crates/ourios-telemetry/src/lib.rs Extends the exported-telemetry filter to mute rmcp internal instrumentation noise.
crates/ourios-server/tests/rfc0038_1_mcp_span.rs Asserts the four GenAI/MCP span attributes (including session id) on MCP tool spans.
crates/ourios-server/src/mcp.rs Emits canonical gen_ai.*/mcp.* attributes on MCP tool spans and records mcp.session.id from request headers.
.github/workflows/ci.yml Enables MCP in live-check, drives an MCP tools/call, and gates on filtered violation count exempting only the relocation deprecations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/ci.yml
The MCP handshake driving the `execute_tool` span is best-effort (its
curls are `|| true`), so a failed `tools/call` could let the live-check
gate pass while never exercising the gen_ai.*/mcp.* attribute + exemption
path — a silent false negative (Copilot, #623).

Confirm the outcome instead of the curl exit: after weaver writes its
report, check whether the `execute_tool` span actually reached it
(`gen_ai.operation.name` present) and emit a `::warning::` if not. This
catches every miss (curl hiccup, session failure, span not exported), not
just a non-zero curl exit. Kept a warning, not a hard failure: a missed
handshake is a coverage gap for that run (the HTTP path still validates
the rest), and failing on a transient handshake would be flaky.

Signed-off-by: Jens Holdgaard Pedersen <Jens@holdgaard.org>

Copilot AI left a comment

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.

Pull request overview

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

Comment thread .github/workflows/ci.yml
Comment thread docs/rfcs/0038-self-tracing.md Outdated
… test

RFC0038.7's §3.6 said the span name is "the derived {gen_ai.operation.name}
{gen_ai.tool.name} pair, not a duplicate source of truth", but
`#[tracing::instrument]` requires a static name literal, so the name and
the two attributes are in fact written separately per tool (Copilot,
#623). Acknowledge that: the MCP-span unit test asserts both the name and
the attribute values, so a drift between them fails the test.

Signed-off-by: Jens Holdgaard Pedersen <Jens@holdgaard.org>
The exempted gen_ai.*/mcp.* violations make weaver exit non-zero on every
clean run, so status alone is no signal — but a non-zero status with zero
violations in the report means weaver failed for a non-policy reason
(internal error) after writing a report, which the filtered gate would
otherwise mask (Copilot, #623). Warn on exactly that case.

Signed-off-by: Jens Holdgaard Pedersen <Jens@holdgaard.org>

Copilot AI left a comment

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.

Pull request overview

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

@jensholdgaard
jensholdgaard merged commit ada046b into main Jul 24, 2026
27 checks passed
@jensholdgaard
jensholdgaard deleted the rfc0038-mcp-genai-attrs branch July 24, 2026 18:17
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.

2 participants