feat(dev-tools): add codebase-memory-mcp local check and docs

Document MIT dev-tool setup for Cursor code intelligence and add an
offline probe for CLI, Cursor MCP config, and Memind index readiness.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-09-10 08:32:56 +08:00
parent 2bab7eb62d
commit 47d0d2accd
3 changed files with 197 additions and 0 deletions
+74
View File
@@ -0,0 +1,74 @@
# codebase-memory-mcp 本地开发
> MIT · 仅本机 Cursor / code 任务开发工具 · **不进入 MeMind 103 运行时**
> 关联:[context-runtime-harness-fusion-plan.md](./context-runtime-harness-fusion-plan.md) §6.6
## 用途边界
| 允许 | 禁止 |
|------|------|
| Cursor 内代码库结构查询、调用链、架构图 | 个人生活流 / h5 用户记忆主检索 |
| 未来挂到 `tool-gateway` 的 aider/openhands 路径 | 替代 Memory V2 / Context Runtime Phase 23 |
| Phase 5 Personal KG **仅借 schema 思想** | 把索引目录提交进 Git |
## 安装(本机一次)
```bash
npm install -g codebase-memory-mcp
codebase-memory-mcp install -y # 写入 ~/.cursor/mcp.json 等,属设计行为
```
安装后 **重启 Cursor**。全局二进制缓存由 npm 包管理;图数据在 CBM 本地 daemon/SQLite**不在** Memind 仓库根目录。
## 首次索引 Memind
**方式 A — Cursor(推荐)**
重启后对 agent 说:**「Index this project」**。
**方式 B — CLI**
```bash
cd /Users/john/Project/Memind
codebase-memory-mcp cli --progress index_repository '{"repo_path":"/Users/john/Project/Memind"}'
```
可选:常驻 daemon 减少 CLI 冷启动:
```bash
codebase-memory-mcp daemon start
```
## 离线验证
```bash
codebase-memory-mcp --version
node scripts/check-codebase-memory-mcp-local.mjs
```
- 仅验证 CLI + Cursor 配置:`MEMIND_CBM_REQUIRE_INDEX=0 node scripts/check-codebase-memory-mcp-local.mjs`
- 完整通过需已索引,输出 **`CODEBASE_MEMORY_MCP_OK`**
## 常用 CLI 探针
```bash
codebase-memory-mcp cli --json list_projects '{}'
codebase-memory-mcp cli --json search_graph '{"name_pattern":".*headroom.*","label":"Function"}'
codebase-memory-mcp cli --json get_architecture '{}'
```
## 与 zvec-grep 的分工
| 工具 | 强项 |
|------|------|
| **codebase-memory-mcp** | AST 知识图:符号、CALLS、路由、Cypher |
| **zvec-grep** | workspace 语义/关键词文件检索(`.zvec-grep/` |
两者互补;Context Runtime 本地清单见 [context-runtime-local-dev.md](./context-runtime-local-dev.md)。
## 卸载 / 更新
```bash
codebase-memory-mcp update
codebase-memory-mcp uninstall -y # 仅移除 agent MCP 配置,不删全局 npm 包
```
+3
View File
@@ -56,6 +56,9 @@ node scripts/check-zvec-workspace-local.mjs
# MCP compactor shadow/active 逻辑
node scripts/check-mcp-compactor-local.mjs
# codebase-memory-mcp CLI + Memind 索引(见 docs/codebase-memory-mcp-local.md
node scripts/check-codebase-memory-mcp-local.mjs
```
## 用户自测清单(有 LLM 配额时)
+120
View File
@@ -0,0 +1,120 @@
#!/usr/bin/env node
/**
* Local codebase-memory-mcp smoke (dev machine only).
*
* Verifies the global CLI is installed and, when MEMIND_CBM_REQUIRE_INDEX=1
* (default), that this repository is indexed.
*/
import { spawnSync } from 'node:child_process';
import { existsSync, readFileSync } from 'node:fs';
import { homedir } from 'node:os';
import { basename, resolve } from 'node:path';
const repoRoot = resolve(process.cwd());
const requireIndex = process.env.MEMIND_CBM_REQUIRE_INDEX !== '0';
const cliName = process.env.MEMIND_CBM_CLI ?? 'codebase-memory-mcp';
function runCli(tool, args = {}) {
const payload = JSON.stringify(args);
const result = spawnSync(cliName, ['cli', '--json', tool, payload], {
encoding: 'utf8',
maxBuffer: 16 * 1024 * 1024,
});
const stdout = (result.stdout ?? '').trim();
const stderr = (result.stderr ?? '').trim();
if (result.error) {
return { ok: false, error: result.error.message, stdout, stderr };
}
if (result.status !== 0) {
return {
ok: false,
error: stderr.split('\n').pop() || `exit ${result.status}`,
stdout,
stderr,
};
}
try {
const parsed = JSON.parse(stdout);
const structured = parsed.structuredContent ?? parsed;
if (structured?.error || parsed.isError) {
return { ok: false, error: structured.error ?? parsed.isError, data: structured, stdout, stderr };
}
return { ok: true, data: structured, stdout, stderr };
} catch {
return { ok: false, error: 'invalid JSON from cli', stdout, stderr };
}
}
const versionResult = spawnSync(cliName, ['--version'], { encoding: 'utf8' });
const version = (versionResult.stdout ?? versionResult.stderr ?? '').trim();
if (versionResult.status !== 0 || !version) {
console.error('CODEBASE_MEMORY_MCP_FAIL: CLI not found');
console.error(' install: npm install -g codebase-memory-mcp && codebase-memory-mcp install -y');
process.exit(1);
}
console.log('CODEBASE_MEMORY_MCP_PROBE:');
console.log(` version=${version}`);
console.log(` repo=${repoRoot}`);
const cursorMcpPath = resolve(homedir(), '.cursor/mcp.json');
if (existsSync(cursorMcpPath)) {
try {
const cursorConfig = JSON.parse(readFileSync(cursorMcpPath, 'utf8'));
const servers = cursorConfig.mcpServers ?? cursorConfig;
const configured = Boolean(servers?.['codebase-memory-mcp']);
console.log(` cursor_mcp_configured=${configured}`);
if (!configured) {
console.warn('CODEBASE_MEMORY_MCP_WARN: ~/.cursor/mcp.json missing codebase-memory-mcp (run: codebase-memory-mcp install -y)');
}
} catch {
console.warn('CODEBASE_MEMORY_MCP_WARN: could not parse ~/.cursor/mcp.json');
}
} else {
console.warn('CODEBASE_MEMORY_MCP_WARN: ~/.cursor/mcp.json not found');
}
const projects = runCli('list_projects', {});
if (!projects.ok) {
console.error(`CODEBASE_MEMORY_MCP_FAIL: list_projects — ${projects.error}`);
process.exit(1);
}
const projectNames = (projects.data.projects ?? []).map((p) => p.name ?? p.project ?? p);
console.log(` indexed_projects=${projectNames.length}`);
const repoName = basename(repoRoot);
const matched = projectNames.find((name) => {
const normalized = String(name).toLowerCase();
return normalized === repoName.toLowerCase() || normalized.includes('memind');
});
if (!matched) {
const hint = 'codebase-memory-mcp cli --progress index_repository \'{"repo_path":"' + repoRoot + '"}\'';
if (requireIndex) {
console.error('CODEBASE_MEMORY_MCP_FAIL: Memind not indexed yet');
console.error(` run: ${hint}`);
console.error(' or in Cursor after restart: "Index this project"');
process.exit(1);
}
console.warn('CODEBASE_MEMORY_MCP_WARN: Memind not indexed (MEMIND_CBM_REQUIRE_INDEX=0)');
console.log('CODEBASE_MEMORY_MCP_CLI_OK');
process.exit(0);
}
const status = runCli('index_status', { project: matched });
if (!status.ok) {
console.error(`CODEBASE_MEMORY_MCP_FAIL: index_status — ${status.error}`);
process.exit(1);
}
const summary = {
project: status.data.project ?? matched,
status: status.data.status ?? null,
nodes: status.data.nodes ?? null,
edges: status.data.edges ?? null,
parse_partial_count: status.data.parse_partial?.count ?? status.data.parse_partial?.files?.length ?? 0,
};
console.log(` project=${summary.project}`);
console.log(` index=${JSON.stringify(summary)}`);
console.log('CODEBASE_MEMORY_MCP_OK');