typegraph-mcp 0.9.27 → 0.9.29
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 +22 -0
- package/check.ts +8 -2
- package/cli.ts +78 -4
- package/dist/check.js +8 -1
- package/dist/cli.js +74 -5
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -80,6 +80,8 @@ This gives you 14 MCP tools, 5 workflow skills that teach Claude *when* and *how
|
|
|
80
80
|
|
|
81
81
|
**Other agents** (Cursor, Codex CLI, Gemini CLI, GitHub Copilot) — restart your agent session. The MCP server and skills are already configured.
|
|
82
82
|
|
|
83
|
+
For **Codex CLI**, setup now registers the server with `codex mcp add` using absolute paths so the tools work even when Codex launches from outside your project root.
|
|
84
|
+
|
|
83
85
|
First query takes ~2s (tsserver warmup). Subsequent queries: 1-60ms.
|
|
84
86
|
|
|
85
87
|
## Requirements
|
|
@@ -147,6 +149,26 @@ npx typegraph-mcp check
|
|
|
147
149
|
|
|
148
150
|
## Manual MCP configuration
|
|
149
151
|
|
|
152
|
+
### Codex CLI
|
|
153
|
+
|
|
154
|
+
Register the server with absolute paths:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
codex mcp add typegraph \
|
|
158
|
+
--env TYPEGRAPH_PROJECT_ROOT=/absolute/path/to/your-project \
|
|
159
|
+
--env TYPEGRAPH_TSCONFIG=/absolute/path/to/your-project/tsconfig.json \
|
|
160
|
+
-- npx tsx /absolute/path/to/your-project/plugins/typegraph-mcp/server.ts
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Verify with:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
codex mcp get typegraph
|
|
167
|
+
codex mcp list
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### JSON-based MCP clients
|
|
171
|
+
|
|
150
172
|
Add to `.claude/mcp.json` (or `~/.claude/mcp.json` for global):
|
|
151
173
|
|
|
152
174
|
```json
|
package/check.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import * as fs from "node:fs";
|
|
13
13
|
import * as path from "node:path";
|
|
14
14
|
import { createRequire } from "node:module";
|
|
15
|
-
import { spawn } from "node:child_process";
|
|
15
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
16
16
|
import { resolveConfig, type TypegraphConfig } from "./config.js";
|
|
17
17
|
|
|
18
18
|
// ─── Result Type ─────────────────────────────────────────────────────────────
|
|
@@ -186,10 +186,17 @@ export async function main(configOverride?: TypegraphConfig): Promise<CheckResul
|
|
|
186
186
|
// Check for plugin .mcp.json in the tool directory (embedded plugin install)
|
|
187
187
|
const pluginMcpPath = path.join(toolDir, ".mcp.json");
|
|
188
188
|
const hasPluginMcp = fs.existsSync(pluginMcpPath) && fs.existsSync(path.join(toolDir, ".claude-plugin/plugin.json"));
|
|
189
|
+
const codexGet = spawnSync("codex", ["mcp", "get", "typegraph"], {
|
|
190
|
+
stdio: "pipe",
|
|
191
|
+
encoding: "utf-8",
|
|
192
|
+
});
|
|
193
|
+
const hasCodexRegistration = codexGet.status === 0;
|
|
189
194
|
if (process.env.CLAUDE_PLUGIN_ROOT) {
|
|
190
195
|
pass("MCP registered via plugin (CLAUDE_PLUGIN_ROOT set)");
|
|
191
196
|
} else if (hasPluginMcp) {
|
|
192
197
|
pass("MCP registered via plugin (.mcp.json + .claude-plugin/ present)");
|
|
198
|
+
} else if (hasCodexRegistration) {
|
|
199
|
+
pass("MCP registered in Codex CLI");
|
|
193
200
|
} else {
|
|
194
201
|
const mcpJsonPath = path.resolve(projectRoot, ".claude/mcp.json");
|
|
195
202
|
if (fs.existsSync(mcpJsonPath)) {
|
|
@@ -450,4 +457,3 @@ export async function main(configOverride?: TypegraphConfig): Promise<CheckResul
|
|
|
450
457
|
|
|
451
458
|
return { passed, failed, warned };
|
|
452
459
|
}
|
|
453
|
-
|
package/cli.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
import * as fs from "node:fs";
|
|
17
17
|
import * as path from "node:path";
|
|
18
|
-
import { execSync } from "node:child_process";
|
|
18
|
+
import { execSync, spawnSync } from "node:child_process";
|
|
19
19
|
import * as p from "@clack/prompts";
|
|
20
20
|
import { resolveConfig } from "./config.js";
|
|
21
21
|
|
|
@@ -177,6 +177,21 @@ const MCP_SERVER_ENTRY = {
|
|
|
177
177
|
},
|
|
178
178
|
};
|
|
179
179
|
|
|
180
|
+
function getAbsoluteMcpServerEntry(projectRoot: string): {
|
|
181
|
+
command: string;
|
|
182
|
+
args: string[];
|
|
183
|
+
env: Record<string, string>;
|
|
184
|
+
} {
|
|
185
|
+
return {
|
|
186
|
+
command: "npx",
|
|
187
|
+
args: ["tsx", path.resolve(projectRoot, PLUGIN_DIR_NAME, "server.ts")],
|
|
188
|
+
env: {
|
|
189
|
+
TYPEGRAPH_PROJECT_ROOT: projectRoot,
|
|
190
|
+
TYPEGRAPH_TSCONFIG: path.resolve(projectRoot, "tsconfig.json"),
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
180
195
|
/** Register the typegraph MCP server in agent-specific config files */
|
|
181
196
|
function registerMcpServers(projectRoot: string, selectedAgents: AgentId[]): void {
|
|
182
197
|
if (selectedAgents.includes("cursor")) {
|
|
@@ -259,6 +274,57 @@ function deregisterJsonMcp(projectRoot: string, configPath: string, rootKey: str
|
|
|
259
274
|
|
|
260
275
|
/** Register MCP server in Codex CLI's TOML config */
|
|
261
276
|
function registerCodexMcp(projectRoot: string): void {
|
|
277
|
+
const absoluteEntry = getAbsoluteMcpServerEntry(projectRoot);
|
|
278
|
+
|
|
279
|
+
const codexGet = spawnSync("codex", ["mcp", "get", "typegraph"], {
|
|
280
|
+
stdio: "pipe",
|
|
281
|
+
encoding: "utf-8",
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
if (codexGet.status === 0) {
|
|
285
|
+
const output = `${codexGet.stdout ?? ""}${codexGet.stderr ?? ""}`;
|
|
286
|
+
const hasServerPath = output.includes(absoluteEntry.args[1]!);
|
|
287
|
+
const hasProjectRoot = output.includes("TYPEGRAPH_PROJECT_ROOT=*****") || output.includes(projectRoot);
|
|
288
|
+
const hasTsconfig = output.includes("TYPEGRAPH_TSCONFIG=*****") || output.includes(path.resolve(projectRoot, "tsconfig.json"));
|
|
289
|
+
if (hasServerPath && hasProjectRoot && hasTsconfig) {
|
|
290
|
+
p.log.info("Codex CLI: typegraph MCP server already registered");
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
spawnSync("codex", ["mcp", "remove", "typegraph"], {
|
|
294
|
+
stdio: "pipe",
|
|
295
|
+
encoding: "utf-8",
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const codexAdd = spawnSync(
|
|
300
|
+
"codex",
|
|
301
|
+
[
|
|
302
|
+
"mcp",
|
|
303
|
+
"add",
|
|
304
|
+
"typegraph",
|
|
305
|
+
"--env",
|
|
306
|
+
`TYPEGRAPH_PROJECT_ROOT=${absoluteEntry.env.TYPEGRAPH_PROJECT_ROOT}`,
|
|
307
|
+
"--env",
|
|
308
|
+
`TYPEGRAPH_TSCONFIG=${absoluteEntry.env.TYPEGRAPH_TSCONFIG}`,
|
|
309
|
+
"--",
|
|
310
|
+
absoluteEntry.command,
|
|
311
|
+
...absoluteEntry.args,
|
|
312
|
+
],
|
|
313
|
+
{
|
|
314
|
+
stdio: "pipe",
|
|
315
|
+
encoding: "utf-8",
|
|
316
|
+
}
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
if (codexAdd.status === 0) {
|
|
320
|
+
p.log.success("Codex CLI: registered typegraph MCP server");
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
p.log.warn(
|
|
325
|
+
`Codex CLI registration failed — falling back to ${".codex/config.toml"}`
|
|
326
|
+
);
|
|
327
|
+
|
|
262
328
|
const configPath = ".codex/config.toml";
|
|
263
329
|
const fullPath = path.resolve(projectRoot, configPath);
|
|
264
330
|
let content = "";
|
|
@@ -275,9 +341,9 @@ function registerCodexMcp(projectRoot: string): void {
|
|
|
275
341
|
const block = [
|
|
276
342
|
"",
|
|
277
343
|
"[mcp_servers.typegraph]",
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
344
|
+
`command = "${absoluteEntry.command}"`,
|
|
345
|
+
`args = ["${absoluteEntry.args[0]}", "${absoluteEntry.args[1]}"]`,
|
|
346
|
+
`env = { TYPEGRAPH_PROJECT_ROOT = "${absoluteEntry.env.TYPEGRAPH_PROJECT_ROOT}", TYPEGRAPH_TSCONFIG = "${absoluteEntry.env.TYPEGRAPH_TSCONFIG}" }`,
|
|
281
347
|
"",
|
|
282
348
|
].join("\n");
|
|
283
349
|
|
|
@@ -292,6 +358,14 @@ function registerCodexMcp(projectRoot: string): void {
|
|
|
292
358
|
|
|
293
359
|
/** Deregister MCP server from Codex CLI's TOML config */
|
|
294
360
|
function deregisterCodexMcp(projectRoot: string): void {
|
|
361
|
+
const codexRemove = spawnSync("codex", ["mcp", "remove", "typegraph"], {
|
|
362
|
+
stdio: "pipe",
|
|
363
|
+
encoding: "utf-8",
|
|
364
|
+
});
|
|
365
|
+
if (codexRemove.status === 0) {
|
|
366
|
+
p.log.info("Codex CLI: removed typegraph MCP server");
|
|
367
|
+
}
|
|
368
|
+
|
|
295
369
|
const configPath = ".codex/config.toml";
|
|
296
370
|
const fullPath = path.resolve(projectRoot, configPath);
|
|
297
371
|
if (!fs.existsSync(fullPath)) return;
|
package/dist/check.js
CHANGED
|
@@ -355,7 +355,7 @@ var init_module_graph = __esm({
|
|
|
355
355
|
import * as fs2 from "fs";
|
|
356
356
|
import * as path3 from "path";
|
|
357
357
|
import { createRequire } from "module";
|
|
358
|
-
import { spawn } from "child_process";
|
|
358
|
+
import { spawn, spawnSync } from "child_process";
|
|
359
359
|
|
|
360
360
|
// config.ts
|
|
361
361
|
import * as path from "path";
|
|
@@ -495,10 +495,17 @@ async function main(configOverride) {
|
|
|
495
495
|
}
|
|
496
496
|
const pluginMcpPath = path3.join(toolDir, ".mcp.json");
|
|
497
497
|
const hasPluginMcp = fs2.existsSync(pluginMcpPath) && fs2.existsSync(path3.join(toolDir, ".claude-plugin/plugin.json"));
|
|
498
|
+
const codexGet = spawnSync("codex", ["mcp", "get", "typegraph"], {
|
|
499
|
+
stdio: "pipe",
|
|
500
|
+
encoding: "utf-8"
|
|
501
|
+
});
|
|
502
|
+
const hasCodexRegistration = codexGet.status === 0;
|
|
498
503
|
if (process.env.CLAUDE_PLUGIN_ROOT) {
|
|
499
504
|
pass("MCP registered via plugin (CLAUDE_PLUGIN_ROOT set)");
|
|
500
505
|
} else if (hasPluginMcp) {
|
|
501
506
|
pass("MCP registered via plugin (.mcp.json + .claude-plugin/ present)");
|
|
507
|
+
} else if (hasCodexRegistration) {
|
|
508
|
+
pass("MCP registered in Codex CLI");
|
|
502
509
|
} else {
|
|
503
510
|
const mcpJsonPath = path3.resolve(projectRoot, ".claude/mcp.json");
|
|
504
511
|
if (fs2.existsSync(mcpJsonPath)) {
|
package/dist/cli.js
CHANGED
|
@@ -375,7 +375,7 @@ __export(check_exports, {
|
|
|
375
375
|
import * as fs2 from "fs";
|
|
376
376
|
import * as path3 from "path";
|
|
377
377
|
import { createRequire } from "module";
|
|
378
|
-
import { spawn } from "child_process";
|
|
378
|
+
import { spawn, spawnSync } from "child_process";
|
|
379
379
|
function findFirstTsFile(dir) {
|
|
380
380
|
const skipDirs = /* @__PURE__ */ new Set(["node_modules", "dist", ".git", ".wrangler", "coverage"]);
|
|
381
381
|
try {
|
|
@@ -502,10 +502,17 @@ async function main(configOverride) {
|
|
|
502
502
|
}
|
|
503
503
|
const pluginMcpPath = path3.join(toolDir, ".mcp.json");
|
|
504
504
|
const hasPluginMcp = fs2.existsSync(pluginMcpPath) && fs2.existsSync(path3.join(toolDir, ".claude-plugin/plugin.json"));
|
|
505
|
+
const codexGet = spawnSync("codex", ["mcp", "get", "typegraph"], {
|
|
506
|
+
stdio: "pipe",
|
|
507
|
+
encoding: "utf-8"
|
|
508
|
+
});
|
|
509
|
+
const hasCodexRegistration = codexGet.status === 0;
|
|
505
510
|
if (process.env.CLAUDE_PLUGIN_ROOT) {
|
|
506
511
|
pass("MCP registered via plugin (CLAUDE_PLUGIN_ROOT set)");
|
|
507
512
|
} else if (hasPluginMcp) {
|
|
508
513
|
pass("MCP registered via plugin (.mcp.json + .claude-plugin/ present)");
|
|
514
|
+
} else if (hasCodexRegistration) {
|
|
515
|
+
pass("MCP registered in Codex CLI");
|
|
509
516
|
} else {
|
|
510
517
|
const mcpJsonPath = path3.resolve(projectRoot3, ".claude/mcp.json");
|
|
511
518
|
if (fs2.existsSync(mcpJsonPath)) {
|
|
@@ -2795,7 +2802,7 @@ var init_server = __esm({
|
|
|
2795
2802
|
init_config();
|
|
2796
2803
|
import * as fs8 from "fs";
|
|
2797
2804
|
import * as path9 from "path";
|
|
2798
|
-
import { execSync as execSync2 } from "child_process";
|
|
2805
|
+
import { execSync as execSync2, spawnSync as spawnSync2 } from "child_process";
|
|
2799
2806
|
import * as p from "@clack/prompts";
|
|
2800
2807
|
var AGENT_SNIPPET = `
|
|
2801
2808
|
## TypeScript Navigation (typegraph-mcp)
|
|
@@ -2915,6 +2922,16 @@ var MCP_SERVER_ENTRY = {
|
|
|
2915
2922
|
TYPEGRAPH_TSCONFIG: "./tsconfig.json"
|
|
2916
2923
|
}
|
|
2917
2924
|
};
|
|
2925
|
+
function getAbsoluteMcpServerEntry(projectRoot3) {
|
|
2926
|
+
return {
|
|
2927
|
+
command: "npx",
|
|
2928
|
+
args: ["tsx", path9.resolve(projectRoot3, PLUGIN_DIR_NAME, "server.ts")],
|
|
2929
|
+
env: {
|
|
2930
|
+
TYPEGRAPH_PROJECT_ROOT: projectRoot3,
|
|
2931
|
+
TYPEGRAPH_TSCONFIG: path9.resolve(projectRoot3, "tsconfig.json")
|
|
2932
|
+
}
|
|
2933
|
+
};
|
|
2934
|
+
}
|
|
2918
2935
|
function registerMcpServers(projectRoot3, selectedAgents) {
|
|
2919
2936
|
if (selectedAgents.includes("cursor")) {
|
|
2920
2937
|
registerJsonMcp(projectRoot3, ".cursor/mcp.json", "mcpServers");
|
|
@@ -2977,6 +2994,51 @@ function deregisterJsonMcp(projectRoot3, configPath, rootKey) {
|
|
|
2977
2994
|
}
|
|
2978
2995
|
}
|
|
2979
2996
|
function registerCodexMcp(projectRoot3) {
|
|
2997
|
+
const absoluteEntry = getAbsoluteMcpServerEntry(projectRoot3);
|
|
2998
|
+
const codexGet = spawnSync2("codex", ["mcp", "get", "typegraph"], {
|
|
2999
|
+
stdio: "pipe",
|
|
3000
|
+
encoding: "utf-8"
|
|
3001
|
+
});
|
|
3002
|
+
if (codexGet.status === 0) {
|
|
3003
|
+
const output = `${codexGet.stdout ?? ""}${codexGet.stderr ?? ""}`;
|
|
3004
|
+
const hasServerPath = output.includes(absoluteEntry.args[1]);
|
|
3005
|
+
const hasProjectRoot = output.includes("TYPEGRAPH_PROJECT_ROOT=*****") || output.includes(projectRoot3);
|
|
3006
|
+
const hasTsconfig = output.includes("TYPEGRAPH_TSCONFIG=*****") || output.includes(path9.resolve(projectRoot3, "tsconfig.json"));
|
|
3007
|
+
if (hasServerPath && hasProjectRoot && hasTsconfig) {
|
|
3008
|
+
p.log.info("Codex CLI: typegraph MCP server already registered");
|
|
3009
|
+
return;
|
|
3010
|
+
}
|
|
3011
|
+
spawnSync2("codex", ["mcp", "remove", "typegraph"], {
|
|
3012
|
+
stdio: "pipe",
|
|
3013
|
+
encoding: "utf-8"
|
|
3014
|
+
});
|
|
3015
|
+
}
|
|
3016
|
+
const codexAdd = spawnSync2(
|
|
3017
|
+
"codex",
|
|
3018
|
+
[
|
|
3019
|
+
"mcp",
|
|
3020
|
+
"add",
|
|
3021
|
+
"typegraph",
|
|
3022
|
+
"--env",
|
|
3023
|
+
`TYPEGRAPH_PROJECT_ROOT=${absoluteEntry.env.TYPEGRAPH_PROJECT_ROOT}`,
|
|
3024
|
+
"--env",
|
|
3025
|
+
`TYPEGRAPH_TSCONFIG=${absoluteEntry.env.TYPEGRAPH_TSCONFIG}`,
|
|
3026
|
+
"--",
|
|
3027
|
+
absoluteEntry.command,
|
|
3028
|
+
...absoluteEntry.args
|
|
3029
|
+
],
|
|
3030
|
+
{
|
|
3031
|
+
stdio: "pipe",
|
|
3032
|
+
encoding: "utf-8"
|
|
3033
|
+
}
|
|
3034
|
+
);
|
|
3035
|
+
if (codexAdd.status === 0) {
|
|
3036
|
+
p.log.success("Codex CLI: registered typegraph MCP server");
|
|
3037
|
+
return;
|
|
3038
|
+
}
|
|
3039
|
+
p.log.warn(
|
|
3040
|
+
`Codex CLI registration failed \u2014 falling back to ${".codex/config.toml"}`
|
|
3041
|
+
);
|
|
2980
3042
|
const configPath = ".codex/config.toml";
|
|
2981
3043
|
const fullPath = path9.resolve(projectRoot3, configPath);
|
|
2982
3044
|
let content = "";
|
|
@@ -2990,9 +3052,9 @@ function registerCodexMcp(projectRoot3) {
|
|
|
2990
3052
|
const block = [
|
|
2991
3053
|
"",
|
|
2992
3054
|
"[mcp_servers.typegraph]",
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
3055
|
+
`command = "${absoluteEntry.command}"`,
|
|
3056
|
+
`args = ["${absoluteEntry.args[0]}", "${absoluteEntry.args[1]}"]`,
|
|
3057
|
+
`env = { TYPEGRAPH_PROJECT_ROOT = "${absoluteEntry.env.TYPEGRAPH_PROJECT_ROOT}", TYPEGRAPH_TSCONFIG = "${absoluteEntry.env.TYPEGRAPH_TSCONFIG}" }`,
|
|
2996
3058
|
""
|
|
2997
3059
|
].join("\n");
|
|
2998
3060
|
const dir = path9.dirname(fullPath);
|
|
@@ -3004,6 +3066,13 @@ function registerCodexMcp(projectRoot3) {
|
|
|
3004
3066
|
p.log.success(`${configPath}: registered typegraph MCP server`);
|
|
3005
3067
|
}
|
|
3006
3068
|
function deregisterCodexMcp(projectRoot3) {
|
|
3069
|
+
const codexRemove = spawnSync2("codex", ["mcp", "remove", "typegraph"], {
|
|
3070
|
+
stdio: "pipe",
|
|
3071
|
+
encoding: "utf-8"
|
|
3072
|
+
});
|
|
3073
|
+
if (codexRemove.status === 0) {
|
|
3074
|
+
p.log.info("Codex CLI: removed typegraph MCP server");
|
|
3075
|
+
}
|
|
3007
3076
|
const configPath = ".codex/config.toml";
|
|
3008
3077
|
const fullPath = path9.resolve(projectRoot3, configPath);
|
|
3009
3078
|
if (!fs8.existsSync(fullPath)) return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typegraph-mcp",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.29",
|
|
4
4
|
"description": "Type-aware codebase navigation for AI coding agents — 14 MCP tools powered by tsserver + oxc",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -43,6 +43,7 @@
|
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/node": "^25.3.0",
|
|
45
45
|
"tsup": "^8.5.0",
|
|
46
|
+
"tsx": "^4.21.0",
|
|
46
47
|
"typescript": "^5.8.0"
|
|
47
48
|
}
|
|
48
49
|
}
|