# Model Context Protocol (MCP)

Memgraph offers Memgraph the [Memgraph MCP
Server](https://github.com/memgraph/ai-toolkit/tree/main/integrations/mcp-memgraph)
- a lightweight server implementation of the Model Context Protocol (MCP)
designed to connect Memgraph with LLMs.

![mcp-server](https://memgraph.com/docs/pages/ai-ecosystem/integrations/mcp-server.png)

### Run Memgraph MCP server

1. Install [`uv`](https://docs.astral.sh/uv/getting-started/installation/)
2. Install [Claude for Desktop](https://claude.ai/download).
3. Add the Memgraph server to Claude config:

Open the config file in your favorite text editor. The location of the config
file depends on your operating system:

**MacOS/Linux**
```
~/Library/Application\ Support/Claude/claude_desktop_config.json
```

**Windows**

```
$env:AppData\Claude\claude_desktop_config.json
```

Add the following config:
```json
{
    "mcpServers": {
      "mpc-memgraph": {
        "command": "uv",
        "args": [
            "run",
            "--with",
            "mcp-memgraph",
            "--python",
            "3.13",
            "mcp-memgraph"
        ]
     }
   }
}
```

> **Info**
>
> You may need to put the full path to the uv executable in
>   the command field. You can get this by running `which uv` on MacOS/Linux or
>   `where uv` on Windows. Make sure you pass in the absolute path to your server.

#### Chat with the database
1. Run Memgraph MAGE:
```bash
docker run -p 7687:7687 memgraph/memgraph-mage --schema-info-enabled=True
```

   The `--schema-info-enabled` configuration setting is set to `True` to allow
   LLM to run `SHOW SCHEMA INFO` query.
2. Open Claude Desktop and see the Memgraph tools and resources listed. Try it
   out! (You can load dummy data from Memgraph Lab
   [Datasets](https://memgraph.com/docs/memgraph-lab/getting-started/data-migration#datasets))

### Run Memgraph MCP server with Docker

### Build the Docker image
To build the Docker image using your local `memgraph-toolbox` code, run from the
root of the monorepo:

```
cd /path/to/ai-toolkit
docker build -f integrations/mcp-memgraph/Dockerfile -t mcp-memgraph:latest .
```

This will install your local `memgraph-toolbox` into the image.
### Run the Docker image
**1. Streamable HTTP mode (recommended)**

To expose the MCP HTTP server locally:

```
docker run --rm mcp-memgraph:latest
```

The server will be available at `http://localhost:8000/mcp/`

**2. Stdio mode (for integration with MCP stdio clients)**

Configure your MCP host to run the docker command and utilize stdio:

```
docker run --rm -i -e MCP_TRANSPORT=stdio mcp-memgraph:latest
```

> **Info**
>
> By default, the server will connect to a Memgraph instance running on
>   localhost docker network `bolt://host.docker.internal:7687`. If you have a
>   Memgraph instance running on a different host or port, you can specify it
>   using environment variables.

**3. Custom Memgraph connection (external instance, no host network)**

To avoid using host networking, or to connect to an external Memgraph instance:

```
docker run --rm \
  -p 8000:8000 \
  -e MEMGRAPH_URL=bolt://memgraph:7687 \
  -e MEMGRAPH_USER=myuser \
  -e MEMGRAPH_PASSWORD=password \
  mcp-memgraph:latest
```
### Connect from developer tools
**Visual Studio Code (HTTP MCP extension)**

If you are using VS Code MCP extension or similar, your configuration for an
HTTP server would look like:

```json
{
  "servers": {
    "mcp-memgraph-http": {
      "url": "http://localhost:8000/mcp/"
    }
  }
}
```

> **Info**
>
> The URL must end in /mcp/

**Visual Studio Code (stdio using Docker)**

You can also run the server using stdio for integration with MCP stdio clients:

1. Open Visual Studio Code, open Command Palette (Ctrl+Shift+P or Cmd+Shift+P on
   Mac), and select `MCP: Add server...`.
2. Choose `Command (stdio)`
3. Enter `docker` as the command to run.
4. For Server ID enter `mcp-memgraph`.
5. Choose "User" (adds to user-space `settings.json`) or "Workspace" (adds to
   `.vscode/mcp.json`).

When the settings open, enhance the args as follows:

```json
{
  "servers": {
    "mcp-memgraph": {
      "type": "stdio",
      "command": "docker",
      "args": [
        "run",
        "--rm",
        "-i",
        "-e", "MCP_TRANSPORT=stdio",
        "mcp-memgraph:latest"
      ]
    }
  }
}
```

To connect to a remote Memgraph instance with authentication, add environment
variables to the `args` list:

```json
{
  "servers": {
    "mcp-memgraph": {
      "type": "stdio",
      "command": "docker",
      "args": [
        "run",
        "--rm",
        "-i",
        "-e", "MCP_TRANSPORT=stdio",
        "-e", "MEMGRAPH_URL=bolt://memgraph:7687",
        "-e", "MEMGRAPH_USER=myuser",
        "-e", "MEMGRAPH_PASSWORD=mypassword",
        "mcp-memgraph:latest"
      ]
    }
  }
}
```

Then open GitHub Copilot in Agent mode, and interact with Memgraph using natural
language.

### Multi-tenant authentication (OIDC / JWT)

The MCP server can optionally enforce **OIDC / JWT authentication** on the
streamable-HTTP transport and route each authenticated session to a different
Memgraph logical database based on JWT claims. This is disabled by default —
when off, the server behaves exactly as documented in the sections above.

Enable it when you want to:

- Serve different users different Memgraph databases on the same MCP
  deployment.
- Place MCP behind an OIDC provider (Keycloak, Auth0, Okta, Entra ID, …).
- Capture per-user audit trails on tool calls.
#### Auth-only tools
When `MCP_AUTH_ENABLED=true`, the server exposes two additional tools:

| Tool                   | Description                                                                                                                                            |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `list_databases()`     | Returns the databases the calling user is authorized to access (the intersection of their JWT `tenants` claim and `MCP_TENANT_CATALOG`). Flags the currently-active database. |
| `use_database(name)`   | Switches the active database for the current MCP session. `name` must be in the caller's allowed set — the tool cannot expand authorization beyond what the JWT grants. |
#### Environment variables
All of these are no-ops when `MCP_AUTH_ENABLED=false` (the default). When auth
is enabled, the server **fails fast at startup** if any of the three required
variables are missing.

| Variable                          | Default                                              | Required | Purpose                                                                                                                          |
| --------------------------------- | ---------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `MCP_AUTH_ENABLED`                | `false`                                              | —        | Master switch.                                                                                                                   |
| `MCP_AUTH_ISSUER`                 | —                                                    | ✓        | OIDC issuer URL, e.g. `https://auth.example.com/realms/memgraph`.                                                                |
| `MCP_AUTH_AUDIENCE`               | —                                                    | ✓        | Expected `aud` claim on accepted JWTs.                                                                                            |
| `MCP_TENANT_CATALOG`              | —                                                    | ✓        | Comma-separated tenants this MCP deployment serves. Names must match both JWT `tenants` claim values and Memgraph database names. |
| `MCP_AUTH_JWKS_URL`               | derived: `<issuer>/protocol/openid-connect/certs`    | —        | Override the JWKS endpoint (rarely needed).                                                                                       |
| `MCP_AUTH_TENANTS_CLAIM`          | `tenants`                                            | —        | Claim holding the user's allowed tenant list (must be an array of strings).                                                       |
| `MCP_AUTH_DEFAULT_TENANT_CLAIM`   | `default_tenant`                                     | —        | Optional claim selecting the user's preferred initial tenant; if absent, the server picks the alphabetically-first allowed one.   |
| `MCP_AUTH_REQUIRED_SCOPE`         | `mcp:tools`                                          | —        | Scope the JWT must carry.                                                                                                         |
| `MCP_AUTH_STATIC_CLIENT_ID`       | —                                                    | —        | Opt-in DCR intercept — see [DCR intercept](#dcr-intercept-workaround-for-claude-code) below.                                      |
#### How it works
1. Every request to `/mcp` must carry `Authorization: Bearer <JWT>`.
2. The middleware validates the JWT signature against the IdP's JWKS (cached
   in-process and auto-refreshed when an unknown `kid` arrives).
3. It verifies `iss`, `aud`, `exp`, and the required scope.
4. It reads the `tenants` array claim, intersects it with `MCP_TENANT_CATALOG`,
   and builds a per-session `SessionAuth` keyed by `Mcp-Session-Id`.
5. The session's `current_tenant` defaults to the JWT's `default_tenant` claim
   (when present and allowed), otherwise the first allowed tenant.
6. Each tool call routes to the Memgraph database with the same name as
   `current_tenant`.

Within a session, users can switch among their allowed databases with the
`use_database` tool, and discover them with `list_databases`.
#### Discovery endpoints exposed when auth is enabled
| Path                                            | Purpose                                                                                                  |
| ----------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
| `GET /.well-known/oauth-protected-resource`     | RFC 9728 PRM telling MCP clients which authorization server to use.                                       |
| `GET /.well-known/oauth-authorization-server`   | RFC 8414 AS metadata (proxied from the upstream IdP).                                                     |
| `GET /.well-known/openid-configuration`         | OIDC discovery (proxied from the upstream IdP).                                                           |
| `POST /register`                                | DCR intercept — only present when `MCP_AUTH_STATIC_CLIENT_ID` is set.                                     |

The discovery document fetched from the upstream IdP is cached in-process and
re-fetched on the next request if the cache is empty (e.g., the IdP was down
on the first attempt).
#### DCR intercept (workaround for Claude Code)
Some MCP clients — notably current Claude Code (see
[anthropics/claude-code#26675](https://github.com/anthropics/claude-code/issues/26675))
— force Dynamic Client Registration even when a pre-registered `clientId` is
configured. Setting `MCP_AUTH_STATIC_CLIENT_ID=<your-public-client-id>` makes
the MCP server return the same pre-registered client ID for every DCR request,
sidestepping the bug.

When that variable is set, the PRM document also advertises the MCP server
itself as the `authorization_server` so DCR requests come back to the MCP
server instead of going directly to the IdP. All other OAuth flows
(authorize, token, JWKS) still happen against the real IdP.

> **Info**
>
> Leave `MCP_AUTH_STATIC_CLIENT_ID` unset for production deployments whose
>   clients respect pre-configured `clientId` values.

#### What you need on the IdP side
In any OIDC provider, roughly:

1. A public client with PKCE enabled, with redirect URI patterns matching the
   IDEs you'll use (e.g., `http://localhost:*`, `vscode://*`, `cursor://*`,
   `claude://*`).
2. A `tenants` claim mapper that emits a JSON-array claim of the user's tenant
   memberships (in Keycloak: a Group Membership mapper; in Auth0/Okta: a
   custom rule reading group or role attributes).
3. An audience claim mapper baking your `MCP_AUTH_AUDIENCE` value into issued
   tokens.
4. A scope (default: `mcp:tools`) attached to the client.
5. For each tenant in `MCP_TENANT_CATALOG`, a corresponding Memgraph logical
   database created via `CREATE DATABASE <name>`.

### Run Memgraph MCP server on Kubernetes

A dedicated [`memgraph-mcp` Helm
chart](https://github.com/memgraph/helm-charts/tree/main/charts/memgraph-mcp)
deploys the MCP server on Kubernetes alongside an existing Memgraph backend.
See the [Memgraph MCP Helm
chart](https://memgraph.com/docs/getting-started/install-memgraph/kubernetes#memgraph-mcp-helm-chart)
section for installation steps and configuration options.
### Resources
- [Introducing the Memgraph MCP
  Server](https://memgraph.com/blog/introducing-memgraph-mcp-server): A blog
  post on how to run Memgraph MCP Server and what are the future plans. 

### MCP server in Lab

Memgraph Lab has become an MCP Client and now has built-in support for MCP servers, including the Memgraph MCP Server. This means you can build your agentic applications powered by Memgraph MCP, Toolkit and Lab.

![mcp-lab](https://memgraph.com/docs/pages/ai-ecosystem/integrations/lab-mcp.png)

More details about the MCP connection in Memgraph Lab can be found in the [Memgraph Lab](https://memgraph.com/docs/memgraph-lab/features/graphchat#mcp-servers) documentation.

### MCP server for docs

Memgraph provides a public MCP server for its documentation. Connect it to any
MCP-capable AI assistant to ask questions about Memgraph and get answers
grounded in the current docs, with sources. There is no API key or sign-in
required, just one endpoint.

- **Endpoint:** `https://mcp-docs.memgraph.com`
- **Tool provided:** `search_memgraph_knowledge_sources`

**Claude Code (CLI):**

```bash
claude mcp add --transport http memgraph-docs https://mcp-docs.memgraph.com
```

**Cursor** (`~/.cursor/mcp.json` or project `.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "memgraph-docs": {
      "url": "https://mcp-docs.memgraph.com"
    }
  }
}
```

**VS Code** (`.vscode/mcp.json`):

```json
{
  "servers": {
    "memgraph-docs": {
      "type": "http",
      "url": "https://mcp-docs.memgraph.com"
    }
  }
}
```

**Claude Desktop and other stdio-only clients** (needs Node.js, via the
`mcp-remote` bridge):

```json
{
  "mcpServers": {
    "memgraph-docs": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote@latest",
        "https://mcp-docs.memgraph.com"
      ]
    }
  }
}
```

After adding it, restart your client and ask a Memgraph question — the assistant
pulls the relevant documentation automatically.

> **Info**
>
> The assistant answers from the current docs with links, so you can follow up
>   with "show me the exact config" or "give me the full working example" and it
>   will pull the specifics.

#### Sample prompts to get started
Once connected, ask your assistant these in plain language. It will call the
docs server and answer with sources. Copy one, then adapt it to your own schema
and data.

**Getting started and core querying**

- "How do I install Memgraph with Docker and connect to it from Python?"
- "I'm coming from Neo4j. What Cypher differences should I know about in
  Memgraph, and can I reuse my existing queries?"
- "Show me how to bulk-load a CSV of nodes and relationships efficiently using
  LOAD CSV."
- "How do I define indexes and constraints in Memgraph, and when should I add
  them?"

**Performance and production**

- "Memgraph is in-memory. How do I configure durability with snapshots and WAL
  so I don't lose data on restart?"
- "My traversal query is slow. How do I read a query plan with EXPLAIN and
  PROFILE, and what do I optimize first?"
- "What's the recommended way to run Memgraph in high availability with
  replication?"
- "How much memory will I need for a graph with 50M nodes and 200M
  relationships, and how do I control memory limits?"

**Graph algorithms and analytics (MAGE)**

- "Which MAGE algorithms are available, and how do I run PageRank and community
  detection (Louvain) on my graph?"
- "How do I find the shortest path between two nodes, and how do weighted vs.
  unweighted shortest path differ?"
- "How do I write a custom graph algorithm as a Python query module and call it
  from Cypher?"
- "Set up a dynamic PageRank that updates as new edges stream in, instead of
  recomputing each time."

**GraphRAG and AI**

- "How do I build a GraphRAG pipeline on Memgraph? Walk me through schema,
  ingestion, and retrieval."
- "How do I use vector search in Memgraph to store embeddings and run similarity
  queries alongside graph traversals?"
- "Show me how to combine a vector similarity search with a multi-hop Cypher
  traversal to ground an LLM answer in my knowledge graph."
- "What's the best way to model a knowledge graph for retrieval, and how do I
  keep embeddings in sync as data changes?"

**Art of the possible**

- "Build me a real-time fraud detection pattern: detect when a new transaction
  closes a suspicious cycle between accounts."
- "Model a recommendation engine over users, products, and purchases, and write
  the Cypher to surface 'others also bought' results."
- "I have a supply chain with suppliers, parts, and factories. Show me how to
  trace every downstream product affected by one failed supplier."
- "Design a service dependency graph and query for the blast radius if one
  service goes down."
