Skip to content

feat(mcp): comprehensive logging#3555

Merged
jqnatividad merged 3 commits into
masterfrom
mcp-comprehensive-logging
Mar 2, 2026
Merged

feat(mcp): comprehensive logging#3555
jqnatividad merged 3 commits into
masterfrom
mcp-comprehensive-logging

Conversation

@jqnatividad

Copy link
Copy Markdown
Collaborator

No description provided.

jqnatividad and others added 2 commits March 2, 2026 00:23
…logging

Enable agents to write structured entries (user_prompt, agent_reasoning,
agent_action, result_summary, note) to the qsv audit log (qsvmcp.log)
with u- prefixed UUIDs, distinct from automatic s-/e- audit entries.
Automatic audit logging is skipped for qsv_log calls to avoid recursion.
Messages are truncated at 4096 chars and logging failures never break
the workflow. Server instructions updated to guide agents on when/how
to log for third-party reproducibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All 421 tests pass, 0 failures. The change is correct.
Changes:
- Fix Unicode truncation fast-path to use UTF-16 length as a cheap guard (strings shorter in UTF-16 are guaranteed shorter in codepoints), only performing expensive `Array.from()` codepoint conversion when the string exceeds the limit

Address review findings (job 606)

All 72 tests pass (0 failures), including the 3 new tests for missing params.
Changes:
- Check for `null`/`undefined` params explicitly before string coercion in `handleLogCall`, returning clear "is required" error messages (finding #1)
- Trim and strip newlines from log messages before writing, preventing multi-line log entries and inconsistent whitespace (findings #2, #3)
- Added tests for missing `entry_type`, missing `message`, and entirely empty params (finding #5)

Address review findings (job 607)

All 418 tests pass, including the new one.
Changes:
- Add test for newline-only message (`'\n\n'`) confirming it's rejected as non-empty string

Address review findings (job 609)

All 74 tests pass (0 failures), including all the new and existing `handleLogCall` tests.
Changes:
- Log `catch` block now writes error details to stderr via `console.error` instead of silently swallowing
- Added `--` separator before the message argument in `qsv log` CLI call to prevent messages starting with `-` from being misinterpreted as flags
- Documented newline collapsing behavior in the tool description ("Newlines are collapsed to spaces")
- Added test for non-string type coercion (`{ entry_type: 123, message: true }`) confirming `String()` coercion behavior

Address review findings (job 610)

All 420 tests pass.
Changes:
- Include truncated error message in the success result returned to the agent (not just stderr), so the agent has actionable context when `qsv_log` write fails
- Add test for non-string message coercion with valid `entry_type` to verify `String()` coercion works for the message path

Address review findings (job 611)

All 420 tests pass. The Rust diagnostics are pre-existing and unrelated to this change.
Changes:
- Added `assert.ok(!result.isError)` to the `handleLogCall` non-string message coercion test to explicitly verify the result is not an error, making the test intent clearer

Address review findings (job 613)

All 420 tests pass, 0 failures. The changes are verified.
Changes:
- Added comment on `--` separator in `handleLogCall` args explaining it guards against messages starting with `-` being parsed as flags (addresses medium finding)
- Added `config.qsvValidation.valid` skip guard to `handleLogCall coerces non-string message` test so it properly tests the success path instead of passing accidentally via error swallowing (addresses low finding #4)
- Added assertion that success response doesn't contain "warning" to confirm actual success vs swallowed error

Address review findings (job 615)

No CLAUDE.md changes needed for the `--` removal. All changes are complete and tests pass.
Changes:
- Remove unnecessary `--` end-of-options sentinel from `qsv log` args — `qsv log` uses docopt variadic `[<message>...]` which handles this correctly, and messages always start with `[entry_type]` so they can never be misinterpreted as flags
- Fix Unicode-safe truncation using `Array.from()` instead of `String.slice()` to avoid splitting surrogate pairs in non-ASCII messages
- Add throttling guidance to server instructions ("Avoid excessive logging — for simple interactions, a single user_prompt + result_summary pair is enough")
- Add test for the `handleLogCall` error-swallowing catch path using a non-existent working directory

Address review findings (job 616)

The change looks correct. The length check and truncation now both operate on codepoints consistently.
Changes:
- Fix Unicode truncation length mismatch: use codepoint count (`Array.from(sanitized).length`) for both the gate condition and the truncation, avoiding inconsistency between UTF-16 `.length` and codepoint-aware `Array.from().slice()`

Address review findings (job 618)

All 421 tests pass, 0 failures. All `handleLogCall` tests pass including the updated write-failure test.
Changes:
- Reworded catch-path message from misleading `"Logged ... (warning: write failed: ...)"` to clearer `"Log write failed (non-fatal): ... Workflow continues."` (issue 1)
- Added fast-path optimization for Unicode truncation: only call `Array.from()` when `sanitized.length > MAX_LOG_MESSAGE_LEN`, avoiding unnecessary codepoint conversion on short messages (issue 3)
- Updated test assertions to match the new error message wording

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a qsv_log MCP tool that allows AI agents to write structured audit log entries to qsvmcp.log, enabling reproducibility by explicitly capturing user prompts, agent reasoning, actions, and result summaries. It is positioned alongside the existing automatic s-/e- prefixed server-side audit logging, adding user-initiated u- prefixed entries.

Changes:

  • Adds createLogTool() and handleLogCall() to mcp-tools.ts, with input validation, message sanitization/truncation, and graceful failure handling.
  • Registers qsv_log in mcp-server.ts as a core tool with skip-audit-log logic to prevent recursive noise, and adds a REPRODUCIBILITY LOG section to the server instructions.
  • Updates all affected test files (mcp-tools.test.ts, mcp-server.test.ts, deferred-loading.test.ts) and CLAUDE.md to reflect the new 10-tool core set.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
.claude/skills/src/mcp-tools.ts Adds MAX_LOG_MESSAGE_LEN, createLogTool(), and handleLogCall() with validation, sanitization, and error swallowing
.claude/skills/src/mcp-server.ts Registers qsv_log tool, adds skip-audit-log guard, updates server instructions with reproducibility guidance
.claude/skills/tests/mcp-tools.test.ts Comprehensive tests for the new log tool (validation, coercion, truncation, file write, failure path)
.claude/skills/tests/mcp-server.test.ts Updates mirrored CORE_TOOLS array and count to 10
.claude/skills/tests/deferred-loading.test.ts Updates mirrored CORE_TOOLS array and count to 10
.claude/skills/CLAUDE.md Updates core tool count and documents new constant and behavior

Comment thread .claude/skills/CLAUDE.md Outdated
Comment thread .claude/skills/tests/mcp-tools.test.ts
Comment thread .claude/skills/src/mcp-tools.ts Outdated
- Move skipAuditLog from "Key Constants" to a behavior note in CLAUDE.md
  (it's a local variable, not a module-level constant)
- Reorder enum and LOG_ENTRY_TYPES Set to match description order
  (reasoning before action)
- Add unique temp dir + cleanup to coercion test to prevent log
  file accumulation in OS temp root

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@jqnatividad

Copy link
Copy Markdown
Collaborator Author

OK to merge even with the errors as they have an old version of the binary. Works locally.

@jqnatividad jqnatividad merged commit f0cd3ac into master Mar 2, 2026
18 of 27 checks passed
@jqnatividad jqnatividad deleted the mcp-comprehensive-logging branch March 2, 2026 10:53
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.

2 participants