Connecting an MCP client

luplo ships a Model Context Protocol server on stdio. Any MCP-compatible client — Claude Code, Claude Desktop, Cursor, Zed, or something built on the MCP SDKs — can call luplo’s tools during a coding session.

This guide shows how to wire up the most common clients and how to sanity-check the connection. For the full tool surface see MCP tool reference.

The launch command

Every client spawns the luplo MCP server the same way:

uv run --directory /absolute/path/to/luplo python -m luplo.mcp

…with LUPLO_DB_URL in the environment so the server can reach Postgres. What varies between clients is only the config file shape that describes this command.

Tip

Use an absolute path for --directory. MCP hosts don’t execute from your shell’s working directory.

Claude Code

Claude Code auto-detects .mcp.json in the workspace root.

cp .mcp.json.example .mcp.json
# edit the path and DB URL
{
  "mcpServers": {
    "luplo": {
      "command": "uv",
      "args": [
        "run", "--directory", "/absolute/path/to/luplo",
        "python", "-m", "luplo.mcp"
      ],
      "env": {
        "LUPLO_DB_URL": "postgresql://USER:PASSWORD@localhost/luplo"
      }
    }
  }
}

Reopen the workspace. Claude Code will show luplo under MCP servers and the tools become callable.

Claude Desktop

Merge the same mcpServers block into:

  • macOS~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows%APPDATA%\Claude\claude_desktop_config.json

  • Linux~/.config/Claude/claude_desktop_config.json

Restart Claude Desktop after editing.

Cursor

Cursor reads ~/.cursor/mcp.json (global) or .cursor/mcp.json (per project). The schema is identical to Claude Code’s:

{
  "mcpServers": {
    "luplo": {
      "command": "uv",
      "args": [
        "run", "--directory", "/absolute/path/to/luplo",
        "python", "-m", "luplo.mcp"
      ],
      "env": {
        "LUPLO_DB_URL": "postgresql://USER:PASSWORD@localhost/luplo"
      }
    }
  }
}

Restart Cursor (or open the project fresh).

Zed

Zed’s MCP support is evolving; consult the Zed docs for the current config path. The command shape is the same uv run --directory python -m luplo.mcp.

Other clients

Any MCP client that speaks the stdio transport can host luplo. If you are building a custom client, see the MCP client SDKs. Pass the same command, args, and env through the client’s server-config shape.

Smoke test

Once connected, ask the client:

“What did we decide about auth in this project?”

A correctly wired client will call luplo_item_search with a query derived from your question, return the matching decisions, and cite the ids. If you get no results, either no decisions are saved yet or the project id is wrong.

You can also verify manually from the CLI:

uv run lp items search "auth" --project myapp

If the CLI sees items and the MCP client doesn’t, the client is pointing at a different DB (check LUPLO_DB_URL) or a different project (check the project_id argument in the tool calls).

How clients should use luplo

From luplo’s perspective, a well-behaved MCP client:

  1. Calls luplo_brief at most once per session, only when the human asks for context — not on every prompt. See Philosophy on why there is no auto-injection.

  2. Calls luplo_item_search liberally — it is cheap, glossary-expanded, and returns match reasons.

  3. Calls luplo_save_decisions and luplo_item_upsert only when the human explicitly says so (“save this decision”, “log that we decided…”). Never auto-extracts.

These are conventions, not enforcement. luplo has no way to stop a client from spamming luplo_brief on every tool call — that’s a client bug to fix there, not a feature to code around here.

Trouble

Client can’t find the server.

Run the launch command by hand from your shell. If uv run works there, the host is either using a non-login shell (no PATH) or --directory points at the wrong place. Use absolute paths.

Tool call succeeds but returns empty.

Check the project_id. luplo is per-project; an empty project responds with nothing. Seed via lp init.

Server crashes on start.

Inspect stderr via the client’s MCP logs. The most common cause is LUPLO_DB_URL pointing at a DB that isn’t up or doesn’t have migrations applied — run alembic upgrade head.