Feature Branch: 021-request-id-logging
Created: 2026-01-07
Status: Draft
Input: User description: "Create a request ID mechanism for all clients (CLI, tray, Web UI) to enable request-scoped logging and error tracking"
When errors occur in mcpproxy, users and developers have difficulty correlating client-side errors with server-side logs. Currently:
- No standard way to trace a request through the system
- Error messages don't include identifiers for log lookup
- OAuth flows use
correlation_idbut other requests have no tracking - Users can't easily report issues with reproducible context
Current Behavior:
- Client makes request to daemon
- Error occurs and is returned to client
- User sees error message but cannot find related logs
- Support/debugging requires manual timestamp correlation
Desired Behavior:
- Client sends
X-Request-Idheader (or server generates one) - All request-scoped logs include this
request_id - Error responses include
request_idin JSON payload - CLI prints "Request ID: " on error with log lookup suggestion
- Tray/Web UI display Request ID with "Copy ID" affordance
This feature applies uniformly to all clients:
| Client | Request ID Source | Error Display | Log Retrieval |
|---|---|---|---|
| CLI | Optional X-Request-Id header; core generates if missing |
Print to stderr | mcpproxy logs --request-id <id> |
| Tray | Optional X-Request-Id header; core generates if missing |
Notification with copy button | Link to logs endpoint |
| Web UI | Optional X-Request-Id header; core generates if missing |
Modal with copy button | Display logs inline or link |
Request ID Generation: Clients are NOT required to send X-Request-Id. If omitted, mcpproxy core generates a random UUID v4 and uses it for the request. The generated ID is returned in the X-Request-Id response header and included in error response bodies.
All clients use the same REST API endpoints. The server always returns X-Request-Id in response headers.
Every error response includes a request_id field that users can use to find related logs.
Why this priority: Core value proposition - enables log correlation without any client changes.
Independent Test: Make any API call that returns an error and verify request_id in response body and X-Request-Id header.
Acceptance Scenarios:
- Given a client makes a request without
X-Request-Id, When an error occurs, Then response includes generatedrequest_idin JSON body andX-Request-Idheader - Given a client sends
X-Request-Id: abc123, When an error occurs, Then response includesrequest_id: "abc123"in JSON body andX-Request-Id: abc123header - Given a client sends
X-Request-Id: abc123, When request succeeds, Then response includesX-Request-Id: abc123header (body may or may not include it)
All log entries for a request include the request_id, enabling filtering.
Why this priority: Without this, the request ID has no value - logs must be findable.
Independent Test: Make a request with X-Request-Id, check daemon logs contain the ID.
Acceptance Scenarios:
- Given a request with
X-Request-Id: abc123, When server processes it, Then all log entries includerequest_id=abc123 - Given a request without
X-Request-Id, When server generatesxyz789, Then all log entries includerequest_id=xyz789 - Given an OAuth flow with
correlation_id, When started via request withrequest_id, Then logs include bothrequest_idandcorrelation_id
CLI displays the request ID on errors and suggests how to retrieve logs.
Why this priority: Primary developer interface; immediate value for debugging.
Independent Test: Run a CLI command that fails and verify Request ID is printed with log suggestion.
Acceptance Scenarios:
- Given
mcpproxy upstream listfails with server error, When CLI receives error response, Then stderr showsRequest ID: <id>andRun 'mcpproxy logs --request-id <id>' to see detailed logs - Given
mcpproxy auth loginfails validation, When CLI receives 400 error, Then stderr shows Request ID with log suggestion - Given request succeeds, When CLI receives success response, Then Request ID is NOT displayed (avoid noise)
Users can retrieve logs filtered by request ID.
Why this priority: Completes the debugging workflow started by error display.
Independent Test: Make request, get request ID from error, retrieve logs using that ID.
Acceptance Scenarios:
- Given a request ID from an error, When user runs
mcpproxy logs --request-id <id>, Then only logs with that request ID are displayed - Given a request ID, When user calls
GET /api/v1/logs?request_id=<id>, Then response contains filtered log entries - Given a non-existent request ID, When user queries logs, Then empty result is returned (not an error)
Tray and Web UI display Request ID on errors with copy affordance.
Why this priority: Important for non-CLI users but lower priority than CLI workflow.
Independent Test: Trigger an error via tray menu or Web UI and verify Request ID is displayed with copy button.
Acceptance Scenarios:
- Given tray triggers login that fails, When error notification appears, Then notification includes Request ID with "Copy ID" action
- Given Web UI makes request that fails, When error modal appears, Then modal includes Request ID with copy button and link to logs
- Given successful operation in tray/Web UI, When success is displayed, Then Request ID is NOT shown (reduce clutter)
- What happens when
X-Request-Idheader contains invalid characters? Server sanitizes or rejects with 400 - What happens when
X-Request-Idis extremely long (>256 chars)? Server truncates to 256 chars - What happens when multiple requests have same
X-Request-Id? Logs share the ID (caller's responsibility) - What happens when daemon restarts during request? Request ID is lost; logs from new process won't have it
- What happens with WebSocket/SSE connections? Request ID applies to initial connection request
- FR-001: mcpproxy core MUST generate a random UUID v4
request_idfor requests withoutX-Request-Idheader (clients are NOT required to provide one) - FR-002: mcpproxy core MUST use client-provided
X-Request-Idvalue when present and valid - FR-003: mcpproxy core MUST return
X-Request-Idheader in ALL responses (success and error) - FR-004: mcpproxy core MUST include
request_idfield in ALL error JSON responses - FR-005: mcpproxy core MUST include
request_idin all log entries for request-scoped operations - FR-006: mcpproxy core MUST validate
X-Request-Idheader (alphanumeric, dashes, underscores, max 256 chars) - FR-007: CLI MUST display Request ID on error responses with log retrieval suggestion
- FR-008: CLI MUST NOT display Request ID on successful responses
- FR-009: Server MUST provide endpoint or CLI command to retrieve logs by
request_id - FR-010: OAuth flows MUST include both
request_id(from triggering request) andcorrelation_idin logs - FR-011: Request ID MUST NOT contain sensitive information (safe to display to users)
- RequestContext: Request-scoped context containing
request_id, propagated through handlers - LogEntry: Extended to include optional
request_idfield for request-scoped logs - ErrorResponse: Standard error response structure including
request_id
- SC-001: 100% of API error responses include
request_idfield in JSON body - SC-002: 100% of API responses include
X-Request-Idheader - SC-003: CLI displays Request ID for all error cases with log lookup suggestion
- SC-004: Logs can be filtered by
request_idreturning only matching entries - SC-005: OAuth flow logs are findable by either
request_idorcorrelation_id - SC-006: Request ID generation adds less than 1ms latency to requests
Request IDs are designed to be safe for display to end users:
- Generated IDs are random UUIDs with no embedded information
- Client-provided IDs are validated (alphanumeric, dashes, underscores only)
- IDs do not contain secrets, tokens, or PII
- IDs are not used for authentication or authorization
- IDs can be safely shared in bug reports, support tickets, and logs
- Request IDs themselves do not identify users
- Log retrieval by request ID does not bypass access controls
- API key authentication still required for log retrieval endpoints
- Maximum ID length (256 chars) prevents memory exhaustion
- Character validation prevents injection attacks
- Rate limiting applies to log retrieval endpoints (existing limits)
- Daemon already has structured logging via Zap
- Activity log infrastructure exists (spec 016) and can be extended
- CLI already handles error responses and exit codes
- Web UI has error handling infrastructure
- Tray shows notifications for errors
- Distributed tracing (spans, parent IDs) - request ID is single-hop only
- Request ID persistence across daemon restarts
- Automatic log cleanup based on request ID
- Request ID in MCP protocol messages (only REST API)
- Tray/Web UI implementation (they receive response, implement their own UX)
The correlation_id in OAuth responses is complementary to request_id:
| ID Type | Scope | Purpose |
|---|---|---|
request_id |
Single HTTP request | Correlate request with immediate logs |
correlation_id |
OAuth flow (may span multiple requests) | Track entire OAuth flow across callbacks |
When POST /api/v1/servers/{id}/login is called:
- Response includes both
request_id(for this request) andcorrelation_id(for OAuth flow) - Logs include both IDs
- User can search logs by either ID
When committing changes for this feature, follow these guidelines:
- Use:
Related #[issue-number]- Links the commit to the issue without auto-closing - Do NOT use:
Fixes #[issue-number],Closes #[issue-number],Resolves #[issue-number]- These auto-close issues on merge
Rationale: Issues should only be closed manually after verification and testing in production, not automatically on merge.
- Do NOT include:
Co-Authored-By: Claude <noreply@anthropic.com> - Do NOT include: "Generated with Claude Code"
Rationale: Commit authorship should reflect the human contributors, not the AI tools used.
feat(api): add request ID to all API responses and error payloads
Related #XXX
Implements request-scoped logging with X-Request-Id header support.
Server generates UUID if client doesn't provide one. All error
responses include request_id for log correlation.
## Changes
- Add X-Request-Id header processing middleware
- Include request_id in all error JSON responses
- Add request_id to structured log context
- Add --request-id flag to logs command
## Testing
- Verified request ID in error responses
- Tested client-provided vs server-generated IDs
- Confirmed logs filterable by request_id