| 43 | } |
| 44 | |
| 45 | func (t *Tool) Call(ctx context.Context, input any, tracer trace.Tracer) (_ *mcp.CallToolResult, outErr error) { |
| 46 | if t == nil { |
| 47 | return nil, xerrors.New("nil tool") |
| 48 | } |
| 49 | if t.Client == nil { |
| 50 | return nil, xerrors.New("nil client") |
| 51 | } |
| 52 | |
| 53 | spanAttrs := append( |
| 54 | tracing.InterceptionAttributesFromContext(ctx), |
| 55 | attribute.String(tracing.MCPToolName, t.Name), |
| 56 | attribute.String(tracing.MCPServerName, t.ServerName), |
| 57 | attribute.String(tracing.MCPServerURL, t.ServerURL), |
| 58 | ) |
| 59 | ctx, span := tracer.Start(ctx, "Intercept.ProcessRequest.ToolCall", trace.WithAttributes(spanAttrs...)) |
| 60 | defer tracing.EndSpanErr(span, &outErr) |
| 61 | |
| 62 | inputJSON, err := json.Marshal(input) |
| 63 | if err != nil { |
| 64 | t.Logger.Warn(ctx, "failed to marshal tool input, will be omitted from span attrs", slog.Error(err)) |
| 65 | } else { |
| 66 | strJSON := string(inputJSON) |
| 67 | if len(strJSON) > maxSpanInputAttrLen { |
| 68 | strJSON = strJSON[:maxSpanInputAttrLen] |
| 69 | } |
| 70 | span.SetAttributes(attribute.String(tracing.MCPInput, strJSON)) |
| 71 | } |
| 72 | |
| 73 | start := time.Now() |
| 74 | var res *mcp.CallToolResult |
| 75 | res, outErr = t.Client.CallTool(ctx, mcp.CallToolRequest{ |
| 76 | Params: mcp.CallToolParams{ |
| 77 | Name: t.Name, |
| 78 | Arguments: input, |
| 79 | }, |
| 80 | }) |
| 81 | |
| 82 | logFn := t.Logger.Debug |
| 83 | if outErr != nil { |
| 84 | logFn = t.Logger.Warn |
| 85 | } |
| 86 | |
| 87 | // We don't log MCP results because they could be large or contain sensitive information. |
| 88 | logFn(ctx, "injected tool invoked", |
| 89 | slog.F("name", t.Name), |
| 90 | slog.F("server", t.ServerName), |
| 91 | slog.F("input", inputJSON), |
| 92 | slog.F("duration_sec", time.Since(start).Seconds()), |
| 93 | slog.Error(outErr), |
| 94 | ) |
| 95 | |
| 96 | return res, outErr |
| 97 | } |
| 98 | |
| 99 | // EncodeToolID namespaces the given tool name with a prefix to identify tools injected by this library. |
| 100 | // Claude Code, for example, prefixes the tools it includes from defined MCP servers with the "mcp__" prefix. |