Add MCP execution audit hook example - #56
Conversation
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
Bugbot Autofix is ON, but it could not run because the branch was deleted or merged before autofix could start.
Reviewed by Cursor Bugbot for commit 8e86766. Configure here.
| if (input !== null) record.tool_input = redact(input); | ||
| const resultPreview = preview(payload.result_json); | ||
| if (resultPreview !== null) record.result.preview = preview(JSON.stringify(redact(result)) || resultPreview); | ||
| } |
There was a problem hiding this comment.
Verbose preview ignores raw result
Low Severity · Logic Bug
Verbose mode always builds result.preview from JSON.stringify(redact(result)). When result_json is missing or not JSON, result is null, so that stringify is the string null and the already-computed resultPreview is never used. The audit line then stores a null preview instead of a bounded preview of the actual payload, so non-JSON MCP outputs are misrecorded in verbose logs.
Reviewed by Cursor Bugbot for commit 8e86766. Configure here.


What this PR adds
This PR adds a copyable example for auditing MCP tool calls made by Cursor Agent.
When an MCP tool finishes, Cursor runs the configured
afterMCPExecutionhook. The new hook reads that event and appends one JSON object per line to:Example record:
{ "timestamp": "2026-08-20T12:44:33.693Z", "event": "afterMCPExecution", "tool_name": "search_contacts", "duration_ms": 42, "server": null, "tool_input": { "type": "object", "keys": ["query", "api_key"] }, "result": { "type": "json", "length": 29, "has_error": false } }Privacy and safety
The default mode does not write MCP arguments or results to disk. It records only the input shape and field names, result size, duration, and error status.
If verbose mode is explicitly enabled with
CURSOR_MCP_AUDIT_VERBOSE=1, credential-like fields such asapi_key,token,password, andauthorizationare redacted. The hook also limits previews and handles malformed input without failing the MCP call.The log location can be changed with:
MCP server identity
The documented
afterMCPExecutionpayload currently contains:tool_nametool_inputresult_jsondurationIt does not currently contain the MCP server name. The example therefore records
server: nullrather than guessing the server from a tool name. If a runtime-specific payload providesserver_nameormcp_server, the hook preserves it.Files changed
hooks/.cursor/hooks.json— registers the new hookhooks/.cursor/hooks/audit-mcp-execution.mjs— implementationhooks/.cursor/hooks/test-audit-mcp-execution.mjs— self-contained testhooks/README.md— setup and usage documentationTesting
Passed locally:
node hooks/.cursor/hooks/test-audit-mcp-execution.mjs node -e "JSON.parse(require('fs').readFileSync('hooks/.cursor/hooks.json'))" git diff --checkThe hook is observational and uses
failClosed: false, so an audit/logging problem cannot turn a successful MCP call into a failed agent operation.