Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/services/authentication/browser/authenticationMcpUsageService.ts
3296 views
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 { Queue } from '../../../../base/common/async.js';
7
import { Disposable } from '../../../../base/common/lifecycle.js';
8
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
9
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
10
import { ILogService } from '../../../../platform/log/common/log.js';
11
import { IProductService } from '../../../../platform/product/common/productService.js';
12
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
13
import { IAuthenticationService } from '../common/authentication.js';
14
15
export interface IAuthenticationMcpUsage {
16
mcpServerId: string;
17
mcpServerName: string;
18
lastUsed: number;
19
scopes?: string[];
20
}
21
22
export const IAuthenticationMcpUsageService = createDecorator<IAuthenticationMcpUsageService>('IAuthenticationMcpUsageService');
23
export interface IAuthenticationMcpUsageService {
24
readonly _serviceBrand: undefined;
25
/**
26
* Initializes the cache of MCP servers that use authentication. Ideally used in a contribution that can be run eventually after the workspace is loaded.
27
*/
28
initializeUsageCache(): Promise<void>;
29
/**
30
* Checks if an MCP server uses authentication
31
* @param mcpServerId The id of the MCP server to check
32
*/
33
hasUsedAuth(mcpServerId: string): Promise<boolean>;
34
/**
35
* Reads the usages for an account
36
* @param providerId The id of the authentication provider to get usages for
37
* @param accountName The name of the account to get usages for
38
*/
39
readAccountUsages(providerId: string, accountName: string,): IAuthenticationMcpUsage[];
40
/**
41
*
42
* @param providerId The id of the authentication provider to get usages for
43
* @param accountName The name of the account to get usages for
44
*/
45
removeAccountUsage(providerId: string, accountName: string): void;
46
/**
47
* Adds a usage for an account
48
* @param providerId The id of the authentication provider to get usages for
49
* @param accountName The name of the account to get usages for
50
* @param mcpServerId The id of the MCP server to add a usage for
51
* @param mcpServerName The name of the MCP server to add a usage for
52
*/
53
addAccountUsage(providerId: string, accountName: string, scopes: ReadonlyArray<string>, mcpServerId: string, mcpServerName: string): void;
54
}
55
56
export class AuthenticationMcpUsageService extends Disposable implements IAuthenticationMcpUsageService {
57
_serviceBrand: undefined;
58
59
private _queue = new Queue();
60
private _mcpServersUsingAuth = new Set<string>();
61
62
constructor(
63
@IStorageService private readonly _storageService: IStorageService,
64
@IAuthenticationService private readonly _authenticationService: IAuthenticationService,
65
@ILogService private readonly _logService: ILogService,
66
@IProductService productService: IProductService,
67
) {
68
super();
69
70
// If an MCP server is listed in `trustedMcpAuthAccess` we should consider it as using auth
71
const trustedMcpAuthAccess = productService.trustedMcpAuthAccess;
72
if (Array.isArray(trustedMcpAuthAccess)) {
73
for (const mcpServerId of trustedMcpAuthAccess) {
74
this._mcpServersUsingAuth.add(mcpServerId);
75
}
76
} else if (trustedMcpAuthAccess) {
77
for (const mcpServers of Object.values(trustedMcpAuthAccess)) {
78
for (const mcpServerId of mcpServers) {
79
this._mcpServersUsingAuth.add(mcpServerId);
80
}
81
}
82
}
83
84
this._register(this._authenticationService.onDidRegisterAuthenticationProvider(
85
provider => this._queue.queue(
86
() => this._addToCache(provider.id)
87
)
88
));
89
}
90
91
async initializeUsageCache(): Promise<void> {
92
await this._queue.queue(() => Promise.all(this._authenticationService.getProviderIds().map(providerId => this._addToCache(providerId))));
93
}
94
95
async hasUsedAuth(mcpServerId: string): Promise<boolean> {
96
await this._queue.whenIdle();
97
return this._mcpServersUsingAuth.has(mcpServerId);
98
}
99
100
readAccountUsages(providerId: string, accountName: string): IAuthenticationMcpUsage[] {
101
const accountKey = `${providerId}-${accountName}-mcpserver-usages`;
102
const storedUsages = this._storageService.get(accountKey, StorageScope.APPLICATION);
103
let usages: IAuthenticationMcpUsage[] = [];
104
if (storedUsages) {
105
try {
106
usages = JSON.parse(storedUsages);
107
} catch (e) {
108
// ignore
109
}
110
}
111
112
return usages;
113
}
114
115
removeAccountUsage(providerId: string, accountName: string): void {
116
const accountKey = `${providerId}-${accountName}-mcpserver-usages`;
117
this._storageService.remove(accountKey, StorageScope.APPLICATION);
118
}
119
120
addAccountUsage(providerId: string, accountName: string, scopes: string[], mcpServerId: string, mcpServerName: string): void {
121
const accountKey = `${providerId}-${accountName}-mcpserver-usages`;
122
const usages = this.readAccountUsages(providerId, accountName);
123
124
const existingUsageIndex = usages.findIndex(usage => usage.mcpServerId === mcpServerId);
125
if (existingUsageIndex > -1) {
126
usages.splice(existingUsageIndex, 1, {
127
mcpServerId,
128
mcpServerName,
129
scopes,
130
lastUsed: Date.now()
131
});
132
} else {
133
usages.push({
134
mcpServerId,
135
mcpServerName,
136
scopes,
137
lastUsed: Date.now()
138
});
139
}
140
141
this._storageService.store(accountKey, JSON.stringify(usages), StorageScope.APPLICATION, StorageTarget.MACHINE);
142
this._mcpServersUsingAuth.add(mcpServerId);
143
}
144
145
private async _addToCache(providerId: string) {
146
try {
147
const accounts = await this._authenticationService.getAccounts(providerId);
148
for (const account of accounts) {
149
const usage = this.readAccountUsages(providerId, account.label);
150
for (const u of usage) {
151
this._mcpServersUsingAuth.add(u.mcpServerId);
152
}
153
}
154
} catch (e) {
155
this._logService.error(e);
156
}
157
}
158
}
159
160
registerSingleton(IAuthenticationMcpUsageService, AuthenticationMcpUsageService, InstantiationType.Delayed);
161
162