cd /news/developer-tools/run-the-neo4j-mcp-server-locally-wit… · home topics developer-tools article
[ARTICLE · art-46172] src=pub.towardsai.net ↗ pub= topic=developer-tools verified=true sentiment=↑ positive

Run the Neo4j MCP Server Locally with Docker (No Codespaces Needed)

Neo4j's MCP server can now be run locally with Docker, bypassing the need for GitHub Codespaces and their free-tier limits. A docker-compose setup launches both Neo4j and the MCP server, enabling developers to test MCP tools like get-schema and read-cypher on their own machines. The guide clarifies that the MCP server is a self-hosted program connecting to any database, not a cloud service.

read6 min views1 publishedJul 1, 2026

Neo4j’s GraphAcademy course “Developing with Neo4j MCP Tools” is excellent, but it assumes you’ll run everything inside a GitHub Codespace. Codespaces have a monthly free limit, and once you hit it you’re stuck — unless you self-host.

Good news: you don’t need Codespaces at all. The MCP server is just a small program, and you can run the whole stack locally with Docker in about half an hour. This guide walks through exactly that, and along the way you’ll pick up how MCP actually fits together.

Everything below has been tested end-to-end.

VS Code (host)  ──HTTP /mcp + auth──►  neo4j-mcp (server)  ──Bolt──►  Neo4j (database)

Three separate pieces — and understanding the split is half the battle:

A common misconception: there is no remote “MCP database” somewhere in the cloud. The MCP server is a program you run. It connects out to whatever database you point it at.

That’s it. No local Python, no Neo4j install — Docker handles both.

Make a project folder and drop in a docker-compose.yml:

services:  neo4j:    image: neo4j:5.26    container_name: neo4j    ports:      - "7474:7474"          # Neo4j Browser  -> http://localhost:7474      - "7687:7687"          # Bolt    environment:      NEO4J_AUTH: "neo4j/password123"      NEO4J_PLUGINS: '["apoc","graph-data-science"]'   # needed for get-schema + GDS tool    volumes:      - neo4j_data:/data    healthcheck:      test: ["CMD-SHELL", "cypher-shell -u neo4j -p password123 'RETURN 1' || exit 1"]      interval: 10s      timeout: 10s      retries: 12      start_period: 30s
neo4j-mcp:    build:      context: "https://github.com/neo4j/mcp.git#v1.5.2"   # builds the official server from source    container_name: neo4j-mcp    depends_on:      neo4j:        condition: service_healthy    ports:      - "8000:8000"          # MCP endpoint -> http://localhost:8000/mcp    environment:      NEO4J_URI: "bolt://neo4j:7687"      NEO4J_DATABASE: "neo4j"      NEO4J_TRANSPORT_MODE: "http"     # networked service, not a stdio subprocess      NEO4J_MCP_HTTP_HOST: "0.0.0.0"   # bind all interfaces so the host can reach it      NEO4J_MCP_HTTP_PORT: "8000"      # must be >1024 (container runs as non-root)
volumes:  neo4j_data:

Two things worth knowing here:

docker compose up -d --build

First run pulls the Neo4j image, builds the Go MCP server, and downloads the APOC + GDS plugins. Give it a minute, then check both containers are up:

docker compose ps

Wait until neo4j shows (healthy).

The MCP endpoint is http://localhost:8000/mcp. Don't open it in a browser — you'll get Method Not Allowed: only POST is supported, which is actually a good sign (the server is up; browsers just send GET).

Test it properly with curl. First, confirm auth is enforced:

curl -i -X POST http://localhost:8000/mcp        # expect 401 Unauthorized

Now list the tools, authenticating with the database credentials (neo4j:password123):

curl -s -u neo4j:password123 -H "Content-Type: application/json" \  -d '{"jsonrpc":"2.0","method":"tools/list","id":1}' \  http://localhost:8000/mcp

You should see: get-schema, read-cypher, write-cypher.

The course lists four tools — the fourth is list-gds-procedures. If it's missing, don't panic. That tool is registered *lazily during the MCP *initialize handshake, and only if Graph Data Science is installed. A bare tools/list curl skips initialize, so it never appears that way.

Send an initialize request first, then list again:

curl -s -u neo4j:password123 -H "Content-Type: application/json" \  -d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"t","version":"1"}},"id":1}' \  http://localhost:8000/mcp
curl -s -u neo4j:password123 -H "Content-Type: application/json" \  -d '{"jsonrpc":"2.0","method":"tools/list","id":2}' \  http://localhost:8000/mcp

Now all four appear. (Real MCP clients like VS Code do the initialize step automatically — this only bites you with raw curl.)

In your project, create .vscode/mcp.json:

{    "servers": {        "neo4j": {            "type": "http",            "url": "http://localhost:8000/mcp",            "headers": {                "Authorization": "Basic bmVvNGo6cGFzc3dvcmQxMjM="            }        }    }}

That Authorization value is just base64 of neo4j:password123. If you change the password, regenerate it:

printf 'neo4j:yourpassword' | base64

⚠️Most common mistake:using the course’sstdioconfig ("type": "stdio", "command": "neo4j-mcp") with this Docker setup. That tells VS Code to launch a local binary you don't have. For the containerized server you must use thehttpconfig above.

Then in VS Code: Cmd/Ctrl + Shift + P → MCP: List Servers → select neo4jStart Server. Open Chat in Agent mode (Cmd/Ctrl + Shift + I) and ask:

Which MCP tools are available? List their ID and description.

You’ll get all four tools back.

Your local database is empty, so let’s point a second, throwaway MCP container at Neo4j’s public movies demo database — the same dataset the course uses — on a different port. This leaves your main stack untouched:

docker run --rm -d --name mcp-movies \  -e NEO4J_URI="neo4j+s://demo.neo4jlabs.com" \  -e NEO4J_DATABASE="recommendations" \  -e NEO4J_TRANSPORT_MODE="http" \  -e NEO4J_MCP_HTTP_HOST="0.0.0.0" \  -e NEO4J_MCP_HTTP_PORT="8001" \  -p 8001:8001 \  <your-project-name>-neo4j-mcp

(The image name is whatever docker compose built — check docker images; it looks like yourfolder-neo4j-mcp.)

Read the schema — what relationships does a User have?

curl -s -u recommendations:recommendations -H "Content-Type: application/json" \  -d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"read-cypher","arguments":{"query":"MATCH (u:User)-[r]->() RETURN DISTINCT type(r) AS rel"}},"id":2}' \  http://localhost:8001/mcp

Result: RATED — i.e. (:User)-[:RATED]->(:Movie).

Generate a query — the highest-rated movie (note the non-null guard, since not every movie has a rating):

curl -s -u recommendations:recommendations -H "Content-Type: application/json" \  -d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"read-cypher","arguments":{"query":"MATCH (m:Movie) WHERE m.imdbRating IS NOT NULL RETURN m.title AS title, m.imdbRating AS rating ORDER BY m.imdbRating DESC LIMIT 1"}},"id":3}' \  http://localhost:8001/mcp

When you’re done with the demo:

docker stop mcp-movies

The course’s capstone is “vibe coding” a Python CLI that returns the top 5 movies in a genre. Here’s a clean, dependency-light version. The genre is passed as a query parameter (never string-concatenated) and the query filters out null ratings:

import os, sysfrom neo4j import GraphDatabase
php
QUERY = """MATCH (m:Movie)-[:IN_GENRE]->(:Genre {name: $genre})WHERE m.imdbRating IS NOT NULLRETURN m.title AS title, m.imdbRating AS ratingORDER BY m.imdbRating DESCLIMIT 5"""
python
def main():    uri = os.environ["NEO4J_URI"]    user = os.environ["NEO4J_USERNAME"]    pwd = os.environ["NEO4J_PASSWORD"]    db = os.environ.get("NEO4J_DATABASE", "neo4j")
genre = input("Enter a movie genre: ").strip()    with GraphDatabase.driver(uri, auth=(user, pwd)) as driver:        driver.verify_connectivity()        records, _, _ = driver.execute_query(QUERY, genre=genre, database_=db)
print(f"\nTop {len(records)} '{genre}' movies:")    for i, r in enumerate(records, 1):        print(f"  {i}. {r['title']} ({r['rating']})")
if __name__ == "__main__":    main()

Run it against the demo database:

pip install neo4jexport NEO4J_URI="neo4j+s://demo.neo4jlabs.com"export NEO4J_USERNAME="recommendations"export NEO4J_PASSWORD="recommendations"export NEO4J_DATABASE="recommendations"python3 movie_recommender.py      # then type: Mystery

In about 30 minutes you’ve stood up the full Neo4j MCP stack locally — no Codespaces, no cloud bill:

It’s tempting to see this as just “avoiding a paywall,” but the self-hosted setup teaches something more useful. MCP is quietly becoming the standard way AI agents reach real systems — databases, APIs, internal tools — and the interesting engineering questions live exactly where we ended up: How is the server transported? How are requests authenticated? What stops an agent from running a destructive query?

Running the server yourself over HTTP, with per-request auth and a read-only switch, surfaces those questions in a way a pre-baked cloud sandbox hides. As more teams put agents in front of production data, the ability to run an MCP server as a controlled, observable service — rather than a mystery box someone else hosts — stops being a nice-to-have. The 30 minutes you spent here map directly onto how you’d deploy the same server behind a gateway with TLS and a secrets manager for real.

SymptomCause / FixMethod Not Allowed in browserYou sent a GET. The endpoint is POST-only — use curl or a client.401 UnauthorizedMissing/wrong Basic Auth. Use the DB username:password.Only 3 tools listedSend an initialize request first; ensure APOC + GDS are installed.get-schema errorsAPOC not installed — add it to NEO4J_PLUGINS.MCP server won't start, complains about username/passwordYou set NEO4J_USERNAME/PASSWORD in HTTP mode. Remove them.VS Code says server "requires interaction to start"Your mcp.json is using the stdio config. Switch to the http config.Permission denied binding portKeep NEO4J_MCP_HTTP_PORT above 1024 (container is non-root).

Happy graphing.

Run the Neo4j MCP Server Locally with Docker (No Codespaces Needed) was originally published in Towards AI on Medium, where people are continuing the conversation by highlighting and responding to this story.

── more in #developer-tools 4 stories · sorted by recency
── more on @neo4j 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/run-the-neo4j-mcp-se…] indexed:0 read:6min 2026-07-01 ·