Skip to main content

Remote MCP

One memory across machines: the MCP tools over HTTP, behind bearer keys, for your laptop, desktop and CI.

5 min readUpdated November 2026Experimental

Make a key and start the server

The HTTP transport needs the same mcp extra and nothing else. It binds 127.0.0.1 unless you pass --host, and refuses any other interface without a key.

terminalbash
export LLMSLIM_MCP_API_KEYS="$(llmslim serve --new-key)"     # keep it; each client sends it
llmslim mcp --transport http --user-id asha --db ~/.llmslim/memory.db
outputtext
LLMSlim MCP server on http://127.0.0.1:8000/mcp, memory of user "asha" (every request needs an API key)

Give several keys, one per machine, to revoke one by restarting without it: repeat --api-key, or separate them with commas. These keys reach only this server's scope. llmslim serve's keys (LLMSLIM_API_KEYS) reach every user, so this server never reads that variable, and warns if one of its keys is also there.

Put it behind TLS

The key travels in a header, so anything past this machine must be HTTPS. Keep the server on 127.0.0.1 and let a reverse proxy on the same host terminate TLS, then pin the name it answers to with --allowed-host memory.example.com. With Caddy, which gets the certificate itself:

Caddyfiletext
memory.example.com {
    reverse_proxy 127.0.0.1:8000
}

Responses are plain JSON, not event streams, so proxies need no buffering settings. A private network such as Tailscale or WireGuard works too: bind its address with --host and keep the key.

Connect each client

Point each client at https://memory.example.com/mcp with the header Authorization: Bearer <key>. In Claude Code:

terminalbash
claude mcp add --transport http llmslim https://memory.example.com/mcp \
  --header "Authorization: Bearer $LLMSLIM_KEY"
VS Code: .vscode/mcp.json (asks for the key once, stores it as a secret)json
{
  "inputs": [
    { "type": "promptString", "id": "llmslim-key", "description": "LLMSlim API key", "password": true }
  ],
  "servers": {
    "llmslim": {
      "type": "http",
      "url": "https://memory.example.com/mcp",
      "headers": { "Authorization": "Bearer ${input:llmslim-key}" }
    }
  }
}
Cursor: ~/.cursor/mcp.jsonjson
{
  "mcpServers": {
    "llmslim": {
      "url": "https://memory.example.com/mcp",
      "headers": { "Authorization": "Bearer ${env:LLMSLIM_KEY}" }
    }
  }
}

Other clients take the same URL and header. GET /healthz answers {"status": "ok"} without a key, for health checks.

Check it from Python

With the MCP Python SDK, a client sends the key on every request:

remote_check.pypython
import asyncio, os

import httpx2
from mcp import Client
from mcp.client.streamable_http import streamable_http_client


async def main():
    headers = {"Authorization": f"Bearer {os.environ['LLMSLIM_KEY']}"}
    async with httpx2.AsyncClient(headers=headers) as http:
        async with Client(streamable_http_client("http://127.0.0.1:8000/mcp", http_client=http)) as client:
            await client.call_tool("remember", {"text": "My sister's wedding is in Jaipur in December."})
            result = await client.call_tool("recall", {"query": "When is the wedding?"})
            print(result.content[0].text)


asyncio.run(main())

A request without the key, or with a wrong one, gets a 401 with WWW-Authenticate: Bearer. The key is never logged or echoed.

Who can read whose memory

Every key reaches the server's one scope, with all five tools, including forget. A client can't widen it: as over stdio, no tool takes a user or agent id, and arguments a tool doesn't declare are dropped. For several people, run one server each, with its own --user-id, keys and port (or --path behind the proxy). They can share one database: SQLite for a few processes on one host, Postgres or MongoDB for more, or for servers on several hosts. To give an application every user's memory, use llmslim serve from your backend instead.

Flags

These apply only with --transport http; passing one with stdio is an error. There is no environment variable for the transport itself, so a shell variable can't turn the stdio server a client launches into an HTTP server.

FlagEnvironment variableDefaultMeaning
--transport stdio|httpstdioHow clients reach the server.
--hostLLMSLIM_MCP_HOST127.0.0.1Interface to bind; any other than loopback needs a key.
--portLLMSLIM_MCP_PORT8000Port.
--path/mcpURL path of the MCP endpoint.
--api-keyLLMSLIM_MCP_API_KEYSnoneA bearer key of at least 16 characters; repeat for several.
--allowed-hostLLMSLIM_ALLOWED_HOSTSnoneA host name clients reach the server by; * for any. Without a key, other names get a 403.

Request bodies are capped at 1 MB (413), malformed JSON-RPC is a 400, and on shutdown running requests get 10 seconds to finish. Clients on the 2026-07-28 MCP revision and those that start with initialize both work.

Questions

Can one server hold several people's memory?

No. One server holds one scope, the --user-id and --agent-id it was started with, and every key reaches that scope. For several people, run one server each; they can share a database.

Does it support OAuth?

No: bearer keys only. A key is a password for a machine, not an identity.

Does a restart break connected clients?

No. The server is stateless and answers in JSON, so it runs behind any load balancer, and several replicas can serve one Postgres or MongoDB memory.