diff options
| author | christine betts <[email protected]> | 2025-08-04 21:36:23 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-08-04 21:36:23 +0000 |
| commit | 93f8fe3671babbd3065d7a80b9e5ac50c42042da (patch) | |
| tree | 5a1ab2c6a3a863f24a27ced76c0d56bea173e58f /packages/vscode-ide-companion/src/ide-server.ts | |
| parent | e7b468e122a29341a6e2e2ca67366e6d62014a6d (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.ts | 70 |
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; }; |
