@theia/ai-registry 1.73.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -0
- package/lib/browser/ai-registry-frontend-module.d.ts +5 -0
- package/lib/browser/ai-registry-frontend-module.d.ts.map +1 -0
- package/lib/browser/ai-registry-frontend-module.js +45 -0
- package/lib/browser/ai-registry-frontend-module.js.map +1 -0
- package/lib/browser/ai-registry-toolbar-contribution.d.ts +9 -0
- package/lib/browser/ai-registry-toolbar-contribution.d.ts.map +1 -0
- package/lib/browser/ai-registry-toolbar-contribution.js +53 -0
- package/lib/browser/ai-registry-toolbar-contribution.js.map +1 -0
- package/lib/browser/mcp/mcp-entries.d.ts +40 -0
- package/lib/browser/mcp/mcp-entries.d.ts.map +1 -0
- package/lib/browser/mcp/mcp-entries.js +143 -0
- package/lib/browser/mcp/mcp-entries.js.map +1 -0
- package/lib/browser/mcp/mcp-extensions-contribution.d.ts +45 -0
- package/lib/browser/mcp/mcp-extensions-contribution.d.ts.map +1 -0
- package/lib/browser/mcp/mcp-extensions-contribution.js +198 -0
- package/lib/browser/mcp/mcp-extensions-contribution.js.map +1 -0
- package/lib/browser/mcp/mcp-extensions-contribution.spec.d.ts +2 -0
- package/lib/browser/mcp/mcp-extensions-contribution.spec.d.ts.map +1 -0
- package/lib/browser/mcp/mcp-extensions-contribution.spec.js +266 -0
- package/lib/browser/mcp/mcp-extensions-contribution.spec.js.map +1 -0
- package/lib/browser/mcp/mcp-install-service.d.ts +72 -0
- package/lib/browser/mcp/mcp-install-service.d.ts.map +1 -0
- package/lib/browser/mcp/mcp-install-service.js +255 -0
- package/lib/browser/mcp/mcp-install-service.js.map +1 -0
- package/lib/browser/mcp/mcp-install-service.spec.d.ts +2 -0
- package/lib/browser/mcp/mcp-install-service.spec.d.ts.map +1 -0
- package/lib/browser/mcp/mcp-install-service.spec.js +604 -0
- package/lib/browser/mcp/mcp-install-service.spec.js.map +1 -0
- package/lib/browser/mcp/mcp-registry-ui-bridge-impl.d.ts +27 -0
- package/lib/browser/mcp/mcp-registry-ui-bridge-impl.d.ts.map +1 -0
- package/lib/browser/mcp/mcp-registry-ui-bridge-impl.js +136 -0
- package/lib/browser/mcp/mcp-registry-ui-bridge-impl.js.map +1 -0
- package/lib/common/ai-registry-configuration.d.ts +28 -0
- package/lib/common/ai-registry-configuration.d.ts.map +1 -0
- package/lib/common/ai-registry-configuration.js +56 -0
- package/lib/common/ai-registry-configuration.js.map +1 -0
- package/lib/common/mcp/mcp-registry-entry-resolver.d.ts +12 -0
- package/lib/common/mcp/mcp-registry-entry-resolver.d.ts.map +1 -0
- package/lib/common/mcp/mcp-registry-entry-resolver.js +68 -0
- package/lib/common/mcp/mcp-registry-entry-resolver.js.map +1 -0
- package/lib/common/mcp/mcp-registry-entry-resolver.spec.d.ts +2 -0
- package/lib/common/mcp/mcp-registry-entry-resolver.spec.d.ts.map +1 -0
- package/lib/common/mcp/mcp-registry-entry-resolver.spec.js +230 -0
- package/lib/common/mcp/mcp-registry-entry-resolver.spec.js.map +1 -0
- package/lib/common/mcp/mcp-registry-types.d.ts +105 -0
- package/lib/common/mcp/mcp-registry-types.d.ts.map +1 -0
- package/lib/common/mcp/mcp-registry-types.js +18 -0
- package/lib/common/mcp/mcp-registry-types.js.map +1 -0
- package/lib/common/registry-fetch-service.d.ts +24 -0
- package/lib/common/registry-fetch-service.d.ts.map +1 -0
- package/lib/common/registry-fetch-service.js +72 -0
- package/lib/common/registry-fetch-service.js.map +1 -0
- package/lib/common/registry-fetch-service.spec.d.ts +2 -0
- package/lib/common/registry-fetch-service.spec.d.ts.map +1 -0
- package/lib/common/registry-fetch-service.spec.js +129 -0
- package/lib/common/registry-fetch-service.spec.js.map +1 -0
- package/lib/package.spec.d.ts +1 -0
- package/lib/package.spec.d.ts.map +1 -0
- package/lib/package.spec.js +26 -0
- package/lib/package.spec.js.map +1 -0
- package/package.json +50 -0
- package/src/browser/ai-registry-frontend-module.ts +48 -0
- package/src/browser/ai-registry-toolbar-contribution.ts +51 -0
- package/src/browser/mcp/mcp-entries.tsx +288 -0
- package/src/browser/mcp/mcp-extensions-contribution.spec.ts +294 -0
- package/src/browser/mcp/mcp-extensions-contribution.ts +199 -0
- package/src/browser/mcp/mcp-install-service.spec.ts +673 -0
- package/src/browser/mcp/mcp-install-service.ts +300 -0
- package/src/browser/mcp/mcp-registry-ui-bridge-impl.ts +130 -0
- package/src/browser/style/mcp-entries.css +56 -0
- package/src/common/ai-registry-configuration.ts +52 -0
- package/src/common/mcp/mcp-registry-entry-resolver.spec.ts +248 -0
- package/src/common/mcp/mcp-registry-entry-resolver.ts +68 -0
- package/src/common/mcp/mcp-registry-types.ts +119 -0
- package/src/common/registry-fetch-service.spec.ts +136 -0
- package/src/common/registry-fetch-service.ts +78 -0
- package/src/package.spec.ts +28 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-extensions-contribution.js","sourceRoot":"","sources":["../../../src/browser/mcp/mcp-extensions-contribution.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-extensions-contribution.spec.d.ts","sourceRoot":"","sources":["../../../src/browser/mcp/mcp-extensions-contribution.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// *****************************************************************************
|
|
3
|
+
// Copyright (C) 2026 EclipseSource GmbH.
|
|
4
|
+
//
|
|
5
|
+
// This program and the accompanying materials are made available under the
|
|
6
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
7
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
8
|
+
//
|
|
9
|
+
// This Source Code may also be made available under the following Secondary
|
|
10
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
11
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
12
|
+
// with the GNU Classpath Exception which is available at
|
|
13
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
14
|
+
//
|
|
15
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
16
|
+
// *****************************************************************************
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
const frontend_application_config_provider_1 = require("@theia/core/lib/browser/frontend-application-config-provider");
|
|
19
|
+
const jsdom_1 = require("@theia/core/lib/browser/test/jsdom");
|
|
20
|
+
// Entries render against the shared ExtensionCard, which pulls in browser-side modules,
|
|
21
|
+
// so a DOM is required at import time.
|
|
22
|
+
const disableJSDOM = (0, jsdom_1.enableJSDOM)();
|
|
23
|
+
try {
|
|
24
|
+
frontend_application_config_provider_1.FrontendApplicationConfigProvider.get();
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
frontend_application_config_provider_1.FrontendApplicationConfigProvider.set({});
|
|
28
|
+
}
|
|
29
|
+
const chai_1 = require("chai");
|
|
30
|
+
const inversify_1 = require("@theia/core/shared/inversify");
|
|
31
|
+
const core_1 = require("@theia/core");
|
|
32
|
+
const browser_1 = require("@theia/core/lib/browser");
|
|
33
|
+
const mcp_preferences_1 = require("@theia/ai-mcp/lib/common/mcp-preferences");
|
|
34
|
+
const mcp_server_manager_1 = require("@theia/ai-mcp/lib/common/mcp-server-manager");
|
|
35
|
+
const mcp_server_editor_1 = require("@theia/ai-mcp/lib/browser/mcp-server-editor");
|
|
36
|
+
const mcp_server_install_dialog_1 = require("@theia/ai-mcp/lib/browser/mcp-server-install-dialog");
|
|
37
|
+
const registry_fetch_service_1 = require("../../common/registry-fetch-service");
|
|
38
|
+
const mcp_registry_entry_resolver_1 = require("../../common/mcp/mcp-registry-entry-resolver");
|
|
39
|
+
const mcp_install_service_1 = require("./mcp-install-service");
|
|
40
|
+
const mcp_extensions_contribution_1 = require("./mcp-extensions-contribution");
|
|
41
|
+
after(() => disableJSDOM());
|
|
42
|
+
class FakePreferenceService {
|
|
43
|
+
constructor() {
|
|
44
|
+
this.store = new Map();
|
|
45
|
+
this.listeners = [];
|
|
46
|
+
}
|
|
47
|
+
get(key, defaultValue) {
|
|
48
|
+
return (this.store.has(key) ? this.store.get(key) : defaultValue);
|
|
49
|
+
}
|
|
50
|
+
async set(key, value) {
|
|
51
|
+
this.store.set(key, value);
|
|
52
|
+
for (const l of this.listeners) {
|
|
53
|
+
l({ preferenceName: key });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
onPreferenceChanged(listener) {
|
|
57
|
+
this.listeners.push(listener);
|
|
58
|
+
return { dispose: () => { } };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
class StubRegistryFetchService {
|
|
62
|
+
constructor(entries = []) {
|
|
63
|
+
this.entries = entries;
|
|
64
|
+
this.onDidChangeEmitter = new core_1.Emitter();
|
|
65
|
+
this.onDidChange = this.onDidChangeEmitter.event;
|
|
66
|
+
}
|
|
67
|
+
async getEntries() {
|
|
68
|
+
return this.entries;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function buildContainer(prefs, fetch) {
|
|
72
|
+
const container = new inversify_1.Container();
|
|
73
|
+
container.bind(core_1.PreferenceService).toConstantValue(prefs);
|
|
74
|
+
container.bind(registry_fetch_service_1.RegistryFetchService).toConstantValue(fetch);
|
|
75
|
+
container.bind(mcp_registry_entry_resolver_1.MCPRegistryEntryResolverImpl).toSelf().inSingletonScope();
|
|
76
|
+
container.bind(mcp_registry_entry_resolver_1.MCPRegistryEntryResolver).toService(mcp_registry_entry_resolver_1.MCPRegistryEntryResolverImpl);
|
|
77
|
+
// Editor dependencies — the contribution doesn't invoke the install path here, but
|
|
78
|
+
// MCPInstallService now injects MCPServerEditor so we stub its required services.
|
|
79
|
+
container.bind(core_1.MessageService).toConstantValue({ error: () => undefined });
|
|
80
|
+
container.bind(mcp_server_manager_1.MCPFrontendService).toConstantValue({});
|
|
81
|
+
container.bind(browser_1.HoverService).toConstantValue({ requestHover: () => undefined });
|
|
82
|
+
// The contribution doesn't open dialogs in these tests; bind factories that fail loudly if used.
|
|
83
|
+
container.bind(mcp_server_editor_1.MCPServerEditDialogFactory).toConstantValue(() => {
|
|
84
|
+
throw new Error('MCPServerEditDialogFactory should not be invoked in these tests');
|
|
85
|
+
});
|
|
86
|
+
container.bind(mcp_server_install_dialog_1.MCPServerInstallDialogFactory).toConstantValue(() => {
|
|
87
|
+
throw new Error('MCPServerInstallDialogFactory should not be invoked in these tests');
|
|
88
|
+
});
|
|
89
|
+
container.bind(mcp_server_editor_1.MCPServerEditorImpl).toSelf().inSingletonScope();
|
|
90
|
+
container.bind(mcp_server_editor_1.MCPServerEditor).toService(mcp_server_editor_1.MCPServerEditorImpl);
|
|
91
|
+
container.bind(mcp_install_service_1.MCPInstallServiceImpl).toSelf().inSingletonScope();
|
|
92
|
+
container.bind(mcp_install_service_1.MCPInstallService).toService(mcp_install_service_1.MCPInstallServiceImpl);
|
|
93
|
+
container.bind(mcp_extensions_contribution_1.MCPExtensionsContribution).toSelf().inSingletonScope();
|
|
94
|
+
return container;
|
|
95
|
+
}
|
|
96
|
+
const exampleRegistryEntry = {
|
|
97
|
+
serverId: 'io.github.example/example-mcp',
|
|
98
|
+
name: 'Example',
|
|
99
|
+
description: 'Example MCP server',
|
|
100
|
+
localName: 'example',
|
|
101
|
+
config: { command: 'npx', args: ['-y', 'example-mcp'] },
|
|
102
|
+
version: '^1.0.0',
|
|
103
|
+
configHash: 'hash-v1',
|
|
104
|
+
mcpRegistryVerified: true
|
|
105
|
+
};
|
|
106
|
+
describe('MCPExtensionsContribution.resolveInstalled', () => {
|
|
107
|
+
it('only surfaces servers tied to a registry entry; user-added entries are filtered out', async () => {
|
|
108
|
+
const prefs = new FakePreferenceService();
|
|
109
|
+
await prefs.set(mcp_preferences_1.MCP_SERVERS_PREF, {
|
|
110
|
+
// Linked: matches a registry entry by serverId.
|
|
111
|
+
example: {
|
|
112
|
+
command: 'npx',
|
|
113
|
+
args: ['-y', 'example-mcp'],
|
|
114
|
+
registryMetadata: {
|
|
115
|
+
serverId: exampleRegistryEntry.serverId,
|
|
116
|
+
version: exampleRegistryEntry.version,
|
|
117
|
+
configHash: exampleRegistryEntry.configHash
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
// User-added: no registry counterpart at all.
|
|
121
|
+
standalone: { command: 'node', args: ['srv.js'] }
|
|
122
|
+
});
|
|
123
|
+
const fetch = new StubRegistryFetchService([exampleRegistryEntry]);
|
|
124
|
+
const contribution = buildContainer(prefs, fetch).get(mcp_extensions_contribution_1.MCPExtensionsContribution);
|
|
125
|
+
const entries = [...await contribution.resolveInstalled()];
|
|
126
|
+
(0, chai_1.expect)(entries.map(e => e.local.name)).to.deep.equal(['example']);
|
|
127
|
+
(0, chai_1.expect)(entries[0].state).to.deep.equal({ kind: 'installed-from-registry', updateAvailable: false });
|
|
128
|
+
});
|
|
129
|
+
it('surfaces installed-link-stale entries so the view can render the warning + Unlink/Uninstall actions', async () => {
|
|
130
|
+
const prefs = new FakePreferenceService();
|
|
131
|
+
await prefs.set(mcp_preferences_1.MCP_SERVERS_PREF, {
|
|
132
|
+
stale: {
|
|
133
|
+
command: 'npx',
|
|
134
|
+
args: ['-y', 'gone-mcp'],
|
|
135
|
+
registryMetadata: {
|
|
136
|
+
serverId: 'io.github.example/gone-server',
|
|
137
|
+
version: '^1.0.0'
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
const fetch = new StubRegistryFetchService([exampleRegistryEntry]);
|
|
142
|
+
const contribution = buildContainer(prefs, fetch).get(mcp_extensions_contribution_1.MCPExtensionsContribution);
|
|
143
|
+
const entries = [...await contribution.resolveInstalled()];
|
|
144
|
+
(0, chai_1.expect)(entries.map(e => e.local.name)).to.deep.equal(['stale']);
|
|
145
|
+
(0, chai_1.expect)(entries[0].state).to.deep.equal({ kind: 'installed-link-stale' });
|
|
146
|
+
});
|
|
147
|
+
it('shows installed-link-stale (Unlink + Uninstall) when the local is linked to a missing id, even if the key still matches a registry entry', async () => {
|
|
148
|
+
// PR scenario: user installs from the registry, then manually rewrites
|
|
149
|
+
// `registryMetadata.serverId` to a value that no longer exists. The local key
|
|
150
|
+
// still matches a registry `localName`, but the broken id linkage must take
|
|
151
|
+
// precedence - the entry has to surface as link-stale so the user sees the
|
|
152
|
+
// Unlink + Uninstall affordances and the warning, not Link (which would suggest
|
|
153
|
+
// the entry is merely unlinked).
|
|
154
|
+
const prefs = new FakePreferenceService();
|
|
155
|
+
await prefs.set(mcp_preferences_1.MCP_SERVERS_PREF, {
|
|
156
|
+
example: {
|
|
157
|
+
command: 'npx',
|
|
158
|
+
args: ['-y', 'example-mcp'],
|
|
159
|
+
registryMetadata: {
|
|
160
|
+
serverId: 'io.example/gone',
|
|
161
|
+
version: '^1.0.0',
|
|
162
|
+
configHash: 'hash-v1'
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
const fetch = new StubRegistryFetchService([exampleRegistryEntry]);
|
|
167
|
+
const contribution = buildContainer(prefs, fetch).get(mcp_extensions_contribution_1.MCPExtensionsContribution);
|
|
168
|
+
const entries = [...await contribution.resolveInstalled()];
|
|
169
|
+
(0, chai_1.expect)(entries).to.have.length(1);
|
|
170
|
+
(0, chai_1.expect)(entries[0].state).to.deep.equal({ kind: 'installed-link-stale' });
|
|
171
|
+
});
|
|
172
|
+
it('skips malformed stored entries whose `command` is not a string — mere key presence is not enough', async () => {
|
|
173
|
+
const prefs = new FakePreferenceService();
|
|
174
|
+
await prefs.set(mcp_preferences_1.MCP_SERVERS_PREF, {
|
|
175
|
+
// `command` is present but typed wrong; the shared MCPServersPreference.isValue
|
|
176
|
+
// guard must reject this so it doesn't get cast to MCPServerDescription.
|
|
177
|
+
broken: { command: 42, args: ['-y', 'whatever'] },
|
|
178
|
+
example: {
|
|
179
|
+
command: 'npx',
|
|
180
|
+
args: ['-y', 'example-mcp'],
|
|
181
|
+
registryMetadata: {
|
|
182
|
+
serverId: exampleRegistryEntry.serverId,
|
|
183
|
+
version: exampleRegistryEntry.version,
|
|
184
|
+
configHash: exampleRegistryEntry.configHash
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
const fetch = new StubRegistryFetchService([exampleRegistryEntry]);
|
|
189
|
+
const contribution = buildContainer(prefs, fetch).get(mcp_extensions_contribution_1.MCPExtensionsContribution);
|
|
190
|
+
const entries = [...await contribution.resolveInstalled()];
|
|
191
|
+
(0, chai_1.expect)(entries.map(e => e.local.name)).to.deep.equal(['example']);
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
describe('MCPExtensionsContribution.resolveSearchResults', () => {
|
|
195
|
+
const githubEntry = {
|
|
196
|
+
serverId: 'io.github.github/github-mcp-server',
|
|
197
|
+
name: 'GitHub',
|
|
198
|
+
description: 'Connect AI assistants to GitHub repositories',
|
|
199
|
+
localName: 'github',
|
|
200
|
+
config: { command: 'docker', args: ['run', '-i', '--rm'] },
|
|
201
|
+
version: '^1.0.0',
|
|
202
|
+
configHash: 'hash-github',
|
|
203
|
+
mcpRegistryVerified: true
|
|
204
|
+
};
|
|
205
|
+
it('returns nothing for an empty or whitespace-only query', async () => {
|
|
206
|
+
const prefs = new FakePreferenceService();
|
|
207
|
+
const fetch = new StubRegistryFetchService([exampleRegistryEntry, githubEntry]);
|
|
208
|
+
const contribution = buildContainer(prefs, fetch).get(mcp_extensions_contribution_1.MCPExtensionsContribution);
|
|
209
|
+
const empty = [...await contribution.resolveSearchResults('', { verifiedOnly: false })];
|
|
210
|
+
const whitespace = [...await contribution.resolveSearchResults(' ', { verifiedOnly: false })];
|
|
211
|
+
(0, chai_1.expect)(empty).to.be.empty;
|
|
212
|
+
(0, chai_1.expect)(whitespace).to.be.empty;
|
|
213
|
+
});
|
|
214
|
+
it('returns all entries with searchableText covering name, serverId and description so the global fuzzy ranker can match any of them', async () => {
|
|
215
|
+
const prefs = new FakePreferenceService();
|
|
216
|
+
const fetch = new StubRegistryFetchService([exampleRegistryEntry, githubEntry]);
|
|
217
|
+
const contribution = buildContainer(prefs, fetch).get(mcp_extensions_contribution_1.MCPExtensionsContribution);
|
|
218
|
+
// The contribution intentionally does not filter by the query string: that's the
|
|
219
|
+
// view's job (`VSXExtensionsSource.collectSearchResults` runs `FuzzySearch.filter`
|
|
220
|
+
// across results from every contribution). The contribution's only responsibility
|
|
221
|
+
// is to supply candidates with rich `searchableText`.
|
|
222
|
+
const results = [...await contribution.resolveSearchResults('REPOSITORIES', { verifiedOnly: false })];
|
|
223
|
+
(0, chai_1.expect)(results).to.have.length(2);
|
|
224
|
+
const githubResult = results.find(r => r.element.entry.serverId === githubEntry.serverId);
|
|
225
|
+
(0, chai_1.expect)(githubResult.searchableText).to.contain(githubEntry.name);
|
|
226
|
+
(0, chai_1.expect)(githubResult.searchableText).to.contain(githubEntry.serverId);
|
|
227
|
+
(0, chai_1.expect)(githubResult.searchableText).to.contain(githubEntry.description);
|
|
228
|
+
});
|
|
229
|
+
it('classifies a registry entry as installed-link-stale when the matching-key local is linked to a server id missing from the registry', async () => {
|
|
230
|
+
// PR scenario: user installed `example` from the registry, then manually pointed
|
|
231
|
+
// its `registryMetadata.serverId` at an id not in the registry. In Search results
|
|
232
|
+
// the matching registry entry must show the **Unlink / Uninstall** affordances -
|
|
233
|
+
// mirroring what the Installed view shows - instead of **Link** (which would
|
|
234
|
+
// imply the local is merely unlinked rather than stale-linked).
|
|
235
|
+
const prefs = new FakePreferenceService();
|
|
236
|
+
await prefs.set(mcp_preferences_1.MCP_SERVERS_PREF, {
|
|
237
|
+
example: {
|
|
238
|
+
command: 'npx',
|
|
239
|
+
args: ['-y', 'example-mcp'],
|
|
240
|
+
registryMetadata: {
|
|
241
|
+
serverId: 'io.example/gone',
|
|
242
|
+
version: '^1.0.0',
|
|
243
|
+
configHash: 'hash-v1'
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
const fetch = new StubRegistryFetchService([exampleRegistryEntry]);
|
|
248
|
+
const contribution = buildContainer(prefs, fetch).get(mcp_extensions_contribution_1.MCPExtensionsContribution);
|
|
249
|
+
const results = [...await contribution.resolveSearchResults('example', { verifiedOnly: false })];
|
|
250
|
+
const exampleResult = results.find(r => r.element.entry.serverId === exampleRegistryEntry.serverId);
|
|
251
|
+
(0, chai_1.expect)(exampleResult, 'registry entry must surface in search results').to.not.be.undefined;
|
|
252
|
+
(0, chai_1.expect)(exampleResult.element.state).to.deep.equal({ kind: 'installed-link-stale' });
|
|
253
|
+
});
|
|
254
|
+
it('omits unverified entries when verifiedOnly is true and keeps verified ones', async () => {
|
|
255
|
+
const unverified = { ...exampleRegistryEntry, mcpRegistryVerified: false };
|
|
256
|
+
const prefs = new FakePreferenceService();
|
|
257
|
+
const fetch = new StubRegistryFetchService([unverified, githubEntry]);
|
|
258
|
+
const contribution = buildContainer(prefs, fetch).get(mcp_extensions_contribution_1.MCPExtensionsContribution);
|
|
259
|
+
const all = [...await contribution.resolveSearchResults('example', { verifiedOnly: false })];
|
|
260
|
+
const verifiedOnly = [...await contribution.resolveSearchResults('example', { verifiedOnly: true })];
|
|
261
|
+
(0, chai_1.expect)(all).to.have.length(2);
|
|
262
|
+
(0, chai_1.expect)(verifiedOnly).to.have.length(1);
|
|
263
|
+
(0, chai_1.expect)(verifiedOnly[0].element.entry.serverId).to.equal(githubEntry.serverId);
|
|
264
|
+
});
|
|
265
|
+
});
|
|
266
|
+
//# sourceMappingURL=mcp-extensions-contribution.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-extensions-contribution.spec.js","sourceRoot":"","sources":["../../../src/browser/mcp/mcp-extensions-contribution.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { PreferenceService } from '@theia/core';
|
|
2
|
+
import { MCPInstallEntryConfig, MCPRegistryMetadata, MCPServerDescription } from '@theia/ai-mcp/lib/common/mcp-server-manager';
|
|
3
|
+
import { MCPInstallOverrides, MCPServerEditor } from '@theia/ai-mcp/lib/browser/mcp-server-editor';
|
|
4
|
+
import { ClassificationResult, ResolvedRegistryEntry } from '../../common/mcp/mcp-registry-types';
|
|
5
|
+
export { MCPInstallOverrides };
|
|
6
|
+
type StoredEntry = MCPInstallEntryConfig & {
|
|
7
|
+
autostart?: boolean;
|
|
8
|
+
registryMetadata?: MCPRegistryMetadata;
|
|
9
|
+
};
|
|
10
|
+
type StoredServers = Record<string, StoredEntry>;
|
|
11
|
+
export declare const MCPInstallService: unique symbol;
|
|
12
|
+
export interface MCPInstallService {
|
|
13
|
+
/** Installs a registry entry, applying any user-supplied overrides collected by the install dialog. */
|
|
14
|
+
install(entry: ResolvedRegistryEntry, overrides?: MCPInstallOverrides): Promise<void>;
|
|
15
|
+
/** Restores a drifted entry's registry-owned config fields while preserving user-owned ones. */
|
|
16
|
+
fixConfig(entry: ResolvedRegistryEntry): Promise<void>;
|
|
17
|
+
/** Applies a newer registry approval to an installed entry, preserving user-supplied additions. */
|
|
18
|
+
update(entry: ResolvedRegistryEntry): Promise<void>;
|
|
19
|
+
/** Links an existing local server to a registry entry by stamping its registry metadata. */
|
|
20
|
+
link(entry: ResolvedRegistryEntry): Promise<void>;
|
|
21
|
+
/** Drops the registry link from a local server while keeping its config intact. */
|
|
22
|
+
unlink(name: string): Promise<void>;
|
|
23
|
+
/** Removes an installed server entry by its local preference key. */
|
|
24
|
+
uninstall(name: string): Promise<void>;
|
|
25
|
+
/** Classifies a locally stored server against the registry (for the Installed view). */
|
|
26
|
+
classifyLocalServer(local: MCPServerDescription, registryEntries: ResolvedRegistryEntry[]): ClassificationResult;
|
|
27
|
+
/** Classifies a registry entry against the locally stored servers (for the Search view). */
|
|
28
|
+
classifyRegistryEntry(entry: ResolvedRegistryEntry, locals: MCPServerDescription[], registryEntries: ResolvedRegistryEntry[]): ClassificationResult;
|
|
29
|
+
}
|
|
30
|
+
export declare class MCPInstallServiceImpl implements MCPInstallService {
|
|
31
|
+
protected readonly preferenceService: PreferenceService;
|
|
32
|
+
protected readonly editor: MCPServerEditor;
|
|
33
|
+
/** Delegates to the generic editor so both registry installs and `install-mcp` URL handlers go through the same code path. */
|
|
34
|
+
install(entry: ResolvedRegistryEntry, overrides?: MCPInstallOverrides): Promise<void>;
|
|
35
|
+
fixConfig(entry: ResolvedRegistryEntry): Promise<void>;
|
|
36
|
+
update(entry: ResolvedRegistryEntry): Promise<void>;
|
|
37
|
+
link(entry: ResolvedRegistryEntry): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Drop the registry link from a local server while keeping its config intact.
|
|
40
|
+
* Used to convert a stale-linked entry (registry no longer lists the serverId)
|
|
41
|
+
* into a plain user-added entry without losing the user's running server config.
|
|
42
|
+
*/
|
|
43
|
+
unlink(name: string): Promise<void>;
|
|
44
|
+
uninstall(name: string): Promise<void>;
|
|
45
|
+
protected readServers(): StoredServers;
|
|
46
|
+
protected writeServers(next: StoredServers): Promise<void>;
|
|
47
|
+
/** Registry-managed metadata block written onto every linked server entry. */
|
|
48
|
+
protected metadata(entry: ResolvedRegistryEntry): MCPRegistryMetadata;
|
|
49
|
+
classifyLocalServer(local: MCPServerDescription, registryEntries: ResolvedRegistryEntry[]): ClassificationResult;
|
|
50
|
+
classifyRegistryEntry(entry: ResolvedRegistryEntry, locals: MCPServerDescription[], registryEntries: ResolvedRegistryEntry[]): ClassificationResult;
|
|
51
|
+
/**
|
|
52
|
+
* Classify a local server that is already linked to a registry entry. Either the
|
|
53
|
+
* registry config matches (eligible for Update when the registry has published a new
|
|
54
|
+
* approval - detected via `configHash`) or it has drifted away (`fix-config`).
|
|
55
|
+
*
|
|
56
|
+
* Update detection uses `registryMetadata.configHash` exclusively.
|
|
57
|
+
* `registryMetadata.version` is kept on the local entry for display only; the
|
|
58
|
+
* registry may publish a new version without changing the install config, in which
|
|
59
|
+
* case we still want to offer Update.
|
|
60
|
+
*/
|
|
61
|
+
protected classifyLinked(entry: ResolvedRegistryEntry, local: MCPServerDescription): ClassificationResult;
|
|
62
|
+
/**
|
|
63
|
+
* True when the registry's `configHash` differs from the locally stored
|
|
64
|
+
* `registryMetadata.configHash`. Returns false when the registry has no `configHash`
|
|
65
|
+
* to compare against (older payloads) - without a hash we cannot make a confident
|
|
66
|
+
* "update available" decision and prefer not to nag the user.
|
|
67
|
+
*/
|
|
68
|
+
protected isUpdateAvailable(entry: ResolvedRegistryEntry, local: MCPServerDescription): boolean;
|
|
69
|
+
protected matchesByConfig(entry: ResolvedRegistryEntry, local: MCPServerDescription): boolean;
|
|
70
|
+
protected envMatches(registryEnv: Record<string, string> | undefined, localEnv: Record<string, string> | undefined): boolean;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=mcp-install-service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-install-service.d.ts","sourceRoot":"","sources":["../../../src/browser/mcp/mcp-install-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// *****************************************************************************
|
|
3
|
+
// Copyright (C) 2026 EclipseSource GmbH.
|
|
4
|
+
//
|
|
5
|
+
// This program and the accompanying materials are made available under the
|
|
6
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
7
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
8
|
+
//
|
|
9
|
+
// This Source Code may also be made available under the following Secondary
|
|
10
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
11
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
12
|
+
// with the GNU Classpath Exception which is available at
|
|
13
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
14
|
+
//
|
|
15
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
16
|
+
// *****************************************************************************
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.MCPInstallServiceImpl = exports.MCPInstallService = void 0;
|
|
19
|
+
const tslib_1 = require("tslib");
|
|
20
|
+
const inversify_1 = require("@theia/core/shared/inversify");
|
|
21
|
+
const core_1 = require("@theia/core");
|
|
22
|
+
const mcp_server_manager_1 = require("@theia/ai-mcp/lib/common/mcp-server-manager");
|
|
23
|
+
const mcp_preferences_1 = require("@theia/ai-mcp/lib/common/mcp-preferences");
|
|
24
|
+
const mcp_server_editor_1 = require("@theia/ai-mcp/lib/browser/mcp-server-editor");
|
|
25
|
+
exports.MCPInstallService = Symbol('MCPInstallService');
|
|
26
|
+
let MCPInstallServiceImpl = class MCPInstallServiceImpl {
|
|
27
|
+
/** Delegates to the generic editor so both registry installs and `install-mcp` URL handlers go through the same code path. */
|
|
28
|
+
async install(entry, overrides) {
|
|
29
|
+
await this.editor.installFromEntry(entry, overrides);
|
|
30
|
+
}
|
|
31
|
+
async fixConfig(entry) {
|
|
32
|
+
// Overwrite the registry-owned config fields, but carry forward user-owned ones
|
|
33
|
+
// (today: autostart). The registry has no opinion on `autostart`, so wiping it on
|
|
34
|
+
// fix-config would silently discard a user preference. Once the registry grows a
|
|
35
|
+
// formal notion of "user-configurable parameters", extend the forwarded set here.
|
|
36
|
+
const existing = this.readServers()[entry.localName];
|
|
37
|
+
const overrides = {};
|
|
38
|
+
if (existing?.autostart !== undefined) {
|
|
39
|
+
overrides.autostart = existing.autostart;
|
|
40
|
+
}
|
|
41
|
+
await this.install(entry, overrides);
|
|
42
|
+
}
|
|
43
|
+
async update(entry) {
|
|
44
|
+
const current = this.readServers();
|
|
45
|
+
const existing = current[entry.localName];
|
|
46
|
+
if (!existing) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
// If the registry switched the entry's transport (e.g. local stdio -> remote URL),
|
|
50
|
+
// drop the previous side's fields so settings.json doesn't end up carrying both.
|
|
51
|
+
const sanitized = { ...existing };
|
|
52
|
+
if (entry.config.serverUrl !== undefined) {
|
|
53
|
+
delete sanitized.command;
|
|
54
|
+
delete sanitized.args;
|
|
55
|
+
delete sanitized.env;
|
|
56
|
+
}
|
|
57
|
+
else if (entry.config.command !== undefined) {
|
|
58
|
+
delete sanitized.serverUrl;
|
|
59
|
+
delete sanitized.serverAuthToken;
|
|
60
|
+
delete sanitized.serverAuthTokenHeader;
|
|
61
|
+
delete sanitized.headers;
|
|
62
|
+
}
|
|
63
|
+
// Preserve user-added env keys; registry values win for keys the registry sets.
|
|
64
|
+
// Asymmetry: keys the registry previously set and has since dropped are also
|
|
65
|
+
// preserved here, because we cannot distinguish them from user-added keys without
|
|
66
|
+
// tracking provenance. A registry approval that published e.g. `LOG_LEVEL` in v1
|
|
67
|
+
// and removes it in v2 will leave the stale key in the local entry. This will be
|
|
68
|
+
// addressed alongside the planned "user-configurable parameters" work, which
|
|
69
|
+
// introduces an explicit registry-set vs. user-set distinction.
|
|
70
|
+
const mergedEnv = (entry.config.env || sanitized.env)
|
|
71
|
+
? { ...sanitized.env, ...(entry.config.env ?? {}) }
|
|
72
|
+
: undefined;
|
|
73
|
+
// Preserve user-supplied additions across updates. Today we only carry the auth
|
|
74
|
+
// token forward - registries should not ship secrets, so the new approval will
|
|
75
|
+
// either omit `serverAuthToken` entirely or carry it as an empty slot, both of
|
|
76
|
+
// which would otherwise wipe a token the user previously entered in the install
|
|
77
|
+
// dialog. A broader policy for user-additions belongs with the planned parameter
|
|
78
|
+
// configuration work.
|
|
79
|
+
const userAdditions = sanitized.serverAuthToken !== undefined
|
|
80
|
+
? { serverAuthToken: sanitized.serverAuthToken }
|
|
81
|
+
: {};
|
|
82
|
+
const updated = {
|
|
83
|
+
...sanitized,
|
|
84
|
+
...entry.config,
|
|
85
|
+
...userAdditions,
|
|
86
|
+
...(mergedEnv && { env: mergedEnv }),
|
|
87
|
+
registryMetadata: this.metadata(entry)
|
|
88
|
+
};
|
|
89
|
+
await this.writeServers({ ...current, [entry.localName]: updated });
|
|
90
|
+
}
|
|
91
|
+
async link(entry) {
|
|
92
|
+
const current = this.readServers();
|
|
93
|
+
const existing = current[entry.localName];
|
|
94
|
+
if (!existing) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
await this.writeServers({
|
|
98
|
+
...current,
|
|
99
|
+
[entry.localName]: { ...existing, registryMetadata: this.metadata(entry) }
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Drop the registry link from a local server while keeping its config intact.
|
|
104
|
+
* Used to convert a stale-linked entry (registry no longer lists the serverId)
|
|
105
|
+
* into a plain user-added entry without losing the user's running server config.
|
|
106
|
+
*/
|
|
107
|
+
async unlink(name) {
|
|
108
|
+
const current = this.readServers();
|
|
109
|
+
const existing = current[name];
|
|
110
|
+
if (!existing || existing.registryMetadata === undefined) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const next = { ...existing };
|
|
114
|
+
delete next.registryMetadata;
|
|
115
|
+
await this.writeServers({ ...current, [name]: next });
|
|
116
|
+
}
|
|
117
|
+
async uninstall(name) {
|
|
118
|
+
const current = this.readServers();
|
|
119
|
+
if (!(name in current)) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const next = { ...current };
|
|
123
|
+
delete next[name];
|
|
124
|
+
await this.writeServers(next);
|
|
125
|
+
}
|
|
126
|
+
readServers() {
|
|
127
|
+
return this.preferenceService.get(mcp_preferences_1.MCP_SERVERS_PREF, {}) ?? {};
|
|
128
|
+
}
|
|
129
|
+
async writeServers(next) {
|
|
130
|
+
await this.preferenceService.set(mcp_preferences_1.MCP_SERVERS_PREF, next, core_1.PreferenceScope.User);
|
|
131
|
+
}
|
|
132
|
+
/** Registry-managed metadata block written onto every linked server entry. */
|
|
133
|
+
metadata(entry) {
|
|
134
|
+
return {
|
|
135
|
+
serverId: entry.serverId,
|
|
136
|
+
...(entry.version !== undefined && { version: entry.version }),
|
|
137
|
+
...(entry.configHash !== undefined && { configHash: entry.configHash })
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
classifyLocalServer(local, registryEntries) {
|
|
141
|
+
const linkedId = local.registryMetadata?.serverId;
|
|
142
|
+
if (linkedId) {
|
|
143
|
+
const byServerId = registryEntries.find(e => e.serverId === linkedId);
|
|
144
|
+
if (!byServerId) {
|
|
145
|
+
return { kind: 'installed-link-stale' };
|
|
146
|
+
}
|
|
147
|
+
return this.classifyLinked(byServerId, local);
|
|
148
|
+
}
|
|
149
|
+
const matchingEntry = registryEntries.find(e => e.localName === local.name);
|
|
150
|
+
if (!matchingEntry) {
|
|
151
|
+
return { kind: 'installed-user-added' };
|
|
152
|
+
}
|
|
153
|
+
// Unlinked + same key: always offer Link, regardless of config drift. Drift is only
|
|
154
|
+
// considered actionable (fix-config) once the user has opted in by linking.
|
|
155
|
+
return { kind: 'installed-manually' };
|
|
156
|
+
}
|
|
157
|
+
classifyRegistryEntry(entry, locals, registryEntries) {
|
|
158
|
+
const local = locals.find(l => l.name === entry.localName);
|
|
159
|
+
if (!local) {
|
|
160
|
+
return { kind: 'not-installed' };
|
|
161
|
+
}
|
|
162
|
+
const linkedId = local.registryMetadata?.serverId;
|
|
163
|
+
if (linkedId === entry.serverId) {
|
|
164
|
+
return this.classifyLinked(entry, local);
|
|
165
|
+
}
|
|
166
|
+
// Local links to a registry id that doesn't exist in the registry - the link is
|
|
167
|
+
// stale. Surface the same state Installed shows so the user sees the Unlink and
|
|
168
|
+
// Uninstall affordances in both views instead of a misleading Link button.
|
|
169
|
+
if (linkedId && !registryEntries.some(e => e.serverId === linkedId)) {
|
|
170
|
+
return { kind: 'installed-link-stale' };
|
|
171
|
+
}
|
|
172
|
+
// Same key but not linked (no registryMetadata, or pointing to a different valid
|
|
173
|
+
// id): offer Link before surfacing any drift - drift handling is a post-link concern.
|
|
174
|
+
return { kind: 'installed-manually' };
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Classify a local server that is already linked to a registry entry. Either the
|
|
178
|
+
* registry config matches (eligible for Update when the registry has published a new
|
|
179
|
+
* approval - detected via `configHash`) or it has drifted away (`fix-config`).
|
|
180
|
+
*
|
|
181
|
+
* Update detection uses `registryMetadata.configHash` exclusively.
|
|
182
|
+
* `registryMetadata.version` is kept on the local entry for display only; the
|
|
183
|
+
* registry may publish a new version without changing the install config, in which
|
|
184
|
+
* case we still want to offer Update.
|
|
185
|
+
*/
|
|
186
|
+
classifyLinked(entry, local) {
|
|
187
|
+
if (!this.matchesByConfig(entry, local)) {
|
|
188
|
+
return { kind: 'fix-config' };
|
|
189
|
+
}
|
|
190
|
+
const updateAvailable = this.isUpdateAvailable(entry, local);
|
|
191
|
+
return { kind: 'installed-from-registry', updateAvailable };
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* True when the registry's `configHash` differs from the locally stored
|
|
195
|
+
* `registryMetadata.configHash`. Returns false when the registry has no `configHash`
|
|
196
|
+
* to compare against (older payloads) - without a hash we cannot make a confident
|
|
197
|
+
* "update available" decision and prefer not to nag the user.
|
|
198
|
+
*/
|
|
199
|
+
isUpdateAvailable(entry, local) {
|
|
200
|
+
if (entry.configHash === undefined) {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
return local.registryMetadata?.configHash !== entry.configHash;
|
|
204
|
+
}
|
|
205
|
+
matchesByConfig(entry, local) {
|
|
206
|
+
if (entry.config.command !== undefined) {
|
|
207
|
+
if (!(0, mcp_server_manager_1.isLocalMCPServerDescription)(local)) {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
if (local.command !== entry.config.command) {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
const entryArgs = entry.config.args ?? [];
|
|
214
|
+
const localArgs = local.args ?? [];
|
|
215
|
+
if (entryArgs.length !== localArgs.length) {
|
|
216
|
+
return false;
|
|
217
|
+
}
|
|
218
|
+
if (!entryArgs.every((value, index) => value === localArgs[index])) {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
return this.envMatches(entry.config.env, local.env);
|
|
222
|
+
}
|
|
223
|
+
if (entry.config.serverUrl !== undefined) {
|
|
224
|
+
if (!(0, mcp_server_manager_1.isRemoteMCPServerDescription)(local)) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
return local.serverUrl === entry.config.serverUrl;
|
|
228
|
+
}
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
envMatches(registryEnv, localEnv) {
|
|
232
|
+
if (!registryEnv) {
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
for (const key of Object.keys(registryEnv)) {
|
|
236
|
+
if (localEnv?.[key] !== registryEnv[key]) {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
exports.MCPInstallServiceImpl = MCPInstallServiceImpl;
|
|
244
|
+
tslib_1.__decorate([
|
|
245
|
+
(0, inversify_1.inject)(core_1.PreferenceService),
|
|
246
|
+
tslib_1.__metadata("design:type", Object)
|
|
247
|
+
], MCPInstallServiceImpl.prototype, "preferenceService", void 0);
|
|
248
|
+
tslib_1.__decorate([
|
|
249
|
+
(0, inversify_1.inject)(mcp_server_editor_1.MCPServerEditor),
|
|
250
|
+
tslib_1.__metadata("design:type", Object)
|
|
251
|
+
], MCPInstallServiceImpl.prototype, "editor", void 0);
|
|
252
|
+
exports.MCPInstallServiceImpl = MCPInstallServiceImpl = tslib_1.__decorate([
|
|
253
|
+
(0, inversify_1.injectable)()
|
|
254
|
+
], MCPInstallServiceImpl);
|
|
255
|
+
//# sourceMappingURL=mcp-install-service.js.map
|