Skip to content

Add MCP execution audit hook example - #56

Open
12britz wants to merge 1 commit into
cursor:mainfrom
12britz:add-mcp-execution-audit-hook
Open

Add MCP execution audit hook example#56
12britz wants to merge 1 commit into
cursor:mainfrom
12britz:add-mcp-execution-audit-hook

Conversation

@12britz

@12britz 12britz commented Aug 20, 2026

Copy link
Copy Markdown

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 afterMCPExecution hook. The new hook reads that event and appends one JSON object per line to:

.cursor/hook-logs/mcp-execution.jsonl

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 as api_key, token, password, and authorization are redacted. The hook also limits previews and handles malformed input without failing the MCP call.

The log location can be changed with:

CURSOR_MCP_AUDIT_LOG=/path/to/mcp-execution.jsonl

MCP server identity

The documented afterMCPExecution payload currently contains:

  • tool_name
  • tool_input
  • result_json
  • duration

It does not currently contain the MCP server name. The example therefore records server: null rather than guessing the server from a tool name. If a runtime-specific payload provides server_name or mcp_server, the hook preserves it.

Files changed

  • hooks/.cursor/hooks.json — registers the new hook
  • hooks/.cursor/hooks/audit-mcp-execution.mjs — implementation
  • hooks/.cursor/hooks/test-audit-mcp-execution.mjs — self-contained test
  • hooks/README.md — setup and usage documentation

Testing

Passed locally:

node hooks/.cursor/hooks/test-audit-mcp-execution.mjs
node -e "JSON.parse(require('fs').readFileSync('hooks/.cursor/hooks.json'))"
git diff --check

The hook is observational and uses failClosed: false, so an audit/logging problem cannot turn a successful MCP call into a failed agent operation.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

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);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8e86766. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant