MCP Integration

Demo

What MCP is

  • MCP is a protocol. Today, stdio, HTTP, and SSE are the canonical transports. A WebSocket transport for MCP is under discussion (SEP‑1288). Faxbot provides a Node WebSocket helper for convenience; it mirrors tool calls but is not a formal MCP WebSocket transport.

Quick Start (Claude/Cursor)

  • Add Faxbot MCP to your assistant config (stdio). Then call send_fax with a local filePath.

Claude Desktop or Cursor config example:

{
  "mcpServers": {
    "faxbot": {
      "command": "node",
      "args": ["src/servers/stdio.js"],
      "cwd": "/PATH/TO/faxbot/node_mcp",
      "env": { "FAX_API_URL": "http://localhost:8080", "API_KEY": "your_api_key" }
    }
  }
}

Use these tools (Node & Python MCP)

  • send_fax: { to, filePath } (stdio) or { to, fileUrl } or { to, fileContent, fileName, fileType }
  • get_fax_status: { jobId }
  • get_fax: { id } — works for outbound job ids and inbound ids
  • list_inbound: { limit?, cursor? } — recent inbound metadata
  • get_inbound_pdf: { inboundId, asBase64? } — returns base64 or a path/URI to fetch

Important notes

  • File types: only PDF and TXT. Convert images (PNG/JPG) to PDF first.
  • Stdio: use filePath so the MCP reads the file locally and posts it to Faxbot.
  • HTTP/SSE: provide base64 content; MCP JSON limit is ~16 MB; REST API raw limit is 10 MB.
  • Backends: works with any Faxbot backend (phaxio, sinch, or sip).

Examples

  • Natural language: “Fax insurance_card.pdf to SkyRidge Cardiology.” The MCP client can look up the number using its own tools, then call send_fax. Follow with get_fax_status.
  • Tool calls:
    • send_fax with { to: "+15551234567", filePath: "/Users/me/Documents/letter.pdf" }
    • get_fax_status with { jobId: "<id>" }
    • get_fax with { id: "in_123" } (inbound) or { id: "fbj_ABC" } (outbound)
    • get_inbound_pdf with { inboundId: "in_123", asBase64: true }

Docker Quick Start (HTTP MCP)

  • Start the API and MCP via Docker Compose:
    docker compose up -d --build api
    docker compose --profile mcp up -d --build faxbot-mcp
    
  • The MCP HTTP server listens on http://localhost:3001.
  • Use this when integrating web clients or cloud AI that speak MCP over HTTP.
  • For Claude Desktop or Cursor (stdio), run the MCP directly on the host instead of Docker.

Turnkey SSE (HIPAA‑oriented) via Docker Compose

  • Node SSE (port 3002):
    export OAUTH_ISSUER=https://YOUR_ISSUER
    export OAUTH_AUDIENCE=faxbot-mcp
    export OAUTH_JWKS_URL=https://YOUR_ISSUER/.well-known/jwks.json
    docker compose --profile mcp up -d --build faxbot-mcp-sse
    
  • Python SSE (port 3003):
    export OAUTH_ISSUER=https://YOUR_ISSUER
    export OAUTH_AUDIENCE=faxbot-mcp
    export OAUTH_JWKS_URL=https://YOUR_ISSUER/.well-known/jwks.json
    docker compose --profile mcp up -d --build faxbot-mcp-py-sse
    
  • Choose one. Both require Bearer JWTs issued by your IdP; tokens are verified via JWKS.
  • Detailed OIDC setup guidance and provider links: see OAUTH_SETUP.md.

MCP Inspector (explore tools/resources/prompts)

  • Start the Inspector UI via Docker:
    docker compose --profile mcp up -d mcp-inspector
    open http://localhost:6274
    
  • Or run locally:
    npx @modelcontextprotocol/inspector
    
  • Connect the Inspector to your Faxbot MCP server:
    • Stdio: launch node node_mcp/src/servers/stdio.js (or python python_mcp/stdio_server.py) with FAX_API_URL and API_KEY env.
    • HTTP: set transport “streamable-http” and point to http://localhost:3001.
    • SSE: set transport “sse” and point to http://localhost:3002/sse (Node) or http://localhost:3003/sse (Python). Include Authorization: Bearer <JWT>.
    • WebSocket (Node, helper): connect to ws://localhost:3004 (optionally add ?key=<API_KEY>). This helper mirrors tool calls and is not a formal MCP transport.

Example mcp.json for MCP Inspector

{
  "mcpServers": {
    "faxbot-node-stdio": {
      "type": "stdio",
      "command": "node",
      "args": ["src/servers/stdio.js"],
      "cwd": "./node_mcp",
      "env": {
        "FAX_API_URL": "http://localhost:8080",
        "API_KEY": "your_api_key"
      }
    },
    "faxbot-node-http": {
      "type": "streamable-http",
      "url": "http://localhost:3001/mcp"
    },
    "faxbot-node-sse": {
      "type": "sse",
      "url": "http://localhost:3002/sse"
    },
    "faxbot-py-stdio": {
      "type": "stdio",
      "command": "python",
      "args": ["stdio_server.py"],
      "cwd": "./python_mcp",
      "env": {
        "FAX_API_URL": "http://localhost:8080",
        "API_KEY": "your_api_key"
      }
    },
    "faxbot-py-sse": {
      "type": "sse",
      "url": "http://localhost:3003/sse"
    }
  }
}

Notes:

  • For SSE entries, provide Authorization: Bearer <JWT> in the Inspector UI headers before connecting.
  • If you keep only one server entry or name one default-server, Inspector selects it automatically.

Transports × servers (language matrix)

2 languages × 3 transports = 6 options.

Node MCP:

  • stdio: node_mcp/src/servers/stdio.js
  • HTTP: node_mcp/src/servers/http.js (port 3001)
  • SSE+OAuth: node_mcp/src/servers/sse.js (port 3002)
  • WebSocket: node_mcp/src/servers/ws.js (port 3004)

Python MCP:

  • stdio: python_mcp/stdio_server.py
  • HTTP: python_mcp/http_server.py
  • SSE+OAuth: python_mcp/server.py

Node MCP start commands

cd node_mcp && npm install
FAX_API_URL=http://localhost:8080 API_KEY=$API_KEY ./scripts/start-stdio.sh     # stdio
FAX_API_URL=http://localhost:8080 API_KEY=$API_KEY MCP_HTTP_PORT=3001 ./scripts/start-http.sh
OAUTH_ISSUER=... OAUTH_AUDIENCE=... FAX_API_URL=http://localhost:8080 API_KEY=$API_KEY \
  MCP_SSE_PORT=3002 ./scripts/start-sse.sh
MCP_WS_PORT=3004 API_KEY=$API_KEY node src/servers/ws.js  # WebSocket

Python MCP start commands

cd python_mcp
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
export FAX_API_URL=http://localhost:8080
export API_KEY=your_api_key
python stdio_server.py               # stdio
# or: uvicorn http_server:app --host 0.0.0.0 --port 3004
# or: uvicorn server:app --host 0.0.0.0 --port 3003 (SSE+OAuth)

HTTP and SSE details

  • HTTP uses Streamable HTTP with sessions: POST /mcp, GET /mcp (SSE), DELETE /mcp.
  • SSE+OAuth requires Bearer JWT with iss/aud; JWKS is fetched from the issuer.
  • Place HTTP/SSE behind auth/rate limits for production.

Voice examples

  • ❌ “Fax document.pdf to +1234567890” (missing file access/base64)
  • ✅ “Call send_fax with { to: “+1234567890”, filePath: “/path/to/file.pdf” }”
  • For HTTP/SSE, read and base64‑encode the file before calling send_fax.

File conversion hints

  • macOS Preview: File → Export As… → PDF
  • macOS CLI: sips -s format pdf "in.png" --out "out.pdf"
  • Linux: img2pdf in.png -o out.pdf or magick convert in.png out.pdf
  • Windows: “Print to PDF”.

See also: Images vs Text PDFs guide (docs/IMAGES_AND_PDFS.md).

Secure SSE with OAuth2 (Admin Console path)

  1. Open Settings → MCP in the Admin Console
  2. Enable Node SSE and/or Python SSE
  3. Enter the OAuth issuer, expected audience, and optional JWKS URL
  4. Apply and confirm health. Faxbot reloads the MCP workers and refuses connections without a valid Bearer token.
  5. Configure assistants to send a short-lived JWT (Authorization: Bearer <token>) on every SSE request.

Pair SSE with TLS termination and strict scopes when processing PHI. The Security docs include IdP-specific examples.


Copyright © 2024 Faxbot. Distributed under the MIT License.