feat(contrib/mark3labs/mcp-go): expose captured intent to tool handlers via context#4941
Conversation
🎉 All green!🧪 All tests passed 🎯 Code Coverage (details) 🔗 Commit SHA: 2de53a9 | Docs | Datadog PR Page | Give us feedback! |
BenchmarksBenchmark execution time: 2026-07-01 16:38:39 Comparing candidate commit 2de53a9 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.
|
0f308e2 to
301b597
Compare
301b597 to
ce524bf
Compare
ce524bf to
ec14544
Compare
a2b4f0a to
13679e8
Compare
ec14544 to
0c444d5
Compare
…rs via context The intent-capture middleware annotates the LLMObs span with the client- supplied telemetry.intent, but tool handlers had no way to read it without re-parsing the telemetry blob (which the same middleware strips before the handler runs). Stash the intent on context.Context alongside the existing LLMObs annotation and export IntentFromContext / ContextWithIntent helpers so handlers can forward the intent downstream (e.g. to a search API for retrieval/ranking experiments). Ported from internal dd-source PR #443664.
e46fd46 to
b88a735
Compare
08d7e54 to
13679e8
Compare
b88a735 to
e46fd46
Compare
13679e8 to
2de53a9
Compare
4b636a7
into
main
…tools (#4942) This PR stack ports functionality added in the clone of this contrib in dd-source back to dd-trace-go. ## Summary The intent-capture `ListTools` hook unconditionally adds `telemetry` as a required field to every tool's input schema. That breaks tools annotated as UI-only (`_meta.ui.visibility` excluding `"model"`): they are invoked by the app UI, not by the model, so the UI caller has no `intent` to supply. OpenAI's MCP client strictly validates tool arguments against the advertised schema and rejects every UI-driven call as a result. This change adds an `isModelCallable` helper that inspects `*mcp.Meta.AdditionalFields["ui"]["visibility"]` (handling both `[]string` and `[]any` shapes from JSON round-trips) and short-circuits the injection when the model is not in the visibility list. Tools with no `_meta.ui.visibility` continue to default to model-callable per the MCP Apps spec. Ported from internal dd-source PR [#420911](DataDog/dd-source#420911). ## Test plan - [x] `TestIntentCaptureSkipsUIOnlyTools` — three tools (model-only, UI-only `[app]`, dual `[app, model]`); asserts `telemetry` is injected for model and dual but not for UI-only. - [x] Existing intent-capture tests still pass. Stacked on #4941. ## MCP standard reference The `_meta.ui.visibility` field is part of the official [MCP Apps extension](https://modelcontextprotocol.io/extensions/apps/overview). Values: `["model", "app"]` (default), `["model"]`, or `["app"]` — they control which actor may invoke the tool. UI-only tools (`["app"]`) are invoked by the host shell, never by the model. This PR's skip logic respects that standard. --- Parallel port in the modelcontextprotocol/go-sdk contrib: #4949 Co-authored-by: jboolean <julian.boilen@datadoghq.com>

This PR stack ports functionality added in the clone of this contrib in dd-source back to dd-trace-go so that the clone can be removed.
Summary
The intent-capture middleware annotates the LLMObs span with the client-supplied
telemetry.intent, but tool handlers had no way to read it without re-parsing the telemetry blob — which the same middleware strips before the handler runs.This change:
context.Contextalongside the existing LLMObs annotation.IntentFromContext(ctx) (string, bool)andContextWithIntent(ctx, intent) context.Contextso tool handlers can forward the intent downstream (e.g. to a search API for retrieval/ranking experiments).processTelemetryintoextractIntent+annotateIntentOnSpanfor clarity; behavior is otherwise unchanged.Ported from internal dd-source PR #443664.
Test plan
TestIntentFromContext— round-trip + empty-intent + missing-key behavior.TestIntentCaptureStashesIntentOnContext— end-to-end: atools/callwithtelemetry.intentmakes the value visible to the handler viaIntentFromContext.Stacked on #4940.