MCP — Model Context Protocol

muLLM exposes its routing pipeline as MCP tools, allowing any MCP-compatible client (Claude Code, Cursor, custom agents) to use muLLM for cost-optimized AI queries.

MCP Client → JSON-RPC 2.0 → muLLM MCP Server → classify → route → Cheapest Model

Available MCP Tools

mullm_query
Route an AI query through the cost-optimized pipeline. Returns response from the cheapest capable model.
params: content (string, required), skip_cache (bool), force_tier (string)
mullm_split
Decompose a multi-part query and route each sub-task to the cheapest appropriate tier.
params: content (string, required)
mullm_budget
Get current budget and savings counters.
params: none
mullm_classify
Classify a prompt without executing it. Returns category, complexity, freshness, and suggested tier.
params: content (string, required)
mullm_budget
Return current budget counters and spend-limit state.
params: none
mullm_system
Return CPU, RAM, GPU, VRAM, and Ollama status.
params: none

Usage Examples

curl
Python
Node.js
Claude Code

List tools

bashcurl -s https://localhost:6856/mcp/tools | jq

Call a tool (MCP tools/call)

bashcurl -s -X POST https://localhost:6856/mcp/call \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "mullm_query",
      "arguments": {
        "content": "What is the capital of France?"
      }
    }
  }' | jq

Query the pipeline directly

bashcurl -s -X POST https://localhost:6856/query \
  -H 'Content-Type: application/json' \
  -d '{"content": "Explain quicksort", "source": "api"}' | jq

Split routing

bashcurl -s -X POST https://localhost:6856/query/split \
  -H 'Content-Type: application/json' \
  -d '{"content": "What is 2+2? Also write a haiku about rain."}' | jq

Get budget status

bashcurl -s https://localhost:6856/api/budget | jq

Get cost stats

bashcurl -s https://localhost:6856/api/stats | jq

Basic query

pythonimport httpx

client = httpx.Client(base_url="https://localhost:6856", verify=False)

# Simple query
r = client.post("/query", json={"content": "What is quicksort?", "source": "api"})
data = r.json()
print(f"Tier: {data['tier_used']}, Cost: ${data['cost']:.4f}")
print(data["response"])

MCP tool call

pythonimport httpx

client = httpx.Client(base_url="https://localhost:6856", verify=False)

# List available tools
tools = client.get("/mcp/tools").json()
for tool in tools["tools"]:
    print(f"  {tool['name']}: {tool['description']}")

# Call a tool via MCP protocol
r = client.post("/mcp/call", json={
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
        "name": "mullm_query",
        "arguments": {"content": "Explain async/await"}
    }
})
print(r.json())

Streaming (SSE)

pythonimport httpx

with httpx.stream("GET", "https://localhost:6856/query/stream",
                   params={"q": "Write a poem about code"},
                   verify=False) as r:
    for line in r.iter_lines():
        if line.startswith("data: "):
            chunk = line[6:]
            if chunk == "[DONE]":
                break
            print(chunk, end="", flush=True)

Dashboard + Budget

pythonimport httpx

client = httpx.Client(base_url="https://localhost:6856", verify=False)

# Cost stats (real numbers, no estimates)
stats = client.get("/api/stats").json()
print(f"All-time cost: ${stats['all_time']['total_cost']:.4f}")
print(f"Total queries: {stats['all_time']['total_queries']}")
for tier, info in stats["by_tier"].items():
    print(f"  {tier}: {info['queries']}q, ${info['cost']:.4f}")

# Budget status
budget = client.get("/api/budget").json()
print(f"Daily: ${budget['daily_spend']:.2f} / ${budget['effective_daily_limit']:.2f}")

Basic query

javascriptconst r = await fetch('https://localhost:6856/query', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({content: 'What is quicksort?', source: 'api'})
});
const data = await r.json();
console.log(`Tier: ${data.tier_used}, Cost: $${data.cost.toFixed(4)}`);
console.log(data.response);

MCP tool call

javascript// List tools
const tools = await fetch('https://localhost:6856/mcp/tools').then(r => r.json());
tools.tools.forEach(t => console.log(`  ${t.name}: ${t.description}`));

// Call tool
const r = await fetch('https://localhost:6856/mcp/call', {
  method: 'POST',
  headers: {'Content-Type': 'application/json'},
  body: JSON.stringify({
    jsonrpc: '2.0', id: 1,
    method: 'tools/call',
    params: {name: 'mullm_query', arguments: {content: 'Explain closures'}}
  })
});
console.log(await r.json());

Streaming (SSE)

javascriptconst es = new EventSource(
  'https://localhost:6856/query/stream?content=' + encodeURIComponent('Write a haiku')
);
es.onmessage = (e) => {
  if (e.data === '[DONE]') { es.close(); return; }
  process.stdout.write(e.data);
};

HTTP client note

json{
  "endpoint": "https://localhost:6856/mcp/call",
  "transport": "http-json-rpc"
}

Usage

textOnce configured, Claude Code can call muLLM tools directly:

"Use mullm_query to ask 'What is the time complexity of quicksort?'"
"Use mullm_split to decompose this multi-part question"
"Use mullm_budget to check current savings"

muLLM will route each query to the cheapest capable model,
saving you money on every call.

JSON-RPC 2.0 Protocol

All MCP communication follows the JSON-RPC 2.0 specification.

Request
{"jsonrpc":"2.0", "id":1, "method":"tools/call", "params":{...}}

Response (success)
{"jsonrpc":"2.0", "id":1, "result":{...}}

Response (error)
{"jsonrpc":"2.0", "id":1, "error":{"code":-32601, "message":"Method not found"}}

Error Codes

reference-32700  Parse error       Invalid JSON
-32600  Invalid request   Missing required fields
-32601  Method not found  Unknown tool/method
-32602  Invalid params    Wrong argument types
-32603  Internal error    Server-side failure