feat(contrib/mark3labs/mcp-go): support per-request intent capture#4944
Conversation
🎉 All green!🧪 All tests passed 🎯 Code Coverage (details) 🔗 Commit SHA: 2e459f6 | Docs | Datadog PR Page | Give us feedback! |
BenchmarksBenchmark execution time: 2026-07-01 16:47:14 Comparing candidate commit 2e459f6 in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 321 metrics, 2 unstable metrics, 1 flaky benchmarks without significant changes.
|
4304847 to
d0520e7
Compare
c008d76 to
0dbe777
Compare
0dbe777 to
e079d34
Compare
d0520e7 to
685d0fd
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 685d0fd9e4
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // IntentCaptureEnabledFunc is a per-request predicate that gates intent capture | ||
| // at runtime. When non-nil, the intent-capture hook and middleware are registered | ||
| // and consult the predicate on every tools/list and tools/call: if it returns | ||
| // false, that request behaves as if intent capture were disabled (no schema | ||
| // injection, no telemetry stripping, no intent annotation). | ||
| // | ||
| // If both IntentCaptureEnabled and IntentCaptureEnabledFunc are set, the | ||
| // predicate wins. If both are unset, intent capture is disabled. | ||
| IntentCaptureEnabledFunc func(ctx context.Context) bool |
There was a problem hiding this comment.
Document the new intent-capture predicate
This adds a new public customization path for the tracer, but the commit does not update the required docs. The root AGENTS.md says CONTRIBUTING.md must be updated for significant features, including a new method of interacting with or customizing the tracer; the contrib README still only documents IntentCaptureEnabled, so users won't discover the per-request predicate or the bool-vs-predicate precedence.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Same response as on #4945: this stack documents new TracingConfig knobs via GoDoc on the field, matching how IntentCaptureEnabled and Hooks are documented today. CONTRIBUTING.md has no MCP section to extend. [claude]
e079d34 to
f0a5ee7
Compare
685d0fd to
7e486c3
Compare
f0a5ee7 to
5142cf6
Compare
7e486c3 to
7a44561
Compare
5142cf6 to
9036f6d
Compare
7a44561 to
f97103f
Compare
9036f6d to
f6787f2
Compare
f97103f to
a7f854e
Compare
Config Audit |
14db9c7 to
952cf50
Compare
5c4c2b1 to
f6787f2
Compare
910e0f2 to
5deafee
Compare
f6787f2 to
716a66d
Compare
2e6bb68 to
9036f6d
Compare
716a66d to
f6787f2
Compare
9036f6d to
952cf50
Compare
Add IntentCaptureEnabledFunc to TracingConfig: a per-request predicate that gates intent capture at runtime, enabling toggling per org/feature flag without restarting the server. When non-nil, the predicate is consulted on every tools/list and tools/call: returning false makes that request behave as if intent capture were disabled (no schema injection, no telemetry stripping, no intent annotation). The static IntentCaptureEnabled bool is preserved for back-compat; if both are set the predicate wins. The injection hook and tool-call middleware were refactored into factory functions taking the predicate. Generalizes the conditional intent-capture pattern that the internal dd-source copy uses (no single PR — landed across several commits there).
952cf50 to
2e459f6
Compare
…bs traces (#4945) This PR stack ports functionality added in the clone of this contrib in dd-source back to dd-trace-go. ## Summary Add `RedactToolOutput bool` to `TracingConfig`. When set, the tool result body sent to LLMObs is replaced with `"[REDACTED]"`; the `result.IsError` flag is still honored for span error status. This is needed when downstream access controls (e.g. org2-dac in the internal dd-source copy) forbid forwarding tool output to LLMObs traces — partner teams need to see how their tools are being used in the MCP server, but not what those tools returned. Implements the functionality of PR [#429591](DataDog/dd-source#429591), which hardcoded the substitution to `"[REDACTED]"` in the middleware. Here it's a configuration option so the original always-on behavior remains the default for external users. ## Test plan - [x] `TestRedactToolOutput` — success case: output is exactly `"[REDACTED]"` and the actual result body does not leak into span metadata. - [x] `TestRedactToolOutputStillReportsIsError` — `mcp.NewToolResultError` with redaction enabled still sets `error.message` on the span; the error detail string does not appear in the output annotation. - [x] All existing tracing and intent-capture tests still pass (output redaction defaults to off). Stacked on #4944. Co-authored-by: jboolean <julian.boilen@datadoghq.com>
… capture predicate (#4976) This PR stack ports functionality added in the clone of this contrib in dd-source back to dd-trace-go (Rapid clone at `domains/api_platform/libs/go/mcp/tracing`). ## Summary The SDK contribs, both for mcp-go and go-sdk, were cloned into dd-source in order to feature flag them. This was intended to be temporary. In order to remove the clones, we must port back divergent functionality to the SDK contribs. We also want the contribs to match. This adds `WithIntentCapturePredicate(func(context.Context) bool) Option`. The existing `WithIntentCapture()` is now a thin wrapper that returns `true` for every request, so existing callers are unaffected. When the predicate returns false, the middleware passes through untouched (no schema injection, no telemetry stripping, no intent annotation). ## What this enables in dd-source The Rapid clone ships its own `isIntentCaptureEnabled(ctx)` predicate inline in the middleware. With this PR, dd-source can call `WithIntentCapturePredicate(isIntentCaptureEnabled)` and delete the local fork. Source PR (initial clone with the predicate signature): DataDog/dd-source#414005 This mirrors the design of #4944 for the mark3labs contrib so both libraries match. ## Test plan - [x] `TestIntentCapturePredicate` — same option, two states: predicate `false` skips schema injection AND leaves the telemetry argument intact in the handler args; predicate `true` injects and strips. - [x] All existing intent-capture and tracing tests still pass. Stacked on #4949. --- Parallel port in the mark3labs/mcp-go contrib: #4944 Co-authored-by: jboolean <julian.boilen@datadoghq.com>

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 inmcp-go/flags.goand 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 throughTracingConfig.IntentCaptureEnabledFuncand delete the local fork of the hook/middleware.Test plan
TestIntentCaptureEnabledFunc— same config, two contexts: predicatefalseskips schema injection AND leaves the telemetry argument intact in the handler args; predicatetrueinjects and strips.TestIntentCaptureEnabledFuncOverridesBool— when both the staticbooland the predicate are set, the predicate wins.Stacked on #4943.
Parallel port in the modelcontextprotocol/go-sdk contrib: #4950