context-mcp-server 1.0.7 → 1.1.0

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.
package/README.md CHANGED
@@ -25,8 +25,8 @@ This gets worse as projects grow — reading 20 files to answer "what calls this
25
25
 
26
26
  ## What It Solves
27
27
 
28
- - **Persistent memory** — decisions, bugs, notes, and architecture saved across sessions, loaded automatically at conversation start
29
- - **Shared store** — `~/.context-mcp/` is one place on your machine; all AI tools read and write it
28
+ - **Persistent memory** — decisions, bugs, notes, and config saved across sessions, loaded automatically at conversation start
29
+ - **Shared store** — `~/.context-mcp/projects/<name>/` per-project on your machine; all AI tools read and write it
30
30
  - **ContextGraph** — build a knowledge graph of your codebase once, answer structural questions in ~500 tokens instead of ~50,000
31
31
 
32
32
  Real measured reduction on this project: **162× fewer tokens**, **99.38% reduction** per conversation.
@@ -95,10 +95,10 @@ ctx online --port 3200 # different port
95
95
  Both `ctx` and `context` are aliases for the same CLI.
96
96
 
97
97
  ```bash
98
- ctx # interactive mode (UI — no "ctx" prefix inside)
98
+ ctx # interactive mode (UI)
99
99
 
100
100
  # Context
101
- ctx list [project] # list entries, discussions, graphs
101
+ ctx list [project] # list entries by tree: graph / context / summary / plans
102
102
  ctx projects # all projects with graph status + recent entries
103
103
  ctx search "query" # keyword → semantic fallback search
104
104
  ctx add # add entry interactively
@@ -115,7 +115,6 @@ ctx settings # view and edit config interactively
115
115
 
116
116
  # Tools
117
117
  ctx benchmark # token savings report (memory + graph)
118
- ctx discuss [project] # view discussions
119
118
  ```
120
119
 
121
120
  ---
@@ -136,12 +135,12 @@ Any file or git operation outside that directory is rejected. Applies to all HTT
136
135
 
137
136
  ### Memory
138
137
 
139
- - `context.resume` — loads recent entries, discussions, and graph status; registers `rootPath` for sandboxing
140
- - `context.save` — store decisions, bugs, notes, architecture with type tags
141
- - `context.get` / `context.update` / `context.delete` — full CRUD
138
+ - `context.resume` — loads recent entries, active plans, and graph status; registers `rootPath` for sandboxing
139
+ - `context.save` — store context with 4 types: `decision`, `bug`, `note`, `config`
140
+ - `context.get` / `context.update` / `context.delete` — full CRUD, single or batch
142
141
  - `search` — keyword-first, semantic fallback
143
- - `discussion` — threaded plans with steps and cross-session continuity
144
- - Auto-deduplication on save; auto-compact at 20 entries
142
+ - `plan` — auto-triggered when AI makes any plan; saves a markdown summary to a `planDir` you specify
143
+ - Auto-deduplication on save; auto-compact at 20 entries → stored in `summary.json`
145
144
 
146
145
  ### ContextGraph
147
146
 
@@ -153,7 +152,7 @@ Any file or git operation outside that directory is rejected. Applies to all HTT
153
152
  codegraph_build(path)
154
153
  ```
155
154
 
156
- Parses codebase via tree-sitter AST (16 languages, regex fallback). Extracts functions, classes, imports, call edges. Saved to `~/.context-mcp/`.
155
+ Parses codebase via tree-sitter AST (16 languages, regex fallback). Extracts functions, classes, imports, call edges. Build metadata saved to `~/.context-mcp/projects/<name>/graph.json`.
157
156
 
158
157
  **Step 2 — Query** (instant, forever):
159
158
 
@@ -237,6 +237,49 @@ def _general_search(matched: list, nodes: list, edges: list) -> dict:
237
237
  }
238
238
 
239
239
 
240
+ def module_map(graph_dict: dict, limit: int = 100) -> dict:
241
+ """
242
+ Return a module map: for each file, its exported functions/classes and what it imports.
243
+ Output grouped by file, sorted by export count descending.
244
+ """
245
+ nodes = graph_dict.get("nodes", [])
246
+ edges = graph_dict.get("edges", [])
247
+
248
+ files: dict[str, dict] = {}
249
+ for n in nodes:
250
+ f = n.get("file") or "unknown"
251
+ if f not in files:
252
+ files[f] = {"exports": [], "imports": set()}
253
+ node_type = n.get("type", "?")
254
+ if node_type in ("function", "class", "struct"):
255
+ files[f]["exports"].append({"name": n["name"], "type": node_type})
256
+
257
+ node_map = {n["id"]: n for n in nodes}
258
+ for e in edges:
259
+ from_node = node_map.get(e.get("from", ""))
260
+ to_node = node_map.get(e.get("to", ""))
261
+ if not from_node or not to_node:
262
+ continue
263
+ from_file = from_node.get("file") or "unknown"
264
+ to_file = to_node.get("file") or "unknown"
265
+ if from_file != to_file and from_file in files:
266
+ files[from_file]["imports"].add(to_file)
267
+
268
+ result = []
269
+ for fpath, data in sorted(files.items(), key=lambda x: -len(x[1]["exports"])):
270
+ result.append({
271
+ "file": fpath,
272
+ "exports": data["exports"][:30],
273
+ "imports": sorted(data["imports"])[:20],
274
+ })
275
+
276
+ return {
277
+ "files": result[:limit],
278
+ "total_files": len(files),
279
+ "truncated": len(files) > limit,
280
+ }
281
+
282
+
240
283
  def _render_subgraph(result_nodes: list, all_edges: list, token_budget: int) -> str:
241
284
  """
242
285
  Render a subgraph as structured plain text (graphify-style).
@@ -4,10 +4,10 @@ codegraph/server.py — MCP server exposing codebase knowledge graph tools.
4
4
 
5
5
  Tools:
6
6
  codegraph_build — scan project, extract AST nodes, build graph (local only, no API)
7
- codegraph_query — structural question OR single-node lookup (or both); replaces codegraph_explain
7
+ codegraph_query — structural question OR single-node lookup (or both)
8
+ codegraph_arch — module map: every file with its exports and imports
8
9
  codegraph_report — return full CODEGRAPH_REPORT.md
9
10
  codegraph_nodes — list nodes of a given type
10
- codegraph_path — shortest path between two concepts
11
11
  """
12
12
 
13
13
  import asyncio
@@ -25,7 +25,7 @@ from .config import classify_file
25
25
  from .cache import file_hash, set_cached_nodes, save_cache
26
26
  from .extractors.ast_extractor import extract as ast_extract
27
27
  from .graph.builder import build, to_json_dict, save_graph, load_graph
28
- from .graph.query import answer as graph_answer, find_path
28
+ from .graph.query import answer as graph_answer, module_map
29
29
  from .graph.clustering import detect_communities
30
30
  from .report import generate as generate_report
31
31
 
@@ -95,16 +95,19 @@ TOOLS = [
95
95
  },
96
96
  ),
97
97
  Tool(
98
- name="codegraph_path",
99
- description="Find the shortest relationship path between two concepts in the graph.",
98
+ name="codegraph_arch",
99
+ description=(
100
+ "Return a module map: every file with its exported functions/classes and what it imports. "
101
+ "Use this to understand project structure without reading any files. "
102
+ "Call after codegraph_build. Much faster than reading each file."
103
+ ),
100
104
  inputSchema={
101
105
  "type": "object",
102
106
  "properties": {
103
- "path": {"type": "string"},
104
- "from": {"type": "string"},
105
- "to": {"type": "string"},
107
+ "path": {"type": "string", "description": "Project root"},
108
+ "limit": {"type": "integer", "description": "Max files in output (default 100)"},
106
109
  },
107
- "required": ["path", "from", "to"],
110
+ "required": ["path"],
108
111
  },
109
112
  ),
110
113
  ]
@@ -125,12 +128,11 @@ async def call_tool(name: str, arguments: dict):
125
128
 
126
129
 
127
130
  async def _dispatch(name: str, args: dict):
128
- if name == "codegraph_build": return await _build(args)
129
- if name == "codegraph_query": return await _query(args)
130
- if name == "codegraph_explain": return await _query(args)
131
- if name == "codegraph_report": return await _report(args)
132
- if name == "codegraph_nodes": return await _nodes(args)
133
- if name == "codegraph_path": return await _path(args)
131
+ if name == "codegraph_build": return await _build(args)
132
+ if name == "codegraph_query": return await _query(args)
133
+ if name == "codegraph_report": return await _report(args)
134
+ if name == "codegraph_nodes": return await _nodes(args)
135
+ if name == "codegraph_arch": return await _arch(args)
134
136
  raise ValueError(f"Unknown tool: {name}")
135
137
 
136
138
 
@@ -285,11 +287,12 @@ async def _nodes(args: dict) -> dict:
285
287
  return {"type": node_type, "count": len(matched), "nodes": matched[:limit]}
286
288
 
287
289
 
288
- async def _path(args: dict) -> dict:
290
+ async def _arch(args: dict) -> dict:
289
291
  graph_dict = load_graph(args["path"])
290
292
  if not graph_dict:
291
293
  raise ValueError("No graph found. Run codegraph_build first.")
292
- return find_path(args["from"], args["to"], graph_dict)
294
+ limit = args.get("limit", 100)
295
+ return module_map(graph_dict, limit=limit)
293
296
 
294
297
 
295
298
  # ── Entry point ───────────────────────────────────────────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "context-mcp-server",
3
- "version": "1.0.7",
3
+ "version": "1.1.0",
4
4
  "description": "Persistent AI memory + codebase knowledge graph MCP server. Works across Claude Code, Cursor, Gemini CLI, Codex, Windsurf, VS Code Copilot, Claude.ai, and ChatGPT.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,7 +14,7 @@
14
14
  "mcp": "node src/index.js",
15
15
  "mcp-server": "node src/http.js",
16
16
  "cli": "node src/cli.js",
17
- "check": "node --check src/index.js && node --check src/server.js && node --check src/db.js && node --check src/vector.js && node --check src/summarizer.js && node --check src/search.js && node --check src/config.js && node --check src/cli.js && node --check src/http.js && node --check src/tools/context.js && node --check src/tools/search.js && node --check src/tools/discussion.js && node --check src/tools/errorCheck.js && node --check src/tools/fileTools.js && node --check src/tools/gitTools.js && node --check src/tools/codegraph.js && node --check src/hooks/autoLink.js && node --check src/hooks/autoContext.js",
17
+ "check": "node --check src/index.js && node --check src/server.js && node --check src/db.js && node --check src/vector.js && node --check src/summarizer.js && node --check src/search.js && node --check src/config.js && node --check src/cli.js && node --check src/http.js && node --check src/tools/context.js && node --check src/tools/search.js && node --check src/tools/plan.js &&node --check src/tools/errorCheck.js && node --check src/tools/fileTools.js && node --check src/tools/gitTools.js && node --check src/tools/codegraph.js && node --check src/hooks/autoLink.js && node --check src/hooks/autoContext.js",
18
18
  "check-mcp": "npm run check",
19
19
  "test": "node --test",
20
20
  "prepublishOnly": "npm run check"
package/pyproject.toml CHANGED
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "codegraph-mcp"
7
- version = "1.0.7"
7
+ version = "1.1.0"
8
8
  description = "Codebase knowledge graph MCP server — AST extraction, graph queries, community detection"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"