From a626be423816402e09e1c7f8717cb70414a7bdab Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Sat, 2 May 2026 14:28:44 -0400 Subject: [PATCH] fix(telemetry): emit Tool.execute span for MCP and plugin tools MCP-served tools and plugin-defined tools were bypassing the Tool.execute span that wraps native tool runs. Native tools get the span via wrap() in tool/tool.ts, called from Tool.define(); MCP tools are constructed as AI SDK dynamicTools in mcp/index.ts and inserted via a parallel path in session/prompt.ts, and plugin tools are built in registry.ts fromPlugin() without going through Tool.define(). Verified against trace 33c8941c89094d50650c2b91e244c778: 28 ai.toolCall spans had only 24 Tool.execute children; the missing 4 were all MCP tools (sentry_*, exa_*). Cross-cutting telemetry filtering on operation=Tool.execute was silently dropping MCP and plugin traffic. --- packages/opencode/src/session/prompt.ts | 15 ++++++++++++--- packages/opencode/src/tool/registry.ts | 11 ++++++++++- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index fb822ff17e8b..80c47d3ceda0 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -464,9 +464,18 @@ NOTE: At any point in time through this workflow you should feel free to ask the { tool: key, sessionID: ctx.sessionID, callID: opts.toolCallId }, { args }, ) - yield* ctx.ask({ permission: key, metadata: {}, patterns: ["*"], always: ["*"] }) - const result: Awaited>> = yield* Effect.promise(() => - execute(args, opts), + const result: Awaited>> = yield* Effect.gen(function* () { + yield* ctx.ask({ permission: key, metadata: {}, patterns: ["*"], always: ["*"] }) + return yield* Effect.promise(() => execute(args, opts)) + }).pipe( + Effect.withSpan("Tool.execute", { + attributes: { + "tool.name": key, + "tool.call_id": opts.toolCallId, + "session.id": ctx.sessionID, + "message.id": input.processor.message.id, + }, + }), ) yield* plugin.trigger( "tool.execute.after", diff --git a/packages/opencode/src/tool/registry.ts b/packages/opencode/src/tool/registry.ts index a9a853e504eb..ebe3bb530cde 100644 --- a/packages/opencode/src/tool/registry.ts +++ b/packages/opencode/src/tool/registry.ts @@ -154,7 +154,16 @@ export const layer: Layer.Layer< ...(out.truncated && { outputPath: out.outputPath }), }, } - }), + }).pipe( + Effect.withSpan("Tool.execute", { + attributes: { + "tool.name": id, + "session.id": toolCtx.sessionID, + "message.id": toolCtx.messageID, + ...(toolCtx.callID ? { "tool.call_id": toolCtx.callID } : {}), + }, + }), + ), } }