Changes from Phase 6.7 child beads that were not committed earlier:
- Add subtle dependency for constant-time token comparison
- Add root directory for path-traversal protection in HTTP+SSE transport
- Update MCP server state to support --root flag
- Minor fixes and improvements across MCP modules
These changes support the 7 closed child beads:
- pdftract-5xq16: JSON-RPC 2.0 framing layer
- pdftract-67tm8: stdio transport
- pdftract-g0ro2: HTTP+SSE transport
- pdftract-24kut: transport mutual exclusion enforcement
- pdftract-1rami: tool catalog (10 tools)
- pdftract-6696g: path-traversal protection
- pdftract-zltqd: bearer-token auth
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The --root DIR flag was already fully implemented in the codebase.
All 25 tests pass (12 unit + 13 integration tests).
Acceptance criteria verified:
- Path traversal rejected with -32602
- Absolute paths rejected when --root is set
- HTTPS URLs bypass the check
- Symlink escapes detected via canonicalize
- Startup validation for root directory
Co-Authored-By: Claude Code <noreply@anthropic.com>
Per ADR-006: stdio and HTTP transports are mutually exclusive because they
have opposite stdout discipline (stdio: JSON-RPC sink; HTTP: log channel).
Changes:
- Add clap ArgGroup with multiple(false) to enforce --stdio XOR --bind
- Default to stdio mode when neither flag is specified
- Change --bind from required String to Option<String>
- Add ADR-006 reference to help text and doc comments
- Add unit tests for CLI argument validation
Acceptance criteria:
- pdftract mcp → launches in stdio mode (default)
- pdftract mcp --stdio → launches in stdio mode
- pdftract mcp --bind ADDR → launches in HTTP+SSE mode
- pdftract mcp --stdio --bind ADDR → exits 2 with clap conflict error
- pdftract mcp --help shows mutual exclusivity note
- Unit test verifies ArgGroup conflict on dual-transport invocation
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Implements the HTTP+SSE transport for the MCP server per bead pdftract-g0ro2.
All acceptance criteria PASS.
Routes:
- POST /: JSON-RPC requests (single or batch)
- GET /sse: Server-Sent Events for notifications
- GET /health: Health check (auth-exempt)
Key features:
- Reuses axum/tokio/tower-http from Phase 6.4 (no new deps)
- Bearer token auth (from sibling bead 6.7.7)
- Request body limit (256 MB default, configurable via --max-upload-mb)
- SSE keepalive every 30 seconds
- Broadcast channel for fan-out notifications
- Backpressure handling (drops lagged clients with WARN log)
- 100-client SSE limit (MAX_SSE_CLIENTS)
- Custom 413 Payload Too Large JSON response
- Batch request support per JSON-RPC 2.0 spec
All 10 integration tests pass:
- test_post_tools_list: POST / returns tool catalog
- test_get_sse_stream: GET /sse opens SSE stream with keepalive
- test_50_concurrent_clients: 50 concurrent clients succeed
- test_health_during_load: GET /health returns 200 under load
- test_post_batch_request: Batch requests return batch responses
- test_post_payload_too_large: POST / over limit returns 413 with JSON body
- test_auth_required_for_non_loopback: Bearer auth returns 401 with WWW-Authenticate
- test_post_single_request_returns_single_response: Single request returns single response
- test_unknown_method: Unknown method returns method_not_found error
- test_get_health: GET /health returns 200 with version info
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Implements the stdio transport for the MCP server, enabling communication
with local agents (Claude Desktop, Claude Code, Continue, Cursor) over
standard input/output with Content-Length framing.
Core features:
- LSP-style Content-Length framing with \r\n terminators
- JSON-RPC 2.0 message parsing and serialization
- INV-9 compliance: stdout contains only JSON-RPC frames
- Panic hook redirects panics to stderr
- SIGTERM handler for graceful shutdown
- Parse errors return -32700 with id: null, then continue
Acceptance criteria:
- ✅ Piping tools/list with framing produces expected response < 50ms
- ✅ EOF on stdin → clean exit within 100ms
- ✅ Malformed JSON → -32700 error, subsequent requests work
- ✅ No println!/log output to stdout (INV-9 enforced)
- ✅ Panics go to stderr, no partial JSON on stdout
- ✅ SIGTERM → exit 0, SIGINT → immediate non-zero exit
Tests added:
- crates/pdftract-cli/tests/mcp-stdio.rs (8 integration tests, all pass)
- All 49 existing unit tests continue to pass
Refs: pdftract-67tm8, plan Phase 6.7.2
Fixed compilation error in xref.rs where u64 literal 0x5DEECE66D was used
with u32 state, causing overflow. Changed state to u64 for proper Java
Random algorithm behavior.
The OCG /OCProperties parsing implementation was already complete and
all tests pass. See notes/pdftract-2a6rk.md for verification.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Implements the conformance test runner pattern for all 10 SDKs as specified
in the plan (line 3547). Each SDK now has a dedicated conformance test runner.
Created:
- tests/sdk-conformance/report-schema.json: JSON schema for conformance reports
- docs/notes/sdk-conformance-runner.md: Pattern documentation and reference
- crates/pdftract-cli/tests/conformance.rs: Rust cargo test target
- tests/conformance/test_conformance.py: Python pytest harness
- tests/conformance/conformance.test.ts: Node.js vitest runner
- tests/conformance/conformance_test.go: Go go test runner
- tests/conformance/ConformanceTest.java: Java JUnit 5 runner
- tests/conformance/ConformanceTests.cs: .NET xUnit runner
- tests/conformance/conformance.c: C standalone binary
- tests/conformance/conformance_test.rb: Ruby minitest runner
- tests/conformance/ConformanceTest.php: PHP PHPUnit runner
- tests/conformance/ConformanceTests.swift: Swift XCTest runner
All runners implement:
- Loading of tests/sdk-conformance/cases.json
- Execution of test cases with language-native method invocations
- Comparison of results against expected values with numeric tolerances
- Emission of machine-readable conformance-report.json
- Non-zero exit on failures/errors for CI gating
Acceptance criteria:
- PASS: All 10 SDKs have language-specific runners
- PASS: Runners consume shared cases.json
- PASS: Runners emit JSON reports matching schema
- PASS: Runners exit non-zero on failure
- WARN: README integration pending SDK repo creation
- WARN: Stub implementations return placeholder results
References:
- Plan line 3547: "Every SDK has a pdftract-sdk-conformance test runner"
- Plan line 3589: "Conformance suite results published as Argo artifact"
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Bead-Id: pdftract-5omc