Skip to content

Commit e3a9376

Browse files
dmitrivMSCopilot
andcommitted
Initial revision of enterprise MCP allowlist support,
Co-authored-by: Copilot <copilot@github.com>
1 parent 8c15ca4 commit e3a9376

10 files changed

Lines changed: 547 additions & 8 deletions

File tree

package-lock.json

Lines changed: 22 additions & 0 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 & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
"@anthropic-ai/sandbox-runtime": "0.0.42",
9191
"@github/copilot": "^1.0.11",
9292
"@github/copilot-sdk": "^0.2.0",
93+
"@github/mcp-registry": "^0.1.5",
9394
"@microsoft/1ds-core-js": "^3.2.13",
9495
"@microsoft/1ds-post-js": "^3.2.13",
9596
"@microsoft/dev-tunnels-connections": "^1.3.41",

src/vs/base/common/defaultAccount.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,35 @@ export interface IEntitlementsData extends ILegacyQuotaSnapshotData {
4141
};
4242
}
4343

44+
/**
45+
* An enterprise MCP registry entry from the `copilot/mcp_registry` response
46+
* that signals GitHub-native enterprise allowlist enforcement.
47+
*/
48+
export interface IMcpAllowlistEntry {
49+
/** The enterprise registry base URL (e.g., "https://registry.github.com/mcp") */
50+
readonly registryUrl: string;
51+
/** The registry access level */
52+
readonly registryAccess: 'allow_all' | 'registry_only';
53+
/** The owner (org or enterprise) login */
54+
readonly ownerLogin: string;
55+
/** The owner (org or enterprise) numeric ID */
56+
readonly ownerId: number;
57+
/** The owner type (e.g., "Organization") */
58+
readonly ownerType: string;
59+
/** Parent enterprise login, if the owner is an org under an enterprise */
60+
readonly parentLogin: string | null;
61+
/** Priority for evaluation ordering */
62+
readonly priority: number;
63+
}
64+
4465
export interface IPolicyData {
4566
readonly mcp?: boolean;
4667
readonly chat_preview_features_enabled?: boolean;
4768
readonly chat_agent_enabled?: boolean;
4869
readonly mcpRegistryUrl?: string;
4970
readonly mcpAccess?: 'allow_all' | 'registry_only';
71+
/** Enterprise MCP allowlist entries discovered from `copilot/mcp_registry`. */
72+
readonly mcpAllowlistEntries?: readonly IMcpAllowlistEntry[];
5073
}
5174

5275
export interface ICopilotTokenInfo {
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { CancellationToken } from '../../../base/common/cancellation.js';
7+
import { IMarkdownString } from '../../../base/common/htmlContent.js';
8+
import { createDecorator } from '../../instantiation/common/instantiation.js';
9+
10+
/**
11+
* State of the enterprise MCP allow list service.
12+
*/
13+
export const enum McpAllowListState {
14+
/** Enterprise allow list enforcement is not applicable (no enterprise entries). */
15+
NotApplicable,
16+
/** The allow list is currently being fetched. */
17+
Loading,
18+
/** The allow list has been loaded and is ready for enforcement. */
19+
Ready,
20+
/** The allow list could not be loaded (network failure, etc.). */
21+
Unavailable,
22+
}
23+
24+
/**
25+
* Service that manages enterprise MCP server allow lists.
26+
*
27+
* When a user is in an enterprise with MCP allow list policies, this service
28+
* fetches the allow list from the enterprise registry and gates server launches.
29+
*/
30+
export const IMcpAllowListService = createDecorator<IMcpAllowListService>('IMcpAllowListService');
31+
export interface IMcpAllowListService {
32+
readonly _serviceBrand: undefined;
33+
34+
/** State of the allow list service. */
35+
readonly state: McpAllowListState;
36+
37+
/**
38+
* Waits until the allow list is loaded or the service determines that
39+
* enterprise allow list enforcement is not applicable. Returns immediately
40+
* if already resolved.
41+
*/
42+
waitForReady(token?: CancellationToken): Promise<void>;
43+
44+
/**
45+
* Checks whether a server (identified by its fingerprint) is allowed to run.
46+
*
47+
* @param fingerprint The computed SHA-256 fingerprint of the server's identity.
48+
* @returns `true` if the server is allowed, or an `IMarkdownString` explaining why it was blocked.
49+
*/
50+
isAllowed(fingerprint: string): true | IMarkdownString;
51+
}

src/vs/workbench/contrib/git/common/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ function getOrderedRemotes(repositoryState: GitRepositoryState): readonly GitRem
6464
return Array.from(remotes.values());
6565
}
6666

67-
function parseRemoteUrl(fetchUrl: string): { host: string; rawHost: string; path: string } | undefined {
67+
export function parseRemoteUrl(fetchUrl: string): { host: string; rawHost: string; path: string } | undefined {
6868
fetchUrl = fetchUrl.trim();
6969
try {
7070
// Normalize git shorthand syntax (git@github.com:user/repo.git) into an explicit ssh:// url

src/vs/workbench/contrib/mcp/browser/mcp.contribution.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { SyncDescriptor } from '../../../../platform/instantiation/common/descri
99
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
1010
import * as jsonContributionRegistry from '../../../../platform/jsonschemas/common/jsonContributionRegistry.js';
1111
import { mcpAccessConfig, McpAccessValue } from '../../../../platform/mcp/common/mcpManagement.js';
12+
import { IMcpAllowListService } from '../../../../platform/mcp/common/mcpAllowListService.js';
1213
import { IQuickAccessRegistry, Extensions as QuickAccessExtensions } from '../../../../platform/quickinput/common/quickAccess.js';
1314
import { Registry } from '../../../../platform/registry/common/platform.js';
1415
import { EditorPaneDescriptor, IEditorPaneRegistry } from '../../../browser/editor.js';
@@ -49,7 +50,9 @@ import { McpServerEditor } from './mcpServerEditor.js';
4950
import { McpServerEditorInput } from './mcpServerEditorInput.js';
5051
import { McpServersViewsContribution } from './mcpServersView.js';
5152
import { MCPContextsInitialisation, McpWorkbenchService } from './mcpWorkbenchService.js';
53+
import { McpAllowListService } from '../common/mcpAllowListService.js';
5254

55+
registerSingleton(IMcpAllowListService, McpAllowListService, InstantiationType.Delayed);
5356
registerSingleton(IMcpRegistry, McpRegistry, InstantiationType.Delayed);
5457
registerSingleton(IMcpSandboxService, McpSandboxService, InstantiationType.Delayed);
5558
registerSingleton(IMcpService, McpService, InstantiationType.Delayed);

0 commit comments

Comments
 (0)