This is a personal playground for experimenting with MCP (Model Context Protocol) servers and Neo4j.
The ts-mcp-cypher directory contains TypeScript experiments while go-mcp-cypher contains Go experiments.
The ts-mcp-cypher contains all the experiments as it is used to experiment with the MCP protocol and an official SDK,
the other packages may have less features.
Create the root .env file with default Neo4j configuration:
touch .envConfigure your Environment:
NEO4J_URI="bolt://localhost:7687"
NEO4J_USERNAME="neo4j"
NEO4J_PASSWORD="password"
The repository contains multiple language-specific implementation but a root MakeFile to keep consistency when switching between them: Note that the MakeFile is used just as a task-runner; no incremental build is happening.
Run the TS-MCP-SERVER
make run-tsInspect the TS-MCP-SERVER
make inspect-tsClean the TS-MCP-SERVER build
make clean-ts--- GO targets ---
Build the GO-MCP-SERVER
make build-goRun the GO-MCP-SERVER
make run-goInspect the GO-MCP-SERVER
make inspect-goClean the GO-MCP-SERVER build
make clean-goTo start experimenting with it, you can:
make inspect-ts- A shortcut fornpx @modelcontextprotocol/inspector our-stdio-serverFor HTTP transport:
- Create the HTTP server:
make run-ts ARGS="--transport http"- Run the inspector as a separate process:
npx @modelcontextprotocol/inspector
make inspect-tsYou should see a browser tab open with the mcp inspector.
You can do a simple flow such as:
- connect (stdio)
- list tools
- click on read-cypher
- click on Run Tool
The the server logs are visible in the STDERR visible on the bottom-left of the inspector. It is also possible to review the History on the bottom.
Create the server:
make run-ts ARGS="--transport http"Run the inspector separately:
npx @modelcontextprotocol/inspectorIgnore this flow, this flow was used to test behaviour when disabling/enabling/removing tools in a multi-client environment Test it with the inspector could be misleading as it creates different session for tab but also different subprocess And tools seems not to be implicitly session bounded.
To demonstrate dynamic tooling for specific session a tool call enable-admin-cypher is exposed as a tool.
Execute the enable-admin-cypher passing "write" as permission to enable the admin-cypher tool.
You should see the server notifications with the event list_changed listed.
Refresh the tool, and you'll see admin-cypher available for that session, while enable-admin-cypher has been removed.
Add the environment variable READ_ONLY=true before running the server and the tool/list will return only read-cypher
READ_ONLY=true make inspect-tsYou should see the debug log manually handle list/tools
initialize
echo '{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2024-11-05", "capabilities": { "roots": { "listChanged": true }, "sampling": {}, "elicitation": {} }, "clientInfo": { "name": "bash-test", "title": "Bash test", "version": "1.0.0" } } }' | make run-tstool/list
echo '{"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {}}' | make run-tstool/call
echo '{"jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": {"name": "read-cypher", "arguments": {"cypherQuery": "MATCH (n) RETURN n LIMIT 5"}}}' | make run-tstool/call with server notification
echo '{"jsonrpc": "2.0", "id": 4, "method": "tools/call", "params": { "name": "enable-admin-cypher", "arguments": { "permission": "write" }, "_meta": { "progressToken": 0 } } }' | make run-tstool/call on disabled tool
echo '{"jsonrpc": "2.0", "id": 5, "method": "tools/call", "params": { "name": "admin-cypher", "arguments": { "cypherQuery": "CREATE(n:User) SET n.name = \"MPC-USER\"" }, "_meta": { "progressToken": 2 } } }' | make run-tsThe above recreate a new process for each tool calling, to test stateful operation such as the enable-admin-cypher -> admin-cypher flow,
I made a really simple REPL JSON-RPC 2.0 client that takes as input the JSON-RPC message and send it to the MCP Server subprocess.
Just run:
node json-rpc-client.js node ./ts-mcp-cypher/build/index.jsYou will be prompted:
Enter JSON-RPC 2.0 message (or "quit" to exit):Try the flow above, starting from:
{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2024-11-05", "capabilities": { "roots": { "listChanged": true }, "sampling": {}, "elicitation": {} }, "clientInfo": { "name": "bash-test", "title": "Bash test", "version": "1.0.0" } } }
The STDERR is redirected to a file named json-rpc-client-${pid}.debuglog
Note the as only read-cypher/write-cypher are exposed with not detailed description and no schema is returned or no list-database is exposed the behavior it's actually limited
Run the http server:
make run-ts ARGS="--transport http"Add it on VSCode: mcp.json
{
"servers": {
"mcp-cypher-playground": {
"type": "http",
"url": "http://localhost:3000/mcp/"
}
}
}or as stdio:
{
"servers": {
"mcp-playground": {
"type": "stdio",
"command": "node",
"args": [
"{{your-folder}}/MCP-playground/ts-mcp-cypher/build/index.js"
],
"env": {
"NEO4J_PASSWORD": "your-password"
}
}
}
}The NEO4J_TOOLSET environment variable can be defined. This demonstrate how an environment variable can be used to enable specific tools.
Available values:
all(default) - Registers all available tools:read-cypher,write-cypher,admin-cypher, andenable-admin-cypherread-cypher- Only the read-only Cypher query toolwrite-cypher- Only the write Cypher query tooladmin-cypher- Admin Cypher tool plus the enable tool- Comma-separated combinations - e.g.,
read-cypher,write-cypher(not trimmed for demonstration, don't add extra spaces)
Examples:
# Only read operations
NEO4J_TOOLSET=read-cypher make inspect-ts
# Read and write operations only
NEO4J_TOOLSET=read-cypher,write-cypher make inspect-ts
# Admin tools only
NEO4J_TOOLSET=admin-cypher make inspect-ts
# All tools (same as default)
NEO4J_TOOLSET=all make inspect-tsNote: When admin-cypher is included, the enable-admin-cypher tool is automatically registered as well.
- test confirmation as server-initiated elicitation
- convert experiments to mark3labs/mcp-go / official SDKs
- experiment with genai-toolbox