Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ This gives you 14 MCP tools, 5 workflow skills that teach Claude *when* and *how

**Other agents** (Cursor, Codex CLI, Gemini CLI, GitHub Copilot) — restart your agent session. The MCP server and skills are already configured.

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.

First query takes ~2s (tsserver warmup). Subsequent queries: 1-60ms.

## Requirements
Expand Down Expand Up @@ -147,6 +149,26 @@ npx typegraph-mcp check

## Manual MCP configuration

### Codex CLI

Register the server with absolute paths:

```bash
codex mcp add typegraph \
--env TYPEGRAPH_PROJECT_ROOT=/absolute/path/to/your-project \
--env TYPEGRAPH_TSCONFIG=/absolute/path/to/your-project/tsconfig.json \
-- npx tsx /absolute/path/to/your-project/plugins/typegraph-mcp/server.ts
```

Verify with:

```bash
codex mcp get typegraph
codex mcp list
```

### JSON-based MCP clients

Add to `.claude/mcp.json` (or `~/.claude/mcp.json` for global):

```json
Expand Down
10 changes: 8 additions & 2 deletions check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import * as fs from "node:fs";
import * as path from "node:path";
import { createRequire } from "node:module";
import { spawn } from "node:child_process";
import { spawn, spawnSync } from "node:child_process";
import { resolveConfig, type TypegraphConfig } from "./config.js";

// ─── Result Type ─────────────────────────────────────────────────────────────
Expand Down Expand Up @@ -186,10 +186,17 @@ export async function main(configOverride?: TypegraphConfig): Promise<CheckResul
// Check for plugin .mcp.json in the tool directory (embedded plugin install)
const pluginMcpPath = path.join(toolDir, ".mcp.json");
const hasPluginMcp = fs.existsSync(pluginMcpPath) && fs.existsSync(path.join(toolDir, ".claude-plugin/plugin.json"));
const codexGet = spawnSync("codex", ["mcp", "get", "typegraph"], {
stdio: "pipe",
encoding: "utf-8",
});
const hasCodexRegistration = codexGet.status === 0;
if (process.env.CLAUDE_PLUGIN_ROOT) {
pass("MCP registered via plugin (CLAUDE_PLUGIN_ROOT set)");
} else if (hasPluginMcp) {
pass("MCP registered via plugin (.mcp.json + .claude-plugin/ present)");
} else if (hasCodexRegistration) {
pass("MCP registered in Codex CLI");
} else {
const mcpJsonPath = path.resolve(projectRoot, ".claude/mcp.json");
if (fs.existsSync(mcpJsonPath)) {
Expand Down Expand Up @@ -450,4 +457,3 @@ export async function main(configOverride?: TypegraphConfig): Promise<CheckResul

return { passed, failed, warned };
}

82 changes: 78 additions & 4 deletions cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

import * as fs from "node:fs";
import * as path from "node:path";
import { execSync } from "node:child_process";
import { execSync, spawnSync } from "node:child_process";
import * as p from "@clack/prompts";
import { resolveConfig } from "./config.js";

Expand Down Expand Up @@ -177,6 +177,21 @@ const MCP_SERVER_ENTRY = {
},
};

function getAbsoluteMcpServerEntry(projectRoot: string): {
command: string;
args: string[];
env: Record<string, string>;
} {
return {
command: "npx",
args: ["tsx", path.resolve(projectRoot, PLUGIN_DIR_NAME, "server.ts")],
env: {
TYPEGRAPH_PROJECT_ROOT: projectRoot,
TYPEGRAPH_TSCONFIG: path.resolve(projectRoot, "tsconfig.json"),
},
};
}

/** Register the typegraph MCP server in agent-specific config files */
function registerMcpServers(projectRoot: string, selectedAgents: AgentId[]): void {
if (selectedAgents.includes("cursor")) {
Expand Down Expand Up @@ -259,6 +274,57 @@ function deregisterJsonMcp(projectRoot: string, configPath: string, rootKey: str

/** Register MCP server in Codex CLI's TOML config */
function registerCodexMcp(projectRoot: string): void {
const absoluteEntry = getAbsoluteMcpServerEntry(projectRoot);

const codexGet = spawnSync("codex", ["mcp", "get", "typegraph"], {
stdio: "pipe",
encoding: "utf-8",
});

if (codexGet.status === 0) {
const output = `${codexGet.stdout ?? ""}${codexGet.stderr ?? ""}`;
const hasServerPath = output.includes(absoluteEntry.args[1]!);
const hasProjectRoot = output.includes("TYPEGRAPH_PROJECT_ROOT=*****") || output.includes(projectRoot);
const hasTsconfig = output.includes("TYPEGRAPH_TSCONFIG=*****") || output.includes(path.resolve(projectRoot, "tsconfig.json"));
if (hasServerPath && hasProjectRoot && hasTsconfig) {
p.log.info("Codex CLI: typegraph MCP server already registered");
return;
}
spawnSync("codex", ["mcp", "remove", "typegraph"], {
stdio: "pipe",
encoding: "utf-8",
});
}

const codexAdd = spawnSync(
"codex",
[
"mcp",
"add",
"typegraph",
"--env",
`TYPEGRAPH_PROJECT_ROOT=${absoluteEntry.env.TYPEGRAPH_PROJECT_ROOT}`,
"--env",
`TYPEGRAPH_TSCONFIG=${absoluteEntry.env.TYPEGRAPH_TSCONFIG}`,
"--",
absoluteEntry.command,
...absoluteEntry.args,
],
{
stdio: "pipe",
encoding: "utf-8",
}
);

if (codexAdd.status === 0) {
p.log.success("Codex CLI: registered typegraph MCP server");
return;
}

p.log.warn(
`Codex CLI registration failed — falling back to ${".codex/config.toml"}`
);

const configPath = ".codex/config.toml";
const fullPath = path.resolve(projectRoot, configPath);
let content = "";
Expand All @@ -275,9 +341,9 @@ function registerCodexMcp(projectRoot: string): void {
const block = [
"",
"[mcp_servers.typegraph]",
'command = "npx"',
'args = ["tsx", "./plugins/typegraph-mcp/server.ts"]',
'env = { TYPEGRAPH_PROJECT_ROOT = ".", TYPEGRAPH_TSCONFIG = "./tsconfig.json" }',
`command = "${absoluteEntry.command}"`,
`args = ["${absoluteEntry.args[0]}", "${absoluteEntry.args[1]}"]`,
`env = { TYPEGRAPH_PROJECT_ROOT = "${absoluteEntry.env.TYPEGRAPH_PROJECT_ROOT}", TYPEGRAPH_TSCONFIG = "${absoluteEntry.env.TYPEGRAPH_TSCONFIG}" }`,
"",
].join("\n");

Expand All @@ -292,6 +358,14 @@ function registerCodexMcp(projectRoot: string): void {

/** Deregister MCP server from Codex CLI's TOML config */
function deregisterCodexMcp(projectRoot: string): void {
const codexRemove = spawnSync("codex", ["mcp", "remove", "typegraph"], {
stdio: "pipe",
encoding: "utf-8",
});
if (codexRemove.status === 0) {
p.log.info("Codex CLI: removed typegraph MCP server");
}

const configPath = ".codex/config.toml";
const fullPath = path.resolve(projectRoot, configPath);
if (!fs.existsSync(fullPath)) return;
Expand Down
44 changes: 44 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"devDependencies": {
"@types/node": "^25.3.0",
"tsup": "^8.5.0",
"tsx": "^4.21.0",
"typescript": "^5.8.0"
}
}