java -jar graph-server.jar --mcp --demo /tmp/demo # loopback:8083, read-only
npx @modelcontextprotocol/inspector # → http://127.0.0.1:8083/mcp/sse
Two transports, HTTP+SSE and WebSocket, both speaking JSON-RPC 2.0 at protocol revision 2025-03-26.
Why it is off by default when nothing else is
Every other port defaults to on. This one does not.
There is no authentication anywhere in this server. For the HTTP and binary ports that means "anyone who can reach it can read everything", which is stated plainly and bounded by where you put it. MCP is different in kind: it is a remote code path an LLM drives, against a database, over a protocol whose whole purpose is to let a model decide what to run. The blast radius of leaving it open is not the same as for a port a person has to point a client at on purpose.
So it is opt-in, and when it is on it binds loopback, and widening it is a second deliberate act.
The tools
| Tool | Writes | What it is for |
|---|---|---|
|
The grammar this build implements, and what it does not |
|
|
Labels, relationship types and property keys, with counts |
|
|
Size and health: is a full scan affordable? |
|
|
The databases under the root |
|
|
Which pairs are a lookup rather than a scan |
|
|
per query |
Run Cypher, return rows |
|
yes |
Declare an index, optionally unique |
|
yes |
Drop one; the data is untouched |
The guide is the one that earns its place
It looks like documentation and it is the highest-value tool here. A model that has seen Neo4j writes
OPTIONAL MATCH within two turns. This engine refuses it at parse time — correctly — and the
model is left with an error it cannot reason its way out of, so it tries a synonym, and then another. One call
replaces that whole loop.
The row cap
An LLM context is not a result set. graph_query stops at 200 rows by default and 1000 at most, enforced through
the engine’s own back-pressure so the scan actually stops rather than being truncated after it has already been paid
for. The response says when it was truncated: a model told it saw everything when it did not will draw a conclusion
from half an answer.
What is not exposed
Creating or dropping a database. Dropping already sits behind its own flag, separate from --allow-write, because
it destroys a whole directory in one request — and handing that to a model is further still.
The write gate is checked twice
One rule, the server’s own --allow-write, and two enforcement points: tools/list omits write tools on a read-only
server, and tools/call re-checks before dispatch. Either alone is a hole — listing without dispatch checking
trusts the client’s memory, dispatch checking without listing wastes the model’s time.
A refusal comes back as a tool result flagged as an error, whose text names the flag and says do not retry, rather than as a JSON-RPC error the model would reasonably retry.
Client configuration
{
"mcpServers": {
"metaloom-graph": {
"url": "http://127.0.0.1:8083/mcp/sse"
}
}
}
There is no token, because there is no authentication. If the port is reachable, so is everything in every database under the root.