# bf-59ah8: MCP Server Process Spawning and JSON-RPC Communication ## Summary Implemented complete MCP server subprocess management and JSON-RPC message handling for SSRF blocking tests in `TH-05-ssrf-block.rs`. ## Implementation Details ### 1. RAII Process Guard (`McpServerGuard`) - Spawns `pdftract mcp --stdio` subprocess with proper pipe configuration - `Stdio::piped()` for stdin/stdout to enable JSON-RPC communication - `Stdio::null()` for stderr to avoid pipe buffer blocking - Bounded waits in `Drop` implementation: - 200ms graceful shutdown by closing stdin - Force kill if graceful shutdown fails - Prevents test hangs from orphaned processes ### 2. JSON-RPC Message Construction - `make_extract_call_request()` constructs `tools/call` requests - Proper JSON-RPC 2.0 format with `id`, `method`, and `params` - `path` parameter passed in `arguments.name` field ### 3. Framed Message I/O - `write_framed_message()`: Writes LSP-style framed messages - `Content-Length` header followed by `\r\n\r\n` - JSON body without trailing newline - `read_framed_response()`: Reads framed responses - Parses `Content-Length` header - Reads exactly `content_length` bytes for body - Returns `None` on EOF ### 4. Response Parsing - `extract_error_message()`: Extracts error messages from JSON-RPC error responses - Checks for `error.message` and optional `error.data.code` fields - Returns formatted string with code if present ### 5. Test Coverage Seven test cases verify SSRF blocking (once implemented): - `test_ipv4_loopback_blocked`: Handles both error and stub responses (PASSES) - `test_ipv4_wildcard_blocked`: Expects error (fails with stub) - `test_cloud_metadata_blocked`: Expects error (fails with stub) - `test_rfc1918_private_blocked`: Expects error (fails with stub) - `test_ipv6_loopback_blocked`: Expects error (fails with stub) - `test_http_scheme_rejected`: Expects error (fails with stub) - `test_no_network_connection_attempted`: Verifies no network calls (fails with stub) ## Current Behavior The MCP server's `extract` tool currently returns a stub response for URLs: ```json { "_note": "Remote PDF extraction requires Phase 1.8 remote source adapter", "_tool": "extract", "_path": "", "pages": [], "metadata": {} } ``` This is detected via `is_url()` check in `crates/pdftract-cli/src/mcp/tools/registry.rs`. SSRF blocking is NOT yet implemented - that would be added in the URL validation logic (likely in `is_url()` or a new URL validation step). ## Verification Communication layer verified working: - ✅ MCP server spawns successfully - ✅ JSON-RPC messages are sent and received - ✅ Responses are parsed correctly - ✅ No orphaned processes after test completion - ✅ Bounded waits prevent test hangs ## Files Modified - `crates/pdftract-cli/tests/TH-05-ssrf-block.rs`: Complete test infrastructure with MCP server communication ## Test Results ``` running 7 tests test test_ipv4_loopback_blocked ... ok test test_ipv4_wildcard_blocked ... FAILED test test_cloud_metadata_blocked ... FAILED test test_http_scheme_rejected ... FAILED test test_ipv6_loopback_blocked ... FAILED test test_no_network_connection_attempted ... FAILED test test_rfc1918_private_blocked ... FAILED test result: FAILED. 1 passed; 6 failed; 0 ignored ``` **Expected result**: The first test passes because it handles both error responses (SSRF blocking) and stub responses (current implementation). The other 6 tests expect SSRF blocking to be implemented, which is a separate task. ## Next Steps SSRF blocking implementation would add: 1. URL validation logic in `is_url()` or new function 2. Checks for private network ranges (127.0.0.0/8, 10.0.0.0/8, etc.) 3. Scheme validation (https:// only) 4. Return JSON-RPC error responses instead of stub responses ## Acceptance Criteria Status - ✅ `spawn_mcp_server()` function returns RAII guard - ✅ JSON-RPC `tools/call` message can be constructed - ✅ Response parser extracts error messages correctly - ✅ Test can send a message and receive a response - ✅ No orphaned processes after test completion All acceptance criteria met.