archgraph-mcp 1.0.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.
Files changed (42) hide show
  1. archgraph_mcp-1.0.0/LICENSE +21 -0
  2. archgraph_mcp-1.0.0/PKG-INFO +27 -0
  3. archgraph_mcp-1.0.0/README.md +394 -0
  4. archgraph_mcp-1.0.0/pyproject.toml +79 -0
  5. archgraph_mcp-1.0.0/setup.cfg +4 -0
  6. archgraph_mcp-1.0.0/src/archgraph_mcp/__init__.py +3 -0
  7. archgraph_mcp-1.0.0/src/archgraph_mcp/__main__.py +144 -0
  8. archgraph_mcp-1.0.0/src/archgraph_mcp/enums.py +27 -0
  9. archgraph_mcp-1.0.0/src/archgraph_mcp/graph/__init__.py +0 -0
  10. archgraph_mcp-1.0.0/src/archgraph_mcp/graph/builder.py +142 -0
  11. archgraph_mcp-1.0.0/src/archgraph_mcp/graph/query_engine.py +211 -0
  12. archgraph_mcp-1.0.0/src/archgraph_mcp/logging_config.py +27 -0
  13. archgraph_mcp-1.0.0/src/archgraph_mcp/models.py +56 -0
  14. archgraph_mcp-1.0.0/src/archgraph_mcp/parser/__init__.py +0 -0
  15. archgraph_mcp-1.0.0/src/archgraph_mcp/parser/base.py +61 -0
  16. archgraph_mcp-1.0.0/src/archgraph_mcp/parser/java.py +182 -0
  17. archgraph_mcp-1.0.0/src/archgraph_mcp/parser/kotlin.py +226 -0
  18. archgraph_mcp-1.0.0/src/archgraph_mcp/parser/typescript.py +192 -0
  19. archgraph_mcp-1.0.0/src/archgraph_mcp/semantic/__init__.py +1 -0
  20. archgraph_mcp-1.0.0/src/archgraph_mcp/semantic/build.py +29 -0
  21. archgraph_mcp-1.0.0/src/archgraph_mcp/semantic/embeddings.py +170 -0
  22. archgraph_mcp-1.0.0/src/archgraph_mcp/semantic/vector_index.py +98 -0
  23. archgraph_mcp-1.0.0/src/archgraph_mcp/server/__init__.py +0 -0
  24. archgraph_mcp-1.0.0/src/archgraph_mcp/server/mcp_server.py +339 -0
  25. archgraph_mcp-1.0.0/src/archgraph_mcp/storage/__init__.py +0 -0
  26. archgraph_mcp-1.0.0/src/archgraph_mcp/storage/kuzu_store.py +246 -0
  27. archgraph_mcp-1.0.0/src/archgraph_mcp/utils/__init__.py +0 -0
  28. archgraph_mcp-1.0.0/src/archgraph_mcp/utils/scanner.py +89 -0
  29. archgraph_mcp-1.0.0/src/archgraph_mcp.egg-info/PKG-INFO +27 -0
  30. archgraph_mcp-1.0.0/src/archgraph_mcp.egg-info/SOURCES.txt +40 -0
  31. archgraph_mcp-1.0.0/src/archgraph_mcp.egg-info/dependency_links.txt +1 -0
  32. archgraph_mcp-1.0.0/src/archgraph_mcp.egg-info/entry_points.txt +2 -0
  33. archgraph_mcp-1.0.0/src/archgraph_mcp.egg-info/requires.txt +22 -0
  34. archgraph_mcp-1.0.0/src/archgraph_mcp.egg-info/top_level.txt +1 -0
  35. archgraph_mcp-1.0.0/tests/test_embeddings.py +73 -0
  36. archgraph_mcp-1.0.0/tests/test_graph_builder.py +32 -0
  37. archgraph_mcp-1.0.0/tests/test_graph_ui.py +27 -0
  38. archgraph_mcp-1.0.0/tests/test_kuzu_store.py +45 -0
  39. archgraph_mcp-1.0.0/tests/test_mcp_server.py +49 -0
  40. archgraph_mcp-1.0.0/tests/test_parser.py +91 -0
  41. archgraph_mcp-1.0.0/tests/test_query_engine.py +51 -0
  42. archgraph_mcp-1.0.0/tests/test_scanner.py +42 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 ArchGraph MCP Contributors
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,27 @@
1
+ Metadata-Version: 2.4
2
+ Name: archgraph-mcp
3
+ Version: 1.0.0
4
+ Summary: MCP server that builds a knowledge graph of a software codebase
5
+ Requires-Python: >=3.12
6
+ License-File: LICENSE
7
+ Requires-Dist: pydantic>=2.13.4
8
+ Requires-Dist: networkx>=3.6.1
9
+ Requires-Dist: mcp<2.0,>=1.28.1
10
+ Requires-Dist: uvicorn>=0.51.0
11
+ Requires-Dist: starlette>=1.3.1
12
+ Requires-Dist: tree-sitter>=0.26.0
13
+ Requires-Dist: tree-sitter-typescript>=0.23.2
14
+ Requires-Dist: tree-sitter-java>=0.23.5
15
+ Requires-Dist: tree-sitter-kotlin>=1.1.0
16
+ Requires-Dist: kuzu>=0.11.3
17
+ Provides-Extra: semantic
18
+ Requires-Dist: numpy>=2.5.1; extra == "semantic"
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest>=9.1.1; extra == "dev"
21
+ Requires-Dist: pytest-asyncio>=1.4.0; extra == "dev"
22
+ Requires-Dist: ruff>=0.15.22; extra == "dev"
23
+ Requires-Dist: mypy>=2.3.0; extra == "dev"
24
+ Requires-Dist: types-networkx>=3.6.1.20260624; extra == "dev"
25
+ Requires-Dist: mdformat>=1.0; extra == "dev"
26
+ Requires-Dist: mdformat-gfm>=1.0; extra == "dev"
27
+ Dynamic: license-file
@@ -0,0 +1,394 @@
1
+ # ArchGraph MCP
2
+
3
+ [![Tests](https://github.com/mustafa-zidan/archgraph-mcp/actions/workflows/test.yml/badge.svg)](https://github.com/mustafa-zidan/archgraph-mcp/actions/workflows/test.yml)
4
+ [![PyPI version](https://img.shields.io/pypi/v/archgraph-mcp.svg)](https://pypi.org/project/archgraph-mcp/)
5
+ [![Python versions](https://img.shields.io/pypi/pyversions/archgraph-mcp.svg)](https://pypi.org/project/archgraph-mcp/)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
+
8
+ ArchGraph MCP turns a repository into a queryable graph. It parses TypeScript, Java, and Kotlin source with
9
+ [Tree-sitter](https://tree-sitter.github.io/), builds a directed graph of files, symbols, and dependencies, and exposes
10
+ that graph to AI coding agents over the [Model Context Protocol](https://modelcontextprotocol.io/). Instead of grepping
11
+ for call sites, an agent can ask what a function depends on, what breaks if it changes, or how two nodes connect.
12
+
13
+ ## How a repository becomes a queryable graph
14
+
15
+ ```
16
+ Repository
17
+
18
+ File Scanner (lazy, generator-based)
19
+
20
+ Parser Layer (Tree-sitter: TypeScript, Java, Kotlin)
21
+
22
+ Graph Builder (NetworkX DiGraph)
23
+
24
+ Kuzu Storage (embedded graph DB + full-text search)
25
+
26
+ Query Engine (BFS, shortest path, impact analysis)
27
+
28
+ MCP Server (FastMCP: stdio, sse, or streamable-http transport)
29
+
30
+ AI Agent (Cursor, Windsurf, Claude Code, etc.)
31
+ ```
32
+
33
+ The graph itself lives in **NetworkX** at query time; traversals (BFS, shortest path, impact analysis) run in memory
34
+ against that structure. **Kuzu**'s job is persistence and lexical search: it stores nodes and edges across restarts and
35
+ powers BM25-style `search_nodes`, falling back to substring matching when full-text search finds nothing. Semantic
36
+ search is a separate, optional layer: embedding vectors live in NumPy files next to the Kuzu path rather than inside the
37
+ graph database itself.
38
+
39
+ ## Documentation
40
+
41
+ This README covers installation, usage, and the reference tables. Three guides go deeper:
42
+
43
+ - [Setup and MCP](docs/setup-and-mcp.md): install, first-time analyze, environment variables, stdio vs HTTP, Claude
44
+ Desktop, Cursor, VS Code, remote URLs, Docker, troubleshooting.
45
+ - [Local build and semantic](docs/local-build-and-semantic.md): developing from a clone, `analyze --semantic-index`,
46
+ embedding backends, and serving with the vector index.
47
+ - [Release cycle](docs/release-cycle.md): versioning and PyPI releases for maintainers.
48
+
49
+ ## Installing it
50
+
51
+ `uvx archgraph-mcp` works once the package is on PyPI. Until the first release ships, install from a clone.
52
+
53
+ ### From PyPI, with uvx
54
+
55
+ [`uvx`](https://docs.astral.sh/uv/guides/tools/) runs the published tool in an isolated environment, no global install
56
+ needed:
57
+
58
+ ```bash
59
+ uvx archgraph-mcp --help
60
+ ```
61
+
62
+ The optional **`[semantic]`** extra pulls in NumPy for `search_nodes_semantic` and the vector index. Pass it with
63
+ `--with` so the tool environment includes it:
64
+
65
+ ```bash
66
+ uvx --with "archgraph-mcp[semantic]" archgraph-mcp --help
67
+ ```
68
+
69
+ ### From a git clone
70
+
71
+ ```bash
72
+ git clone https://github.com/mustafa-zidan/archgraph-mcp.git
73
+ cd archgraph-mcp
74
+ uv sync --extra dev --extra semantic
75
+ uv run archgraph-mcp --help
76
+ ```
77
+
78
+ Drop `--extra semantic` if you don't need vector search; the core graph and full-text search work without it.
79
+
80
+ ## Analyzing and serving a repository
81
+
82
+ Examples below use `uvx` (PyPI). From a clone, replace `uvx …` with `uv run …`.
83
+
84
+ ### Analyze
85
+
86
+ ```bash
87
+ uvx archgraph-mcp analyze ./your-repo
88
+ ```
89
+
90
+ This scans the repo, parses it, and writes a Kuzu database (`archgraph.kuzu` by default). Add `--semantic-index` to also
91
+ build the vector index, which needs `[semantic]` in the environment:
92
+
93
+ ```bash
94
+ uvx --with "archgraph-mcp[semantic]" archgraph-mcp analyze ./your-repo --semantic-index
95
+ ```
96
+
97
+ ### Serve over stdio (local)
98
+
99
+ Most desktop agents spawn the process and talk over stdin/stdout:
100
+
101
+ ```bash
102
+ uvx archgraph-mcp serve ./your-repo
103
+ ```
104
+
105
+ With semantic tooling available to the server process:
106
+
107
+ ```bash
108
+ uvx --with "archgraph-mcp[semantic]" archgraph-mcp serve ./your-repo
109
+ ```
110
+
111
+ ### Serve over HTTP (remote)
112
+
113
+ ```bash
114
+ uvx archgraph-mcp serve ./your-repo --transport streamable-http --port 3847
115
+ ```
116
+
117
+ ### Graph viewer (HTTP transports only)
118
+
119
+ `--graph-ui` (or `GRAPH_UI=1`) exposes a [vis-network](https://visjs.github.io/vis-network/docs/network/) view at
120
+ `/graph` and raw JSON at `/api/graph` (optional `limit` query param, default `500`, caps node count for responsiveness).
121
+ It's ignored under `stdio`, since there's no HTTP server to attach it to.
122
+
123
+ ```bash
124
+ uvx archgraph-mcp serve ./your-repo --transport streamable-http --port 3847 --graph-ui
125
+ ```
126
+
127
+ ## Wiring it into an MCP client
128
+
129
+ Full walkthroughs for Claude Desktop, Cursor, VS Code, and remote URLs are in
130
+ [docs/setup-and-mcp.md](docs/setup-and-mcp.md). Quick reference below; it requires `uv` on `PATH` so `uvx` resolves.
131
+
132
+ **Core** (lexical `search_nodes` only):
133
+
134
+ ```json
135
+ {
136
+ "mcpServers": {
137
+ "archgraph": {
138
+ "command": "uvx",
139
+ "args": [
140
+ "archgraph-mcp",
141
+ "serve",
142
+ "/absolute/path/to/your/repo"
143
+ ]
144
+ }
145
+ }
146
+ }
147
+ ```
148
+
149
+ **With `[semantic]`** (NumPy + `search_nodes_semantic`, once an index exists):
150
+
151
+ ```json
152
+ {
153
+ "mcpServers": {
154
+ "archgraph": {
155
+ "command": "uvx",
156
+ "args": [
157
+ "--with",
158
+ "archgraph-mcp[semantic]",
159
+ "archgraph-mcp",
160
+ "serve",
161
+ "/absolute/path/to/your/repo"
162
+ ]
163
+ }
164
+ }
165
+ }
166
+ ```
167
+
168
+ **From a git clone** (before a PyPI release, or for development):
169
+
170
+ ```json
171
+ {
172
+ "mcpServers": {
173
+ "archgraph": {
174
+ "command": "uv",
175
+ "args": [
176
+ "run",
177
+ "--directory",
178
+ "/absolute/path/to/archgraph-mcp",
179
+ "archgraph-mcp",
180
+ "serve",
181
+ "/absolute/path/to/your/repo"
182
+ ]
183
+ }
184
+ }
185
+ }
186
+ ```
187
+
188
+ Run `uv sync --extra dev --extra semantic` in that clone before starting the MCP client.
189
+
190
+ Optional env, e.g. a custom Kuzu path:
191
+
192
+ ```json
193
+ {
194
+ "mcpServers": {
195
+ "archgraph": {
196
+ "command": "uvx",
197
+ "args": [
198
+ "archgraph-mcp",
199
+ "serve",
200
+ "/path/to/repo"
201
+ ],
202
+ "env": {
203
+ "ARCHGRAPH_STORE": "/path/to/repo/.archgraph/archgraph.kuzu"
204
+ }
205
+ }
206
+ }
207
+ }
208
+ ```
209
+
210
+ **Remote server** (streamable-http / SSE):
211
+
212
+ ```json
213
+ {
214
+ "mcpServers": {
215
+ "archgraph": {
216
+ "url": "http://your-server:3847/mcp"
217
+ }
218
+ }
219
+ }
220
+ ```
221
+
222
+ Start the process itself with `uvx archgraph-mcp serve /repo --transport streamable-http --port 3847` (Docker
223
+ instructions below).
224
+
225
+ ## The tools it exposes
226
+
227
+ | Tool | Description |
228
+ | ----------------------- | ------------------------------------------------- |
229
+ | `search_nodes` | Lexical search (FTS + substring fallback) by type |
230
+ | `search_nodes_semantic` | Cosine similarity (requires `[semantic]` + index) |
231
+ | `trace_dependencies` | What does this node depend on? |
232
+ | `trace_dependents` | What depends on this node? |
233
+ | `impact_analysis` | What breaks if this node changes? |
234
+ | `trace_path` | Shortest path between two nodes |
235
+ | `architecture_summary` | High-level graph summary |
236
+
237
+ Node ids follow a `type:identifier` shape, e.g. `function:auth.loginUser` or `file:src/auth.ts`. Run `search_nodes`
238
+ first if you don't know the exact id.
239
+
240
+ ```
241
+ search_nodes(query="login", node_type="function")
242
+ impact_analysis(node_id="function:auth.loginUser")
243
+ trace_path(source_id="file:src/auth.ts", target_id="database:users")
244
+ architecture_summary()
245
+ ```
246
+
247
+ ## Semantic search
248
+
249
+ Lexical search (`search_nodes`) matches names and text. Semantic search (`search_nodes_semantic`) matches meaning, at
250
+ the cost of an embedding backend and a build step.
251
+
252
+ 1. Install `[semantic]` into the tool environment:
253
+ `uvx --with "archgraph-mcp[semantic]" archgraph-mcp analyze ./repo --semantic-index` (or `uv sync --extra semantic`
254
+ from a clone).
255
+ 2. Pick a backend via `ARCHGRAPH_EMBED_BACKEND`:
256
+ - `openai` (default): `POST {OPENAI_BASE_URL}/v1/embeddings`. Works against LM Studio, Ollama's OpenAI-compatible
257
+ mode, or OpenAI itself.
258
+ - `local`: in-process models via `sentence-transformers`, installed separately (
259
+ `pip install sentence-transformers`).
260
+ 3. Build the index during analyze, with the flag or the env var: `archgraph-mcp analyze ./repo --semantic-index` or
261
+ `ARCHGRAPH_BUILD_SEMANTIC_INDEX=1`. This writes `archgraph.vectors.npz` and `archgraph.embeddings.json` next to the
262
+ Kuzu file (`--store` / `ARCHGRAPH_STORE`).
263
+
264
+ | Variable | Purpose |
265
+ | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
266
+ | `ARCHGRAPH_EMBED_BACKEND` | `openai` or `local` |
267
+ | `ARCHGRAPH_EMBED_BATCH_SIZE` | OpenAI HTTP backend: inputs per request (default `64`). If the server returns fewer vectors than inputs, the client retries one string per request automatically; set `1` to skip the slow failed-batch attempt. |
268
+ | `OPENAI_BASE_URL` | e.g. `http://127.0.0.1:1234/v1` for LM Studio |
269
+ | `OPENAI_API_KEY` | Bearer token (dummy value is fine if the server ignores it) |
270
+ | `OPENAI_EMBEDDING_MODEL` | Model id for `/v1/embeddings` |
271
+ | `ARCHGRAPH_LOCAL_EMBED_MODEL` | Sentence-transformers model id when backend is `local` |
272
+
273
+ The index build and the query-time call must agree on backend and model; a mismatch produces vectors that don't line up,
274
+ not an error.
275
+
276
+ ## Supported languages
277
+
278
+ - TypeScript / TSX
279
+ - Java
280
+ - Kotlin (`.kt`, `.kts`)
281
+
282
+ ## Version support
283
+
284
+ Requires Python 3.12+ (`requires-python` in [`pyproject.toml`](pyproject.toml)). CI
285
+ ([`.github/workflows/test.yml`](.github/workflows/test.yml)) runs this matrix on every push:
286
+
287
+ | OS | 3.12 | 3.13 | 3.14 |
288
+ | ------- | ---- | ---- | ---------------------- |
289
+ | Linux | ✅ | ✅ | ✅ |
290
+ | macOS | ✅ | ✅ | ✅ (built from source) |
291
+ | Windows | ✅ | ✅ | ❌ see note below |
292
+
293
+ Windows + Python 3.14 is excluded from CI. [`kuzu`](https://pypi.org/project/kuzu/#files) 0.11.3 ships a `cp314` wheel
294
+ for Linux but not for Windows or macOS, so both fall back to a source build. macOS's build succeeds because Xcode's
295
+ command line tools provide `make`; the Windows runner has no such toolchain, so the same fallback fails there. It's an
296
+ upstream packaging gap, not something this project controls. Docker sidesteps it entirely, since the container is
297
+ Linux-based regardless of host OS.
298
+
299
+ ## Running it as a service
300
+
301
+ ### Docker
302
+
303
+ ```bash
304
+ docker build -t archgraph-mcp .
305
+ docker run -p 3847:3847 -v /path/to/repo:/repo archgraph-mcp
306
+ ```
307
+
308
+ ### Railway
309
+
310
+ 1. Connect the GitHub repo at [railway.app](https://railway.app).
311
+ 2. Set the environment variable `REPO_PATH=/repo`.
312
+ 3. Deploy; Railway picks up `railway.json` automatically.
313
+
314
+ ### Fly.io
315
+
316
+ ```bash
317
+ fly launch
318
+ fly deploy
319
+ ```
320
+
321
+ ## Environment variables
322
+
323
+ | Variable | Default | Description |
324
+ | -------------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------- |
325
+ | `REPO_PATH` | `.` | Path to the repository to analyze |
326
+ | `ARCHGRAPH_STORE` | `archgraph.kuzu` | Kuzu database path (overrides the default when the CLI does not pass `--store`) |
327
+ | `PORT` | `3847` | Port for SSE transport |
328
+ | `MCP_TRANSPORT` | `stdio` | Transport mode: `stdio`, `sse`, or `streamable-http` |
329
+ | `GRAPH_UI` | unset | Set to `1` / `true` to enable `/graph` and `/api/graph` (same as `--graph-ui`; HTTP transports only) |
330
+ | `ARCHGRAPH_BUILD_SEMANTIC_INDEX` | unset | Set to `1` / `true` to build the vector index when serving triggers a full analyze (optional) |
331
+
332
+ ## Developing on it
333
+
334
+ ```bash
335
+ uv sync --extra dev
336
+ # or: pip install -e ".[dev]"
337
+ ```
338
+
339
+ Lint and format:
340
+
341
+ ```bash
342
+ ruff check src tests
343
+ ruff format src tests
344
+ ```
345
+
346
+ Markdown (see [`.mdformat.toml`](.mdformat.toml); [GFM](https://github.github.com/gfm/) tables and wrapping):
347
+
348
+ ```bash
349
+ mdformat README.md CHANGELOG.md docs/
350
+ mdformat --check README.md CHANGELOG.md docs/
351
+ ```
352
+
353
+ Static typing:
354
+
355
+ ```bash
356
+ mypy src
357
+ ```
358
+
359
+ Tests:
360
+
361
+ ```bash
362
+ pytest tests/ -v
363
+ ```
364
+
365
+ Optional [pre-commit](https://pre-commit.com/) hooks run Ruff lint and format on commit:
366
+
367
+ ```bash
368
+ pip install pre-commit
369
+ pre-commit install
370
+ ```
371
+
372
+ ## Releasing to PyPI
373
+
374
+ [`.github/workflows/test.yml`](.github/workflows/test.yml) runs on every push and PR to `main`, `master`, or `develop`:
375
+ `uv sync --extra dev`, Ruff, mdformat, mypy, and pytest, across Ubuntu, macOS, and Windows on Python 3.12, 3.13, and
376
+ 3.14.
377
+
378
+ [`.github/workflows/release.yml`](.github/workflows/release.yml) is manual (`workflow_dispatch`) and publishes to
379
+ [PyPI](https://pypi.org/p/archgraph-mcp) via [trusted publishing](https://docs.pypi.org/trusted-publishers/) (OIDC, no
380
+ long-lived token). To cut a release:
381
+
382
+ 1. Bump `version` in [`pyproject.toml`](pyproject.toml) and add a matching section to [`CHANGELOG.md`](CHANGELOG.md),
383
+ then merge to the default branch.
384
+ 2. One-time setup: on PyPI, add a trusted publisher for this repo (workflow `release.yml`, environment `pypi`); on
385
+ GitHub, create an environment named `pypi`.
386
+ 3. Run **Actions → Release → Run workflow**, entering the same version string as in `pyproject.toml`.
387
+
388
+ The workflow tags `vX.Y.Z`, builds with `uv build`, publishes to PyPI, signs the artifacts with Sigstore, and creates a
389
+ GitHub Release with notes pulled from the changelog. Full maintainer guide:
390
+ [docs/release-cycle.md](docs/release-cycle.md).
391
+
392
+ ## License
393
+
394
+ MIT, see [LICENSE](LICENSE).
@@ -0,0 +1,79 @@
1
+ [build-system]
2
+ requires = ["setuptools>=80.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "archgraph-mcp"
7
+ version = "1.0.0"
8
+ description = "MCP server that builds a knowledge graph of a software codebase"
9
+ requires-python = ">=3.12"
10
+ dependencies = [
11
+ "pydantic>=2.13.4",
12
+ "networkx>=3.6.1",
13
+ "mcp>=1.28.1,<2.0",
14
+ "uvicorn>=0.51.0",
15
+ "starlette>=1.3.1",
16
+ "tree-sitter>=0.26.0",
17
+ "tree-sitter-typescript>=0.23.2",
18
+ "tree-sitter-java>=0.23.5",
19
+ "tree-sitter-kotlin>=1.1.0",
20
+ "kuzu>=0.11.3",
21
+ ]
22
+
23
+ [project.optional-dependencies]
24
+ semantic = [
25
+ "numpy>=2.5.1",
26
+ ]
27
+ dev = [
28
+ "pytest>=9.1.1",
29
+ "pytest-asyncio>=1.4.0",
30
+ "ruff>=0.15.22",
31
+ "mypy>=2.3.0",
32
+ "types-networkx>=3.6.1.20260624",
33
+ "mdformat>=1.0",
34
+ "mdformat-gfm>=1.0",
35
+ ]
36
+
37
+ [project.scripts]
38
+ archgraph-mcp = "archgraph_mcp.__main__:main"
39
+
40
+ [tool.setuptools.packages.find]
41
+ where = ["src"]
42
+
43
+ [tool.pytest.ini_options]
44
+ pythonpath = ["src"]
45
+
46
+ [tool.ruff]
47
+ target-version = "py312"
48
+ line-length = 120
49
+ src = ["src", "tests"]
50
+
51
+ [tool.ruff.lint]
52
+ select = ["E", "F", "I", "UP", "B"]
53
+
54
+ [tool.ruff.lint.isort]
55
+ known-first-party = ["archgraph_mcp"]
56
+
57
+ [tool.ruff.format]
58
+ quote-style = "double"
59
+
60
+ [tool.mypy]
61
+ python_version = "3.12"
62
+ mypy_path = "src"
63
+ packages = ["archgraph_mcp"]
64
+ warn_return_any = false
65
+ warn_unused_configs = true
66
+ disallow_untyped_defs = false
67
+ check_untyped_defs = true
68
+
69
+ [[tool.mypy.overrides]]
70
+ module = [
71
+ "tree_sitter.*",
72
+ "tree_sitter_typescript.*",
73
+ "tree_sitter_java.*",
74
+ "tree_sitter_kotlin.*",
75
+ "kuzu.*",
76
+ "numpy.*",
77
+ "sentence_transformers.*",
78
+ ]
79
+ ignore_missing_imports = true
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,3 @@
1
+ """ArchGraph MCP — codebase knowledge graph server."""
2
+
3
+ __version__ = "0.1.0"
@@ -0,0 +1,144 @@
1
+ """CLI entry-point for ArchGraph MCP.
2
+
3
+ Usage:
4
+ python -m archgraph_mcp analyze ./my_repo
5
+ python -m archgraph_mcp serve ./my_repo
6
+ python -m archgraph_mcp serve ./my_repo --transport sse --port 3847
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import json
13
+ import logging
14
+ import os
15
+ from pathlib import Path
16
+ from typing import Literal, cast
17
+
18
+ from archgraph_mcp.graph.builder import GraphBuilder
19
+ from archgraph_mcp.graph.query_engine import QueryEngine
20
+ from archgraph_mcp.logging_config import setup_logging
21
+ from archgraph_mcp.storage.kuzu_store import KuzuStore
22
+
23
+
24
+ def _default_store_path() -> str:
25
+ return os.environ.get("ARCHGRAPH_STORE") or "archgraph.kuzu"
26
+
27
+
28
+ def main(argv: list[str] | None = None) -> None:
29
+ setup_logging()
30
+ parser = argparse.ArgumentParser(
31
+ prog="archgraph-mcp",
32
+ description="Build and query a knowledge graph of your codebase.",
33
+ )
34
+ sub = parser.add_subparsers(dest="command", required=True)
35
+
36
+ # ---- analyze ----
37
+ p_analyze = sub.add_parser("analyze", help="Analyze a repository and print summary")
38
+ p_analyze.add_argument(
39
+ "repo", type=Path, nargs="?", default=Path(os.environ.get("REPO_PATH", ".")), help="Path to the repository root"
40
+ )
41
+ p_analyze.add_argument(
42
+ "--store",
43
+ type=str,
44
+ default=_default_store_path(),
45
+ help="Kuzu database path (default: archgraph.kuzu or ARCHGRAPH_STORE)",
46
+ )
47
+ p_analyze.add_argument(
48
+ "--semantic-index",
49
+ action="store_true",
50
+ help="Build embedding vector index (requires pip install archgraph-mcp[semantic])",
51
+ )
52
+
53
+ # ---- serve ----
54
+ p_serve = sub.add_parser("serve", help="Start the MCP server")
55
+ p_serve.add_argument(
56
+ "repo", type=Path, nargs="?", default=Path(os.environ.get("REPO_PATH", ".")), help="Path to the repository root"
57
+ )
58
+ p_serve.add_argument(
59
+ "--store",
60
+ type=str,
61
+ default=_default_store_path(),
62
+ help="Kuzu database path (default: archgraph.kuzu or ARCHGRAPH_STORE)",
63
+ )
64
+ p_serve.add_argument(
65
+ "--transport",
66
+ type=str,
67
+ default=os.environ.get("MCP_TRANSPORT", "stdio"),
68
+ choices=["stdio", "sse", "streamable-http"],
69
+ help="MCP transport: stdio (local), sse, or streamable-http (remote)",
70
+ )
71
+ p_serve.add_argument(
72
+ "--port",
73
+ type=int,
74
+ default=int(os.environ.get("PORT", "3847")),
75
+ help="Port for HTTP transports (default 3847, or PORT env)",
76
+ )
77
+ p_serve.add_argument(
78
+ "--graph-ui",
79
+ action="store_true",
80
+ help="Expose GET /graph and /api/graph (HTTP transports only; not stdio)",
81
+ )
82
+
83
+ args = parser.parse_args(argv)
84
+
85
+ if args.command == "analyze":
86
+ _run_analyze(args.repo, args.store, semantic_index=args.semantic_index)
87
+ elif args.command == "serve":
88
+ graph_ui_flag = args.graph_ui or os.environ.get("GRAPH_UI", "").strip().lower() in (
89
+ "1",
90
+ "true",
91
+ "yes",
92
+ )
93
+ _run_serve(args.repo, args.store, args.transport, args.port, graph_ui=graph_ui_flag)
94
+
95
+
96
+ def _run_analyze(repo: Path, store_path: str, *, semantic_index: bool = False) -> None:
97
+ if semantic_index:
98
+ os.environ["ARCHGRAPH_BUILD_SEMANTIC_INDEX"] = "1"
99
+
100
+ builder = GraphBuilder()
101
+ builder.build_from_repository(repo.resolve())
102
+
103
+ resolved = str(Path(store_path).resolve())
104
+ store = KuzuStore(resolved)
105
+ store.save_graph(builder.all_nodes(), builder.all_edges())
106
+
107
+ from archgraph_mcp.semantic.build import maybe_build_semantic_index
108
+
109
+ maybe_build_semantic_index(resolved, builder.all_nodes())
110
+
111
+ engine = QueryEngine(builder.graph, builder._node_index, fts_store=store)
112
+ summary = engine.architecture_summary()
113
+ store.close()
114
+ print(json.dumps(summary.model_dump(), indent=2))
115
+
116
+
117
+ def _run_serve(
118
+ repo: Path,
119
+ store_path: str,
120
+ transport: str,
121
+ port: int,
122
+ *,
123
+ graph_ui: bool = False,
124
+ ) -> None:
125
+ # FastMCP binds ``self.settings.port`` from values captured when ``mcp`` is constructed
126
+ # (import time). Set these *before* importing ``mcp_server`` so ``--port`` is honored.
127
+ os.environ["PORT"] = str(port)
128
+ os.environ["FASTMCP_PORT"] = str(port)
129
+
130
+ from archgraph_mcp.server.mcp_server import initialize, mcp
131
+
132
+ log = logging.getLogger("archgraph_mcp")
133
+ graph_ui_effective = graph_ui and transport != "stdio"
134
+ if graph_ui and transport == "stdio":
135
+ log.warning(
136
+ "--graph-ui is ignored for stdio transport (no HTTP server). "
137
+ "Use --transport sse or streamable-http to enable /graph.",
138
+ )
139
+
140
+ # Build or load the graph
141
+ initialize(str(repo), store_path, graph_ui=graph_ui_effective)
142
+
143
+ # Let FastMCP handle server startup
144
+ mcp.run(transport=cast(Literal["stdio", "sse", "streamable-http"], transport))