package to import ( "context" "encoding/json" "fmt" "gitea.com/gitea/gitea-mcp/pkg/debug" "gitea.com/gitea/gitea-mcp/pkg/flag" "gitea.com/gitea/gitea-mcp/pkg/log" "github.com/mark3labs/mcp-go/mcp" "go.uber.org/zap" ) func TextResult(v any) (*mcp.CallToolResult, error) { resultBytes, err := json.Marshal(v) if err != nil { return nil, fmt.Errorf("marshal result err: %v", err) } if flag.DebugScopeEnabled("tools") { // We can't take a context here without breaking every caller, so we // log without the request_id correlation. The middleware's exit log // records the request_id + duration; this entry adds a (truncated) // payload preview for callers that want to see what came back. log.Debug("tool call: result", zap.Int("bytes", len(resultBytes)), zap.String("preview", debug.TruncatePreview(string(resultBytes))), ) } return mcp.NewToolResultText(string(resultBytes)), nil } // TextResultCtx is the context-aware variant of TextResult. New call sites // should prefer it so log lines carry the request_id and tool name. The // non-context TextResult above is kept for backwards compatibility with // the many existing tool handlers. func TextResultCtx(ctx context.Context, v any) (*mcp.CallToolResult, error) { resultBytes, err := json.Marshal(v) if err != nil { return nil, fmt.Errorf("marshal result err: %v", err) } if flag.DebugScopeEnabled("tools") { log.Debug("tool call: result", zap.String("tool", debug.ToolNameFromContext(ctx)), zap.String("request_id", debug.RequestIDFromContext(ctx)), zap.Int("bytes", len(resultBytes)), zap.String("preview", debug.TruncatePreview(string(resultBytes))), ) } return mcp.NewToolResultText(string(resultBytes)), nil } // ErrorResult returns the error to the MCP layer. We no longer log here — // the ToolLogging middleware emits a structured error entry that includes // the tool name and request_id, which is far more useful than the bare // `log.Errorf("%s", err)` this used to do. func ErrorResult(err error) (*mcp.CallToolResult, error) { return nil, err }