Skip to content

MCP Integration

Model Context Protocol (MCP) endpoint for AI agent integration with Claude Code, GPT, and other AI assistants.

Endpoint

POST https://api.thelawin.dev/mcp

Protocol

  • Protocol: JSON-RPC 2.0 over HTTP
  • Version: 2024-11-05
  • Mode: Sandbox (watermarks applied, unlimited requests)

Authentication

Sandbox Mode Only

MCP requests always run in sandbox mode and do not require API keys. Generated PDFs will have watermarks. Use the regular REST API for production invoices.

Available Tools

1. thelawin_generate

Generate a ZUGFeRD/Factur-X compliant PDF invoice.

Input Schema:

json
{
  "template": "minimal",  // minimal | classic | compact
  "locale": "en",         // de | en | fr | es | it
  "invoice": {
    "number": "MCP-001",
    "date": "2026-01-07",
    "seller": {
      "name": "Test GmbH",
      "vat_id": "DE123456789",
      "city": "Berlin",
      "country": "DE"
    },
    "buyer": {
      "name": "Customer AG",
      "city": "München",
      "country": "DE"
    },
    "items": [{
      "description": "Service",
      "quantity": 1,
      "unit_price": 100
    }]
  }
}

Output: Invoice PDF as base64 resource + metadata

2. thelawin_validate

Validate an existing PDF for ZUGFeRD/Factur-X compliance.

Input Schema:

json
{
  "pdf_base64": "JVBERi0xLjQK..."
}

Output: Validation result with errors/warnings

JSON-RPC Methods

initialize

Initialize MCP session.

Request:

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2024-11-05",
    "capabilities": {},
    "clientInfo": {
      "name": "claude-code",
      "version": "1.0.0"
    }
  }
}

Response:

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "capabilities": {
      "tools": {
        "listChanged": false
      }
    },
    "serverInfo": {
      "name": "thelawin-api",
      "version": "0.1.0"
    }
  }
}

Headers:

  • Mcp-Session-Id: Session ID (UUID)

initialized

Acknowledge initialization (notification, no response).

Request:

json
{
  "jsonrpc": "2.0",
  "method": "initialized"
}

Response: 202 Accepted (no body)

tools/list

List available tools.

Request:

json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/list"
}

Response:

json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      {
        "name": "thelawin_generate",
        "description": "Generate a ZUGFeRD/Factur-X compliant PDF invoice from structured data. Returns a valid PDF/A-3 with embedded XML.",
        "inputSchema": {
          "type": "object",
          "required": ["invoice"],
          "properties": {
            "template": { "type": "string", "enum": ["minimal", "classic", "compact"] },
            "locale": { "type": "string", "enum": ["de", "en", "fr", "es", "it"] },
            "invoice": { ... }
          }
        }
      },
      {
        "name": "thelawin_validate",
        "description": "Validate an existing PDF for ZUGFeRD/Factur-X compliance.",
        "inputSchema": { ... }
      }
    ]
  }
}

tools/call

Execute a tool.

Request:

json
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "thelawin_generate",
    "arguments": {
      "template": "minimal",
      "invoice": {
        "number": "MCP-001",
        "date": "2026-01-07",
        "seller": { "name": "Test GmbH" },
        "buyer": { "name": "Customer AG" },
        "items": [{
          "description": "Service",
          "quantity": 1,
          "unit_price": 100
        }]
      }
    }
  }
}

Response:

json
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Invoice generated successfully!\n\nFilename: rechnung-MCP-001.pdf\nFormat: ZUGFERD\nProfile: EN16931\nVersion: ZUGFeRD 2.3\n\nPDF size: ~14KB\n\nThe PDF is available as a resource below."
      },
      {
        "type": "resource",
        "resource": {
          "uri": "data:application/pdf;base64,JVBERi0xLjQK...",
          "mimeType": "application/pdf",
          "text": "JVBERi0xLjQK..."
        }
      }
    ],
    "isError": false
  }
}

Error Handling

Tool Error

json
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [{
      "type": "text",
      "text": "Error: Missing 'invoice' in arguments"
    }],
    "isError": true
  }
}

JSON-RPC Error

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32601,
    "message": "Method not found: unknown_method"
  }
}

Error Codes:

  • -32700: Parse error
  • -32600: Invalid request
  • -32601: Method not found
  • -32602: Invalid params
  • -32603: Internal error

Usage Examples

curl

bash
# 1. Initialize
curl -X POST https://api.thelawin.dev/mcp \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2024-11-05" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2024-11-05",
      "clientInfo": { "name": "curl", "version": "1.0.0" }
    }
  }'

# 2. List Tools
curl -X POST https://api.thelawin.dev/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/list"
  }'

# 3. Generate Invoice
curl -X POST https://api.thelawin.dev/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "tools/call",
    "params": {
      "name": "thelawin_generate",
      "arguments": {
        "invoice": {
          "number": "TEST-001",
          "date": "2026-01-07",
          "seller": { "name": "Company" },
          "buyer": { "name": "Customer" },
          "items": [{ "description": "Product", "quantity": 1, "unit_price": 100 }]
        }
      }
    }
  }'

Claude Code

thelawin.dev's MCP server can be used directly in Claude Code:

typescript
// MCP server is available as HTTP endpoint
// Claude Code will discover and use it automatically

Claude Code Integration

Claude Code can directly interact with the MCP endpoint without additional configuration. The API is discoverable via /llms.txt.

Python

python
import requests
import json

# MCP client
class TheleminMCPClient:
    def __init__(self, base_url="https://api.thelawin.dev/mcp"):
        self.base_url = base_url
        self.session_id = None
        self.next_id = 1

    def call(self, method, params=None):
        request = {
            "jsonrpc": "2.0",
            "id": self.next_id,
            "method": method
        }
        if params:
            request["params"] = params

        headers = {"Content-Type": "application/json"}
        if self.session_id:
            headers["Mcp-Session-Id"] = self.session_id

        response = requests.post(self.base_url, json=request, headers=headers)

        if "Mcp-Session-Id" in response.headers:
            self.session_id = response.headers["Mcp-Session-Id"]

        self.next_id += 1
        return response.json()

    def initialize(self):
        return self.call("initialize", {
            "protocolVersion": "2024-11-05",
            "clientInfo": {"name": "python-client", "version": "1.0.0"}
        })

    def list_tools(self):
        return self.call("tools/list")

    def generate_invoice(self, invoice_data, template="minimal"):
        return self.call("tools/call", {
            "name": "thelawin_generate",
            "arguments": {
                "template": template,
                "invoice": invoice_data
            }
        })

# Usage
client = TheleminMCPClient()
client.initialize()

result = client.generate_invoice({
    "number": "PYTHON-001",
    "date": "2026-01-07",
    "seller": {"name": "Test Co"},
    "buyer": {"name": "Customer"},
    "items": [{"description": "Service", "quantity": 1, "unit_price": 100}]
})

print(result)

TypeScript

typescript
interface JsonRpcRequest {
  jsonrpc: '2.0';
  id?: number | string;
  method: string;
  params?: any;
}

interface JsonRpcResponse {
  jsonrpc: '2.0';
  id?: number | string;
  result?: any;
  error?: {
    code: number;
    message: string;
  };
}

class TheleminMCPClient {
  private baseUrl: string;
  private sessionId?: string;
  private nextId = 1;

  constructor(baseUrl = 'https://api.thelawin.dev/mcp') {
    this.baseUrl = baseUrl;
  }

  async call(method: string, params?: any): Promise<JsonRpcResponse> {
    const request: JsonRpcRequest = {
      jsonrpc: '2.0',
      id: this.nextId++,
      method,
      ...(params && { params })
    };

    const headers: Record<string, string> = {
      'Content-Type': 'application/json'
    };

    if (this.sessionId) {
      headers['Mcp-Session-Id'] = this.sessionId;
    }

    const response = await fetch(this.baseUrl, {
      method: 'POST',
      headers,
      body: JSON.stringify(request)
    });

    const sessionId = response.headers.get('Mcp-Session-Id');
    if (sessionId) {
      this.sessionId = sessionId;
    }

    return response.json();
  }

  initialize() {
    return this.call('initialize', {
      protocolVersion: '2024-11-05',
      clientInfo: { name: 'typescript-client', version: '1.0.0' }
    });
  }

  listTools() {
    return this.call('tools/list');
  }

  generateInvoice(invoiceData: any, template = 'minimal') {
    return this.call('tools/call', {
      name: 'thelawin_generate',
      arguments: { template, invoice: invoiceData }
    });
  }
}

// Usage
const client = new TheleminMCPClient();
await client.initialize();

const result = await client.generateInvoice({
  number: 'TS-001',
  date: '2026-01-07',
  seller: { name: 'Test Co' },
  buyer: { name: 'Customer' },
  items: [{ description: 'Service', quantity: 1, unit_price: 100 }]
});

console.log(result);

MCP vs REST API

FeatureMCP EndpointREST API
ProtocolJSON-RPC 2.0RESTful HTTP
AuthenticationNone (sandbox)X-API-Key
WatermarkYes (always)No (live keys)
QuotaUnlimitedPlan-based
Use CaseAI agents, testingProduction
Output FormatMCP ContentBlockJSON

When to use MCP

Use MCP for:

  • AI Agent Integration (Claude Code, GPT, etc.)
  • Testing (unlimited sandbox requests)
  • Prototyping (quick testing without API key)

Use REST API for:

  • Production (no watermarks)
  • High Volume (better performance)
  • Full Features (validation, account management)

Specification

Full MCP specification: modelcontextprotocol.io

Further Reading

ZUGFeRD 2.3 & Factur-X 1.0 compliant