Repository navigation
feat: add Copy as cURL to audit log entries - #1046
Conversation
|
👋 Welcome, @AYUshJaiswal454, and thanks for opening your first PR on AnythingMCP! A few quick pointers:
Someone from the core team will look at this within ~48h. If you don't hear back, please ping us in Discussions / Q&A. ⭐ While you wait — if you find AnythingMCP useful, a star helps others discover it. |
|
I have read the CLA Document and I hereby sign the CLA 1 out of 2 committers have signed the CLA. |
|
I have read the CLA Document and I hereby sign the CLA |
|
recheck |
notlakshitha
left a comment
There was a problem hiding this comment.
Hi! Nice feature, and the security thinking up front is great.
What's good
- The auth value is always a placeholder, so no real token ends up in the copied command.
- The request body goes through a quoted heredoc, so shell characters in the arguments are passed through literally.
- The button is disabled, with a clear reason, for rows it can't replay.
- Pulling out
getApiOrigin()removes duplicated code in three places.
Suggestions:
- The URL sits inside double quotes and uses
encodeURI, so a server ID containing$or a backtick could still be expanded by the shell.encodeURIComponentplus single quotes would make it safe whatever the ID contains. - The redaction only checks key names. It misses
auth,pwd,jwt,session,bearerandaccess_key, and it doesn't catch secrets stored in values. Values deeper than 10 levels also come back unredacted. - A replayed
[REDACTED]value fails silently. A warning, or a note at the top of the copied command, would help. log.tool?.name || log.toolId(page.tsx:112) puts a database ID where the tool name should go, so the replay calls a tool that doesn't exist. Disabling the button there might be better.- Any auth mode other than
oauth2gets the API-key header. And until the server info loads, the mode defaults to'both', so a quick click could copy the wrong header. - The pure unit tests sit under Playwright e2e. Maybe add one that proves an argument containing a heredoc breakout like
\nJSON\nstays safe. - Nit (page.tsx:443): the truncation check can be simplified to
'_amcp_truncated' in log.input.
None of these block the PR in my view. Nice work!
…cted arguments Quote the endpoint URL in single quotes with an encoded server id, so nothing in it reaches the shell. Replay only a row's tool name, never its database id. Redact subtrees deeper than the walk instead of passing them through, catch a few more credential key names, and start the command with a comment when arguments were redacted. Tests for heredoc breakout, shell characters in the id and deep values.
helpcodeai
left a comment
There was a problem hiding this comment.
Thanks @AYUshJaiswal454, nice feature, and thanks @notlakshitha for the careful review. I went through it for security and pushed a few changes on top (8849ee7) rather than send you another round:
- The URL is now in single quotes with
encodeURIComponenton the server id, so nothing in it can be expanded by the shell. In practice the id is always a UUID, but this way it doesn't matter. - The replay only uses
log.tool?.name. Falling back totoolIdwould have copied a database id as the tool name, so rows without a name are now disabled instead. - Values nested deeper than the redaction walk are replaced instead of passed through, and the key list also catches pwd, jwt, bearer, access_key and session_id/session_key. I left
authout on purpose, it's a common name for whole config objects. - When something was redacted, the command starts with a comment saying so, so a replay doesn't fail silently.
- Tests for a heredoc breakout attempt, shell characters in the id and deep values, plus a line in the docs about the redaction.
The heredoc itself was already safe: JSON.stringify escapes newlines, so the payload is always one line and can't produce a bare JSON line.
One thing on your side: the cla check fails because your commit is authored as ayushkumar@Ayushs-MacBook-Air-6.local, which isn't linked to your GitHub account, so the bot can't match it to your signature. Could you add that address to your GitHub account (or amend the commit with your GitHub email and force-push)? Then I'll merge.
- Use single-quoted URLs with encodeURIComponent for shell safety - Recursively redact sensitive keys and values with depth boundaries - Emit warning comments when replaying redacted or truncated arguments - Disable copy action when tool name is missing instead of DB ID fallback - Handle authMode loading race conditions and respect clientInfo authMethod - Prevent heredoc delimiter collision on arguments containing JSON - Add Playwright and builder unit tests for all edge cases
…ements with full redaction and edge-case handling
…ng, and security edge case tests
|
recheck |
|
Hi, thanks for pushing the fixes to my PR! I signed the CLA, and GitHub shows the signature event in the PR timeline, but CLA Assistant still fails with:
I also commented Could you please check which commit author the CLA workflow is failing to recognize and help resolve the signature issue? Also, four workflows are still awaiting maintainer approval. Could you approve those workflows so the required backend and frontend checks can run? I haven't changed or rewritten the commit history. Thank you for your help! |
|
It's the first commit, e097ec3. It's authored as No need to rewrite history for it: you signed with this account and the commit is clearly yours, and we squash-merge, so the commit on main is attributed to your GitHub account anyway. For next time, Your follow-up changes look good to me too, the value-based redaction is a nice addition. |
Summary
Adds a "Copy as cURL" button to each expanded audit log row on the Audit Log (
/logs) page to quickly replay the recorded MCPtools/callagainst AnythingMCP outside of an AI client.Changes
packages/frontend/src/lib/curl.ts):buildToolCallCurl({ origin, serverId, toolName, args, authMode }).tools/callwith standard JSON-RPC 2.0 envelope andMCP-Protocol-Version: 2025-06-18./mcp/:serverId) accepts baretools/callrequests directly without requiring aninitializehandshake.--data-binary @- <<'JSON' ... JSON), ensuring that quotes (',"), dollar signs ($), backticks (`), and newlines in arguments survive verbatim without shell expansion issues.-H "X-API-Key: $AMCP_MCP_API_KEY"for legacy/both modes,-H "Authorization: Bearer $AMCP_ACCESS_TOKEN"for OAuth2). Never inserts real secrets or dashboard session tokens (amcp_token). Recursively redacts sensitive credential fields in tool arguments matchingREDACTED_KEY_PATTERN.packages/frontend/src/app/logs/page.tsx):copyTextfrom@/lib/clipboardwith visual feedback ("Copied!" checkmark for 2s, error fallback if denied).server.info()formcpAuthModeto format the correct auth header./mcpendpoint (log.mcpServeris null).log.input._amcp_truncatedis present).packages/frontend/src/lib/origin.ts):getApiOrigin()(localhost-> port 4000, otherwisewindow.location.origin) and reused it inlogs/page.tsx,mcp-server/[id]/page.tsx, andapp/page.tsx.docs/api-reference.md):AMCP_MCP_API_KEY/AMCP_ACCESS_TOKEN.packages/frontend/tests/e2e/audit-log-curl.spec.ts):Type
Testing
audit-log-curl.spec.tspassing.tools/callwithMCP-Protocol-Version: 2025-06-18returns HTTP 200 with result event stream.npx playwright test tests/e2e/audit-log-curl.spec.ts) verifying full UI interaction, clipboard copy, and disabled tooltip states (7/7 passed).redesign.spec.tssmoke test (passed).npx tsc --noEmit -p tsconfig.jsoninpackages/frontend(0 errors).npm run lintinpackages/frontend(0 errors).npm run buildinpackages/frontend(compiled successfully).Checklist
npm test)Related Issues
Closes #999
Relates to #850