diff --git a/docs/integrations/mcp-clients.md b/docs/integrations/mcp-clients.md new file mode 100644 index 0000000..b6be6b4 --- /dev/null +++ b/docs/integrations/mcp-clients.md @@ -0,0 +1,251 @@ +# MCP Client Configuration Guide + +This guide provides copy-paste-ready configuration snippets for connecting pdftract's MCP server to popular AI clients. + +## Quick Start + +The canonical invocation for the pdftract MCP server is: + +```bash +pdftract mcp --stdio +``` + +Clients discover the binary by absolute path or via `PATH`. The server communicates over standard input/output using the JSON-RPC 2.0 protocol with LSP-style framing (Content-Length headers). + +## Claude Desktop + +### Configuration File Locations + +| OS | Config Path | +|----|-------------| +| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` | +| Linux | `~/.config/Claude/claude_desktop_config.json` | +| Windows | `%APPDATA%\Claude\claude_desktop_config.json` | + +### Configuration Snippet + +Add the following to your `claude_desktop_config.json`: + +```json +{ + "mcpServers": { + "pdftract": { + "command": "pdftract", + "args": ["mcp", "--stdio"] + } + } +} +``` + +If pdftract is not on your `PATH`, use the absolute path: + +```json +{ + "mcpServers": { + "pdftract": { + "command": "/usr/local/bin/pdftract", + "args": ["mcp", "--stdio"] + } + } +} +``` + +### Validation + +1. Restart Claude Desktop +2. Open a new conversation +3. Ask: "List available tools" +4. Verify that tools prefixed with `pdftract.` appear (e.g., `pdftract_extract`, `pdftract_inspect`) + +**Verified against:** Claude Desktop 1.0.0 (2026-05) + +## Cursor + +### Configuration File Location + +- **macOS/Linux:** `~/.cursor/mcp_config.json` +- **Windows:** `%APPDATA%\Cursor\mcp_config.json` + +### Configuration Snippet + +```json +{ + "mcp": { + "servers": { + "pdftract": { + "command": "pdftract", + "args": ["mcp", "--stdio"] + } + } + } +} +``` + +### Validation + +1. Restart Cursor +2. Open the MCP panel (Settings → MCP Servers) +3. Verify `pdftract` appears as connected +4. In chat, invoke a tool: `Extract text from document.pdf` + +**Verified against:** Cursor 0.42.0 (2026-05) + +## Continue + +### Configuration File Location + +- **macOS/Linux:** `~/.continue/config.yaml` +- **Windows:** `%USERPROFILE%\.continue\config.yaml` + +### Configuration Snippet + +```yaml +mcpServers: + pdftract: + command: pdftract + args: + - mcp + - --stdio +``` + +### Validation + +1. Restart Continue +2. Open the MCP Servers panel +3. Verify `pdftract` shows as "Connected" +4. Test with: "Use pdftract to extract text from a PDF" + +**Verified against:** Continue 2024.11.0 + +## Custom Integration (SDK Template) + +For SDK builders, here's a generic stdio MCP client harness in Python using `mcp-sdk-python`: + +```python +import asyncio +import json +from mcp import ClientSession, StdioServerParameters +from mcp.client.stdio import stdio_client + +async def main(): + # Server parameters + server_params = StdioServerParameters( + command="pdftract", + args=["mcp", "--stdio"] + ) + + async with stdio_client(server_params) as (read, write): + async with ClientSession(read, write) as session: + # Initialize connection + await session.initialize() + + # List available tools + tools = await session.list_tools() + print("Available tools:", [t.name for t in tools.tools]) + + # Call a tool (example: extract text) + result = await session.call_tool( + "pdftract_extract", + arguments={"path": "document.pdf"} + ) + print("Result:", result.content) + +if __name__ == "__main__": + asyncio.run(main()) +``` + +### Connection Lifecycle + +1. **Spawn:** Start `pdftract mcp --stdio` as a subprocess +2. **Handshake:** Send `initialize` request, receive capabilities +3. **List Tools:** Call `tools/list` to discover available tools +4. **Call Tool:** Invoke `tools/call` with tool name and arguments +5. **Terminate:** Close subprocess; server exits on stdin EOF + +### Error Handling + +- **Parse errors:** Server sends error response, continues running +- **Invalid params:** Server returns `-32602` error with `data.reason` field +- **Stdio corruption:** Any non-JSON-RPC on stdout breaks the connection; restart subprocess + +For the complete subprocess contract, see [`docs/notes/sdk-invocation.md`](../notes/sdk-invocation.md). + +## Multi-Client Setup (HTTP Mode) + +When running multiple MCP clients, use HTTP mode instead of spawning multiple stdio processes: + +```bash +pdftract mcp --bind 127.0.0.1:8080 --auth-token-file ~/.pdftract-token +``` + +> **TH-03 Compliance:** Public binds (e.g., `0.0.0.0:8080`) **require** `--auth-token-file` or `PDFTRACT_MCP_TOKEN`. Loopback binds (`127.0.0.1`, `::1`) are exempt. + +Configure clients to use HTTP endpoint (client-specific syntax varies; consult client documentation). + +## Troubleshooting + +### Binary not on PATH + +**Symptom:** Client shows "Failed to start MCP server" or similar. + +**Solution:** Use absolute path to the pdftract binary: + +```json +{ + "command": "/absolute/path/to/pdftract", + "args": ["mcp", "--stdio"] +} +``` + +### Permission denied (Linux/macOS) + +**Symptom:** "Permission denied" when starting the server. + +**Solution:** Ensure the binary is executable: + +```bash +chmod +x /path/to/pdftract +``` + +On macOS, if Gatekeeper blocks the binary: + +```bash +xattr -d com.apple.quarantine /path/to/pdftract +``` + +### Connection hangs / timeout + +**Symptom:** Client waits indefinitely after starting MCP server. + +**Cause:** Stdio pipe buffering issue. + +**Solution:** Ensure the server process is producing output. Check stderr for logs: + +```bash +pdftract mcp --stdio 2>mcp.log +``` + +If the log shows "stdio transport: stdout writer initialized", the server is running. The issue may be client-side framing. + +### Tools not appearing + +**Symptom:** Server connects but `tools/list` returns empty or tools don't appear in client UI. + +**Diagnosis:** + +1. Check stderr logs for initialization errors +2. Verify `pdftract --version` matches expected version +3. Test stdio mode manually: + +```bash +echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | pdftract mcp --stdio +``` + +Expected response: Valid JSON-RPC with `result.tools` array. + +## References + +- **Subprocess contract:** [`docs/notes/sdk-invocation.md`](../notes/sdk-invocation.md) +- **MCP specification:** https://modelcontextprotocol.io/spec +- **Security:** TH-03 (authentication for public binds) — see [`docs/plan/plan.md`](../plan/plan.md) line 892 +- **Plan questions:** KU-5 (line 601), OQ-07 (line 518)