summaryrefslogtreecommitdiff
path: root/packages/vscode-ide-companion/src/ide-server.ts
diff options
context:
space:
mode:
authorchristine betts <[email protected]>2025-08-04 21:36:23 +0000
committerGitHub <[email protected]>2025-08-04 21:36:23 +0000
commit93f8fe3671babbd3065d7a80b9e5ac50c42042da (patch)
tree5a1ab2c6a3a863f24a27ced76c0d56bea173e58f /packages/vscode-ide-companion/src/ide-server.ts
parente7b468e122a29341a6e2e2ca67366e6d62014a6d (diff)
[ide-mode] Add openDiff tool to IDE MCP server (#4519)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Diffstat (limited to 'packages/vscode-ide-companion/src/ide-server.ts')
-rw-r--r--packages/vscode-ide-companion/src/ide-server.ts70
1 files changed, 65 insertions, 5 deletions
diff --git a/packages/vscode-ide-companion/src/ide-server.ts b/packages/vscode-ide-companion/src/ide-server.ts
index 8296c64c..30215ccc 100644
--- a/packages/vscode-ide-companion/src/ide-server.ts
+++ b/packages/vscode-ide-companion/src/ide-server.ts
@@ -14,6 +14,8 @@ import {
type JSONRPCNotification,
} from '@modelcontextprotocol/sdk/types.js';
import { Server as HTTPServer } from 'node:http';
+import { z } from 'zod';
+import { DiffManager } from './diff-manager.js';
import { OpenFilesManager } from './open-files-manager.js';
const MCP_SESSION_ID_HEADER = 'mcp-session-id';
@@ -45,20 +47,22 @@ export class IDEServer {
private server: HTTPServer | undefined;
private context: vscode.ExtensionContext | undefined;
private log: (message: string) => void;
+ diffManager: DiffManager;
- constructor(log: (message: string) => void) {
+ constructor(log: (message: string) => void, diffManager: DiffManager) {
this.log = log;
+ this.diffManager = diffManager;
}
async start(context: vscode.ExtensionContext) {
this.context = context;
+ const sessionsWithInitialNotification = new Set<string>();
const transports: { [sessionId: string]: StreamableHTTPServerTransport } =
{};
- const sessionsWithInitialNotification = new Set<string>();
const app = express();
app.use(express.json());
- const mcpServer = createMcpServer();
+ const mcpServer = createMcpServer(this.diffManager);
const openFilesManager = new OpenFilesManager(context);
const onDidChangeSubscription = openFilesManager.onDidChange(() => {
@@ -71,6 +75,14 @@ export class IDEServer {
}
});
context.subscriptions.push(onDidChangeSubscription);
+ const onDidChangeDiffSubscription = this.diffManager.onDidChange(
+ (notification: JSONRPCNotification) => {
+ for (const transport of Object.values(transports)) {
+ transport.send(notification);
+ }
+ },
+ );
+ context.subscriptions.push(onDidChangeDiffSubscription);
app.post('/mcp', async (req: Request, res: Response) => {
const sessionId = req.headers[MCP_SESSION_ID_HEADER] as
@@ -88,7 +100,6 @@ export class IDEServer {
transports[newSessionId] = transport;
},
});
-
const keepAlive = setInterval(() => {
try {
transport.send({ jsonrpc: '2.0', method: 'ping' });
@@ -212,7 +223,7 @@ export class IDEServer {
}
}
-const createMcpServer = () => {
+const createMcpServer = (diffManager: DiffManager) => {
const server = new McpServer(
{
name: 'gemini-cli-companion-mcp-server',
@@ -220,5 +231,54 @@ const createMcpServer = () => {
},
{ capabilities: { logging: {} } },
);
+ server.registerTool(
+ 'openDiff',
+ {
+ description:
+ '(IDE Tool) Open a diff view to create or modify a file. Returns a notification once the diff has been accepted or rejcted.',
+ inputSchema: z.object({
+ filePath: z.string(),
+ // TODO(chrstn): determine if this should be required or not.
+ newContent: z.string().optional(),
+ }).shape,
+ },
+ async ({
+ filePath,
+ newContent,
+ }: {
+ filePath: string;
+ newContent?: string;
+ }) => {
+ await diffManager.showDiff(filePath, newContent ?? '');
+ return {
+ content: [
+ {
+ type: 'text',
+ text: `Showing diff for ${filePath}`,
+ },
+ ],
+ };
+ },
+ );
+ server.registerTool(
+ 'closeDiff',
+ {
+ description: '(IDE Tool) Close an open diff view for a specific file.',
+ inputSchema: z.object({
+ filePath: z.string(),
+ }).shape,
+ },
+ async ({ filePath }: { filePath: string }) => {
+ await diffManager.closeDiff(filePath);
+ return {
+ content: [
+ {
+ type: 'text',
+ text: `Closed diff for ${filePath}`,
+ },
+ ],
+ };
+ },
+ );
return server;
};