grafeo-mcp
Health Uyari
- License — License: Apache-2.0
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 5 GitHub stars
Code Gecti
- Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Gecti
- Permissions — No dangerous permissions requested
Bu listing icin henuz AI raporu yok.
Exposes Grafeo as a set of MCP tools so that AI agents and assistants can query, traverse and mutate graph data.
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,MERGEandOPTIONAL MATCHrun as written, with query parameters and write counters - Schema-first - agents discover the graph structure before querying
- Token-aware - all tools have
limitparams and cut large results down to valid JSON - Agent-friendly errors - every failure is one
Error: <tool>: ...message with a hint, flaggedisErrorover 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 (.grafeois 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 asgraph.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:
- Stop every process that uses the database: grafeo-mcp 0.2 servers and any script on grafeo 0.5.x.
- 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. - Upgrade:
uv tool upgrade grafeo-mcp(oruvx grafeo-mcp@latest). - 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
.grafeofile stays at its path in the new format; the original is kept, unchanged, asgraph.grafeo.pre-0.6(with a WAL that still held changes asgraph.grafeo.pre-0.6.wal); - a WAL directory (0.5.x made one for a path without the
.grafeoextension, such asgraph.db) becomes a single file at the same path, and the directory is kept asgraph.db.pre-0.6/. grafeo 0.5.x reopened such a database without its vector, text and property indexes; create them again withcreate_vector_indexandcreate_text_index.
- a
- Check the data (
graph_info), then delete the.pre-0.6copy 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.2is0.3, and1.50keeps its two digits. Tools return decimals as JSON numbers with their exact digits. Write1.5e0ortoFloat(x)for a float. - Numeric errors. Integer or decimal overflow and division by zero fail the query instead of returning null.
- Sorting. GQL
ORDER BYputs nulls last, ascending and descending (NULLS FIRSTchanges it). - Writes and filters. A
WHEREorFILTERright afterINSERT,CREATE,MERGEorDELETEis an error: filter before the write, or withWITH ... WHEREafter 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 afterError: <tool>:. dijkstraweights.dijkstrareads 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
paramsand reference them as$name, e.g. queryMERGE (p:Person {name: $name}) SET p += $props RETURN id(p)withparams={"name": "Ada", "props": {"born": 1815}}. A parameter the query uses butparamslacks 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})) orvector([...]): grafeo stores a plain list literal as a list, which vector indexes skip.create_node,batch_importandupdate_nodestore 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); write1.5e0for a float. Overflow and division by zero fail the query, andORDER BYputs 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, useuv add grafeo-memory[mcp].
License
Apache-2.0
Yorumlar (0)
Yorum birakmak icin giris yap.
Yorum birakSonuc bulunamadi