Skip to content

feat(contrib/mark3labs/mcp-go): set session ID on tool spans at start time#4943

Merged
gh-worker-dd-mergequeue-cf854d[bot] merged 1 commit into
mainfrom
jb/mcp-tool-span-session-id
Jul 3, 2026
Merged

feat(contrib/mark3labs/mcp-go): set session ID on tool spans at start time#4943
gh-worker-dd-mergequeue-cf854d[bot] merged 1 commit into
mainfrom
jb/mcp-tool-span-session-id

Conversation

@jboolean

@jboolean jboolean commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

This PR stack ports functionality added in the clone of this contrib in dd-source back to dd-trace-go.

Summary

Pass llmobs.WithSessionID at StartToolSpan time so LLMObs groups tool spans under their MCP session natively. The session is read from server.ClientSessionFromContext(ctx) if present.

The existing mcp_session_id tag is unchanged — they are complementary: the tag exposes the session ID to span search/filtering, while WithSessionID populates the LLMObs session field used for trace grouping.

Provenance

No single dd-source PR — the change landed as part of a series of LLMObs-session changes. The current dd-source middleware lives at mcp-go/tracing.go#L36-L44:

var toolHandlerMiddleware = func(next server.ToolHandlerFunc) server.ToolHandlerFunc {
    return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
        // Note: WithIntegration is not yet in released llmobs package and cannot be used here
        var startOpts []llmobs.StartSpanOption
        if session := server.ClientSessionFromContext(ctx); session != nil {
            startOpts = append(startOpts, llmobs.WithSessionID(session.SessionID()))
        }
        toolSpan, ctx := llmobs.StartToolSpan(ctx, request.Params.Name, startOpts...)

This PR ports that exact pattern, additionally keeping the existing llmobs.WithIntegration(...) call since the released llmobs package now has it.

Test plan

  • Extended TestIntegrationToolCallSuccess to assert toolSpan.SessionID matches the MCP client session.
  • Existing tracing tests still pass.

Stacked on #4942.

@datadog-datadog-prod-us1

datadog-datadog-prod-us1 Bot commented Jun 24, 2026

Copy link
Copy Markdown

Pipelines  Tests

Fix all issues with BitsAI

⚠️ Warnings

🚦 1 Pipeline job failed

Pull Request Tests | PR Unit and Integration Tests (1.26) / test-core   View in Datadog   GitHub Actions

ℹ️ Info

No other issues found (see more)

🧪 All tests passed
❄️ No new flaky tests detected

🎯 Code Coverage (details)
Patch Coverage: 100.00%
Overall Coverage: 62.79%

Useful? React with 👍 / 👎

This comment will be updated automatically if new data arrives.
🔗 Commit SHA: f6787f2 | Docs | Datadog PR Page | Give us feedback!

@pr-commenter

pr-commenter Bot commented Jun 24, 2026

Copy link
Copy Markdown

Benchmarks

Benchmark execution time: 2026-07-01 16:40:01

Comparing candidate commit f6787f2 in PR branch jb/mcp-tool-span-session-id with baseline commit 2ff4a7b in branch jb/mcp-skip-ui-only-tools.

Found 0 performance improvements and 0 performance regressions! Performance is the same for 321 metrics, 2 unstable metrics, 1 flaky benchmarks without significant changes.

Explanation

This is an A/B test comparing a candidate commit's performance against that of a baseline commit. Performance changes are noted in the tables below as:

  • 🟩 = significantly better candidate vs. baseline
  • 🟥 = significantly worse candidate vs. baseline

We compute a confidence interval (CI) over the relative difference of means between metrics from the candidate and baseline commits, considering the baseline as the reference.

If the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD), the change is considered significant.

Feel free to reach out to #apm-benchmarking-platform on Slack if you have any questions.

More details about the CI and significant changes

You can imagine this CI as a range of values that is likely to contain the true difference of means between the candidate and baseline commits.

CIs of the difference of means are often centered around 0%, because often changes are not that big:

---------------------------------(------|---^--------)-------------------------------->
                              -0.6%    0%  0.3%     +1.2%
                                 |          |        |
         lower bound of the CI --'          |        |
sample mean (center of the CI) -------------'        |
         upper bound of the CI ----------------------'

As described above, a change is considered significant if the CI is entirely outside the configured SIGNIFICANT_IMPACT_THRESHOLD (or the deprecated UNCONFIDENCE_THRESHOLD).

For instance, for an execution time metric, this confidence interval indicates a significantly worse performance:

----------------------------------------|---------|---(---------^---------)---------->
                                       0%        1%  1.3%      2.2%      3.1%
                                                  |   |         |         |
       significant impact threshold --------------'   |         |         |
                      lower bound of CI --------------'         |         |
       sample mean (center of the CI) --------------------------'         |
                      upper bound of CI ----------------------------------'

Known flaky benchmarks

These benchmarks are marked as flaky and will not trigger a failure. Modify FLAKY_BENCHMARKS_REGEX to control which benchmarks are marked as flaky.

Known flaky benchmarks without significant changes:

  • scenario:BenchmarkOTLPTraceWriterFlush

@jboolean jboolean force-pushed the jb/mcp-skip-ui-only-tools branch from d0e5464 to 0d1c005 Compare June 24, 2026 14:43
@jboolean jboolean force-pushed the jb/mcp-tool-span-session-id branch from c008d76 to 0dbe777 Compare June 24, 2026 14:43
@jboolean jboolean requested a review from rgwood-dd June 24, 2026 14:46
@jboolean jboolean changed the base branch from jb/mcp-skip-ui-only-tools to graphite-base/4943 June 24, 2026 15:08
@jboolean jboolean force-pushed the graphite-base/4943 branch from 0d1c005 to a8261f9 Compare June 24, 2026 15:09
@jboolean jboolean force-pushed the jb/mcp-tool-span-session-id branch from 0dbe777 to e079d34 Compare June 24, 2026 15:09
@jboolean jboolean changed the base branch from graphite-base/4943 to jb/mcp-skip-ui-only-tools June 24, 2026 15:09
@jboolean jboolean marked this pull request as ready for review June 24, 2026 15:14
@jboolean jboolean requested review from a team as code owners June 24, 2026 15:14
@jboolean jboolean requested review from rarguelloF and removed request for a team June 24, 2026 15:14
@codecov

codecov Bot commented Jun 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (jb/mcp-skip-ui-only-tools@5f2c10d). Learn more about missing BASE report.

Additional details and impacted files
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@jboolean jboolean force-pushed the jb/mcp-tool-span-session-id branch from e079d34 to f0a5ee7 Compare June 24, 2026 15:28
@jboolean jboolean force-pushed the jb/mcp-skip-ui-only-tools branch from a8261f9 to a850ceb Compare June 24, 2026 15:28
@jboolean jboolean force-pushed the jb/mcp-tool-span-session-id branch from f0a5ee7 to 5142cf6 Compare June 24, 2026 16:48
@jboolean jboolean force-pushed the jb/mcp-skip-ui-only-tools branch from a850ceb to cb69328 Compare June 24, 2026 16:48
@jboolean jboolean requested review from a team as code owners July 1, 2026 15:00
@jboolean jboolean changed the base branch from jb/mcp-skip-ui-only-tools to graphite-base/4943 July 1, 2026 16:07
@jboolean jboolean force-pushed the jb/mcp-tool-span-session-id branch from 716a66d to f6787f2 Compare July 1, 2026 16:07
@jboolean jboolean force-pushed the graphite-base/4943 branch from 0c444d5 to 2ff4a7b Compare July 1, 2026 16:07
@jboolean jboolean changed the base branch from graphite-base/4943 to jb/mcp-skip-ui-only-tools July 1, 2026 16:07

@datadog-datadog-us1-prod datadog-datadog-us1-prod 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.

Datadog Autotest: PASS

More details

The diff is a clean, minimal port from dd-source. Three adversarial scenarios were executed: a tool call with a valid session (session_id field matches mcp_session_id tag), a tool call with no session in context (both fields empty, no panic), and a tool call with an empty-string session ID (gracefully falls through to propagation). All 18 tests pass. One test was added covering the no-session branch through toolHandlerMiddleware, which no existing test exercised.

Was this helpful? React 👍 or 👎

📊 Validated against 3 scenarios · Open Bits AI session

🤖 Datadog Autotest · Commit 716a66d · What is Autotest? · Any feedback? Reach out in #autotest

@jboolean jboolean removed request for a team July 1, 2026 18:26
Base automatically changed from jb/mcp-skip-ui-only-tools to main July 3, 2026 19:31
@gh-worker-dd-mergequeue-cf854d gh-worker-dd-mergequeue-cf854d Bot merged commit 2d2bdea into main Jul 3, 2026
799 of 846 checks passed
@gh-worker-dd-mergequeue-cf854d gh-worker-dd-mergequeue-cf854d Bot deleted the jb/mcp-tool-span-session-id branch July 3, 2026 19:47
gh-worker-dd-mergequeue-cf854d Bot added a commit that referenced this pull request Jul 3, 2026
…4944)

## Summary

One of the reasons we make a clone of this mcp-go contrib in dd-source was for feature flagging. Originally this was supposed to be temporary, but it continues to be used for org opt-outs and compliance. So in order to remove the clone, we now need to build this per-request optionality as a feature of the SDK.

## What this enables in dd-source

The internal dd-source copy of this contrib ships its own `isIntentCaptureEnabled(ctx)` predicate in [`mcp-go/flags.go`](https://github.com/DataDog/dd-source/blob/d10d624c374b69aa02168983be725532a38562b1/domains/mcp_services/libs/go/mcp/pre-release-external/dd-trace-go/contrib/mark3labs/mcp-go/flags.go) and calls it directly inside the hook and middleware (no public knob to override the static boolean). With this PR, dd-source can pass that same predicate through `TracingConfig.IntentCaptureEnabledFunc` and delete the local fork of the hook/middleware.

## Test plan

- [x] `TestIntentCaptureEnabledFunc` — same config, two contexts: predicate `false` skips schema injection AND leaves the telemetry argument intact in the handler args; predicate `true` injects and strips.
- [x] `TestIntentCaptureEnabledFuncOverridesBool` — when both the static `bool` and the predicate are set, the predicate wins.
- [x] All existing intent-capture and tracing tests still pass.

Stacked on #4943.

---

Parallel port in the modelcontextprotocol/go-sdk contrib: #4950


Co-authored-by: jboolean <julian.boilen@datadoghq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

apm:ecosystem contrib/* related feature requests or bugs mergequeue-status: done

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants