{
  "slug": "io-github-neo4j-contrib-mcp-neo4j-cypher",
  "name": "io.github.neo4j-contrib/mcp-neo4j-cypher",
  "title": "mcp-neo4j-cypher",
  "description": "A simple Neo4j MCP server that allows you to run Cypher queries against a Neo4j database.",
  "version": "1.0.0",
  "publishedAt": "2025-11-07T17:27:58.219859Z",
  "updatedAt": "2025-11-07T17:27:58.219859Z",
  "repoUrl": "https://github.com/neo4j-contrib/mcp-neo4j",
  "websiteUrl": null,
  "namespace": {
    "type": "github",
    "owner": "neo4j-contrib"
  },
  "kind": "local",
  "packages": [
    {
      "registryType": "pypi",
      "identifier": "mcp-neo4j-cypher",
      "version": "0.5.1",
      "transport": "stdio",
      "runtimeHint": null
    }
  ],
  "remotes": [],
  "envVars": [
    {
      "name": "NEO4J_URI",
      "isSecret": false,
      "isRequired": true,
      "description": "Neo4j connection URI"
    },
    {
      "name": "NEO4J_USERNAME",
      "isSecret": false,
      "isRequired": true,
      "description": "Neo4j username"
    },
    {
      "name": "NEO4J_PASSWORD",
      "isSecret": true,
      "isRequired": true,
      "description": "Neo4j password"
    },
    {
      "name": "NEO4J_DATABASE",
      "isSecret": false,
      "isRequired": false,
      "description": "Neo4j database name"
    },
    {
      "name": "NEO4J_NAMESPACE",
      "isSecret": false,
      "isRequired": false,
      "description": "Tool namespace prefix"
    },
    {
      "name": "NEO4J_RESPONSE_TOKEN_LIMIT",
      "isSecret": false,
      "isRequired": false,
      "description": "Maximum tokens for read query responses"
    },
    {
      "name": "NEO4J_READ_TIMEOUT",
      "isSecret": false,
      "isRequired": false,
      "description": "Timeout in seconds for read queries"
    },
    {
      "name": "NEO4J_READ_ONLY",
      "isSecret": false,
      "isRequired": false,
      "description": "Allow only read-only queries (true/false)"
    },
    {
      "name": "NEO4J_SCHEMA_SAMPLE_SIZE",
      "isSecret": false,
      "isRequired": false,
      "description": "Schema sample size"
    }
  ],
  "category": "databases",
  "subcategory": "nosql",
  "company": "neo4j",
  "categoryAuto": true,
  "checks": [
    {
      "id": "source-linked",
      "label": "Source repository linked",
      "result": "pass",
      "detail": "https://github.com/neo4j-contrib/mcp-neo4j"
    },
    {
      "id": "version-pinned",
      "label": "Version pinned",
      "result": "pass",
      "detail": "Every package has an explicit version"
    },
    {
      "id": "secrets-requested",
      "label": "Secrets requested",
      "result": "info",
      "detail": "Asks for 1 secret: NEO4J_PASSWORD"
    },
    {
      "id": "known-registry",
      "label": "Known package registry",
      "result": "pass",
      "detail": "All packages come from npm, PyPI, OCI, NuGet or MCPB"
    },
    {
      "id": "namespace",
      "label": "Namespace ownership",
      "result": "info",
      "detail": "Name verified via GitHub account neo4j-contrib"
    },
    {
      "id": "meta-text",
      "label": "Registry text aimed at the AI",
      "result": "pass",
      "detail": "Description and settings contain no hidden characters or instructions to the AI"
    },
    {
      "id": "install-scripts",
      "label": "Install scripts",
      "result": "pass",
      "detail": "mcp-neo4j-cypher 0.5.1 has no setup.py; nothing runs at install"
    },
    {
      "id": "code-flags",
      "label": "Code red flags",
      "result": "pass",
      "detail": "Read 18 files in mcp-neo4j-cypher 0.5.1: no obfuscation, encoded execution, credential reads or data-collection endpoints found"
    },
    {
      "id": "ai-text",
      "label": "Text aimed at the AI",
      "result": "pass",
      "detail": "No hidden characters or instructions to the AI in 18 files, including comments and the README"
    }
  ],
  "scannedAt": "2026-10-29",
  "level": "Scanned",
  "install": [
    {
      "label": "Claude Desktop (pypi)",
      "kind": "claude_desktop_json",
      "text": "{\n  \"mcpServers\": {\n    \"mcp-neo4j-cypher\": {\n      \"command\": \"uvx\",\n      \"args\": [\n        \"mcp-neo4j-cypher==0.5.1\"\n      ],\n      \"env\": {\n        \"NEO4J_URI\": \"<your value>\",\n        \"NEO4J_USERNAME\": \"<your value>\",\n        \"NEO4J_PASSWORD\": \"<your value>\"\n      }\n    }\n  }\n}"
    }
  ],
  "curated": true,
  "stars": 989,
  "archived": false,
  "pushedAt": "2026-09-09T16:31:34Z",
  "review": {
    "package": "mcp-neo4j-cypher",
    "version": "0.5.1",
    "at": "2026-10-31",
    "files": 3,
    "lines": 821,
    "verdict": "pass-with-notes",
    "summary": "Lets an AI read your Neo4j graph schema and run Cypher queries against the database you configure. It only talks to that database (plus a one-time tokenizer download if you set a token limit) and has no telemetry. Write access is on by default, and the write tool can change or delete anything without asking, so start it with --read-only unless you want the AI to edit your graph.",
    "hosts": [
      {
        "host": "the configured Neo4j server (NEO4J_URL/NEO4J_URI, default bolt://localhost:7687)",
        "when": "on tool calls (driver connects lazily)",
        "sends": "Cypher queries and params, username/password"
      },
      {
        "host": "openaipublic.blob.core.windows.net (tiktoken encoding download)",
        "when": "only if NEO4J_RESPONSE_TOKEN_LIMIT/--token-limit is set, on the first read query, unless the tiktoken cache already has the file (dependency behaviour)",
        "sends": "a download request for the gpt-4 tokenizer file; no user data"
      }
    ],
    "env": [
      {
        "name": "NEO4J_URL / NEO4J_URI, NEO4J_USERNAME, NEO4J_PASSWORD, NEO4J_DATABASE",
        "sent_to": "the configured Neo4j server"
      },
      {
        "name": "NEO4J_NAMESPACE, NEO4J_TRANSPORT, NEO4J_MCP_SERVER_HOST/PORT/PATH, NEO4J_MCP_SERVER_ALLOW_ORIGINS, NEO4J_MCP_SERVER_ALLOWED_HOSTS, NEO4J_RESPONSE_TOKEN_LIMIT, NEO4J_READ_TIMEOUT, NEO4J_READ_ONLY, NEO4J_SCHEMA_SAMPLE_SIZE",
        "sent_to": "not sent; local settings"
      }
    ],
    "local": "None by the package itself (no file reads or writes). tiktoken may cache its tokenizer file locally.",
    "exec": "None. No shell, eval or dynamic imports.",
    "telemetry": "None.",
    "tools": [
      "get_neo4j_schema",
      "read_neo4j_cypher",
      "write_neo4j_cypher (hidden when --read-only / NEO4J_READ_ONLY=true)"
    ],
    "toolText": "clean (short accurate descriptions; no hidden or invisible text)",
    "deps": [
      "fastmcp",
      "mcp",
      "neo4j",
      "pydantic",
      "starlette",
      "tiktoken"
    ],
    "findings": [
      {
        "severity": "note",
        "at": "mcp_neo4j_cypher/utils.py:282-297; server.py:225-269",
        "what": "Read-only mode is off by default, so write_neo4j_cypher is available and runs any write Cypher (including DETACH DELETE of the whole graph) without confirmation. Set --read-only / NEO4J_READ_ONLY=true to remove the tool."
      },
      {
        "severity": "note",
        "at": "mcp_neo4j_cypher/server.py:32-37,194-205",
        "what": "read_neo4j_cypher blocks writes with a keyword regex (MERGE/CREATE/SET/DELETE/...) and also runs the query with RoutingControl.READ, so Neo4j's read access mode is the real enforcement. Read queries can still use LOAD CSV FROM 'http://...' or read-mode APOC procedures, which make the Neo4j server fetch arbitrary URLs."
      },
      {
        "severity": "note",
        "at": "mcp_neo4j_cypher/server.py:218-223,264-269",
        "what": "On error, the full query and its params are logged and echoed back in the tool error. Sensitive parameter values would appear in logs."
      },
      {
        "severity": "info",
        "at": "mcp_neo4j_cypher/server.py:84",
        "what": "sample_size is formatted into the APOC call, but it is a pydantic int, so this is not injectable."
      },
      {
        "severity": "info",
        "at": "mcp_neo4j_cypher/server.py:274-343",
        "what": "HTTP/SSE mode binds 127.0.0.1 by default, has TrustedHost (localhost only) and CORS (no origins) middleware, but no authentication."
      },
      {
        "severity": "info",
        "at": "mcp_neo4j_cypher/utils.py:89-99",
        "what": "Falls back to the password 'password' when none is given (logs a warning)."
      },
      {
        "severity": "info",
        "at": "mcp_neo4j_cypher/__init__.py:45; utils.py:250-251,408",
        "what": "--token-limit is parsed as a string (no type=int), so using it from the CLI would raise a TypeError at truncation. This is a bug, not a security issue. server.py:347 calls async main() without arguments (dead code)."
      },
      {
        "severity": "info",
        "at": "(package)",
        "what": "pyproject.toml was not among the reviewed files; dependencies listed come from imports. Line counts use the manifest convention (newline count + 1 per file, i.e. the empty segment after a final newline is counted); every line of every file was read with the Read tool."
      }
    ]
  },
  "health": {
    "score": 76,
    "parts": {
      "popularity": 0.7290521110720563,
      "activity": 0.5868981754213018,
      "issues": 0.7901234567901234,
      "security": 1
    },
    "fail": 0,
    "warn": 0,
    "raw": {
      "stars": 989,
      "forks": 263,
      "downloads": 10897,
      "hn": {
        "n": 0,
        "pts": 0,
        "t": []
      },
      "issuesOpen": 17,
      "issuesClosed": 64,
      "prsMerged": 175,
      "commits90": 2,
      "release": "2026-04-10T18:53:37Z",
      "pushed": "2026-09-09T16:31:34Z",
      "growth": null,
      "growthDays": null,
      "archived": false
    },
    "at": "2026-10-31T07:42:38.200Z"
  },
  "icon": "/icons/co/neo4j.png"
}
