memgraph-ingester-mcp 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- memgraph_ingester_mcp-0.1.0/.github/workflows/publish.yml +43 -0
- memgraph_ingester_mcp-0.1.0/.gitignore +11 -0
- memgraph_ingester_mcp-0.1.0/LICENSE +21 -0
- memgraph_ingester_mcp-0.1.0/PKG-INFO +188 -0
- memgraph_ingester_mcp-0.1.0/README.md +163 -0
- memgraph_ingester_mcp-0.1.0/pyproject.toml +56 -0
- memgraph_ingester_mcp-0.1.0/src/memgraph_ingester_mcp/__init__.py +5 -0
- memgraph_ingester_mcp-0.1.0/src/memgraph_ingester_mcp/__main__.py +6 -0
- memgraph_ingester_mcp-0.1.0/src/memgraph_ingester_mcp/config.py +74 -0
- memgraph_ingester_mcp-0.1.0/src/memgraph_ingester_mcp/db.py +65 -0
- memgraph_ingester_mcp-0.1.0/src/memgraph_ingester_mcp/schema.py +106 -0
- memgraph_ingester_mcp-0.1.0/src/memgraph_ingester_mcp/server.py +215 -0
- memgraph_ingester_mcp-0.1.0/src/memgraph_ingester_mcp/services.py +887 -0
- memgraph_ingester_mcp-0.1.0/tests/test_config.py +21 -0
- memgraph_ingester_mcp-0.1.0/tests/test_services.py +214 -0
- memgraph_ingester_mcp-0.1.0/uv.lock +827 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
push:
|
|
6
|
+
tags:
|
|
7
|
+
- "v*"
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
publish:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
environment:
|
|
13
|
+
name: pypi
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
id-token: write
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- name: Checkout
|
|
20
|
+
uses: actions/checkout@v6
|
|
21
|
+
|
|
22
|
+
- name: Install uv
|
|
23
|
+
uses: astral-sh/setup-uv@v7
|
|
24
|
+
with:
|
|
25
|
+
enable-cache: true
|
|
26
|
+
|
|
27
|
+
- name: Install Python
|
|
28
|
+
run: uv python install 3.13
|
|
29
|
+
|
|
30
|
+
- name: Install dependencies
|
|
31
|
+
run: uv sync --locked --dev
|
|
32
|
+
|
|
33
|
+
- name: Lint
|
|
34
|
+
run: uv run ruff check .
|
|
35
|
+
|
|
36
|
+
- name: Test
|
|
37
|
+
run: uv run pytest
|
|
38
|
+
|
|
39
|
+
- name: Build
|
|
40
|
+
run: uv build --no-sources
|
|
41
|
+
|
|
42
|
+
- name: Publish
|
|
43
|
+
run: uv publish
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Oleksii Usatov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: memgraph-ingester-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP tools for Memgraph graphs created by memgraph-ingester
|
|
5
|
+
Project-URL: Homepage, https://github.com/ousatov-ua/memgraph-ingester-mcp
|
|
6
|
+
Project-URL: Repository, https://github.com/ousatov-ua/memgraph-ingester-mcp
|
|
7
|
+
Project-URL: Issues, https://github.com/ousatov-ua/memgraph-ingester-mcp/issues
|
|
8
|
+
Author: Oleksii Usatov
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: codex,knowledge-graph,mcp,memgraph,rag
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Database
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: mcp>=1.16.0
|
|
23
|
+
Requires-Dist: neo4j>=5.28.0
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# memgraph-ingester-mcp
|
|
27
|
+
|
|
28
|
+
`memgraph-ingester-mcp` exposes safe, high-level MCP tools for Memgraph graphs produced by
|
|
29
|
+
[`memgraph-ingester`](https://github.com/ousatov-ua/memgraph-ingester). It keeps agents out of long
|
|
30
|
+
Cypher instruction blocks for normal work while still offering a project-scoped read-only Cypher
|
|
31
|
+
escape hatch for unusual lookups.
|
|
32
|
+
|
|
33
|
+
The package is intended to be published to PyPI as `memgraph-ingester-mcp` under the
|
|
34
|
+
`ousatov-ua` account.
|
|
35
|
+
|
|
36
|
+
## Tools
|
|
37
|
+
|
|
38
|
+
Code graph tools:
|
|
39
|
+
|
|
40
|
+
- `server_status`: graph inventory, memory counts, and vector index status.
|
|
41
|
+
- `code_orientation`: compact package/type/call overview.
|
|
42
|
+
- `code_search`: CodeChunk vector search for broad discovery.
|
|
43
|
+
- `code_lookup_type`: exact class/interface/annotation lookup with members.
|
|
44
|
+
- `code_lookup_methods`: exact method lookup with source ranges.
|
|
45
|
+
- `code_callers`, `code_callees`: call graph lookups.
|
|
46
|
+
- `code_hierarchy`: class ancestry, children, interfaces, and interface implementors.
|
|
47
|
+
|
|
48
|
+
Memory tools:
|
|
49
|
+
|
|
50
|
+
- `memory_orientation`: rules plus open findings, tasks, questions, and risks.
|
|
51
|
+
- `memory_search`: MemoryChunk vector search with index-only hit metadata.
|
|
52
|
+
- `memory_get`: canonical memory node plus resolved CodeRefs.
|
|
53
|
+
- `memory_upsert`: create/update Decision, ADR, Rule, Context, Finding, Task, Risk, Question, or Idea.
|
|
54
|
+
- `memory_update_status`: lifecycle status update.
|
|
55
|
+
- `memory_link_code_ref`: link memory to a resolved CodeRef target.
|
|
56
|
+
- `memory_refresh_chunk`, `memory_refresh_embeddings`: maintain derived memory RAG data.
|
|
57
|
+
|
|
58
|
+
Fallback:
|
|
59
|
+
|
|
60
|
+
- `raw_read_cypher`: read-only, project-scoped Cypher for edge cases.
|
|
61
|
+
|
|
62
|
+
## Configuration
|
|
63
|
+
|
|
64
|
+
Use namespaced environment variables so this server does not collide with generic shell settings:
|
|
65
|
+
|
|
66
|
+
| Variable | Default | Purpose |
|
|
67
|
+
| --- | --- | --- |
|
|
68
|
+
| `MEMGRAPH_INGESTER_MCP_BOLT_URI` | `bolt://127.0.0.1:7687` | Memgraph Bolt URI |
|
|
69
|
+
| `MEMGRAPH_INGESTER_MCP_USERNAME` | unset | Optional username |
|
|
70
|
+
| `MEMGRAPH_INGESTER_MCP_PASSWORD` | unset | Optional password |
|
|
71
|
+
| `MEMGRAPH_INGESTER_MCP_DATABASE` | unset | Optional database name |
|
|
72
|
+
| `MEMGRAPH_INGESTER_MCP_PROJECT` | unset | Default project name |
|
|
73
|
+
| `MEMGRAPH_INGESTER_MCP_QUERY_TIMEOUT_SECONDS` | `30` | Query timeout |
|
|
74
|
+
| `MEMGRAPH_INGESTER_MCP_READ_ONLY` | `false` | Disable write tools when `true` |
|
|
75
|
+
| `MEMGRAPH_INGESTER_MCP_EMBEDDING_MODEL` | `default` | Metadata stamped on refreshed chunks |
|
|
76
|
+
| `MEMGRAPH_INGESTER_MCP_EMBEDDING_DIMENSIONS` | `384` | Expected memory embedding dimension |
|
|
77
|
+
|
|
78
|
+
## Run Locally
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
uv sync --dev
|
|
82
|
+
uv run memgraph-ingester-mcp
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Run tests:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
uv run ruff check .
|
|
89
|
+
uv run pytest
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Build the package:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
uv build --no-sources
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Client Setup
|
|
99
|
+
|
|
100
|
+
Replace `my-project` with the project name used when running `memgraph-ingester`.
|
|
101
|
+
|
|
102
|
+
### Codex
|
|
103
|
+
|
|
104
|
+
Add this to `~/.codex/config.toml`:
|
|
105
|
+
|
|
106
|
+
```toml
|
|
107
|
+
[mcp_servers.memgraphIngester]
|
|
108
|
+
command = "uvx"
|
|
109
|
+
args = ["memgraph-ingester-mcp"]
|
|
110
|
+
startup_timeout_ms = 20_000
|
|
111
|
+
|
|
112
|
+
[mcp_servers.memgraphIngester.env]
|
|
113
|
+
MEMGRAPH_INGESTER_MCP_BOLT_URI = "bolt://127.0.0.1:7687"
|
|
114
|
+
MEMGRAPH_INGESTER_MCP_PROJECT = "my-project"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Claude Desktop
|
|
118
|
+
|
|
119
|
+
Add this to `claude_desktop_config.json`:
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
{
|
|
123
|
+
"mcpServers": {
|
|
124
|
+
"memgraphIngester": {
|
|
125
|
+
"type": "stdio",
|
|
126
|
+
"command": "uvx",
|
|
127
|
+
"args": ["memgraph-ingester-mcp"],
|
|
128
|
+
"env": {
|
|
129
|
+
"MEMGRAPH_INGESTER_MCP_BOLT_URI": "bolt://127.0.0.1:7687",
|
|
130
|
+
"MEMGRAPH_INGESTER_MCP_PROJECT": "my-project"
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Claude Code can also add the same stdio server directly:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
claude mcp add-json memgraphIngester \
|
|
141
|
+
'{"type":"stdio","command":"uvx","args":["memgraph-ingester-mcp"],"env":{"MEMGRAPH_INGESTER_MCP_BOLT_URI":"bolt://127.0.0.1:7687","MEMGRAPH_INGESTER_MCP_PROJECT":"my-project"}}'
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### GitHub Copilot in VS Code
|
|
145
|
+
|
|
146
|
+
Create `.vscode/mcp.json` in the workspace or add the server to your user MCP configuration:
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"servers": {
|
|
151
|
+
"memgraphIngester": {
|
|
152
|
+
"type": "stdio",
|
|
153
|
+
"command": "uvx",
|
|
154
|
+
"args": ["memgraph-ingester-mcp"],
|
|
155
|
+
"env": {
|
|
156
|
+
"MEMGRAPH_INGESTER_MCP_BOLT_URI": "bolt://127.0.0.1:7687",
|
|
157
|
+
"MEMGRAPH_INGESTER_MCP_PROJECT": "my-project"
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Gemini CLI
|
|
165
|
+
|
|
166
|
+
Add this to Gemini CLI `settings.json`:
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"mcpServers": {
|
|
171
|
+
"memgraphIngester": {
|
|
172
|
+
"command": "uvx",
|
|
173
|
+
"args": ["memgraph-ingester-mcp"],
|
|
174
|
+
"env": {
|
|
175
|
+
"MEMGRAPH_INGESTER_MCP_BOLT_URI": "bolt://127.0.0.1:7687",
|
|
176
|
+
"MEMGRAPH_INGESTER_MCP_PROJECT": "my-project"
|
|
177
|
+
},
|
|
178
|
+
"trust": false
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Agent Guidance
|
|
185
|
+
|
|
186
|
+
Prefer the dedicated tools over `raw_read_cypher`. Use RAG search tools only for broad discovery,
|
|
187
|
+
then follow up with exact lookup tools before making claims or edits. Use memory write tools for
|
|
188
|
+
task lifecycle changes and CodeRef links so derived MemoryChunks stay refreshable.
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# memgraph-ingester-mcp
|
|
2
|
+
|
|
3
|
+
`memgraph-ingester-mcp` exposes safe, high-level MCP tools for Memgraph graphs produced by
|
|
4
|
+
[`memgraph-ingester`](https://github.com/ousatov-ua/memgraph-ingester). It keeps agents out of long
|
|
5
|
+
Cypher instruction blocks for normal work while still offering a project-scoped read-only Cypher
|
|
6
|
+
escape hatch for unusual lookups.
|
|
7
|
+
|
|
8
|
+
The package is intended to be published to PyPI as `memgraph-ingester-mcp` under the
|
|
9
|
+
`ousatov-ua` account.
|
|
10
|
+
|
|
11
|
+
## Tools
|
|
12
|
+
|
|
13
|
+
Code graph tools:
|
|
14
|
+
|
|
15
|
+
- `server_status`: graph inventory, memory counts, and vector index status.
|
|
16
|
+
- `code_orientation`: compact package/type/call overview.
|
|
17
|
+
- `code_search`: CodeChunk vector search for broad discovery.
|
|
18
|
+
- `code_lookup_type`: exact class/interface/annotation lookup with members.
|
|
19
|
+
- `code_lookup_methods`: exact method lookup with source ranges.
|
|
20
|
+
- `code_callers`, `code_callees`: call graph lookups.
|
|
21
|
+
- `code_hierarchy`: class ancestry, children, interfaces, and interface implementors.
|
|
22
|
+
|
|
23
|
+
Memory tools:
|
|
24
|
+
|
|
25
|
+
- `memory_orientation`: rules plus open findings, tasks, questions, and risks.
|
|
26
|
+
- `memory_search`: MemoryChunk vector search with index-only hit metadata.
|
|
27
|
+
- `memory_get`: canonical memory node plus resolved CodeRefs.
|
|
28
|
+
- `memory_upsert`: create/update Decision, ADR, Rule, Context, Finding, Task, Risk, Question, or Idea.
|
|
29
|
+
- `memory_update_status`: lifecycle status update.
|
|
30
|
+
- `memory_link_code_ref`: link memory to a resolved CodeRef target.
|
|
31
|
+
- `memory_refresh_chunk`, `memory_refresh_embeddings`: maintain derived memory RAG data.
|
|
32
|
+
|
|
33
|
+
Fallback:
|
|
34
|
+
|
|
35
|
+
- `raw_read_cypher`: read-only, project-scoped Cypher for edge cases.
|
|
36
|
+
|
|
37
|
+
## Configuration
|
|
38
|
+
|
|
39
|
+
Use namespaced environment variables so this server does not collide with generic shell settings:
|
|
40
|
+
|
|
41
|
+
| Variable | Default | Purpose |
|
|
42
|
+
| --- | --- | --- |
|
|
43
|
+
| `MEMGRAPH_INGESTER_MCP_BOLT_URI` | `bolt://127.0.0.1:7687` | Memgraph Bolt URI |
|
|
44
|
+
| `MEMGRAPH_INGESTER_MCP_USERNAME` | unset | Optional username |
|
|
45
|
+
| `MEMGRAPH_INGESTER_MCP_PASSWORD` | unset | Optional password |
|
|
46
|
+
| `MEMGRAPH_INGESTER_MCP_DATABASE` | unset | Optional database name |
|
|
47
|
+
| `MEMGRAPH_INGESTER_MCP_PROJECT` | unset | Default project name |
|
|
48
|
+
| `MEMGRAPH_INGESTER_MCP_QUERY_TIMEOUT_SECONDS` | `30` | Query timeout |
|
|
49
|
+
| `MEMGRAPH_INGESTER_MCP_READ_ONLY` | `false` | Disable write tools when `true` |
|
|
50
|
+
| `MEMGRAPH_INGESTER_MCP_EMBEDDING_MODEL` | `default` | Metadata stamped on refreshed chunks |
|
|
51
|
+
| `MEMGRAPH_INGESTER_MCP_EMBEDDING_DIMENSIONS` | `384` | Expected memory embedding dimension |
|
|
52
|
+
|
|
53
|
+
## Run Locally
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
uv sync --dev
|
|
57
|
+
uv run memgraph-ingester-mcp
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Run tests:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
uv run ruff check .
|
|
64
|
+
uv run pytest
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Build the package:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
uv build --no-sources
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Client Setup
|
|
74
|
+
|
|
75
|
+
Replace `my-project` with the project name used when running `memgraph-ingester`.
|
|
76
|
+
|
|
77
|
+
### Codex
|
|
78
|
+
|
|
79
|
+
Add this to `~/.codex/config.toml`:
|
|
80
|
+
|
|
81
|
+
```toml
|
|
82
|
+
[mcp_servers.memgraphIngester]
|
|
83
|
+
command = "uvx"
|
|
84
|
+
args = ["memgraph-ingester-mcp"]
|
|
85
|
+
startup_timeout_ms = 20_000
|
|
86
|
+
|
|
87
|
+
[mcp_servers.memgraphIngester.env]
|
|
88
|
+
MEMGRAPH_INGESTER_MCP_BOLT_URI = "bolt://127.0.0.1:7687"
|
|
89
|
+
MEMGRAPH_INGESTER_MCP_PROJECT = "my-project"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Claude Desktop
|
|
93
|
+
|
|
94
|
+
Add this to `claude_desktop_config.json`:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"mcpServers": {
|
|
99
|
+
"memgraphIngester": {
|
|
100
|
+
"type": "stdio",
|
|
101
|
+
"command": "uvx",
|
|
102
|
+
"args": ["memgraph-ingester-mcp"],
|
|
103
|
+
"env": {
|
|
104
|
+
"MEMGRAPH_INGESTER_MCP_BOLT_URI": "bolt://127.0.0.1:7687",
|
|
105
|
+
"MEMGRAPH_INGESTER_MCP_PROJECT": "my-project"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Claude Code can also add the same stdio server directly:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
claude mcp add-json memgraphIngester \
|
|
116
|
+
'{"type":"stdio","command":"uvx","args":["memgraph-ingester-mcp"],"env":{"MEMGRAPH_INGESTER_MCP_BOLT_URI":"bolt://127.0.0.1:7687","MEMGRAPH_INGESTER_MCP_PROJECT":"my-project"}}'
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### GitHub Copilot in VS Code
|
|
120
|
+
|
|
121
|
+
Create `.vscode/mcp.json` in the workspace or add the server to your user MCP configuration:
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"servers": {
|
|
126
|
+
"memgraphIngester": {
|
|
127
|
+
"type": "stdio",
|
|
128
|
+
"command": "uvx",
|
|
129
|
+
"args": ["memgraph-ingester-mcp"],
|
|
130
|
+
"env": {
|
|
131
|
+
"MEMGRAPH_INGESTER_MCP_BOLT_URI": "bolt://127.0.0.1:7687",
|
|
132
|
+
"MEMGRAPH_INGESTER_MCP_PROJECT": "my-project"
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Gemini CLI
|
|
140
|
+
|
|
141
|
+
Add this to Gemini CLI `settings.json`:
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{
|
|
145
|
+
"mcpServers": {
|
|
146
|
+
"memgraphIngester": {
|
|
147
|
+
"command": "uvx",
|
|
148
|
+
"args": ["memgraph-ingester-mcp"],
|
|
149
|
+
"env": {
|
|
150
|
+
"MEMGRAPH_INGESTER_MCP_BOLT_URI": "bolt://127.0.0.1:7687",
|
|
151
|
+
"MEMGRAPH_INGESTER_MCP_PROJECT": "my-project"
|
|
152
|
+
},
|
|
153
|
+
"trust": false
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Agent Guidance
|
|
160
|
+
|
|
161
|
+
Prefer the dedicated tools over `raw_read_cypher`. Use RAG search tools only for broad discovery,
|
|
162
|
+
then follow up with exact lookup tools before making claims or edits. Use memory write tools for
|
|
163
|
+
task lifecycle changes and CodeRef links so derived MemoryChunks stay refreshable.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "memgraph-ingester-mcp"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "MCP tools for Memgraph graphs created by memgraph-ingester"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
authors = [{ name = "Oleksii Usatov" }]
|
|
9
|
+
keywords = ["mcp", "memgraph", "knowledge-graph", "rag", "codex"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 3 - Alpha",
|
|
12
|
+
"Intended Audience :: Developers",
|
|
13
|
+
"License :: OSI Approved :: MIT License",
|
|
14
|
+
"Programming Language :: Python :: 3",
|
|
15
|
+
"Programming Language :: Python :: 3.11",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Programming Language :: Python :: 3.13",
|
|
18
|
+
"Topic :: Database",
|
|
19
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
20
|
+
]
|
|
21
|
+
dependencies = [
|
|
22
|
+
"mcp>=1.16.0",
|
|
23
|
+
"neo4j>=5.28.0",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/ousatov-ua/memgraph-ingester-mcp"
|
|
28
|
+
Repository = "https://github.com/ousatov-ua/memgraph-ingester-mcp"
|
|
29
|
+
Issues = "https://github.com/ousatov-ua/memgraph-ingester-mcp/issues"
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
memgraph-ingester-mcp = "memgraph_ingester_mcp.server:main"
|
|
33
|
+
|
|
34
|
+
[dependency-groups]
|
|
35
|
+
dev = [
|
|
36
|
+
"pytest>=8.3.0",
|
|
37
|
+
"ruff>=0.8.0",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[build-system]
|
|
41
|
+
requires = ["hatchling"]
|
|
42
|
+
build-backend = "hatchling.build"
|
|
43
|
+
|
|
44
|
+
[tool.hatch.build.targets.wheel]
|
|
45
|
+
packages = ["src/memgraph_ingester_mcp"]
|
|
46
|
+
|
|
47
|
+
[tool.ruff]
|
|
48
|
+
line-length = 100
|
|
49
|
+
target-version = "py311"
|
|
50
|
+
|
|
51
|
+
[tool.ruff.lint]
|
|
52
|
+
select = ["E", "F", "I", "UP", "B", "SIM", "C4", "RUF"]
|
|
53
|
+
|
|
54
|
+
[tool.pytest.ini_options]
|
|
55
|
+
addopts = "-q"
|
|
56
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Runtime configuration for the MCP server."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from os import getenv
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _optional_env(name: str) -> str | None:
|
|
10
|
+
value = getenv(name)
|
|
11
|
+
if value is None or value == "":
|
|
12
|
+
return None
|
|
13
|
+
return value
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _bool_env(name: str, default: bool) -> bool:
|
|
17
|
+
value = getenv(name)
|
|
18
|
+
if value is None or value == "":
|
|
19
|
+
return default
|
|
20
|
+
return value.strip().lower() in {"1", "true", "yes", "on"}
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _float_env(name: str, default: float) -> float:
|
|
24
|
+
value = getenv(name)
|
|
25
|
+
if value is None or value == "":
|
|
26
|
+
return default
|
|
27
|
+
return float(value)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _int_env(name: str, default: int) -> int:
|
|
31
|
+
value = getenv(name)
|
|
32
|
+
if value is None or value == "":
|
|
33
|
+
return default
|
|
34
|
+
return int(value)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@dataclass(frozen=True)
|
|
38
|
+
class MemgraphConfig:
|
|
39
|
+
"""Namespaced Memgraph settings used by the stdio MCP process."""
|
|
40
|
+
|
|
41
|
+
bolt_uri: str = "bolt://127.0.0.1:7687"
|
|
42
|
+
username: str | None = None
|
|
43
|
+
password: str | None = None
|
|
44
|
+
database: str | None = None
|
|
45
|
+
default_project: str | None = None
|
|
46
|
+
query_timeout_seconds: float = 30.0
|
|
47
|
+
read_only: bool = False
|
|
48
|
+
embedding_model_name: str = "default"
|
|
49
|
+
embedding_dimensions: int = 384
|
|
50
|
+
|
|
51
|
+
@classmethod
|
|
52
|
+
def from_environment(cls) -> MemgraphConfig:
|
|
53
|
+
"""Load only MCP-specific environment variables to avoid generic name collisions."""
|
|
54
|
+
|
|
55
|
+
return cls(
|
|
56
|
+
bolt_uri=getenv("MEMGRAPH_INGESTER_MCP_BOLT_URI", cls.bolt_uri),
|
|
57
|
+
username=_optional_env("MEMGRAPH_INGESTER_MCP_USERNAME"),
|
|
58
|
+
password=_optional_env("MEMGRAPH_INGESTER_MCP_PASSWORD"),
|
|
59
|
+
database=_optional_env("MEMGRAPH_INGESTER_MCP_DATABASE"),
|
|
60
|
+
default_project=_optional_env("MEMGRAPH_INGESTER_MCP_PROJECT"),
|
|
61
|
+
query_timeout_seconds=_float_env(
|
|
62
|
+
"MEMGRAPH_INGESTER_MCP_QUERY_TIMEOUT_SECONDS",
|
|
63
|
+
cls.query_timeout_seconds,
|
|
64
|
+
),
|
|
65
|
+
read_only=_bool_env("MEMGRAPH_INGESTER_MCP_READ_ONLY", cls.read_only),
|
|
66
|
+
embedding_model_name=getenv(
|
|
67
|
+
"MEMGRAPH_INGESTER_MCP_EMBEDDING_MODEL",
|
|
68
|
+
cls.embedding_model_name,
|
|
69
|
+
),
|
|
70
|
+
embedding_dimensions=_int_env(
|
|
71
|
+
"MEMGRAPH_INGESTER_MCP_EMBEDDING_DIMENSIONS",
|
|
72
|
+
cls.embedding_dimensions,
|
|
73
|
+
),
|
|
74
|
+
)
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"""Thin Memgraph Bolt client."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
from datetime import date, datetime
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from neo4j import GraphDatabase, Query
|
|
10
|
+
from neo4j.time import Date, DateTime, Duration, Time
|
|
11
|
+
|
|
12
|
+
from memgraph_ingester_mcp.config import MemgraphConfig
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class MemgraphError(RuntimeError):
|
|
16
|
+
"""Raised when an MCP operation cannot be executed safely."""
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _to_jsonable(value: Any) -> Any:
|
|
20
|
+
if isinstance(value, Mapping):
|
|
21
|
+
return {str(key): _to_jsonable(item) for key, item in value.items()}
|
|
22
|
+
if isinstance(value, list | tuple):
|
|
23
|
+
return [_to_jsonable(item) for item in value]
|
|
24
|
+
if isinstance(value, DateTime | Date | Time | Duration | datetime | date):
|
|
25
|
+
return str(value)
|
|
26
|
+
return value
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class MemgraphClient:
|
|
30
|
+
"""Execute parameterized Cypher against Memgraph over Bolt."""
|
|
31
|
+
|
|
32
|
+
def __init__(self, config: MemgraphConfig, driver: Any | None = None) -> None:
|
|
33
|
+
self.config = config
|
|
34
|
+
if driver is None:
|
|
35
|
+
auth = None
|
|
36
|
+
if config.username is not None:
|
|
37
|
+
auth = (config.username, config.password or "")
|
|
38
|
+
driver = GraphDatabase.driver(config.bolt_uri, auth=auth)
|
|
39
|
+
self._driver = driver
|
|
40
|
+
|
|
41
|
+
def close(self) -> None:
|
|
42
|
+
close = getattr(self._driver, "close", None)
|
|
43
|
+
if close is not None:
|
|
44
|
+
close()
|
|
45
|
+
|
|
46
|
+
def run(
|
|
47
|
+
self,
|
|
48
|
+
query: str,
|
|
49
|
+
parameters: Mapping[str, Any] | None = None,
|
|
50
|
+
*,
|
|
51
|
+
write: bool = False,
|
|
52
|
+
) -> list[dict[str, Any]]:
|
|
53
|
+
if write and self.config.read_only:
|
|
54
|
+
raise MemgraphError("Write tools are disabled by MEMGRAPH_INGESTER_MCP_READ_ONLY.")
|
|
55
|
+
|
|
56
|
+
session_kwargs: dict[str, Any] = {}
|
|
57
|
+
if self.config.database is not None:
|
|
58
|
+
session_kwargs["database"] = self.config.database
|
|
59
|
+
|
|
60
|
+
with self._driver.session(**session_kwargs) as session:
|
|
61
|
+
result = session.run(
|
|
62
|
+
Query(query, timeout=self.config.query_timeout_seconds),
|
|
63
|
+
dict(parameters or {}),
|
|
64
|
+
)
|
|
65
|
+
return [_to_jsonable(dict(record)) for record in result]
|