Skip to content

Commit 2ad03d2

Browse files
committed
updates
1 parent 4c983ba commit 2ad03d2

5 files changed

Lines changed: 83 additions & 33 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
**30% fewer tokens • 25% fewer tool calls • 100% local**
88

9+
**Works on Windows, macOS, and Linux**
10+
911
[![npm version](https://img.shields.io/npm/v/@colbymchenry/codegraph.svg)](https://www.npmjs.com/package/@colbymchenry/codegraph)
1012
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
1113
[![Node.js](https://img.shields.io/badge/Node.js-18+-green.svg)](https://nodejs.org/)

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@colbymchenry/codegraph",
3-
"version": "0.4.1",
3+
"version": "0.4.3",
44
"description": "Supercharge Claude Code with semantic code intelligence. 30% fewer tokens, 25% fewer tool calls, 100% local.",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

src/mcp/index.ts

Lines changed: 60 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,33 @@
1515
* ```
1616
*/
1717

18+
import * as path from 'path';
1819
import CodeGraph, { findNearestCodeGraphRoot } from '../index';
1920
import { StdioTransport, JsonRpcRequest, JsonRpcNotification, ErrorCodes } from './transport';
2021
import { tools, ToolHandler } from './tools';
2122
import { initSentry, captureException } from '../sentry';
2223

2324
initSentry({ processName: 'codegraph-mcp' });
2425

26+
/**
27+
* Convert a file:// URI to a filesystem path.
28+
* Handles URL encoding and Windows drive letter paths.
29+
*/
30+
function fileUriToPath(uri: string): string {
31+
try {
32+
const url = new URL(uri);
33+
let filePath = decodeURIComponent(url.pathname);
34+
// On Windows, file:///C:/path produces pathname /C:/path — strip leading /
35+
if (process.platform === 'win32' && /^\/[a-zA-Z]:/.test(filePath)) {
36+
filePath = filePath.slice(1);
37+
}
38+
return path.resolve(filePath);
39+
} catch {
40+
// Fallback for non-standard URIs
41+
return uri.replace(/^file:\/\/\/?/, '');
42+
}
43+
}
44+
2545
/**
2646
* MCP Server Info
2747
*/
@@ -44,13 +64,14 @@ const PROTOCOL_VERSION = '2024-11-05';
4464
export class MCPServer {
4565
private transport: StdioTransport;
4666
private cg: CodeGraph | null = null;
47-
private toolHandler: ToolHandler | null = null;
67+
private toolHandler: ToolHandler;
4868
private projectPath: string | null;
49-
private initError: string | null = null;
5069

5170
constructor(projectPath?: string) {
5271
this.projectPath = projectPath || null;
5372
this.transport = new StdioTransport();
73+
// Create ToolHandler eagerly — cross-project queries work even without a default project
74+
this.toolHandler = new ToolHandler(null);
5475
}
5576

5677
/**
@@ -70,30 +91,53 @@ export class MCPServer {
7091
}
7192

7293
/**
73-
* Initialize CodeGraph for the project
94+
* Try to initialize CodeGraph for the default project.
7495
*
7596
* Walks up parent directories to find the nearest .codegraph/ folder,
7697
* similar to how git finds .git/ directories.
98+
*
99+
* If initialization fails, the error is recorded but the server continues
100+
* to work — cross-project queries and retries on subsequent tool calls
101+
* are still possible.
77102
*/
78-
private async initializeCodeGraph(projectPath: string): Promise<void> {
103+
private async tryInitializeDefault(projectPath: string): Promise<void> {
79104
// Walk up parent directories to find nearest .codegraph/
80105
const resolvedRoot = findNearestCodeGraphRoot(projectPath);
81106

82107
if (!resolvedRoot) {
83108
this.projectPath = projectPath;
84-
this.initError = `CodeGraph not initialized in ${projectPath}. Run 'codegraph init' first.`;
85109
return;
86110
}
87111

88112
this.projectPath = resolvedRoot;
89113

90114
try {
91115
this.cg = await CodeGraph.open(resolvedRoot);
92-
this.toolHandler = new ToolHandler(this.cg);
93-
this.initError = null;
116+
this.toolHandler.setDefaultCodeGraph(this.cg);
94117
} catch (err) {
95118
captureException(err);
96-
this.initError = `Failed to open CodeGraph: ${err instanceof Error ? err.message : String(err)}`;
119+
}
120+
}
121+
122+
/**
123+
* Retry initialization of the default project if it previously failed.
124+
* Called lazily on tool calls that need the default project.
125+
*/
126+
private retryInitIfNeeded(): void {
127+
// Already initialized successfully
128+
if (this.toolHandler.hasDefaultCodeGraph()) return;
129+
// No project path to retry with
130+
if (!this.projectPath) return;
131+
132+
const resolvedRoot = findNearestCodeGraphRoot(this.projectPath);
133+
if (!resolvedRoot) return;
134+
135+
try {
136+
this.cg = CodeGraph.openSync(resolvedRoot);
137+
this.projectPath = resolvedRoot;
138+
this.toolHandler.setDefaultCodeGraph(this.cg);
139+
} catch {
140+
// Still failing — will retry on next tool call
97141
}
98142
}
99143

@@ -102,9 +146,7 @@ export class MCPServer {
102146
*/
103147
stop(): void {
104148
// Close all cached cross-project connections first
105-
if (this.toolHandler) {
106-
this.toolHandler.closeAll();
107-
}
149+
this.toolHandler.closeAll();
108150
// Close the main CodeGraph instance
109151
if (this.cg) {
110152
this.cg.close();
@@ -175,19 +217,18 @@ export class MCPServer {
175217
let projectPath = this.projectPath;
176218

177219
if (params?.rootUri) {
178-
// Convert file:// URI to path
179-
projectPath = params.rootUri.replace(/^file:\/\//, '');
220+
projectPath = fileUriToPath(params.rootUri);
180221
} else if (params?.workspaceFolders?.[0]?.uri) {
181-
projectPath = params.workspaceFolders[0].uri.replace(/^file:\/\//, '');
222+
projectPath = fileUriToPath(params.workspaceFolders[0].uri);
182223
}
183224

184225
// Fall back to current working directory if no path provided
185226
if (!projectPath) {
186227
projectPath = process.cwd();
187228
}
188229

189-
// Initialize CodeGraph if we have a project path
190-
await this.initializeCodeGraph(projectPath);
230+
// Try to initialize the default project (non-fatal if it fails)
231+
await this.tryInitializeDefault(projectPath);
191232

192233
// We accept the client's protocol version but respond with our supported version
193234
this.transport.sendResult(request.id, {
@@ -240,19 +281,9 @@ export class MCPServer {
240281
return;
241282
}
242283

243-
// Execute the tool
244-
if (!this.toolHandler) {
245-
const errorMsg = this.initError ||
246-
(this.projectPath
247-
? `CodeGraph not initialized in ${this.projectPath}. Run 'codegraph init' first.`
248-
: 'No project path provided. Ensure Claude Code is running in a project directory.');
249-
this.transport.sendError(
250-
request.id,
251-
ErrorCodes.InternalError,
252-
errorMsg
253-
);
254-
return;
255-
}
284+
// If the default project isn't initialized yet, retry in case it was
285+
// initialized after the MCP server started (e.g. user ran codegraph init)
286+
this.retryInitIfNeeded();
256287

257288
const result = await this.toolHandler.execute(toolName, toolArgs);
258289

src/mcp/tools.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,21 @@ export class ToolHandler {
259259
// Cache of opened CodeGraph instances for cross-project queries
260260
private projectCache: Map<string, CodeGraph> = new Map();
261261

262-
constructor(private cg: CodeGraph) {}
262+
constructor(private cg: CodeGraph | null) {}
263+
264+
/**
265+
* Update the default CodeGraph instance (e.g. after lazy initialization)
266+
*/
267+
setDefaultCodeGraph(cg: CodeGraph): void {
268+
this.cg = cg;
269+
}
270+
271+
/**
272+
* Whether a default CodeGraph instance is available
273+
*/
274+
hasDefaultCodeGraph(): boolean {
275+
return this.cg !== null;
276+
}
263277

264278
/**
265279
* Get CodeGraph instance for a project
@@ -272,6 +286,9 @@ export class ToolHandler {
272286
*/
273287
private getCodeGraph(projectPath?: string): CodeGraph {
274288
if (!projectPath) {
289+
if (!this.cg) {
290+
throw new Error('CodeGraph not initialized for this project. Run \'codegraph init\' first.');
291+
}
275292
return this.cg;
276293
}
277294

0 commit comments

Comments
 (0)