# Installation ## Requirements - **Python** 3.11 or later. On Python 3.10, `pip install` installs 0.2.0 of each server instead, without an error, and these pages do not describe it. - [`uv`](https://docs.astral.sh/uv/) (recommended), whose `uvx` runs a server straight from PyPI without installing it - For the Cypher and memory servers, a running **AgensGraph 2.17 or later**. The driver refuses an older server at connect; `SHOW agversion` tells you which you have. The data-modeling server needs no database. - A database role that is **not a superuser** and not a member of `pg_execute_server_program` (see [Database role](#database-role)) The servers are built on `fastmcp` 3.x and `pydantic`, and talk to AgensGraph through the [`agensgraph-python`](https://pypi.org/project/agensgraph-python/) 2.0 driver, which runs on psycopg 3. The Cypher and memory servers also pull in `psycopg[binary,pool]`. ## Install The servers are released on PyPI as four distributions, all at `0.3.1`: | Distribution | Command it installs | Needs a database | | ------------ | ------------------- | ---------------- | | `mcp-agensgraph-cypher` | `mcp-agensgraph-cypher` | Yes | | `mcp-agensgraph-memory` | `mcp-agensgraph-memory` | Yes | | `mcp-agensgraph-data-modeling` | `mcp-agensgraph-data-modeling` | No | | `mcp-agensgraph-common` | *(none; the shared core, installed automatically)* | — | **Run with `uvx`.** An MCP client normally launches a server itself, and `uvx` fetches and runs it in a throwaway environment, so nothing needs installing first: ```bash uvx mcp-agensgraph-cypher uvx mcp-agensgraph-memory uvx mcp-agensgraph-data-modeling ``` **Install into an environment** when you host a server yourself, for example over HTTP. Install one server by name, or all three through the `agensgraph-ai` umbrella package: ```bash pip install mcp-agensgraph-cypher pip install "agensgraph-ai[mcp]" # the cypher, memory and data-modeling servers ``` Each server distribution puts its command on your `PATH`. The `[mcp]` extra installs the three servers and nothing else; there is no Python module to import from it. ### Exact token counting (optional) A Cypher read response is bounded by a token budget. Without a tokenizer the server estimates a response's size from its bytes. The `tokens` extra of the shared core installs `tiktoken` so the count is exact: ```bash pip install "mcp-agensgraph-common[tokens]" uvx --with "mcp-agensgraph-common[tokens]" mcp-agensgraph-cypher ``` It is an extra because loading a tokenizer fetches the model's encoding file over the network the first time. ### From source To work on the servers themselves, clone the repository and set up a server with `uv` (this also installs the common core it depends on): ```bash git clone https://github.com/skaiworldwide-oss/agensgraph-ai.git cd agensgraph-ai/mcp-agensgraph/servers/mcp-agensgraph-cypher uv sync uv run mcp-agensgraph-cypher --transport stdio ``` ## Database role **A server refuses to start as a role that can run a command on the database host**, that is, a superuser or a member of `pg_execute_server_program`. `COPY ... TO PROGRAM` is not stopped by a read-only transaction, so connected as such a role the read-only tools would not be a boundary. Starting one anyway fails with: ```text RuntimeError: This role can run a command on the server's host, through COPY ... TO PROGRAM, which a read-only transaction does not stop -- so the read tools would not be a boundary. Connect as a role that is neither a superuser nor a member of pg_execute_server_program, or pass --allow-server-programs to accept it. ``` Create an ordinary role for the servers instead. At startup the Cypher server (unless it is read-only) and the memory server create their graph if it is missing, which needs the `CREATE` privilege on the database. They do this before the role check, so a refused start as a superuser can leave that graph behind. ```sql CREATE ROLE mcp LOGIN PASSWORD 'mcp'; -- choose your own password GRANT CREATE ON DATABASE mydb TO mcp; ``` A graph the role creates is its own, so it can read and write it with no further grants. To point a **read-only** Cypher server at a graph another role owns, grant read access to that graph's schema, which has the graph's name: ```sql CREATE ROLE mcp_ro LOGIN PASSWORD 'mcp_ro'; GRANT USAGE ON SCHEMA mygraph TO mcp_ro; GRANT SELECT ON ALL TABLES IN SCHEMA mygraph TO mcp_ro; ``` `GRANT SELECT ON ALL TABLES` covers only the labels that exist when it runs. For labels created later, have the graph's owner also run: ```sql ALTER DEFAULT PRIVILEGES IN SCHEMA mygraph GRANT SELECT ON TABLES TO mcp_ro; ``` If `CONNECT` on the database has been revoked from `PUBLIC`, grant it to the role as well. Label names are case-sensitive to the servers; see [Usage](usage.md#cypher-server) for labels created unquoted. Passing `--allow-server-programs` (or `AGENSGRAPH_ALLOW_SERVER_PROGRAMS=true`) lets a server start as a privileged role anyway. It logs a warning, and the read-only tools are then not a boundary. ## Connection configuration The Cypher and memory servers read their AgensGraph connection from environment variables or the matching CLI flags. A flag wins over its variable. The canonical names, with the legacy aliases still accepted, are: | Variable | Legacy alias | CLI flag | Default | Meaning | | -------- | ------------ | -------- | ------- | ------- | | `AGENSGRAPH_URL` | `AGENSGRAPH_URI` | `--db-url` | `postgresql://localhost:5432` | Connection URL | | `AGENSGRAPH_USERNAME` | — | `--username` | `agens` | Database user | | `AGENSGRAPH_PASSWORD` | — | `--password` | *(unset)* | Database password | | `AGENSGRAPH_DATABASE` | `AGENSGRAPH_DB` | `--database` | `agens` | Database name | | `AGENSGRAPH_GRAPHNAME` | `AGENSGRAPH_GRAPH_NAME` | `--graphname` | `agens` (cypher), `memory` (memory) | Graph name | The URL is a libpq connection URL, so settings it carries, such as `?sslmode=require`, reach the connection. The user, password and database are layered on top of it. Because the user and database default to `agens`, a user or database written in the URL is replaced by those defaults: set `AGENSGRAPH_USERNAME` and `AGENSGRAPH_DATABASE` (or the flags) explicitly. A password in the URL is kept when `AGENSGRAPH_PASSWORD` is unset. The password has no default. Left unset, nothing is sent, and libpq resolves it the way it resolves everything else: `PGPASSWORD`, `.pgpass`, `PGSERVICE`, or an authentication method that needs no password. Prefer the environment variable or `.pgpass` to `--password`, since a password on the command line is visible to every process on the machine through `ps`. ## Transports and server knobs All three servers share these: | Variable | CLI flag | Default | Meaning | | -------- | -------- | ------- | ------- | | `AGENSGRAPH_TRANSPORT` | `--transport` | `stdio` | `stdio`, `http` (Streamable HTTP), or `sse` (deprecated) | | `AGENSGRAPH_NAMESPACE` | `--namespace` | *(none)* | Prefix added to every tool name (`graph1` gives `graph1-`) | | `AGENSGRAPH_MCP_SERVER_HOST` | `--server-host` | `127.0.0.1` | HTTP/SSE bind host | | `AGENSGRAPH_MCP_SERVER_PORT` | `--server-port` | `8000` | HTTP/SSE port | | `AGENSGRAPH_MCP_SERVER_PATH` | `--server-path` | `/mcp/` | HTTP/SSE path | | `AGENSGRAPH_MCP_SERVER_ALLOW_ORIGINS` | `--allow-origins` | *(none)* | Comma-separated CORS origins | | `AGENSGRAPH_MCP_SERVER_ALLOWED_HOSTS` | `--allowed-hosts` | `localhost,127.0.0.1` | Allowed hosts (DNS-rebinding protection) | The host, port and path apply only to `http` and `sse`. ```{warning} The HTTP and SSE transports have **no authentication**. Anything that can reach the port can call every tool the server exposes, with its database credentials. Keep the loopback default, and put something that authenticates in front of a server you expose. `stdio`, which is what Claude Desktop uses, is not reachable by another process. ``` ## Safety flags | CLI flag | Variable | Default | Server | Effect | | -------- | -------- | ------- | ------ | ------ | | `--read-only` | `AGENSGRAPH_READ_ONLY` | `false` | cypher | No write tool | | `--allow-graph-ddl` | `AGENSGRAPH_ALLOW_GRAPH_DDL` | `false` | cypher | Graph DDL through the write tool | | `--allow-server-programs` | `AGENSGRAPH_ALLOW_SERVER_PROGRAMS` | `false` | cypher, memory | Accepts a privileged role | | `--adopt-existing-graph` | `AGENSGRAPH_ADOPT_EXISTING_GRAPH` | `false` | memory | Serves a graph it did not make | What each flag does when set: - `--read-only`: the server does not register the write tool, and does not create the graph at startup. - `--allow-graph-ddl`: the write tool may change a graph's shape: create or drop graphs, labels, indexes and constraints. - `--allow-server-programs`: the server starts even as a superuser or a member of `pg_execute_server_program`. - `--adopt-existing-graph`: the server serves a graph that already holds a `Memory` label this server did not make. A boolean variable takes `true` or `false`. Whatever the flags, the Cypher tools take one graph statement at a time. A second statement after a semicolon, SQL behind `EXPLAIN`, and SQL that begins with a word Cypher also uses (such as `CREATE TABLE` or `INSERT INTO`) are refused. `--adopt-existing-graph` exists because the memory server, at startup, merges entities that share a name and moves relationships onto its own labels. It stops rather than do that to a graph it did not make. Once adopted, the graph is marked as the server's own, and later starts do not ask again. ## Cypher server read controls | Variable | CLI flag | Default | Meaning | | -------- | -------- | ------- | ------- | | `AGENSGRAPH_READ_TIMEOUT` | `--read-timeout` | `30` | Statement timeout in seconds | | `AGENSGRAPH_RESPONSE_TOKEN_LIMIT` | `--token-limit` | `10000` | Token budget for a read response | | `AGENSGRAPH_PAGE_SIZE` | — | `100` | Default rows per read page | | `AGENSGRAPH_MAX_PAGE_SIZE` | — | `1000` | Ceiling on page size (larger requests are clamped) | | `AGENSGRAPH_SCHEMA_SAMPLE` | — | `1000` | Nodes sampled per label when inferring property types | | `AGENSGRAPH_POOL_MIN_SIZE` | — | `4` | Connections the pool holds (Cypher server only) | | `AGENSGRAPH_POOL_MAX_SIZE` | — | `16` | Connections the pool may open (Cypher server only) | - `AGENSGRAPH_READ_TIMEOUT`: the timeout applies to every statement on the connection, writes included. It also sets `lock_timeout` and `idle_in_transaction_session_timeout`. It must be more than 0; a non-numeric variable falls back to 30 with a warning (the flag rejects it). - `AGENSGRAPH_RESPONSE_TOKEN_LIMIT`: whole rows are dropped to fit the budget. `0` turns it off. The **memory server** adds `AGENSGRAPH_MEMORY_LIMIT` (default `1000`, at most `1000`), the default `limit` of `read_graph` and `search_memories` (entities returned) and of `find_memories_by_name` (names looked up). Its statement timeout is fixed at 30 seconds, and its pool at 4 to 16 connections; it does not read `AGENSGRAPH_POOL_*`. ## Use with Claude Desktop Claude Desktop is MCP's native client. Add the servers to its `claude_desktop_config.json` (on macOS, `~/Library/Application Support/Claude/claude_desktop_config.json`; use the equivalent config directory on Linux/Windows). Each entry launches the released package with `uvx`: ```json { "mcpServers": { "agensgraph-cypher": { "command": "uvx", "args": ["mcp-agensgraph-cypher", "--transport", "stdio"], "env": { "AGENSGRAPH_URL": "postgresql://localhost:5432", "AGENSGRAPH_USERNAME": "", "AGENSGRAPH_PASSWORD": "", "AGENSGRAPH_DATABASE": "", "AGENSGRAPH_GRAPHNAME": "" } }, "agensgraph-memory": { "command": "uvx", "args": ["mcp-agensgraph-memory", "--transport", "stdio"], "env": { "AGENSGRAPH_URL": "postgresql://localhost:5432", "AGENSGRAPH_USERNAME": "", "AGENSGRAPH_PASSWORD": "", "AGENSGRAPH_DATABASE": "", "AGENSGRAPH_GRAPHNAME": "memory" } }, "agensgraph-data-modeling": { "command": "uvx", "args": ["mcp-agensgraph-data-modeling", "--transport", "stdio"] } } } ``` The user must be a role like the one in [Database role](#database-role). Claude Desktop needs to find `uvx`; if it does not, give its full path as `command`. Add `--read-only`, `--allow-graph-ddl` and the other flags to `args` as needed. Restart Claude Desktop and the three servers' tools will appear. To run several Cypher servers against different graphs, give each one a distinct `AGENSGRAPH_NAMESPACE` (or `--namespace`) so their tool names don't collide: ```json { "mcpServers": { "graph1-agensgraph": { "command": "uvx", "args": ["mcp-agensgraph-cypher", "--namespace", "graph1"], "env": { "AGENSGRAPH_URL": "postgresql://localhost:5432", "AGENSGRAPH_USERNAME": "", "AGENSGRAPH_PASSWORD": "", "AGENSGRAPH_DATABASE": "", "AGENSGRAPH_GRAPHNAME": "graph1" } }, "graph2-agensgraph": { "command": "uvx", "args": ["mcp-agensgraph-cypher", "--namespace", "graph2"], "env": { "AGENSGRAPH_URL": "postgresql://localhost:5432", "AGENSGRAPH_USERNAME": "", "AGENSGRAPH_PASSWORD": "", "AGENSGRAPH_DATABASE": "", "AGENSGRAPH_GRAPHNAME": "graph2" } } } } ``` The first server's tools are then `graph1-read_agensgraph_cypher` and so on. To validate a server without Claude, use the MCP Inspector. Pass the connection with `-e`, or the server connects with the defaults (`agens`, a superuser on a packaged install) and refuses to start: ```bash npx @modelcontextprotocol/inspector \ -e AGENSGRAPH_USERNAME=mcp -e AGENSGRAPH_PASSWORD= \ -e AGENSGRAPH_DATABASE=mydb -e AGENSGRAPH_GRAPHNAME=mygraph \ -- uvx mcp-agensgraph-cypher --transport stdio ``` See [Usage](usage.md) for the tools each server exposes.