Skip to content

Commit 79e1ad7

Browse files
vritant24Copilot
andcommitted
feat: harden MCP server migration workflow
Revalidate migration candidates against source files, preserve errors and selection state across refreshes, and guard MCP file updates against conflicts and deletion races. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent edfa43f commit 79e1ad7

16 files changed

Lines changed: 1041 additions & 474 deletions

src/vs/sessions/AI_CUSTOMIZATIONS.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ Core workbench registrations may expose Local, Copilot CLI, and Claude harnesses
5151

5252
### `ICustomizationMigrationService`
5353

54-
This shared workbench service computes customization migrations for an explicit chat session. File migrations include source URIs and migratable-configuration metadata for flows that need source type and storage; MCP migrations report known servers' binary harness compatibility, migratable `.vscode/mcp.json` entries and their root `.mcp.json` targets, together with discovery and policy-coverage state. The service also produces a localized, harness-specific hint summarizing available migrations for UI consumers.
54+
This shared workbench service computes customization migrations for an explicit chat session. File migrations include source URIs and migratable-configuration metadata for flows that need source type and storage. Its MCP migration domain owns source canonicalization, destination representability, candidate planning, pre-write revalidation, guarded execution, and typed failure reasons. MCP results also retain the full compatibility inventory, discovery state, and policy coverage. The service produces a localized, harness-specific hint summarizing available migrations for UI consumers.
55+
56+
`CustomizationMigrationModel` owns the editor's reactive migration lifecycle: active-session and MCP refresh inputs, async sequencing, loading/error state, candidates, and destination folders. The management editor owns only selection, rendering, confirmation, and user notifications.
5557

5658
### `IHarnessDescriptor`
5759

src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostMcpServerSupport.ts

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,6 @@ export interface IAgentHostMcpServerSupport {
116116
readonly delivery: AgentHostMcpServerDelivery;
117117
/** Whether that delivery preserves the configuration's behavior. */
118118
readonly compatibility: AgentHostMcpServerCompatibility;
119-
/** Configuration that can be safely persisted to a declarative MCP destination. */
120-
readonly migrationConfiguration?: IMcpServerConfiguration;
121119
}
122120

123121
export interface IAgentHostMcpServerSupportAssessment {
@@ -139,7 +137,6 @@ export interface IAgentHostMcpServerDeliveryResolution {
139137
readonly compatibility: AgentHostMcpServerCompatibility;
140138
readonly source: IAgentHostMcpServerSource;
141139
readonly projectedConfiguration: IMcpServerConfiguration | undefined;
142-
readonly migrationConfiguration?: IMcpServerConfiguration;
143140
}
144141

145142
export interface IAgentHostInstalledMcpServer {
@@ -169,7 +166,7 @@ export async function assessMcpServersForCopilotAgentHost(
169166

170167
const resolved = await resolveMcpServersForAgentHostDelivery(servers, configurationResolverService, sessionType, workingDirectories);
171168
return {
172-
servers: resolved.map(({ server, source, applicability, delivery, compatibility, migrationConfiguration }) => ({
169+
servers: resolved.map(({ server, source, applicability, delivery, compatibility }) => ({
173170
id: server.definition.id,
174171
name: server.definition.label,
175172
collectionId: server.collection.id,
@@ -178,7 +175,6 @@ export async function assessMcpServersForCopilotAgentHost(
178175
applicability,
179176
delivery,
180177
compatibility,
181-
...(source.kind === AgentHostMcpServerSourceKind.VscodeWorkspaceFolder && migrationConfiguration ? { migrationConfiguration } : {}),
182178
})),
183179
discoveryComplete: lazyCollectionState === LazyCollectionState.AllKnown,
184180
};
@@ -279,10 +275,6 @@ async function resolveMcpServerForAgentHostDelivery(
279275
unsupported([AgentHostMcpSupportReason.LaunchNotRepresentable]),
280276
);
281277
}
282-
const migrationConfiguration = Iterable.isEmpty(ConfigurationResolverExpression.parse(projectedConfiguration).unresolved())
283-
&& !(projectedConfiguration.type === McpServerType.LOCAL && projectedConfiguration.cwd !== undefined)
284-
? projectedConfiguration
285-
: undefined;
286278

287279
const unsupportedReasons: AgentHostMcpSupportReason[] = [];
288280
if (collection && McpCollectionDefinition.isVscodeMcpJson(collection)) {
@@ -315,7 +307,6 @@ async function resolveMcpServerForAgentHostDelivery(
315307
: delivery,
316308
compatibility: getCompatibility(unsupportedReasons, partialReasons, unknownReasons),
317309
projectedConfiguration,
318-
migrationConfiguration,
319310
};
320311
}
321312

src/vs/workbench/contrib/chat/browser/aiCustomization/aiCustomizationManagementEditor.ts

Lines changed: 50 additions & 180 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)