-
Notifications
You must be signed in to change notification settings - Fork 184
Terraform MCP Server deployment using Hashicorp VS Code extension #2086
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
f0f3975
feat(mcp-server-integration): TF-28514: Added: mcp server definition …
anubhav-goel cd85748
feat(mcp-server-integration): TF-28514: Added: implementation for MCP…
anubhav-goel c659506
feat(mcp-server-integration): TF-28514: Added: add MCP server provide…
anubhav-goel 40a64ea
feat(mcp-server-integration): TF-28514: Refactored: mcp server label …
anubhav-goel 80ee594
feat(mcp-server-integration): TF-28514: Modified: checking if mcp api…
anubhav-goel 5bddf8a
feat(mcp-server-integration): TF-28514: Modified: checking if docker …
anubhav-goel d03a6e7
feat(mcp-server-integration): TF-28514: Modified: checking if docker …
anubhav-goel 9e7c9a0
feat(mcp-server-integration): TF-28514: Added: mcp server docker inst…
anubhav-goel b574df2
feat(mcp-server-integration): TF-28514: Added: mcp server docker not …
anubhav-goel 20c32c0
feat(mcp-server-integration): TF-28514: Added: unregister the mcp ser…
anubhav-goel a72e09b
feat(mcp-server-integration): TF-28514: Refactored: removed comment
anubhav-goel c75856a
feat(mcp-server-integration): TF-28514: Added: mcp server info messag…
anubhav-goel 60a5301
feat(mcp-server-integration): TF-28514: Added: changelog for mcp serv…
anubhav-goel 762be2c
feat(mcp-server-integration): TF-28514: Modified: show mcp server inf…
anubhav-goel d2c9ad9
feat(mcp-server-integration): TF-28514: Removed: disposables from mcp…
anubhav-goel a0feb2e
feat(mcp-server-integration): TF-28514: Modified: added mcp error log…
anubhav-goel File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
kind: ENHANCEMENTS | ||
body: Terraform MCP Server deployment using Hashicorp VS Code extension | ||
time: 2025-08-21T18:53:55.326683+05:30 | ||
custom: | ||
Issue: "2086" | ||
Repository: vscode-terraform |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
/** | ||
* Copyright (c) HashiCorp, Inc. | ||
* SPDX-License-Identifier: MPL-2.0 | ||
*/ | ||
|
||
import TelemetryReporter from '@vscode/extension-telemetry'; | ||
import { exec } from 'child_process'; | ||
import { promisify } from 'util'; | ||
import * as vscode from 'vscode'; | ||
import which from 'which'; | ||
|
||
const execAsync = promisify(exec); | ||
|
||
interface McpServerDefinition { | ||
label: string; | ||
command: string; | ||
args: string[]; | ||
env: Record<string, string>; | ||
} | ||
|
||
export class McpServerFeature { | ||
constructor( | ||
private context: vscode.ExtensionContext, | ||
private reporter: TelemetryReporter, | ||
private outputChannel: vscode.OutputChannel, | ||
) { | ||
this.activate(); | ||
} | ||
|
||
/** | ||
* Helper method to format and log error information | ||
*/ | ||
private logError(message: string, error: unknown): void { | ||
this.outputChannel.appendLine(`${message}: ${String(error)}`); | ||
if (error instanceof Error && error.stack) { | ||
this.outputChannel.appendLine(`Stack trace: ${error.stack}`); | ||
} | ||
} | ||
|
||
public activate(): void { | ||
try { | ||
if (!this.isMcpApiAvailable()) { | ||
return; | ||
} | ||
|
||
const provider = this.registerMcpServerProvider(); | ||
if (provider) { | ||
this.context.subscriptions.push(provider); | ||
} | ||
} catch (error) { | ||
this.logError('Failed to register MCP server definition provider', error); | ||
// Don't throw - let the extension continue to work without MCP server | ||
} | ||
} | ||
|
||
private isMcpApiAvailable(): boolean { | ||
// Check if VS Code has the MCP API available | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
return typeof (vscode as any).lm?.registerMcpServerDefinitionProvider === 'function'; | ||
} | ||
|
||
private registerMcpServerProvider(): vscode.Disposable | undefined { | ||
try { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const vscodeAny = vscode as any; | ||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return | ||
return vscodeAny.lm.registerMcpServerDefinitionProvider('terraform.mcp.server', { | ||
provideMcpServerDefinitions: () => { | ||
return this.provideMcpServerDefinitions(); | ||
}, | ||
}); | ||
} catch (error) { | ||
this.logError('Error registering MCP server provider', error); | ||
return undefined; | ||
} | ||
} | ||
|
||
private async provideMcpServerDefinitions(): Promise<McpServerDefinition[]> { | ||
try { | ||
const dockerAvailable = await this.dockerValidations(); | ||
if (!dockerAvailable) { | ||
return []; | ||
} | ||
|
||
const server: McpServerDefinition = { | ||
label: 'HashiCorp Terraform MCP Server', | ||
command: 'docker', | ||
args: ['run', '-i', '--rm', 'hashicorp/terraform-mcp-server'], | ||
env: {}, | ||
}; | ||
|
||
this.showMcpServerInfoMessage(); | ||
|
||
return [server]; | ||
} catch (error) { | ||
this.logError('Error providing MCP server definitions', error); | ||
return []; | ||
} | ||
} | ||
private async dockerValidations(): Promise<boolean> { | ||
try { | ||
if (!(await this.checkDockerAvailability())) { | ||
return false; | ||
} | ||
|
||
if (!(await this.checkDockerRunning())) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} catch (error) { | ||
this.logError('Docker validation error', error); | ||
return false; | ||
} | ||
} | ||
|
||
private async checkDockerAvailability(): Promise<boolean> { | ||
try { | ||
await which('docker'); | ||
return true; | ||
} catch { | ||
void vscode.window | ||
.showWarningMessage( | ||
'Docker is required to run the Terraform MCP Server. Please install Docker to use this feature.', | ||
'Learn More', | ||
) | ||
.then((selection) => { | ||
if (selection === 'Learn More') { | ||
void vscode.env.openExternal(vscode.Uri.parse('https://docs.docker.com/get-docker/')); | ||
} | ||
}); | ||
return false; | ||
} | ||
} | ||
|
||
private async checkDockerRunning(): Promise<boolean> { | ||
try { | ||
await execAsync('docker info', { timeout: 5000 }); | ||
return true; | ||
} catch (error) { | ||
this.logError('Docker daemon check failed', error); | ||
void vscode.window | ||
.showWarningMessage( | ||
'Docker is installed but not running. Please start Docker to use the Terraform MCP Server.', | ||
'Learn More', | ||
) | ||
.then((selection) => { | ||
if (selection === 'Learn More') { | ||
void vscode.env.openExternal(vscode.Uri.parse('https://docs.docker.com/get-started/')); | ||
} | ||
}); | ||
return false; | ||
} | ||
} | ||
|
||
private showMcpServerInfoMessage(): void { | ||
const message = 'Terraform MCP Server is now available for GitHub Copilot integration.'; | ||
const startAction = 'Start MCP Server'; | ||
const learnMoreAction = 'Learn More'; | ||
|
||
void vscode.window.showInformationMessage(message, startAction, learnMoreAction).then((selection) => { | ||
if (selection === startAction) { | ||
void vscode.commands.executeCommand('workbench.action.quickOpen', '>MCP: List Servers'); | ||
} else if (selection === learnMoreAction) { | ||
void vscode.env.openExternal(vscode.Uri.parse('https://github.com/hashicorp/terraform-mcp-server')); | ||
} | ||
}); | ||
} | ||
|
||
dispose(): void { | ||
// context.subscriptions will be disposed by the extension, so any explicit code should not be required. | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.