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:
@@ -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 2–3 |
|
||||
| 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 包
|
||||
```
|
||||
@@ -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 配额时)
|
||||
|
||||
@@ -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');
|
||||
Reference in New Issue
Block a user