lelu
Integrations

MCP

Gate Model Context Protocol tool calls through Lelu. Works as a middleware between any MCP client (Claude Desktop, Claude Code, custom hosts) and your MCP server.

Zero-config local server

The fastest way to try Lelu — no account, no Docker. On first run, lelu-mcp downloads the engine binary (cached in ~/.lelu/bin), writes a starter policy to ~/.lelu/policy.yaml, starts the engine locally, and exposes the lelu_agent_authorize tool to your agent.

Claude Code
claude mcp add lelu -- npx -y lelu-mcp start --transport stdio
claude_desktop_config.json / .cursor/mcp.json
{
  "mcpServers": {
    "lelu": {
      "command": "npx",
      "args": ["-y", "lelu-mcp", "start", "--transport", "stdio"]
    }
  }
}

Already running an engine? Point at it instead with --engine-url http://localhost:8082 --api-key <key> — no local engine is spawned when a URL is set.

How it works

Lelu's MCP proxy sits between the client and your server. Every tools/call request is forwarded to the Lelu authorize endpoint before reaching your handler. Denied calls never reach your server. Calls that require human review are held until approved.

MCP client → Lelu proxy → your MCP server

Hosted proxy (coming soon)

A Lelu-managed proxy you point your MCP client at is planned but not yet generally available. Today, use the zero-config local server above or the self-hosted middleware below.

claude_desktop_config.json
{
  "mcpServers": {
    "my-server": {
      "url": "https://mcp.lelu-ai.com/proxy",
      "headers": {
        "X-Lelu-Key": "lelu_sk_...",
        "X-Target-URL": "http://localhost:3001"
      }
    }
  }
}

Self-hosted middleware

Embed Lelu authorization directly in your MCP server using the SDK.

server.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { createClient } from "lelu-agent-auth";

const lelu = createClient({ apiKey: process.env.LELU_API_KEY! });
const server = new McpServer({ name: "my-server", version: "1.0.0" });

server.tool("delete_file", { path: z.string() }, async ({ path }) => {
  const { decision, reason } = await lelu.authorize({ tool: "delete_file" });

  if (decision === "deny") {
    return { content: [{ type: "text", text: `Blocked: ${reason}` }] };
  }

  await fs.unlink(path);
  return { content: [{ type: "text", text: `Deleted ${path}` }] };
});

Policy example

Create a policy in the dashboard that targets your MCP tool names:

Policy rules
deny   delete_file      — Never allow file deletion via MCP
review send_email       — Require human approval before sending
allow  read_file        — Read-only ops are always fine