grafeo-mcp

mcp
Security Audit
Warn
Health Warn
  • License — License: Apache-2.0
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 5 GitHub stars
Code Pass
  • Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

Exposes Grafeo as a set of MCP tools so that AI agents and assistants can query, traverse and mutate graph data.

README.md
grafeo-mcp: An MCP server that gives agents a Grafeo database: queries, search and graph algorithms.

CI
codecov
PyPI
License

MCP server that exposes GrafeoDB, an embedded graph database, to AI agents via the Model Context Protocol.

One install, zero infrastructure. The MCP server is the database.

grafeo-mcp is one of Grafeo's AI integrations; grafeo.ai is their front page.

Features

  • 25 tools - graph CRUD, GQL queries, time-travel reads, batch import, full-text search, vector search, MMR, hybrid retrieval, PageRank, Dijkstra, Louvain and more
  • 3 resources - graph://schema, graph://stats, graph://nodes/{id}
  • 4 workflow prompts - guide agents through exploration, knowledge extraction, graph analysis and similarity search
  • GQL with Cypher-style syntax - CREATE, MERGE and OPTIONAL MATCH run as written, with query parameters and write counters
  • Schema-first - agents discover the graph structure before querying
  • Token-aware - all tools have limit params and cut large results down to valid JSON
  • Agent-friendly errors - every failure is one Error: <tool>: ... message with a hint, flagged isError over MCP
  • Embedded - no separate database server to manage

Quickstart

# Install
uv tool install grafeo-mcp

# Or run it without installing
uvx grafeo-mcp

grafeo-mcp 0.3 needs Python 3.12 or later and grafeo 0.6, which installs with it. Coming from grafeo-mcp 0.2: your database is migrated to the grafeo 0.6 format on the first start, see Upgrading from grafeo-mcp 0.2.

Claude Desktop

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "grafeo": {
      "command": "grafeo-mcp",
      "env": {
        "GRAFEO_DB_PATH": "/path/to/your/graph.grafeo"
      }
    }
  }
}

Claude Code

Add to .mcp.json in your project root:

{
  "mcpServers": {
    "grafeo": {
      "command": "grafeo-mcp",
      "env": {
        "GRAFEO_DB_PATH": "./graph.grafeo"
      }
    }
  }
}

VS Code / Copilot

Add to .vscode/mcp.json:

{
  "servers": {
    "grafeo": {
      "command": "grafeo-mcp",
      "env": {
        "GRAFEO_DB_PATH": "${workspaceFolder}/graph.grafeo"
      }
    }
  }
}

HTTP transport

For remote or multi-client setups:

grafeo-mcp streamable-http

Environment Variables

Variable Description Default
GRAFEO_DB_PATH Path to the database file (such as graph.grafeo); it is created if nothing exists there In-memory
GRAFEO_READ_ONLY 1, true, yes or on disables every write (mutation tools and writing execute_gql) Off
GRAFEO_HISTORY_RETENTION How far back the database keeps history for query_as_of and get_node_as_of: off, forever or a number of seconds (above 0) The stored setting (off for a new database)

A database file stores its history retention, so the setting stays in effect on later starts without the variable. A read-only server keeps the setting stored in the existing database.

Read-only mode

With GRAFEO_READ_ONLY=1 the mutation tools stay visible but return an error, and execute_gql refuses queries with INSERT, CREATE, MERGE, SET, REMOVE, DELETE, DROP or ALTER and runs the rest in a transaction that is always rolled back. When GRAFEO_DB_PATH names an existing database, the server also opens it with grafeo's read-only mode: the engine itself rejects writes, several read-only servers can share the file, and a grafeo 0.5.x database is read without migrating it.

Storage and upgrading

  • One file per database. With grafeo 0.6 a database is always a single file at GRAFEO_DB_PATH, whatever its name (.grafeo is the convention). While the server runs, the write-ahead log lives next to it in <path>.wal/; a clean shutdown folds it into the file. A path that names an existing directory stops the server with an error, unless the directory is a grafeo 0.5.x database (see below): name a file inside it instead, such as graph.grafeo.
  • One writer at a time. A database can be open for writing by one process. Run one grafeo-mcp server per database, or use read-only mode for extra readers.
  • Backups. Stop the server (or every process that has the database open for writing), then copy the database file. Keep the copy somewhere else than <path>.pre-0.6, which the migration below uses.
  • Pinning. Until grafeo 1.0 a minor release may change the file format or the API, so grafeo-mcp pins the grafeo minor version it is tested with (currently grafeo>=0.6.2,<0.7). A weekly CI job runs the test suite against the newest grafeo in that range.

Upgrading from grafeo-mcp 0.2 (grafeo 0.5)

grafeo-mcp 0.3 runs on grafeo 0.6, which writes a new file format. The first read-write open of a grafeo 0.5.x database migrates it in place:

  1. Stop every process that uses the database: grafeo-mcp 0.2 servers and any script on grafeo 0.5.x.
  2. Back it up (the file, or the whole directory for a WAL-directory database such as graph.db/), and make sure there is free disk space for one more copy of the database.
  3. Upgrade: uv tool upgrade grafeo-mcp (or uvx grafeo-mcp@latest).
  4. Start the server once without GRAFEO_READ_ONLY. It migrates the database and logs a warning naming the copy of the original it keeps:
    • a .grafeo file stays at its path in the new format; the original is kept, unchanged, as graph.grafeo.pre-0.6 (with a WAL that still held changes as graph.grafeo.pre-0.6.wal);
    • a WAL directory (0.5.x made one for a path without the .grafeo extension, such as graph.db) becomes a single file at the same path, and the directory is kept as graph.db.pre-0.6/. grafeo 0.5.x reopened such a database without its vector, text and property indexes; create them again with create_vector_index and create_text_index.
  5. Check the data (graph_info), then delete the .pre-0.6 copy when you no longer need a way back.

After the migration grafeo 0.5.x can no longer open the database; to go back, restore the .pre-0.6 copy and use grafeo-mcp 0.2 (see Upgrading from 0.5). A read-only server reads a 0.5.x database without migrating it. grafeo 0.7 will not read 0.5.x databases, so open each one read-write with grafeo 0.6 before moving on.

What else changed with grafeo 0.6

  • Exact decimals. In GQL a number with a point (1.5, 0.1) is an exact decimal: 0.1 + 0.2 is 0.3, and 1.50 keeps its two digits. Tools return decimals as JSON numbers with their exact digits. Write 1.5e0 or toFloat(x) for a float.
  • Numeric errors. Integer or decimal overflow and division by zero fail the query instead of returning null.
  • Sorting. GQL ORDER BY puts nulls last, ascending and descending (NULLS FIRST changes it).
  • Writes and filters. A WHERE or FILTER right after INSERT, CREATE, MERGE or DELETE is an error: filter before the write, or with WITH ... WHERE after it.
  • Limits. A statement may nest 64 levels deep and a property value 128 levels.
  • Engine messages. Error messages from grafeo start with its error code (GRAFEO-V001: ...) and some are worded differently; tools pass them on unchanged after Error: <tool>:.
  • dijkstra weights. dijkstra reads exact decimal weights; a non-number, NaN, infinite or negative weight is an error.

Tools

Query

Tool Description
execute_gql Run one GQL query, with parameters and write counters

Time travel

Both tools read the committed state at as_of: seconds ago ("300") or an ISO-8601 datetime with its offset ("2026-11-09T10:00:00+00:00"). They need history, so start the server with GRAFEO_HISTORY_RETENTION=forever (or a number of seconds). Both work in read-only mode.

Tool Description
query_as_of Run one read-only GQL query as the database was at as_of
get_node_as_of A node's labels and properties as they were at as_of

Graph CRUD & Traversal

Tool Description
create_node Create a node with labels and properties
create_edge Create a directed edge between two nodes
get_node Retrieve a node by ID
update_node Update properties on an existing node
delete_node Delete a node (with optional detach)
update_edge Update properties on an existing edge
delete_edge Delete an edge by ID
get_neighbors Explore a node's neighborhood (1-hop)
search_nodes_by_label Find nodes by label with pagination
graph_info Schema, stats, indexes and engine features

Batch Import

Tool Description
batch_import Bulk-create nodes and edges from JSON arrays

Full-Text Search

Tool Description
create_text_index Create a full-text search index on a property
search_text Keyword search over indexed string properties

Vector Search

Tool Description
vector_search k-NN similarity search (HNSW)
mmr_search Diversity-aware search (Maximal Marginal Relevance)
create_vector_index Create HNSW index on a label + property
vector_graph_search Hybrid: vector search + graph neighborhood expansion

Graph Algorithms

Tool Description
pagerank Rank nodes by importance
dijkstra Shortest weighted path between two nodes
louvain Community detection (Louvain modularity)
betweenness_centrality Find bridge/bottleneck nodes
connected_components Find disconnected subgraphs

Resources

URI Description
graph://schema Rich schema: labels, properties, edge types
graph://stats Counts, memory, disk, config info
graph://nodes/{node_id} Node details + connection summary

Prompts

Prompt Description
explore_graph Guided exploration of the graph structure
knowledge_extraction Extract entities and relationships from text
graph_analysis Structural analysis: communities, PageRank, hubs
similarity_search Vector-powered semantic search with graph context

Which tool when?

I want to... Use this tool Not this
Add a single node create_node execute_gql, batch_import
Add a single edge create_edge execute_gql
Load many nodes and edges at once batch_import create_node in a loop
Look up a node by ID get_node execute_gql
Create or update a node by a key execute_gql with MERGE and params create_node
Update a node's properties update_node execute_gql
Delete a node delete_node execute_gql
Update an edge's properties update_edge execute_gql
Delete an edge delete_edge execute_gql
Browse nodes of a type search_nodes_by_label execute_gql
Explore one hop from a node get_neighbors execute_gql
Run a complex or multi-hop query execute_gql multiple get_neighbors
See what the graph held earlier query_as_of execute_gql
Read a node as it was earlier get_node_as_of get_node
Search by keyword in text search_text execute_gql
Find similar nodes by embedding vector_search execute_gql
Find similar nodes + graph context vector_graph_search vector_search + get_neighbors
Find the most important nodes pagerank execute_gql
Find shortest path between two nodes dijkstra execute_gql
Detect communities louvain execute_gql
Understand the graph before querying graph_info search_nodes_by_label

Batch reference syntax

The batch_import tool lets edges reference nodes created in the same batch using @N notation, where N is the zero-based index into the nodes array:

batch_import(
    nodes=[
        {"labels": ["Person"], "properties": {"name": "Alice"}},  # @0
        {"labels": ["Person"], "properties": {"name": "Bob"}},  # @1
    ],
    edges=[
        {"source_ref": "@0", "target_ref": "@1", "edge_type": "KNOWS"},
    ],
)

You can also mix batch references with existing node IDs: {"source_ref": "@0", "target_ref": 42, ...}.

A batch is all or nothing: it is checked completely before anything is written (labels, edge types, @N references, and that referenced node IDs exist), and if the engine rejects a node or edge partway (for example a UNIQUE constraint), everything the call created is removed again.

Queries

execute_gql passes the query text to grafeo's GQL engine unchanged. The engine also accepts common Cypher syntax such as CREATE, MERGE, OPTIONAL MATCH and DETACH DELETE, so agents trained on Cypher work out of the box.

  • One statement per call. Text with several statements separated by ; is refused before it runs (a trailing ; is fine). Chain clauses instead (INSERT ... INSERT ..., MATCH ... INSERT ...) or send separate calls.
  • Parameters. Pass values in params and reference them as $name, e.g. query MERGE (p:Person {name: $name}) SET p += $props RETURN id(p) with params={"name": "Ada", "props": {"born": 1815}}. A parameter the query uses but params lacks is reported by name.
  • Write counters. Results of writing queries include counters (nodes, edges, properties and labels created, deleted, set or removed).
  • Embeddings. Store vectors through a parameter (INSERT (:Doc {emb: $emb})) or vector([...]): grafeo stores a plain list literal as a list, which vector indexes skip. create_node, batch_import and update_node store lists of floats as vectors.
  • Numbers. A number with a point is an exact decimal and comes back as a JSON number with its digits (1.50); write 1.5e0 for a float. Overflow and division by zero fail the query, and ORDER BY puts nulls last. See What else changed with grafeo 0.6.

Errors

Every tool returns a string. A failure is a single message of the form Error: <tool>: <what went wrong>. Hint: <what to try next>, with the engine's own message included unchanged; over MCP it is returned with isError: true. Successful results are JSON, except the confirmation sentences of delete_node, delete_edge, create_vector_index and create_text_index.

Output size

Results that would exceed about 8,000 characters are cut down to valid JSON: entries are dropped from the end of the largest lists, long strings end with ... [N chars], and the result gets truncated: true, an omitted map (path to number of entries dropped) and a note. A tool that normally returns a JSON array (vector_search, mmr_search, search_text) then returns {"results": [...], "truncated": true, ...}. Embedding properties longer than 32 values are left out of node summaries. execute_gql, search_nodes_by_label and get_neighbors are bounded by their limit instead.

Development

git clone https://github.com/GrafeoDB/grafeo-mcp
cd grafeo-mcp
uv sync
uv run pytest          # Run tests
uv run ruff check .    # Lint
uv run ruff format .   # Format
uv run ty check        # Type check

tests/test_grafeo_contract.py pins every grafeo behavior the tools rely on, so a grafeo release that changes one fails with a message naming it. To try the newest grafeo release (pre-releases included):

uv sync --upgrade-package grafeo --prerelease allow
uv run --no-sync pytest

See Also

  • grafeo-memory includes a built-in MCP server (grafeo-memory-mcp) that wraps the high-level memory API: extract, reconcile, search, summarize. If you need AI memory management rather than raw graph access, use uv add grafeo-memory[mcp].

License

Apache-2.0

Reviews (0)

No results found