#
tokens: 16660/50000 52/52 files
lines: off (toggle) GitHub
raw markdown copy
# Directory Structure

```
├── .editorconfig
├── .github
│   └── workflows
│       └── publish.yml
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .verdaccio
│   └── config.yml
├── .vscode
│   └── extensions.json
├── DEVELOP.md
├── eslint.config.js
├── jest.config.ts
├── jest.preset.js
├── libs
│   └── graphrag-memory
│       ├── eslint.config.js
│       ├── jest.config.ts
│       ├── package.json
│       ├── project.json
│       ├── README.md
│       ├── src
│       │   ├── index.ts
│       │   └── lib
│       │       ├── graphrag-memory.spec.ts
│       │       └── graphrag-memory.ts
│       ├── tsconfig.json
│       ├── tsconfig.lib.json
│       └── tsconfig.spec.json
├── nx.json
├── package-lock.json
├── package.json
├── project.json
├── README.md
├── servers
│   ├── mcp-json-memory
│   │   ├── eslint.config.cjs
│   │   ├── jest.config.ts
│   │   ├── package.json
│   │   ├── project.json
│   │   ├── src
│   │   │   ├── assets
│   │   │   │   └── .gitkeep
│   │   │   ├── json-memory.ts
│   │   │   └── main.ts
│   │   ├── tsconfig.app.json
│   │   ├── tsconfig.json
│   │   └── tsconfig.spec.json
│   ├── mcp-neo4j-cypher
│   │   ├── .flake8
│   │   ├── .python-version
│   │   ├── pyproject.toml
│   │   ├── README.md
│   │   ├── src
│   │   │   └── mcp_neo4j_cypher
│   │   │       ├── __init__.py
│   │   │       ├── __pycache__
│   │   │       │   ├── __init__.cpython-312.pyc
│   │   │       │   └── server.cpython-312.pyc
│   │   │       └── server.py
│   │   └── uv.lock
│   └── mcp-neo4j-memory
│       ├── eslint.config.js
│       ├── jest.config.ts
│       ├── project.json
│       ├── src
│       │   ├── assets
│       │   │   └── .gitkeep
│       │   ├── main.ts
│       │   └── neo4j-memory.ts
│       ├── tsconfig.app.json
│       ├── tsconfig.json
│       └── tsconfig.spec.json
└── tsconfig.base.json
```

# Files

--------------------------------------------------------------------------------
/servers/mcp-json-memory/src/assets/.gitkeep:
--------------------------------------------------------------------------------

```

```

--------------------------------------------------------------------------------
/servers/mcp-neo4j-memory/src/assets/.gitkeep:
--------------------------------------------------------------------------------

```

```

--------------------------------------------------------------------------------
/servers/mcp-neo4j-cypher/.python-version:
--------------------------------------------------------------------------------

```
3.12.7

```

--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------

```
{
  "singleQuote": true
}

```

--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------

```
# Add files here to ignore them from prettier formatting
/dist
/coverage
/.nx/cache
/.nx/workspace-data
```

--------------------------------------------------------------------------------
/servers/mcp-neo4j-cypher/.flake8:
--------------------------------------------------------------------------------

```
[flake8]
exclude =
	.git,
	__pycache__,
	build,
	dist,
	.tox,
	venv,
	.venv,
	.pytest_cache
max-line-length = 120

```

--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------

```
# Editor configuration, see http://editorconfig.org
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
max_line_length = off
trim_trailing_whitespace = false

```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
# See http://help.github.com/ignore-files/ for more about ignoring files.

# compiled output
dist
tmp
/out-tsc

# dependencies
node_modules

# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace

# python venc
.venv

# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json

# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings

# System Files
.DS_Store
Thumbs.db

.nx/cache
.nx/workspace-data

```

--------------------------------------------------------------------------------
/libs/graphrag-memory/README.md:
--------------------------------------------------------------------------------

```markdown
# graphrag-memory

This library was generated with [Nx](https://nx.dev).

## Building

Run `nx build graphrag-memory` to build the library.

## Running unit tests

Run `nx test graphrag-memory` to execute the unit tests via [Jest](https://jestjs.io).

```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
# Neo4j MCP Clients & Servers

Model Context Protocol (MCP) is a [standardized protocol](https://modelcontextprotocol.io/introduction) for managing context between large language models (LLMs) and external systems. 

This lets you use Claude Desktop, or any MCP Client, to use natural language to accomplish things with Neo4j and your Aura account, e.g.:

* `What is in this graph?`

## Servers

### `mcp-neo4j-cypher` - natural language to Cypher queries

### `mcp-neo4j-memory` - knowledge graph memory stored in Neo4j

### `mcp-json-memory` - knowledge graph memory stored in a file

A reference server for modeling memory as a knowledge graph.

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

```

--------------------------------------------------------------------------------
/servers/mcp-neo4j-cypher/README.md:
--------------------------------------------------------------------------------

```markdown
# Neo4j MCP Server

## Overview
A Model Context Protocol (MCP) server implementation that provides database interaction and allows graph exploration capabilities through neo4j. This server enables running Cypher graph queries, analyzing complex domain data, and automatically generating business insights that can be enhanced with Claude's analysis when an Anthropic API key is provided.

## Components

### Resources

### Prompts
The server provides a demonstration prompt:
- `mcp-demo`: Interactive prompt that guides users through database operations
  - Generates appropriate database schemas and sample data

### Tools
The server offers six core tools:

#### Query Tools
- `read-neo4j-cypher`
   - Execute Cypher read queries to read data from the database
   - Input: 
     - `query` (string): The Cypher query to execute
   - Returns: Query results as array of objects

- `write-neo4j-cypher`
   - Execute updating Cypher queries
   - Input:
     - `query` (string): The Cypher update query
   - Returns: a result summary counter with `{ nodes_updated: number, relationships_created: number, ... }`

#### Schema Tools
- `get-neo4j-schema`
   - Get a list of all nodes types in the graph database, their attributes with name, type and relationships to other node types
   - No input required
   - Returns: List of node label with two dictionaries one for attributes and one for relationships

## Usage with Claude Desktop

### Released Package

Can be found on PyPi https://pypi.org/project/mcp-neo4j-cypher/

Add the server to your `claude_desktop_config.json` with configuration of 

* db-url
* username
* password

```json
"mcpServers": {
  "neo4j": {
    "command": "uvx",
    "args": [
      "mcp-neo4j-cypher",
      "--db-url",
      "bolt://localhost",
      "--username",
      "neo4j",
      "--password",
      "<your-password>"
    ]
  }
}
```

Here is an example connection for the movie database with Movie, Person (Actor, Director), Genre, User and ratings.

```json
{
  "mcpServers": {
    "movies-neo4j": {
      "command": "uvx",
      "args": ["mcp-neo4j-cypher", 
      "--db-url", "neo4j+s://demo.neo4jlabs.com", 
      "--user", "recommendations", 
      "--password", "recommendations"]
    }   
  }
}
```

### Development

```json
# Add the server to your claude_desktop_config.json
"mcpServers": {
  "neo4j": {
    "command": "uv",
    "args": [
      "--directory",
      "parent_of_servers_repo/servers/src/neo4j",
      "run",
      "mcp-neo4j-cypher",
      "--db-url",
      "bolt://localhost",
      "--username",
      "neo4j",
      "--password",
      "<your-password>"
    ]
  }
}
```

## License

This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository.

```

--------------------------------------------------------------------------------
/servers/mcp-json-memory/package.json:
--------------------------------------------------------------------------------

```json
{
  "type":"module"
}
```

--------------------------------------------------------------------------------
/libs/graphrag-memory/src/index.ts:
--------------------------------------------------------------------------------

```typescript
export * from './lib/graphrag-memory';

```

--------------------------------------------------------------------------------
/jest.preset.js:
--------------------------------------------------------------------------------

```javascript
const nxPreset = require('@nx/jest/preset').default;

module.exports = { ...nxPreset };

```

--------------------------------------------------------------------------------
/servers/mcp-json-memory/eslint.config.cjs:
--------------------------------------------------------------------------------

```
const baseConfig = require('../../eslint.config.js');

module.exports = [...baseConfig];

```

--------------------------------------------------------------------------------
/servers/mcp-neo4j-memory/eslint.config.js:
--------------------------------------------------------------------------------

```javascript
const baseConfig = require('../../eslint.config.js');

module.exports = [...baseConfig];

```

--------------------------------------------------------------------------------
/jest.config.ts:
--------------------------------------------------------------------------------

```typescript
import { getJestProjectsAsync } from '@nx/jest';

export default async () => ({
  projects: await getJestProjectsAsync(),
});

```

--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------

```json
{
  "recommendations": [
    "nrwl.angular-console",
    "esbenp.prettier-vscode",
    "dbaeumer.vscode-eslint",
    "firsttris.vscode-jest-runner"
  ]
}

```

--------------------------------------------------------------------------------
/libs/graphrag-memory/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "@neo4j/graphrag-memory",
  "version": "0.0.1",
  "dependencies": {},
  "type": "commonjs",
  "main": "./index.cjs",
  "typings": "./index.d.ts"
}

```

--------------------------------------------------------------------------------
/libs/graphrag-memory/src/lib/graphrag-memory.spec.ts:
--------------------------------------------------------------------------------

```typescript
import {  } from './graphrag-memory';

describe('graphragMemory does not yet have functionality', () => {
  it('should be able to run tests', () => {
    expect(true).toEqual(true);
  });
});

```

--------------------------------------------------------------------------------
/libs/graphrag-memory/tsconfig.lib.json:
--------------------------------------------------------------------------------

```json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "../../dist/out-tsc",
    "declaration": true,
    "types": ["node"]
  },
  "include": ["src/**/*.ts"],
  "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
}

```

--------------------------------------------------------------------------------
/servers/mcp-json-memory/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "extends": "../../tsconfig.base.json",
  "files": [],
  "include": [],
  "references": [
    {
      "path": "./tsconfig.app.json"
    },
    {
      "path": "./tsconfig.spec.json"
    }
  ],
  "compilerOptions": {
    "esModuleInterop": true
  }
}

```

--------------------------------------------------------------------------------
/servers/mcp-neo4j-memory/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "extends": "../../tsconfig.base.json",
  "files": [],
  "include": [],
  "references": [
    {
      "path": "./tsconfig.app.json"
    },
    {
      "path": "./tsconfig.spec.json"
    }
  ],
  "compilerOptions": {
    "esModuleInterop": true
  }
}

```

--------------------------------------------------------------------------------
/libs/graphrag-memory/tsconfig.spec.json:
--------------------------------------------------------------------------------

```json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "../../dist/out-tsc",
    "module": "commonjs",
    "types": ["jest", "node"]
  },
  "include": [
    "jest.config.ts",
    "src/**/*.test.ts",
    "src/**/*.spec.ts",
    "src/**/*.d.ts"
  ]
}

```

--------------------------------------------------------------------------------
/servers/mcp-json-memory/tsconfig.spec.json:
--------------------------------------------------------------------------------

```json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "../../dist/out-tsc",
    "module": "commonjs",
    "types": ["jest", "node"]
  },
  "include": [
    "jest.config.ts",
    "src/**/*.test.ts",
    "src/**/*.spec.ts",
    "src/**/*.d.ts"
  ]
}

```

--------------------------------------------------------------------------------
/servers/mcp-neo4j-memory/tsconfig.spec.json:
--------------------------------------------------------------------------------

```json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "../../dist/out-tsc",
    "module": "commonjs",
    "types": ["jest", "node"]
  },
  "include": [
    "jest.config.ts",
    "src/**/*.test.ts",
    "src/**/*.spec.ts",
    "src/**/*.d.ts"
  ]
}

```

--------------------------------------------------------------------------------
/servers/mcp-json-memory/tsconfig.app.json:
--------------------------------------------------------------------------------

```json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "target": "es2022",
    "outDir": "../../dist/out-tsc",
    "module": "ES2022",
    "types": ["node"]
  },
  "include": ["src/**/*.ts"],
  "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
}

```

--------------------------------------------------------------------------------
/servers/mcp-neo4j-memory/tsconfig.app.json:
--------------------------------------------------------------------------------

```json
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "target": "es2022",
    "outDir": "../../dist/out-tsc",
    "module": "ES2022",
    "types": ["node"]
  },
  "include": ["src/**/*.ts"],
  "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
}

```

--------------------------------------------------------------------------------
/libs/graphrag-memory/jest.config.ts:
--------------------------------------------------------------------------------

```typescript
export default {
  displayName: 'graphrag-memory',
  preset: '../../jest.preset.js',
  testEnvironment: 'node',
  transform: {
    '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
  },
  moduleFileExtensions: ['ts', 'js', 'html'],
  coverageDirectory: '../../coverage/libs/graphrag-memory',
};

```

--------------------------------------------------------------------------------
/project.json:
--------------------------------------------------------------------------------

```json
{
  "name": "@mcp-neo4j/source",
  "$schema": "node_modules/nx/schemas/project-schema.json",
  "targets": {
    "local-registry": {
      "executor": "@nx/js:verdaccio",
      "options": {
        "port": 4873,
        "config": ".verdaccio/config.yml",
        "storage": "tmp/local-registry/storage"
      }
    }
  }
}

```

--------------------------------------------------------------------------------
/servers/mcp-json-memory/jest.config.ts:
--------------------------------------------------------------------------------

```typescript
export default {
  displayName: 'mcp-json-memory',
  preset: '../../jest.preset.js',
  testEnvironment: 'node',
  transform: {
    '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
  },
  moduleFileExtensions: ['ts', 'js', 'html'],
  coverageDirectory: '../../coverage/servers/mcp-json-memory',
};

```

--------------------------------------------------------------------------------
/servers/mcp-neo4j-memory/jest.config.ts:
--------------------------------------------------------------------------------

```typescript
export default {
  displayName: 'mcp-neo4j-memory',
  preset: '../../jest.preset.js',
  testEnvironment: 'node',
  transform: {
    '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
  },
  moduleFileExtensions: ['ts', 'js', 'html'],
  coverageDirectory: '../../coverage/servers/mcp-neo4j-memory',
};

```

--------------------------------------------------------------------------------
/servers/mcp-neo4j-cypher/pyproject.toml:
--------------------------------------------------------------------------------

```toml
[project]
name = "mcp-neo4j-cypher"
version = "0.1.1"
description = "A simple Neo4j MCP server"
readme = "README.md"
requires-python = ">=3.10"
dependencies = ["mcp>=0.9.1", "neo4j>=5.26.0"]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.uv]
dev-dependencies = ["pyright>=1.1.389"]

[project.scripts]
mcp-neo4j-cypher = "mcp_neo4j_cypher:main"

```

--------------------------------------------------------------------------------
/libs/graphrag-memory/eslint.config.js:
--------------------------------------------------------------------------------

```javascript
const baseConfig = require('../../eslint.config.js');

module.exports = [
  ...baseConfig,
  {
    files: ['**/*.json'],
    rules: {
      '@nx/dependency-checks': [
        'error',
        {
          ignoredFiles: [
            '{projectRoot}/eslint.config.{js,cjs,mjs}',
            '{projectRoot}/esbuild.config.{js,ts,mjs,mts}',
          ],
        },
      ],
    },
    languageOptions: {
      parser: require('jsonc-eslint-parser'),
    },
  },
];

```

--------------------------------------------------------------------------------
/libs/graphrag-memory/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "module": "commonjs",
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "noImplicitOverride": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noPropertyAccessFromIndexSignature": true
  },
  "files": [],
  "include": [],
  "references": [
    {
      "path": "./tsconfig.lib.json"
    },
    {
      "path": "./tsconfig.spec.json"
    }
  ]
}

```

--------------------------------------------------------------------------------
/tsconfig.base.json:
--------------------------------------------------------------------------------

```json
{
  "compileOnSave": false,
  "compilerOptions": {
    "rootDir": ".",
    "sourceMap": true,
    "declaration": false,
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "importHelpers": true,
    "target": "es2015",
    "module": "esnext",
    "lib": ["es2020", "dom"],
    "skipLibCheck": true,
    "skipDefaultLibCheck": true,
    "baseUrl": ".",
    "paths": {
      "@neo4j/graphrag-memory": ["libs/graphrag-memory/src/index.ts"]
    }
  },
  "exclude": ["node_modules", "tmp"]
}

```

--------------------------------------------------------------------------------
/.verdaccio/config.yml:
--------------------------------------------------------------------------------

```yaml
# path to a directory with all packages
storage: ../tmp/local-registry/storage

# a list of other known repositories we can talk to
uplinks:
  npmjs:
    url: https://registry.npmjs.org/
    maxage: 60m

packages:
  '**':
    # give all users (including non-authenticated users) full access
    # because it is a local registry
    access: $all
    publish: $all
    unpublish: $all

    # if package is not available locally, proxy requests to npm registry
    proxy: npmjs

# log settings
log:
  type: stdout
  format: pretty
  level: warn

publish:
  allow_offline: true # set offline to true to allow publish offline

```

--------------------------------------------------------------------------------
/eslint.config.js:
--------------------------------------------------------------------------------

```javascript
const nx = require('@nx/eslint-plugin');

module.exports = [
  ...nx.configs['flat/base'],
  ...nx.configs['flat/typescript'],
  ...nx.configs['flat/javascript'],
  {
    ignores: ['**/dist'],
  },
  {
    files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
    rules: {
      '@nx/enforce-module-boundaries': [
        'error',
        {
          enforceBuildableLibDependency: true,
          allow: ['^.*/eslint(\\.base)?\\.config\\.[cm]?js$'],
          depConstraints: [
            {
              sourceTag: '*',
              onlyDependOnLibsWithTags: ['*'],
            },
          ],
        },
      ],
    },
  },
  {
    files: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
    // Override or add rules here
    rules: {},
  },
];

```

--------------------------------------------------------------------------------
/servers/mcp-neo4j-cypher/src/mcp_neo4j_cypher/__init__.py:
--------------------------------------------------------------------------------

```python
from . import server
import asyncio
import argparse
import os


def main():
    """Main entry point for the package."""
    parser = argparse.ArgumentParser(description='Neo4j Cypher MCP Server')
    parser.add_argument('--db-url', 
                       default="bolt://localhost:7687",
                       help='Neo4j connection URL')
    parser.add_argument('--username', 
                       default="neo4j",
                       help='Neo4j username')
    parser.add_argument('--password', 
                       default="password",
                       help='Neo4j password')
    
    args = parser.parse_args()
    asyncio.run(server.main(args.db_url, args.username, args.password))


# Optionally expose other important items at package level
__all__ = ["main", "server"]

```

--------------------------------------------------------------------------------
/libs/graphrag-memory/project.json:
--------------------------------------------------------------------------------

```json
{
  "name": "graphrag-memory",
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "sourceRoot": "libs/graphrag-memory/src",
  "projectType": "library",
  "release": {
    "version": {
      "generatorOptions": {
        "packageRoot": "dist/{projectRoot}",
        "currentVersionResolver": "git-tag"
      }
    }
  },
  "tags": [],
  "targets": {
    "build": {
      "executor": "@nx/esbuild:esbuild",
      "outputs": ["{options.outputPath}"],
      "options": {
        "outputPath": "dist/libs/graphrag-memory",
        "main": "libs/graphrag-memory/src/index.ts",
        "tsConfig": "libs/graphrag-memory/tsconfig.lib.json",
        "format": ["cjs"],
        "assets": ["libs/graphrag-memory/*.md"],
        "generatePackageJson": true
      }
    },
    "nx-release-publish": {
      "options": {
        "packageRoot": "dist/{projectRoot}"
      }
    }
  }
}

```

--------------------------------------------------------------------------------
/libs/graphrag-memory/src/lib/graphrag-memory.ts:
--------------------------------------------------------------------------------

```typescript


export interface Entity {
  name: string;
  entityType: string;
  observations: string[];
}

export interface Relation {
  from: string;
  to: string;
  relationType: string;
}

export interface KnowledgeGraph {
  entities: Entity[];
  relations: Relation[];
}

// The KnowledgeGraphMemory interface contains all operations to interact with the knowledge graph
export interface KnowledgeGraphMemory {

  createEntities(entities: Entity[]): Promise<Entity[]>;

  createRelations(relations: Relation[]): Promise<Relation[]>;

  addObservations(observations: { entityName: string; contents: string[] }[]): Promise<{ entityName: string; addedObservations: string[] }[]>;
  
  deleteEntities(entityNames: string[]): Promise<void>;

  deleteObservations(deletions: { entityName: string; observations: string[] }[]): Promise<void>;

  deleteRelations(relations: Relation[]): Promise<void>;

  readGraph(): Promise<KnowledgeGraph>;

  // Very basic search function
  searchNodes(query: string): Promise<KnowledgeGraph>;

  openNodes(names: string[]): Promise<KnowledgeGraph>;

}


```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "@mcp-neo4j/source",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": {},
  "private": true,
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.0.1",
    "axios": "^1.6.0",
    "neo4j-driver": "^5.27.0"
  },
  "devDependencies": {
    "@eslint/js": "^9.8.0",
    "@nx/esbuild": "20.1.4",
    "@nx/eslint": "20.1.4",
    "@nx/eslint-plugin": "20.1.4",
    "@nx/jest": "20.1.4",
    "@nx/js": "20.1.4",
    "@nx/node": "20.1.4",
    "@nx/workspace": "20.1.4",
    "@nxlv/python": "^20.0.1",
    "@swc-node/register": "~1.9.1",
    "@swc/core": "~1.5.7",
    "@swc/helpers": "~0.5.11",
    "@types/jest": "^29.5.12",
    "@types/node": "~18.16.9",
    "esbuild": "^0.19.2",
    "eslint": "^9.8.0",
    "eslint-config-prettier": "^9.0.0",
    "jest": "^29.7.0",
    "jest-environment-node": "^29.7.0",
    "nx": "20.1.4",
    "prettier": "^2.6.2",
    "ts-jest": "^29.1.0",
    "ts-node": "10.9.1",
    "tslib": "^2.3.0",
    "typescript": "~5.5.2",
    "typescript-eslint": "^8.0.0",
    "verdaccio": "^5.0.4"
  },
  "nx": {
    "includedScripts": []
  }
}

```

--------------------------------------------------------------------------------
/nx.json:
--------------------------------------------------------------------------------

```json
{
  "$schema": "./node_modules/nx/schemas/nx-schema.json",
  "namedInputs": {
    "default": ["{projectRoot}/**/*", "sharedGlobals"],
    "production": [
      "default",
      "!{projectRoot}/.eslintrc.json",
      "!{projectRoot}/eslint.config.js",
      "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)",
      "!{projectRoot}/tsconfig.spec.json",
      "!{projectRoot}/jest.config.[jt]s",
      "!{projectRoot}/src/test-setup.[jt]s",
      "!{projectRoot}/test-setup.[jt]s"
    ],
    "sharedGlobals": ["{workspaceRoot}/.github/workflows/ci.yml"]
  },
  "nxCloudId": "6750280b426ab2447467d096",
  "targetDefaults": {
    "@nx/esbuild:esbuild": {
      "cache": true,
      "dependsOn": ["^build"],
      "inputs": ["production", "^production"]
    }
  },
  "plugins": [
    {
      "plugin": "@nx/eslint/plugin",
      "options": {
        "targetName": "lint"
      }
    },
    {
      "plugin": "@nx/jest/plugin",
      "options": {
        "targetName": "test"
      },
      "exclude": [
        "apps/mcp-neo4j-e2e/**/*",
        "mcp-neo4j-memory-e2e/**/*",
        "servers/mcp-neo4j-memory-e2e/**/*",
        "servers/mcp-json-memory-e2e/**/*"
      ]
    },
    {
      "plugin":"@nxlv/python"
    }
  ],
  "release": {
    "version": {
      "preVersionCommand": "npx nx run-many -t build"
    }
  }
}

```

--------------------------------------------------------------------------------
/servers/mcp-json-memory/project.json:
--------------------------------------------------------------------------------

```json
{
  "name": "mcp-json-memory",
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "sourceRoot": "servers/mcp-json-memory/src",
  "projectType": "application",
  "tags": [],
  "targets": {
    "build": {
      "executor": "@nx/esbuild:esbuild",
      "outputs": ["{options.outputPath}"],
      "defaultConfiguration": "production",
      "options": {
        "platform": "node",
        "outputPath": "dist/servers/mcp-json-memory",
        "format": ["esm"],
        "bundle": false,
        "main": "servers/mcp-json-memory/src/main.ts",
        "tsConfig": "servers/mcp-json-memory/tsconfig.app.json",
        "assets": ["servers/mcp-json-memory/src/assets"],
        "generatePackageJson": true,
        "esbuildOptions": {
          "sourcemap": true,
          "outExtension": {
            ".js": ".js"
          }
        }
      },
      "configurations": {
        "development": {},
        "production": {
          "esbuildOptions": {
            "sourcemap": false,
            "outExtension": {
              ".js": ".js"
            }
          }
        }
      }
    },
    "serve": {
      "executor": "@nx/js:node",
      "defaultConfiguration": "development",
      "dependsOn": ["build"],
      "options": {
        "buildTarget": "mcp-json-memory:build",
        "runBuildTargetDependencies": false
      },
      "configurations": {
        "development": {
          "buildTarget": "mcp-json-memory:build:development"
        },
        "production": {
          "buildTarget": "mcp-json-memory:build:production"
        }
      }
    }
  }
}

```

--------------------------------------------------------------------------------
/servers/mcp-neo4j-memory/project.json:
--------------------------------------------------------------------------------

```json
{
  "name": "mcp-neo4j-memory",
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "sourceRoot": "servers/mcp-neo4j-memory/src",
  "projectType": "application",
  "tags": [],
  "targets": {
    "build": {
      "executor": "@nx/esbuild:esbuild",
      "outputs": ["{options.outputPath}"],
      "defaultConfiguration": "production",
      "options": {
        "platform": "node",
        "outputPath": "dist/servers/mcp-neo4j-memory",
        "format": ["esm"],
        "bundle": false,
        "main": "servers/mcp-neo4j-memory/src/main.ts",
        "tsConfig": "servers/mcp-neo4j-memory/tsconfig.app.json",
        "assets": ["servers/mcp-neo4j-memory/src/assets"],
        "generatePackageJson": true,
        "esbuildOptions": {
          "sourcemap": true,
          "outExtension": {
            ".js": ".js"
          }
        }
      },
      "configurations": {
        "development": {},
        "production": {
          "esbuildOptions": {
            "sourcemap": false,
            "outExtension": {
              ".js": ".js"
            }
          }
        }
      }
    },
    "serve": {
      "executor": "@nx/js:node",
      "defaultConfiguration": "development",
      "dependsOn": ["build"],
      "options": {
        "buildTarget": "mcp-neo4j-memory:build",
        "runBuildTargetDependencies": false
      },
      "configurations": {
        "development": {
          "buildTarget": "mcp-neo4j-memory:build:development"
        },
        "production": {
          "buildTarget": "mcp-neo4j-memory:build:production"
        }
      }
    }
  }
}

```

--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------

```yaml
# This workflow will upload a Python Package to PyPI when a release is created
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python#publishing-to-package-registries

# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

name: Publish Python Package

on:
  release:
    types: [published]

permissions:
  contents: read

jobs:
  release-build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-python@v5
        with:
          python-version: "3.x"

      - name: Build release distributions
        run: |
          cd servers/mcp-neo4j-cypher/
          python -m pip install build
          python -m build

      - name: Upload distributions
        uses: actions/upload-artifact@v4
        with:
          name: release-dists
          path: servers/mcp-neo4j-cypher/dist/

  pypi-publish:
    runs-on: ubuntu-latest
    needs:
      - release-build
    permissions:
      # IMPORTANT: this permission is mandatory for trusted publishing
      id-token: write

    # Dedicated environments with protections for publishing are strongly recommended.
    # For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules
    environment:
      name: pypi
      url: https://pypi.org/project/mcp-neo4j-cypher/

    steps:
      - name: Retrieve release distributions
        uses: actions/download-artifact@v4
        with:
          name: release-dists
          path: servers/mcp-neo4j-cypher/dist/

      - name: Publish release distributions to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          packages-dir: servers/mcp-neo4j-cypher/dist/
```

--------------------------------------------------------------------------------
/DEVELOP.md:
--------------------------------------------------------------------------------

```markdown
# McpNeo4j

<a alt="Nx logo" href="https://nx.dev" target="_blank" rel="noreferrer"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-logo.png" width="45"></a>

✨ Your new, shiny [Nx workspace](https://nx.dev) is almost ready ✨.

[Learn more about this workspace setup and its capabilities](https://nx.dev/nx-api/node?utm_source=nx_project&amp;utm_medium=readme&amp;utm_campaign=nx_projects) or run `npx nx graph` to visually explore what was created. Now, let's get you up to speed!

Include python support via [@nxlv/python plugin](https://github.com/lucasvieirasilva/nx-plugins/tree/main/packages/nx-python)

## Finish your CI setup

[Click here to finish setting up your workspace!](https://cloud.nx.app/connect/Wx1erwy80w)


## Run tasks

To run the dev server for your app, use:

```sh
npx nx serve mcp-neo4j
```

To create a production bundle:

```sh
npx nx build mcp-neo4j
```

To see all available targets to run for a project, run:

```sh
npx nx show project mcp-neo4j
```

These targets are either [inferred automatically](https://nx.dev/concepts/inferred-tasks?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects) or defined in the `project.json` or `package.json` files.

[More about running tasks in the docs &raquo;](https://nx.dev/features/run-tasks?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects)

## Add new projects

While you could add new projects to your workspace manually, you might want to leverage [Nx plugins](https://nx.dev/concepts/nx-plugins?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects) and their [code generation](https://nx.dev/features/generate-code?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects) feature.

Use the plugin's generator to create new projects.

To generate a new application, use:

```sh
npx nx g @nx/node:app demo
```

To generate a new library, use:

```sh
npx nx g @nx/node:lib mylib
```

You can use `npx nx list` to get a list of installed plugins. Then, run `npx nx list <plugin-name>` to learn about more specific capabilities of a particular plugin. Alternatively, [install Nx Console](https://nx.dev/getting-started/editor-setup?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects) to browse plugins and generators in your IDE.

[Learn more about Nx plugins &raquo;](https://nx.dev/concepts/nx-plugins?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects) | [Browse the plugin registry &raquo;](https://nx.dev/plugin-registry?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects)


[Learn more about Nx on CI](https://nx.dev/ci/intro/ci-with-nx#ready-get-started-with-your-provider?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects)

## Install Nx Console

Nx Console is an editor extension that enriches your developer experience. It lets you run tasks, generate code, and improves code autocompletion in your IDE. It is available for VSCode and IntelliJ.

[Install Nx Console &raquo;](https://nx.dev/getting-started/editor-setup?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects)

## Useful links

Learn more:

- [Learn more about this workspace setup](https://nx.dev/nx-api/node?utm_source=nx_project&amp;utm_medium=readme&amp;utm_campaign=nx_projects)
- [Learn about Nx on CI](https://nx.dev/ci/intro/ci-with-nx?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects)
- [Releasing Packages with Nx release](https://nx.dev/features/manage-releases?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects)
- [What are Nx plugins?](https://nx.dev/concepts/nx-plugins?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects)

And join the Nx community:
- [Discord](https://go.nx.dev/community)
- [Follow us on X](https://twitter.com/nxdevtools) or [LinkedIn](https://www.linkedin.com/company/nrwl)
- [Our Youtube channel](https://www.youtube.com/@nxdevtools)
- [Our blog](https://nx.dev/blog?utm_source=nx_project&utm_medium=readme&utm_campaign=nx_projects)

```

--------------------------------------------------------------------------------
/servers/mcp-neo4j-cypher/src/mcp_neo4j_cypher/server.py:
--------------------------------------------------------------------------------

```python
import neo4j
import logging
from logging.handlers import RotatingFileHandler
from contextlib import closing
from pathlib import Path
from mcp.server.models import InitializationOptions
import mcp.types as types
from mcp.server import NotificationOptions, Server
import mcp.server.stdio
from pydantic import AnyUrl
from typing import Any
from neo4j import GraphDatabase
import re

logger = logging.getLogger('mcp_neo4j_cypher')
logger.info("Starting MCP neo4j Server")

def is_write_query(query: str) -> bool:
    return re.search(r"\b(MERGE|CREATE|SET|DELETE|REMOVE|ADD)\b", query, re.IGNORECASE) is not None

class neo4jDatabase:
    def __init__(self,  neo4j_uri: str, neo4j_username: str, neo4j_password: str):
        """Initialize connection to the neo4j database"""
        logger.debug(f"Initializing database connection to {neo4j_uri}")
        d = GraphDatabase.driver(neo4j_uri, auth=(neo4j_username, neo4j_password))
        d.verify_connectivity()
        self.driver = d

    def _execute_query(self, query: str, params: dict[str, Any] | None = None) -> list[dict[str, Any]]:
        """Execute a Cypher query and return results as a list of dictionaries"""
        logger.debug(f"Executing query: {query}")
        try:
            result = self.driver.execute_query(query, params)
            counters = vars(result.summary.counters)
            if is_write_query(query):
                logger.debug(f"Write query affected {counters}")
                return [counters]
            else:
                results = [dict(r) for r in result.records]
                logger.debug(f"Read query returned {len(results)} rows")
                return results
        except Exception as e:
            logger.error(f"Database error executing query: {e}\n{query}")
            raise

async def main(neo4j_url: str, neo4j_username: str, neo4j_password: str):
    logger.info(f"Connecting to neo4j MCP Server with DB URL: {neo4j_url}")

    db = neo4jDatabase(neo4j_url, neo4j_username, neo4j_password)
    server = Server("neo4j-manager")

    # Register handlers
    logger.debug("Registering handlers")

    @server.list_tools()
    async def handle_list_tools() -> list[types.Tool]:
        """List available tools"""
        return [
            types.Tool(
                name="read-neo4j-cypher",
                description="Execute a Cypher query on the neo4j database",
                inputSchema={
                    "type": "object",
                    "properties": {
                        "query": {"type": "string", "description": "Cypher read query to execute"},
                    },
                    "required": ["query"],
                },
            ),
            types.Tool(
                name="write-neo4j-cypher",
                description="Execute a write Cypher query on the neo4j database",
                inputSchema={
                    "type": "object",
                    "properties": {
                        "query": {"type": "string", "description": "Cypher write query to execute"},
                    },
                    "required": ["query"],
                },
            ),
            types.Tool(
                name="get-neo4j-schema",
                description="List all node types, their attributes and their relationships TO other node-types in the neo4j database",
                inputSchema={
                    "type": "object",
                    "properties": {},
                },
            )
        ]

    @server.call_tool()
    async def handle_call_tool(
        name: str, arguments: dict[str, Any] | None
    ) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
        """Handle tool execution requests"""
        try:
            if name == "get-neo4j-schema":
                results = db._execute_query(
                    """
call apoc.meta.data() yield label, property, type, other, unique, index, elementType
where elementType = 'node' and not label starts with '_'
with label, 
    collect(case when type <> 'RELATIONSHIP' then [property, type + case when unique then " unique" else "" end + case when index then " indexed" else "" end] end) as attributes,
    collect(case when type = 'RELATIONSHIP' then [property, head(other)] end) as relationships
RETURN label, apoc.map.fromPairs(attributes) as attributes, apoc.map.fromPairs(relationships) as relationships
                    """
                )
                return [types.TextContent(type="text", text=str(results))]

            elif name == "read-neo4j-cypher":
                if is_write_query(arguments["query"]):
                    raise ValueError("Only MATCH queries are allowed for read-query")
                results = db._execute_query(arguments["query"])
                return [types.TextContent(type="text", text=str(results))]

            elif name == "write-neo4j-cypher":
                if not is_write_query(arguments["query"]):
                    raise ValueError("Only write queries are allowed for write-query")
                results = db._execute_query(arguments["query"])
                return [types.TextContent(type="text", text=str(results))]
            
            else:
                raise ValueError(f"Unknown tool: {name}")

        except Exception as e:
            return [types.TextContent(type="text", text=f"Error: {str(e)}")]

    async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
        logger.info("Server running with stdio transport")
        await server.run(
            read_stream,
            write_stream,
            InitializationOptions(
                server_name="neo4j",
                server_version="0.1.0",
                capabilities=server.get_capabilities(
                    notification_options=NotificationOptions(),
                    experimental_capabilities={},
                ),
            ),
        )

```

--------------------------------------------------------------------------------
/servers/mcp-json-memory/src/json-memory.ts:
--------------------------------------------------------------------------------

```typescript

import path from 'path';
import { fileURLToPath } from 'url';
import { promises as fs } from 'fs';
import { KnowledgeGraphMemory, Entity, KnowledgeGraph, Relation } from "@neo4j/graphrag-memory";

// Default path to the JSONL file, you can change this to your desired local path 
// by passing in an arg to the memory-server
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const DEFAULT_MEMORY_FILE_PATH = path.join(__dirname, 'memory.json');

// The JsonMemory class contains all operations to interact with the knowledge graph
export class JsonMemory implements KnowledgeGraphMemory {
  private memoryFilePath: string;
  constructor(args: string[]) {
    this.memoryFilePath = (args.length > 0) ? args[0] : DEFAULT_MEMORY_FILE_PATH;
  }

  private async loadGraph(): Promise<KnowledgeGraph> {
    try {
      const data = await fs.readFile(this.memoryFilePath, "utf-8");
      const lines = data.split("\n").filter(line => line.trim() !== "");
      return lines.reduce((graph: KnowledgeGraph, line) => {
        const item = JSON.parse(line);
        if (item.type === "entity") graph.entities.push(item as Entity);
        if (item.type === "relation") graph.relations.push(item as Relation);
        return graph;
      }, { entities: [], relations: [] });
    } catch (error) {
      if (error instanceof Error && 'code' in error && (error as any).code === "ENOENT") {
        console.error(`Error! (${error})`);
        return { entities: [], relations: [] };
      }
      throw error;
    }
  }

  private async saveGraph(graph: KnowledgeGraph): Promise<void> {
    const lines = [
      ...graph.entities.map(e => JSON.stringify({ type: "entity", ...e })),
      ...graph.relations.map(r => JSON.stringify({ type: "relation", ...r })),
    ];
    await fs.writeFile(this.memoryFilePath, lines.join("\n"));
  }

  async createEntities(entities: Entity[]): Promise<Entity[]> {
    const graph = await this.loadGraph();
    const newEntities = entities.filter(e => !graph.entities.some(existingEntity => existingEntity.name === e.name));
    graph.entities.push(...newEntities);
    await this.saveGraph(graph);
    return newEntities;
  }

  async createRelations(relations: Relation[]): Promise<Relation[]> {
    const graph = await this.loadGraph();
    const newRelations = relations.filter(r => !graph.relations.some(existingRelation => 
      existingRelation.from === r.from && 
      existingRelation.to === r.to && 
      existingRelation.relationType === r.relationType
    ));
    graph.relations.push(...newRelations);
    await this.saveGraph(graph);
    return newRelations;
  }

  async addObservations(observations: { entityName: string; contents: string[] }[]): Promise<{ entityName: string; addedObservations: string[] }[]> {
    const graph = await this.loadGraph();
    const results = observations.map(o => {
      const entity = graph.entities.find(e => e.name === o.entityName);
      if (!entity) {
        throw new Error(`Entity with name ${o.entityName} not found`);
      }
      const newObservations = o.contents.filter(content => !entity.observations.includes(content));
      entity.observations.push(...newObservations);
      return { entityName: o.entityName, addedObservations: newObservations };
    });
    await this.saveGraph(graph);
    return results;
  }

  async deleteEntities(entityNames: string[]): Promise<void> {
    const graph = await this.loadGraph();
    graph.entities = graph.entities.filter(e => !entityNames.includes(e.name));
    graph.relations = graph.relations.filter(r => !entityNames.includes(r.from) && !entityNames.includes(r.to));
    await this.saveGraph(graph);
  }

  async deleteObservations(deletions: { entityName: string; observations: string[] }[]): Promise<void> {
    const graph = await this.loadGraph();
    deletions.forEach(d => {
      const entity = graph.entities.find(e => e.name === d.entityName);
      if (entity) {
        entity.observations = entity.observations.filter(o => !d.observations.includes(o));
      }
    });
    await this.saveGraph(graph);
  }

  async deleteRelations(relations: Relation[]): Promise<void> {
    const graph = await this.loadGraph();
    graph.relations = graph.relations.filter(r => !relations.some(delRelation => 
      r.from === delRelation.from && 
      r.to === delRelation.to && 
      r.relationType === delRelation.relationType
    ));
    await this.saveGraph(graph);
  }

  async readGraph(): Promise<KnowledgeGraph> {

    return this.loadGraph();
  }

  // Very basic search function
  async searchNodes(query: string): Promise<KnowledgeGraph> {
    const graph = await this.loadGraph();

    // Filter entities
    const filteredEntities = graph.entities.filter(e => 
      e.name.toLowerCase().includes(query.toLowerCase()) ||
      e.entityType.toLowerCase().includes(query.toLowerCase()) ||
      e.observations.some(o => o.toLowerCase().includes(query.toLowerCase()))
    );
  
    // Create a Set of filtered entity names for quick lookup
    const filteredEntityNames = new Set(filteredEntities.map(e => e.name));
  
    // Filter relations to only include those between filtered entities
    const filteredRelations = graph.relations.filter(r => 
      filteredEntityNames.has(r.from) && filteredEntityNames.has(r.to)
    );
  
    const filteredGraph: KnowledgeGraph = {
      entities: filteredEntities,
      relations: filteredRelations,
    };
  
    return filteredGraph;
  }

  async openNodes(names: string[]): Promise<KnowledgeGraph> {
    const graph = await this.loadGraph();
    
    // Filter entities
    const filteredEntities = graph.entities.filter(e => names.includes(e.name));
  
    // Create a Set of filtered entity names for quick lookup
    const filteredEntityNames = new Set(filteredEntities.map(e => e.name));
  
    // Filter relations to only include those between filtered entities
    const filteredRelations = graph.relations.filter(r => 
      filteredEntityNames.has(r.from) && filteredEntityNames.has(r.to)
    );
  
    const filteredGraph: KnowledgeGraph = {
      entities: filteredEntities,
      relations: filteredRelations,
    };
  
    return filteredGraph;
  }
}


```

--------------------------------------------------------------------------------
/servers/mcp-neo4j-memory/src/neo4j-memory.ts:
--------------------------------------------------------------------------------

```typescript

import path from 'path';
import { fileURLToPath } from 'url';
import { promises as fs } from 'fs';

import neo4j, { Integer, Node, Relationship, Driver as Neo4jDriver } from 'neo4j-driver'

import { KnowledgeGraphMemory, Entity, KnowledgeGraph, Relation } from "@neo4j/graphrag-memory";

type EntityNode = Node<Integer, Entity>

type EntityRelationship = Relationship<Integer, Relation>

interface EntityWithRelationsResult {
  entity: EntityNode,
  relations: EntityRelationship[]
}

export class Neo4jMemory implements KnowledgeGraphMemory {
  constructor(private neo4jDriver: Neo4jDriver) { }

  private async loadGraph(): Promise<KnowledgeGraph> {
    const session = this.neo4jDriver.session()

    try {
      // Execute a Cypher statement in a Read Transaction
      const res = await session.executeRead(tx => tx.run<EntityWithRelationsResult>(`
        MATCH (entity:Memory)
        OPTIONAL MATCH (entity)-[r]->(other)
        RETURN entity, collect(r) as relations
      `))
      const kgMemory:KnowledgeGraph = res.records.reduce(
        (kg, row) => {
          const entityNode = row.get('entity');
          const entityRelationships = row.get('relations');

          kg.entities.push(entityNode.properties);
          kg.relations.push(...entityRelationships.map(r => r.properties))
          return kg
        }, 
        ({entities:[], relations:[]} as KnowledgeGraph)
      )
  
      console.error(JSON.stringify(kgMemory.entities))
      console.error(JSON.stringify(kgMemory.relations))

      return kgMemory
    } catch (error) {
      console.error(error)
    }
    finally {
      // Close the Session
      await session.close()
    }
    
    return {
      entities: [],
      relations: []    
    };
  }

  private async saveGraph(graph: KnowledgeGraph): Promise<void> {
    const session = this.neo4jDriver.session()

    return session.executeWrite(async txc => {
      await txc.run(`
        UNWIND $memoryGraph.entities as entity
        MERGE (entityMemory:Memory { entityID: entity.name })
        SET entityMemory += entity
        `
        ,
        {
          memoryGraph:graph
        }
      )
      await txc.run(`
        UNWIND $memoryGraph.relations as relation
        MATCH (from:Memory),(to:Memory)
        WHERE from.entityID = relation.from
          AND  to.entityID = relation.to
        MERGE (from)-[r:Memory {relationType:relation.relationType}]->(to)
        `
        ,
        {
          memoryGraph:graph
        }
      )

    })
  
  }

  async createEntities(entities: Entity[]): Promise<Entity[]> {
    const graph = await this.loadGraph();
    const newEntities = entities.filter(e => !graph.entities.some(existingEntity => existingEntity.name === e.name));
    graph.entities.push(...newEntities);
    await this.saveGraph(graph);
    return newEntities;
  }

  async createRelations(relations: Relation[]): Promise<Relation[]> {
    const graph = await this.loadGraph();
    const newRelations = relations.filter(r => !graph.relations.some(existingRelation => 
      existingRelation.from === r.from && 
      existingRelation.to === r.to && 
      existingRelation.relationType === r.relationType
    ));
    graph.relations.push(...newRelations);
    await this.saveGraph(graph);
    return newRelations;
  }

  async addObservations(observations: { entityName: string; contents: string[] }[]): Promise<{ entityName: string; addedObservations: string[] }[]> {
    const graph = await this.loadGraph();
    const results = observations.map(o => {
      const entity = graph.entities.find(e => e.name === o.entityName);
      if (!entity) {
        throw new Error(`Entity with name ${o.entityName} not found`);
      }
      const newObservations = o.contents.filter(content => !entity.observations.includes(content));
      entity.observations.push(...newObservations);
      return { entityName: o.entityName, addedObservations: newObservations };
    });
    await this.saveGraph(graph);
    return results;
  }

  async deleteEntities(entityNames: string[]): Promise<void> {
    const graph = await this.loadGraph();
    graph.entities = graph.entities.filter(e => !entityNames.includes(e.name));
    graph.relations = graph.relations.filter(r => !entityNames.includes(r.from) && !entityNames.includes(r.to));
    await this.saveGraph(graph);
  }

  async deleteObservations(deletions: { entityName: string; observations: string[] }[]): Promise<void> {
    const graph = await this.loadGraph();
    deletions.forEach(d => {
      const entity = graph.entities.find(e => e.name === d.entityName);
      if (entity) {
        entity.observations = entity.observations.filter(o => !d.observations.includes(o));
      }
    });
    await this.saveGraph(graph);
  }

  async deleteRelations(relations: Relation[]): Promise<void> {
    const graph = await this.loadGraph();
    graph.relations = graph.relations.filter(r => !relations.some(delRelation => 
      r.from === delRelation.from && 
      r.to === delRelation.to && 
      r.relationType === delRelation.relationType
    ));
    await this.saveGraph(graph);
  }

  async readGraph(): Promise<KnowledgeGraph> {

    return this.loadGraph();
  }

  // Very basic search function
  async searchNodes(query: string): Promise<KnowledgeGraph> {
    const graph = await this.loadGraph();

    // Filter entities
    const filteredEntities = graph.entities.filter(e => 
      query.toLowerCase().includes(e.name.toLowerCase()) ||
      query.toLowerCase().includes(e.entityType.toLowerCase()) ||
      e.observations.some(o => o.toLowerCase().includes(query.toLowerCase()))
    );
  
    // Create a Set of filtered entity names for quick lookup
    const filteredEntityNames = new Set(filteredEntities.map(e => e.name));
  
    // Filter relations to only include those between filtered entities
    const filteredRelations = graph.relations.filter(r => 
      filteredEntityNames.has(r.from) && filteredEntityNames.has(r.to)
    );
  
    const filteredGraph: KnowledgeGraph = {
      entities: filteredEntities,
      relations: filteredRelations,
    };
  
    return filteredGraph;
  }

  async openNodes(names: string[]): Promise<KnowledgeGraph> {
    const graph = await this.loadGraph();
    
    // Filter entities
    const filteredEntities = graph.entities.filter(e => names.includes(e.name));
  
    // Create a Set of filtered entity names for quick lookup
    const filteredEntityNames = new Set(filteredEntities.map(e => e.name));
  
    // Filter relations to only include those between filtered entities
    const filteredRelations = graph.relations.filter(r => 
      filteredEntityNames.has(r.from) && filteredEntityNames.has(r.to)
    );
  
    const filteredGraph: KnowledgeGraph = {
      entities: filteredEntities,
      relations: filteredRelations,
    };
  
    return filteredGraph;
  }
}


```

--------------------------------------------------------------------------------
/servers/mcp-json-memory/src/main.ts:
--------------------------------------------------------------------------------

```typescript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { KnowledgeGraphMemory, Entity, KnowledgeGraph, Relation } from "@neo4j/graphrag-memory";
import { JsonMemory } from './json-memory.js'


const args = process.argv.slice(2);

// Default to using the json file-based memory
const knowledgeGraphManager:KnowledgeGraphMemory = new JsonMemory(args);

// The server instance and tools exposed to Claude
const server = new Server({
  name: "mcp-json-memory",
  version: "1.0.1",
},    {
    capabilities: {
      tools: {},
    },
  },);

server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "create_entities",
        description: "Create multiple new entities in the knowledge graph",
        inputSchema: {
          type: "object",
          properties: {
            entities: {
              type: "array",
              items: {
                type: "object",
                properties: {
                  name: { type: "string", description: "The name of the entity" },
                  entityType: { type: "string", description: "The type of the entity" },
                  observations: { 
                    type: "array", 
                    items: { type: "string" },
                    description: "An array of observation contents associated with the entity"
                  },
                },
                required: ["name", "entityType", "observations"],
              },
            },
          },
          required: ["entities"],
        },
      },
      {
        name: "create_relations",
        description: "Create multiple new relations between entities in the knowledge graph. Relations should be in active voice",
        inputSchema: {
          type: "object",
          properties: {
            relations: {
              type: "array",
              items: {
                type: "object",
                properties: {
                  from: { type: "string", description: "The name of the entity where the relation starts" },
                  to: { type: "string", description: "The name of the entity where the relation ends" },
                  relationType: { type: "string", description: "The type of the relation" },
                },
                required: ["from", "to", "relationType"],
              },
            },
          },
          required: ["relations"],
        },
      },
      {
        name: "add_observations",
        description: "Add new observations to existing entities in the knowledge graph",
        inputSchema: {
          type: "object",
          properties: {
            observations: {
              type: "array",
              items: {
                type: "object",
                properties: {
                  entityName: { type: "string", description: "The name of the entity to add the observations to" },
                  contents: { 
                    type: "array", 
                    items: { type: "string" },
                    description: "An array of observation contents to add"
                  },
                },
                required: ["entityName", "contents"],
              },
            },
          },
          required: ["observations"],
        },
      },
      {
        name: "delete_entities",
        description: "Delete multiple entities and their associated relations from the knowledge graph",
        inputSchema: {
          type: "object",
          properties: {
            entityNames: { 
              type: "array", 
              items: { type: "string" },
              description: "An array of entity names to delete" 
            },
          },
          required: ["entityNames"],
        },
      },
      {
        name: "delete_observations",
        description: "Delete specific observations from entities in the knowledge graph",
        inputSchema: {
          type: "object",
          properties: {
            deletions: {
              type: "array",
              items: {
                type: "object",
                properties: {
                  entityName: { type: "string", description: "The name of the entity containing the observations" },
                  observations: { 
                    type: "array", 
                    items: { type: "string" },
                    description: "An array of observations to delete"
                  },
                },
                required: ["entityName", "observations"],
              },
            },
          },
          required: ["deletions"],
        },
      },
      {
        name: "delete_relations",
        description: "Delete multiple relations from the knowledge graph",
        inputSchema: {
          type: "object",
          properties: {
            relations: { 
              type: "array", 
              items: {
                type: "object",
                properties: {
                  from: { type: "string", description: "The name of the entity where the relation starts" },
                  to: { type: "string", description: "The name of the entity where the relation ends" },
                  relationType: { type: "string", description: "The type of the relation" },
                },
                required: ["from", "to", "relationType"],
              },
              description: "An array of relations to delete" 
            },
          },
          required: ["relations"],
        },
      },
      {
        name: "read_graph",
        description: "Read the entire knowledge graph",
        inputSchema: {
          type: "object",
          properties: {},
        },
      },
      {
        name: "search_nodes",
        description: "Search for nodes in the knowledge graph based on a query",
        inputSchema: {
          type: "object",
          properties: {
            query: { type: "string", description: "The search query to match against entity names, types, and observation content" },
          },
          required: ["query"],
        },
      },
      {
        name: "open_nodes",
        description: "Open specific nodes in the knowledge graph by their names",
        inputSchema: {
          type: "object",
          properties: {
            names: {
              type: "array",
              items: { type: "string" },
              description: "An array of entity names to retrieve",
            },
          },
          required: ["names"],
        },
      },
    ],
  };
});

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  if (!args) {
    throw new Error(`No arguments provided for tool: ${name}`);
  }

  switch (name) {
    case "create_entities":
      return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphManager.createEntities(args.entities as Entity[]), null, 2) }] };
    case "create_relations":
      return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphManager.createRelations(args.relations as Relation[]), null, 2) }] };
    case "add_observations":
      return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphManager.addObservations(args.observations as { entityName: string; contents: string[] }[]), null, 2) }] };
    case "delete_entities":
      await knowledgeGraphManager.deleteEntities(args.entityNames as string[]);
      return { content: [{ type: "text", text: "Entities deleted successfully" }] };
    case "delete_observations":
      await knowledgeGraphManager.deleteObservations(args.deletions as { entityName: string; observations: string[] }[]);
      return { content: [{ type: "text", text: "Observations deleted successfully" }] };
    case "delete_relations":
      await knowledgeGraphManager.deleteRelations(args.relations as Relation[]);
      return { content: [{ type: "text", text: "Relations deleted successfully" }] };
    case "read_graph":
      return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphManager.readGraph(), null, 2) }] };
    case "search_nodes":
      return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphManager.searchNodes(args.query as string), null, 2) }] };
    case "open_nodes":
      return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphManager.openNodes(args.names as string[]), null, 2) }] };
    default:
      throw new Error(`Unknown tool: ${name}`);
  }
});

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("MCP Knowledge Graph Memory using Neo4j running on stdio");
}

main().catch((error) => {
  console.error("Fatal error in main():", error);
  process.exit(1);
});
```

--------------------------------------------------------------------------------
/servers/mcp-neo4j-memory/src/main.ts:
--------------------------------------------------------------------------------

```typescript
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";

import { driver as connectToNeo4j, auth as Neo4jAuth } from 'neo4j-driver'

import { KnowledgeGraphMemory, Entity, KnowledgeGraph, Relation } from "@neo4j/graphrag-memory";
import { Neo4jMemory } from './neo4j-memory.js'


// const args = process.argv.slice(2);

const neo4jDriver = connectToNeo4j(
  'neo4j://localhost:7687',
  Neo4jAuth.basic('neo4j', 'marwhompa')
)

const knowledgeGraphMemory:KnowledgeGraphMemory = new Neo4jMemory(neo4jDriver);

// The server instance and tools exposed to Claude
const server = new Server({
  name: "mcp-neo4j-memory",
  version: "1.0.1",
},    {
    capabilities: {
      tools: {},
    },
  },);

server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "create_entities",
        description: "Create multiple new entities in the knowledge graph",
        inputSchema: {
          type: "object",
          properties: {
            entities: {
              type: "array",
              items: {
                type: "object",
                properties: {
                  name: { type: "string", description: "The name of the entity" },
                  entityType: { type: "string", description: "The type of the entity" },
                  observations: { 
                    type: "array", 
                    items: { type: "string" },
                    description: "An array of observation contents associated with the entity"
                  },
                },
                required: ["name", "entityType", "observations"],
              },
            },
          },
          required: ["entities"],
        },
      },
      {
        name: "create_relations",
        description: "Create multiple new relations between entities in the knowledge graph. Relations should be in active voice",
        inputSchema: {
          type: "object",
          properties: {
            relations: {
              type: "array",
              items: {
                type: "object",
                properties: {
                  from: { type: "string", description: "The name of the entity where the relation starts" },
                  to: { type: "string", description: "The name of the entity where the relation ends" },
                  relationType: { type: "string", description: "The type of the relation" },
                },
                required: ["from", "to", "relationType"],
              },
            },
          },
          required: ["relations"],
        },
      },
      {
        name: "add_observations",
        description: "Add new observations to existing entities in the knowledge graph",
        inputSchema: {
          type: "object",
          properties: {
            observations: {
              type: "array",
              items: {
                type: "object",
                properties: {
                  entityName: { type: "string", description: "The name of the entity to add the observations to" },
                  contents: { 
                    type: "array", 
                    items: { type: "string" },
                    description: "An array of observation contents to add"
                  },
                },
                required: ["entityName", "contents"],
              },
            },
          },
          required: ["observations"],
        },
      },
      {
        name: "delete_entities",
        description: "Delete multiple entities and their associated relations from the knowledge graph",
        inputSchema: {
          type: "object",
          properties: {
            entityNames: { 
              type: "array", 
              items: { type: "string" },
              description: "An array of entity names to delete" 
            },
          },
          required: ["entityNames"],
        },
      },
      {
        name: "delete_observations",
        description: "Delete specific observations from entities in the knowledge graph",
        inputSchema: {
          type: "object",
          properties: {
            deletions: {
              type: "array",
              items: {
                type: "object",
                properties: {
                  entityName: { type: "string", description: "The name of the entity containing the observations" },
                  observations: { 
                    type: "array", 
                    items: { type: "string" },
                    description: "An array of observations to delete"
                  },
                },
                required: ["entityName", "observations"],
              },
            },
          },
          required: ["deletions"],
        },
      },
      {
        name: "delete_relations",
        description: "Delete multiple relations from the knowledge graph",
        inputSchema: {
          type: "object",
          properties: {
            relations: { 
              type: "array", 
              items: {
                type: "object",
                properties: {
                  from: { type: "string", description: "The name of the entity where the relation starts" },
                  to: { type: "string", description: "The name of the entity where the relation ends" },
                  relationType: { type: "string", description: "The type of the relation" },
                },
                required: ["from", "to", "relationType"],
              },
              description: "An array of relations to delete" 
            },
          },
          required: ["relations"],
        },
      },
      {
        name: "read_graph",
        description: "Read the entire knowledge graph",
        inputSchema: {
          type: "object",
          properties: {},
        },
      },
      {
        name: "search_nodes",
        description: "Search for nodes in the knowledge graph based on a query",
        inputSchema: {
          type: "object",
          properties: {
            query: { type: "string", description: "The search query to match against entity names, types, and observation content" },
          },
          required: ["query"],
        },
      },
      {
        name: "open_nodes",
        description: "Open specific nodes in the knowledge graph by their names",
        inputSchema: {
          type: "object",
          properties: {
            names: {
              type: "array",
              items: { type: "string" },
              description: "An array of entity names to retrieve",
            },
          },
          required: ["names"],
        },
      },
    ],
  };
});

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  if (!args) {
    throw new Error(`No arguments provided for tool: ${name}`);
  }

  switch (name) {
    case "create_entities":
      return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphMemory.createEntities(args.entities as Entity[]), null, 2) }] };
    case "create_relations":
      return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphMemory.createRelations(args.relations as Relation[]), null, 2) }] };
    case "add_observations":
      return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphMemory.addObservations(args.observations as { entityName: string; contents: string[] }[]), null, 2) }] };
    case "delete_entities":
      await knowledgeGraphMemory.deleteEntities(args.entityNames as string[]);
      return { content: [{ type: "text", text: "Entities deleted successfully" }] };
    case "delete_observations":
      await knowledgeGraphMemory.deleteObservations(args.deletions as { entityName: string; observations: string[] }[]);
      return { content: [{ type: "text", text: "Observations deleted successfully" }] };
    case "delete_relations":
      await knowledgeGraphMemory.deleteRelations(args.relations as Relation[]);
      return { content: [{ type: "text", text: "Relations deleted successfully" }] };
    case "read_graph":
      return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphMemory.readGraph(), null, 2) }] };
    case "search_nodes":
      return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphMemory.searchNodes(args.query as string), null, 2) }] };
    case "open_nodes":
      return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphMemory.openNodes(args.names as string[]), null, 2) }] };
    default:
      throw new Error(`Unknown tool: ${name}`);
  }
});

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("MCP Knowledge Graph Memory using Neo4j running on stdio");
}

main().catch((error) => {
  console.error("Fatal error in main():", error);
  process.exit(1);
});
```