agent-discover 1.3.8 → 1.4.0
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/CHANGELOG.md +44 -1
- package/README.md +34 -8
- package/agent-desk-plugin.json +10 -3
- package/dist/context.d.ts +2 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +15 -0
- package/dist/context.js.map +1 -1
- package/dist/domain/log.d.ts +7 -3
- package/dist/domain/log.d.ts.map +1 -1
- package/dist/domain/log.js +15 -5
- package/dist/domain/log.js.map +1 -1
- package/dist/domain/presets.d.ts +30 -0
- package/dist/domain/presets.d.ts.map +1 -0
- package/dist/domain/presets.js +76 -0
- package/dist/domain/presets.js.map +1 -0
- package/dist/domain/proxy.d.ts +153 -0
- package/dist/domain/proxy.d.ts.map +1 -1
- package/dist/domain/proxy.js +396 -3
- package/dist/domain/proxy.js.map +1 -1
- package/dist/domain/sampling.d.ts +9 -0
- package/dist/domain/sampling.d.ts.map +1 -0
- package/dist/domain/sampling.js +68 -0
- package/dist/domain/sampling.js.map +1 -0
- package/dist/storage/database.js +21 -0
- package/dist/storage/database.js.map +1 -1
- package/dist/transport/rest.d.ts.map +1 -1
- package/dist/transport/rest.js +349 -0
- package/dist/transport/rest.js.map +1 -1
- package/dist/transport/ws.d.ts.map +1 -1
- package/dist/transport/ws.js +32 -0
- package/dist/transport/ws.js.map +1 -1
- package/dist/ui/app.js +16 -0
- package/dist/ui/index.html +3 -0
- package/dist/ui/markdown.js +102 -0
- package/dist/ui/schema-form.js +393 -0
- package/dist/ui/styles.css +724 -0
- package/dist/ui/tester-window.html +116 -0
- package/dist/ui/tester-window.js +153 -0
- package/dist/ui/tester.js +1412 -0
- package/package.json +1 -1
package/dist/domain/proxy.d.ts
CHANGED
|
@@ -1,6 +1,90 @@
|
|
|
1
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
2
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
3
|
+
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
4
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
1
5
|
import type { SecretsService } from './secrets.js';
|
|
2
6
|
import type { MetricsService } from './metrics.js';
|
|
3
7
|
import type { LogService } from './log.js';
|
|
8
|
+
type AnyTransport = StdioClientTransport | SSEClientTransport | StreamableHTTPClientTransport;
|
|
9
|
+
export type ResourceEntry = {
|
|
10
|
+
uri: string;
|
|
11
|
+
name: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
mimeType?: string;
|
|
14
|
+
size?: number;
|
|
15
|
+
};
|
|
16
|
+
export type ResourceTemplateEntry = {
|
|
17
|
+
uriTemplate: string;
|
|
18
|
+
name: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
mimeType?: string;
|
|
21
|
+
};
|
|
22
|
+
export type PromptEntry = {
|
|
23
|
+
name: string;
|
|
24
|
+
description?: string;
|
|
25
|
+
arguments?: Array<{
|
|
26
|
+
name: string;
|
|
27
|
+
description?: string;
|
|
28
|
+
required?: boolean;
|
|
29
|
+
}>;
|
|
30
|
+
};
|
|
31
|
+
export type ServerInfo = {
|
|
32
|
+
name: string;
|
|
33
|
+
version: string;
|
|
34
|
+
instructions?: string;
|
|
35
|
+
capabilities: Record<string, unknown>;
|
|
36
|
+
};
|
|
37
|
+
interface ActiveServer {
|
|
38
|
+
client: Client;
|
|
39
|
+
transport: AnyTransport;
|
|
40
|
+
tools: Array<{
|
|
41
|
+
name: string;
|
|
42
|
+
description?: string;
|
|
43
|
+
inputSchema?: Record<string, unknown>;
|
|
44
|
+
}>;
|
|
45
|
+
config: ServerConfig;
|
|
46
|
+
capabilities?: Record<string, unknown>;
|
|
47
|
+
serverVersion?: {
|
|
48
|
+
name: string;
|
|
49
|
+
version: string;
|
|
50
|
+
};
|
|
51
|
+
instructions?: string;
|
|
52
|
+
transient: boolean;
|
|
53
|
+
interactive: boolean;
|
|
54
|
+
lastPingMs?: number;
|
|
55
|
+
}
|
|
56
|
+
export interface PendingElicitation {
|
|
57
|
+
id: string;
|
|
58
|
+
serverName: string;
|
|
59
|
+
message: string;
|
|
60
|
+
requestedSchema: Record<string, unknown>;
|
|
61
|
+
createdAt: number;
|
|
62
|
+
}
|
|
63
|
+
export type ElicitationAction = 'accept' | 'decline' | 'cancel';
|
|
64
|
+
export interface SamplingProvider {
|
|
65
|
+
createMessage(request: {
|
|
66
|
+
serverName: string;
|
|
67
|
+
messages: Array<{
|
|
68
|
+
role: string;
|
|
69
|
+
content: {
|
|
70
|
+
type: string;
|
|
71
|
+
text?: string;
|
|
72
|
+
};
|
|
73
|
+
}>;
|
|
74
|
+
maxTokens?: number;
|
|
75
|
+
temperature?: number;
|
|
76
|
+
systemPrompt?: string;
|
|
77
|
+
modelPreferences?: Record<string, unknown>;
|
|
78
|
+
}): Promise<{
|
|
79
|
+
role: 'assistant';
|
|
80
|
+
content: {
|
|
81
|
+
type: 'text';
|
|
82
|
+
text: string;
|
|
83
|
+
};
|
|
84
|
+
model: string;
|
|
85
|
+
stopReason?: string;
|
|
86
|
+
}>;
|
|
87
|
+
}
|
|
4
88
|
export interface ServerConfig {
|
|
5
89
|
name: string;
|
|
6
90
|
command?: string;
|
|
@@ -19,13 +103,31 @@ export interface ParsedToolName {
|
|
|
19
103
|
serverName: string;
|
|
20
104
|
toolName: string;
|
|
21
105
|
}
|
|
106
|
+
export interface TransientHandle {
|
|
107
|
+
handle: string;
|
|
108
|
+
serverName: string;
|
|
109
|
+
tools: ActiveServer['tools'];
|
|
110
|
+
capabilities: Record<string, unknown>;
|
|
111
|
+
serverVersion?: {
|
|
112
|
+
name: string;
|
|
113
|
+
version: string;
|
|
114
|
+
};
|
|
115
|
+
expiresAt: number;
|
|
116
|
+
}
|
|
22
117
|
export declare class McpProxy {
|
|
23
118
|
private readonly activeServers;
|
|
24
119
|
private readonly activating;
|
|
120
|
+
private readonly transient;
|
|
121
|
+
private transientSeq;
|
|
25
122
|
private secretsService?;
|
|
26
123
|
private metricsService?;
|
|
27
124
|
private logService?;
|
|
28
125
|
private serverIdResolver?;
|
|
126
|
+
private rootsProvider;
|
|
127
|
+
private samplingProvider?;
|
|
128
|
+
private readonly elicitations;
|
|
129
|
+
private elicitationListener?;
|
|
130
|
+
private elicitationSeq;
|
|
29
131
|
setSecretsService(secrets: SecretsService): void;
|
|
30
132
|
setMetricsService(metrics: MetricsService): void;
|
|
31
133
|
setLogService(logs: LogService): void;
|
|
@@ -35,6 +137,7 @@ export declare class McpProxy {
|
|
|
35
137
|
description?: string;
|
|
36
138
|
inputSchema?: Record<string, unknown>;
|
|
37
139
|
}>>;
|
|
140
|
+
private activateInternal;
|
|
38
141
|
deactivate(name: string): Promise<void>;
|
|
39
142
|
callTool(serverName: string, toolName: string, args?: Record<string, unknown>): Promise<{
|
|
40
143
|
content: Array<{
|
|
@@ -53,7 +156,57 @@ export declare class McpProxy {
|
|
|
53
156
|
description?: string;
|
|
54
157
|
}>;
|
|
55
158
|
isActive(name: string): boolean;
|
|
159
|
+
getServerInfo(name: string): ServerInfo | null;
|
|
160
|
+
listToolsLive(name: string): Promise<ActiveServer['tools']>;
|
|
161
|
+
listResources(name: string, cursor?: string): Promise<{
|
|
162
|
+
resources: ResourceEntry[];
|
|
163
|
+
nextCursor?: string;
|
|
164
|
+
}>;
|
|
165
|
+
listResourceTemplates(name: string, cursor?: string): Promise<{
|
|
166
|
+
resourceTemplates: ResourceTemplateEntry[];
|
|
167
|
+
nextCursor?: string;
|
|
168
|
+
}>;
|
|
169
|
+
readResource(name: string, uri: string): Promise<{
|
|
170
|
+
contents: Array<Record<string, unknown>>;
|
|
171
|
+
}>;
|
|
172
|
+
subscribeResource(name: string, uri: string): Promise<void>;
|
|
173
|
+
unsubscribeResource(name: string, uri: string): Promise<void>;
|
|
174
|
+
listPrompts(name: string, cursor?: string): Promise<{
|
|
175
|
+
prompts: PromptEntry[];
|
|
176
|
+
nextCursor?: string;
|
|
177
|
+
}>;
|
|
178
|
+
getPrompt(name: string, promptName: string, args?: Record<string, string>): Promise<{
|
|
179
|
+
messages: Array<Record<string, unknown>>;
|
|
180
|
+
description?: string;
|
|
181
|
+
}>;
|
|
182
|
+
ping(name: string): Promise<{
|
|
183
|
+
ok: boolean;
|
|
184
|
+
rtt_ms: number;
|
|
185
|
+
}>;
|
|
186
|
+
setLoggingLevel(name: string, level: 'debug' | 'info' | 'notice' | 'warning' | 'error' | 'critical' | 'alert' | 'emergency'): Promise<void>;
|
|
187
|
+
exportConfig(name: string, format: 'mcp-json' | 'agent-discover'): Record<string, unknown>;
|
|
188
|
+
activateTransient(config: ServerConfig, ttlMs?: number): Promise<TransientHandle>;
|
|
189
|
+
releaseTransient(handle: string): Promise<void>;
|
|
190
|
+
resolveTransient(handle: string): string | null;
|
|
191
|
+
private pruneTransient;
|
|
192
|
+
setRootsProvider(provider: () => Array<{
|
|
193
|
+
uri: string;
|
|
194
|
+
name?: string;
|
|
195
|
+
}>): void;
|
|
196
|
+
private wireRootsHandler;
|
|
197
|
+
private wireNotificationHandler;
|
|
198
|
+
private requireActive;
|
|
199
|
+
setElicitationListener(listener: (pending: PendingElicitation) => void): void;
|
|
200
|
+
listPendingElicitations(): PendingElicitation[];
|
|
201
|
+
respondElicitation(id: string, response: {
|
|
202
|
+
action: ElicitationAction;
|
|
203
|
+
content?: Record<string, unknown>;
|
|
204
|
+
}): boolean;
|
|
205
|
+
private wireElicitationHandler;
|
|
206
|
+
setSamplingProvider(provider: SamplingProvider): void;
|
|
207
|
+
private wireSamplingHandler;
|
|
56
208
|
private createTransport;
|
|
57
209
|
deactivateAll(): Promise<void>;
|
|
58
210
|
}
|
|
211
|
+
export {};
|
|
59
212
|
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/domain/proxy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/domain/proxy.ts"],"names":[],"mappings":"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"}
|
package/dist/domain/proxy.js
CHANGED
|
@@ -10,6 +10,7 @@ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
|
10
10
|
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
11
11
|
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
12
12
|
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
13
|
+
import { ElicitRequestSchema, CreateMessageRequestSchema, ListRootsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
13
14
|
import { version } from '../version.js';
|
|
14
15
|
const ACTIVATE_TIMEOUT_MS = 60_000;
|
|
15
16
|
const CALL_TIMEOUT_MS = 60_000;
|
|
@@ -31,6 +32,9 @@ function withTimeout(promise, ms, label) {
|
|
|
31
32
|
new Promise((_resolve, reject) => setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms)),
|
|
32
33
|
]);
|
|
33
34
|
}
|
|
35
|
+
const TRANSIENT_TTL_MS = 15 * 60_000;
|
|
36
|
+
const TRANSIENT_NAME_PREFIX = '__transient__';
|
|
37
|
+
const ELICITATION_TIMEOUT_MS = 2 * 60_000;
|
|
34
38
|
export class McpProxy {
|
|
35
39
|
activeServers = new Map();
|
|
36
40
|
// Names currently mid-activation. Held only across the connect/listTools
|
|
@@ -38,10 +42,17 @@ export class McpProxy {
|
|
|
38
42
|
// child processes (the original `if (activeServers.has(name))` guard
|
|
39
43
|
// races because both callers pass it before either awaits).
|
|
40
44
|
activating = new Set();
|
|
45
|
+
transient = new Map();
|
|
46
|
+
transientSeq = 0;
|
|
41
47
|
secretsService;
|
|
42
48
|
metricsService;
|
|
43
49
|
logService;
|
|
44
50
|
serverIdResolver;
|
|
51
|
+
rootsProvider = () => [];
|
|
52
|
+
samplingProvider;
|
|
53
|
+
elicitations = new Map();
|
|
54
|
+
elicitationListener;
|
|
55
|
+
elicitationSeq = 0;
|
|
45
56
|
setSecretsService(secrets) {
|
|
46
57
|
this.secretsService = secrets;
|
|
47
58
|
}
|
|
@@ -55,6 +66,9 @@ export class McpProxy {
|
|
|
55
66
|
this.serverIdResolver = resolver;
|
|
56
67
|
}
|
|
57
68
|
async activate(config) {
|
|
69
|
+
return this.activateInternal(config, false, false);
|
|
70
|
+
}
|
|
71
|
+
async activateInternal(config, transient, interactive) {
|
|
58
72
|
if (this.activeServers.has(config.name) || this.activating.has(config.name)) {
|
|
59
73
|
throw new Error(`Server "${config.name}" is already active`);
|
|
60
74
|
}
|
|
@@ -63,12 +77,42 @@ export class McpProxy {
|
|
|
63
77
|
this.activating.add(config.name);
|
|
64
78
|
try {
|
|
65
79
|
const transport = this.createTransport(config);
|
|
66
|
-
const
|
|
80
|
+
const advertisedCapabilities = {
|
|
81
|
+
roots: { listChanged: true },
|
|
82
|
+
elicitation: {},
|
|
83
|
+
};
|
|
84
|
+
if (interactive) {
|
|
85
|
+
advertisedCapabilities.sampling = {};
|
|
86
|
+
}
|
|
87
|
+
const client = new Client({ name: 'agent-discover', version }, { capabilities: advertisedCapabilities });
|
|
88
|
+
this.wireRootsHandler(client);
|
|
89
|
+
this.wireNotificationHandler(client, config.name);
|
|
90
|
+
if (interactive) {
|
|
91
|
+
this.wireElicitationHandler(client, config.name);
|
|
92
|
+
this.wireSamplingHandler(client, config.name);
|
|
93
|
+
}
|
|
67
94
|
try {
|
|
68
95
|
await withTimeout(client.connect(transport), ACTIVATE_TIMEOUT_MS, 'connect');
|
|
96
|
+
const capabilities = typeof client.getServerCapabilities === 'function'
|
|
97
|
+
? client.getServerCapabilities()
|
|
98
|
+
: undefined;
|
|
99
|
+
const serverVersion = typeof client.getServerVersion === 'function' ? client.getServerVersion() : undefined;
|
|
100
|
+
const instructions = typeof client.getInstructions === 'function' ? client.getInstructions() : undefined;
|
|
69
101
|
const result = await withTimeout(client.listTools(), ACTIVATE_TIMEOUT_MS, 'listTools');
|
|
70
102
|
const tools = result.tools ?? [];
|
|
71
|
-
this.activeServers.set(config.name, {
|
|
103
|
+
this.activeServers.set(config.name, {
|
|
104
|
+
client,
|
|
105
|
+
transport,
|
|
106
|
+
tools,
|
|
107
|
+
config,
|
|
108
|
+
capabilities: capabilities,
|
|
109
|
+
serverVersion: serverVersion
|
|
110
|
+
? { name: serverVersion.name, version: serverVersion.version }
|
|
111
|
+
: undefined,
|
|
112
|
+
instructions,
|
|
113
|
+
transient,
|
|
114
|
+
interactive,
|
|
115
|
+
});
|
|
72
116
|
return tools;
|
|
73
117
|
}
|
|
74
118
|
catch (err) {
|
|
@@ -131,8 +175,19 @@ export class McpProxy {
|
|
|
131
175
|
if (!server)
|
|
132
176
|
throw new Error(`Server "${serverName}" is not active`);
|
|
133
177
|
const start = Date.now();
|
|
178
|
+
const logs = this.logService;
|
|
179
|
+
const onprogress = (notification) => {
|
|
180
|
+
try {
|
|
181
|
+
logs?.pushProgress(serverName, notification.progressToken ?? toolName, notification.progress ?? 0, notification.total, notification.message);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
/* ignore */
|
|
185
|
+
}
|
|
186
|
+
};
|
|
134
187
|
try {
|
|
135
|
-
const result = await withTimeout(server.client.callTool({ name: toolName, arguments: args ?? {} }
|
|
188
|
+
const result = await withTimeout(server.client.callTool({ name: toolName, arguments: args ?? {} }, undefined, {
|
|
189
|
+
onprogress,
|
|
190
|
+
}), CALL_TIMEOUT_MS, `${serverName}/${toolName}`);
|
|
136
191
|
const typed = result;
|
|
137
192
|
const latency = Date.now() - start;
|
|
138
193
|
const success = !typed.isError;
|
|
@@ -215,6 +270,344 @@ export class McpProxy {
|
|
|
215
270
|
isActive(name) {
|
|
216
271
|
return this.activeServers.has(name);
|
|
217
272
|
}
|
|
273
|
+
// ---------------------------------------------------------------------------
|
|
274
|
+
// Tester surface — server info, resources, prompts, ping, logging level
|
|
275
|
+
// ---------------------------------------------------------------------------
|
|
276
|
+
getServerInfo(name) {
|
|
277
|
+
const server = this.activeServers.get(name);
|
|
278
|
+
if (!server)
|
|
279
|
+
return null;
|
|
280
|
+
return {
|
|
281
|
+
name: server.serverVersion?.name ?? server.config.name,
|
|
282
|
+
version: server.serverVersion?.version ?? '',
|
|
283
|
+
instructions: server.instructions,
|
|
284
|
+
capabilities: server.capabilities ?? {},
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
async listToolsLive(name) {
|
|
288
|
+
const server = this.requireActive(name);
|
|
289
|
+
const result = await withTimeout(server.client.listTools(), CALL_TIMEOUT_MS, 'listTools');
|
|
290
|
+
const tools = result.tools ?? [];
|
|
291
|
+
server.tools = tools;
|
|
292
|
+
return tools;
|
|
293
|
+
}
|
|
294
|
+
async listResources(name, cursor) {
|
|
295
|
+
const server = this.requireActive(name);
|
|
296
|
+
const params = cursor ? { cursor } : undefined;
|
|
297
|
+
const result = await withTimeout(server.client.listResources(params), CALL_TIMEOUT_MS, 'listResources');
|
|
298
|
+
return {
|
|
299
|
+
resources: (result.resources ?? []).map((r) => ({
|
|
300
|
+
uri: r.uri,
|
|
301
|
+
name: r.name,
|
|
302
|
+
description: r.description,
|
|
303
|
+
mimeType: r.mimeType,
|
|
304
|
+
size: r.size,
|
|
305
|
+
})),
|
|
306
|
+
nextCursor: result.nextCursor,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
async listResourceTemplates(name, cursor) {
|
|
310
|
+
const server = this.requireActive(name);
|
|
311
|
+
const params = cursor ? { cursor } : undefined;
|
|
312
|
+
const result = await withTimeout(server.client.listResourceTemplates(params), CALL_TIMEOUT_MS, 'listResourceTemplates');
|
|
313
|
+
return {
|
|
314
|
+
resourceTemplates: (result.resourceTemplates ?? []).map((t) => ({
|
|
315
|
+
uriTemplate: t.uriTemplate,
|
|
316
|
+
name: t.name,
|
|
317
|
+
description: t.description,
|
|
318
|
+
mimeType: t.mimeType,
|
|
319
|
+
})),
|
|
320
|
+
nextCursor: result.nextCursor,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
async readResource(name, uri) {
|
|
324
|
+
const server = this.requireActive(name);
|
|
325
|
+
const start = Date.now();
|
|
326
|
+
try {
|
|
327
|
+
const result = await withTimeout(server.client.readResource({ uri }), CALL_TIMEOUT_MS, `${name}/readResource`);
|
|
328
|
+
const latency = Date.now() - start;
|
|
329
|
+
this.logService?.push(name, uri, { uri }, JSON.stringify(result.contents), latency, true, 'resource-read');
|
|
330
|
+
return { contents: result.contents };
|
|
331
|
+
}
|
|
332
|
+
catch (err) {
|
|
333
|
+
const latency = Date.now() - start;
|
|
334
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
335
|
+
this.logService?.push(name, uri, { uri }, msg, latency, false, 'resource-read');
|
|
336
|
+
throw err;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
async subscribeResource(name, uri) {
|
|
340
|
+
const server = this.requireActive(name);
|
|
341
|
+
await withTimeout(server.client.subscribeResource({ uri }), CALL_TIMEOUT_MS, 'subscribe');
|
|
342
|
+
}
|
|
343
|
+
async unsubscribeResource(name, uri) {
|
|
344
|
+
const server = this.requireActive(name);
|
|
345
|
+
await withTimeout(server.client.unsubscribeResource({ uri }), CALL_TIMEOUT_MS, 'unsubscribe');
|
|
346
|
+
}
|
|
347
|
+
async listPrompts(name, cursor) {
|
|
348
|
+
const server = this.requireActive(name);
|
|
349
|
+
const params = cursor ? { cursor } : undefined;
|
|
350
|
+
const result = await withTimeout(server.client.listPrompts(params), CALL_TIMEOUT_MS, 'listPrompts');
|
|
351
|
+
return {
|
|
352
|
+
prompts: (result.prompts ?? []).map((p) => ({
|
|
353
|
+
name: p.name,
|
|
354
|
+
description: p.description,
|
|
355
|
+
arguments: p.arguments,
|
|
356
|
+
})),
|
|
357
|
+
nextCursor: result.nextCursor,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
async getPrompt(name, promptName, args) {
|
|
361
|
+
const server = this.requireActive(name);
|
|
362
|
+
const start = Date.now();
|
|
363
|
+
try {
|
|
364
|
+
const result = await withTimeout(server.client.getPrompt({ name: promptName, arguments: args ?? {} }), CALL_TIMEOUT_MS, `${name}/getPrompt/${promptName}`);
|
|
365
|
+
const latency = Date.now() - start;
|
|
366
|
+
this.logService?.push(name, promptName, (args ?? {}), JSON.stringify(result.messages), latency, true, 'prompt-get');
|
|
367
|
+
return {
|
|
368
|
+
messages: result.messages,
|
|
369
|
+
description: result.description,
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
catch (err) {
|
|
373
|
+
const latency = Date.now() - start;
|
|
374
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
375
|
+
this.logService?.push(name, promptName, (args ?? {}), msg, latency, false, 'prompt-get');
|
|
376
|
+
throw err;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
async ping(name) {
|
|
380
|
+
const server = this.requireActive(name);
|
|
381
|
+
const start = Date.now();
|
|
382
|
+
try {
|
|
383
|
+
await withTimeout(server.client.ping(), CALL_TIMEOUT_MS, 'ping');
|
|
384
|
+
const rtt = Date.now() - start;
|
|
385
|
+
server.lastPingMs = rtt;
|
|
386
|
+
this.logService?.push(name, 'ping', {}, 'pong', rtt, true, 'ping');
|
|
387
|
+
return { ok: true, rtt_ms: rtt };
|
|
388
|
+
}
|
|
389
|
+
catch (err) {
|
|
390
|
+
const rtt = Date.now() - start;
|
|
391
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
392
|
+
this.logService?.push(name, 'ping', {}, msg, rtt, false, 'ping');
|
|
393
|
+
throw err;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
async setLoggingLevel(name, level) {
|
|
397
|
+
const server = this.requireActive(name);
|
|
398
|
+
await withTimeout(server.client.setLoggingLevel(level), CALL_TIMEOUT_MS, 'setLoggingLevel');
|
|
399
|
+
}
|
|
400
|
+
exportConfig(name, format) {
|
|
401
|
+
const server = this.activeServers.get(name);
|
|
402
|
+
if (!server)
|
|
403
|
+
throw new Error(`Server "${name}" is not active`);
|
|
404
|
+
const cfg = server.config;
|
|
405
|
+
const entry = {};
|
|
406
|
+
if (cfg.transport === 'sse' || cfg.transport === 'streamable-http') {
|
|
407
|
+
entry.type = cfg.transport === 'sse' ? 'sse' : 'http';
|
|
408
|
+
if (cfg.url)
|
|
409
|
+
entry.url = cfg.url;
|
|
410
|
+
if (cfg.headers && Object.keys(cfg.headers).length > 0)
|
|
411
|
+
entry.headers = cfg.headers;
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
if (cfg.command)
|
|
415
|
+
entry.command = cfg.command;
|
|
416
|
+
if (cfg.args && cfg.args.length > 0)
|
|
417
|
+
entry.args = cfg.args;
|
|
418
|
+
if (cfg.env && Object.keys(cfg.env).length > 0)
|
|
419
|
+
entry.env = cfg.env;
|
|
420
|
+
}
|
|
421
|
+
if (format === 'agent-discover') {
|
|
422
|
+
return { servers: [{ name: cfg.name, ...entry, auto_activate: true }] };
|
|
423
|
+
}
|
|
424
|
+
return { mcpServers: { [cfg.name]: entry } };
|
|
425
|
+
}
|
|
426
|
+
// ---------------------------------------------------------------------------
|
|
427
|
+
// Transient (ad-hoc) servers
|
|
428
|
+
// ---------------------------------------------------------------------------
|
|
429
|
+
async activateTransient(config, ttlMs = TRANSIENT_TTL_MS) {
|
|
430
|
+
this.pruneTransient();
|
|
431
|
+
const handle = `${Date.now().toString(36)}-${(++this.transientSeq).toString(36)}`;
|
|
432
|
+
const serverName = `${TRANSIENT_NAME_PREFIX}${handle}`;
|
|
433
|
+
const merged = { ...config, name: serverName };
|
|
434
|
+
const tools = await this.activateInternal(merged, true, true);
|
|
435
|
+
const expiresAt = Date.now() + ttlMs;
|
|
436
|
+
this.transient.set(handle, { serverName, expiresAt });
|
|
437
|
+
const active = this.activeServers.get(serverName);
|
|
438
|
+
setTimeout(() => {
|
|
439
|
+
this.releaseTransient(handle).catch(() => { });
|
|
440
|
+
}, ttlMs).unref?.();
|
|
441
|
+
return {
|
|
442
|
+
handle,
|
|
443
|
+
serverName,
|
|
444
|
+
tools,
|
|
445
|
+
capabilities: active.capabilities ?? {},
|
|
446
|
+
serverVersion: active.serverVersion,
|
|
447
|
+
expiresAt,
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
async releaseTransient(handle) {
|
|
451
|
+
const entry = this.transient.get(handle);
|
|
452
|
+
if (!entry)
|
|
453
|
+
return;
|
|
454
|
+
this.transient.delete(handle);
|
|
455
|
+
if (this.activeServers.has(entry.serverName)) {
|
|
456
|
+
try {
|
|
457
|
+
await this.deactivate(entry.serverName);
|
|
458
|
+
}
|
|
459
|
+
catch {
|
|
460
|
+
/* ignore */
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
resolveTransient(handle) {
|
|
465
|
+
const entry = this.transient.get(handle);
|
|
466
|
+
if (!entry)
|
|
467
|
+
return null;
|
|
468
|
+
if (entry.expiresAt < Date.now()) {
|
|
469
|
+
this.releaseTransient(handle).catch(() => { });
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
return entry.serverName;
|
|
473
|
+
}
|
|
474
|
+
pruneTransient() {
|
|
475
|
+
const now = Date.now();
|
|
476
|
+
for (const [handle, entry] of this.transient.entries()) {
|
|
477
|
+
if (entry.expiresAt < now) {
|
|
478
|
+
this.releaseTransient(handle).catch(() => { });
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
// ---------------------------------------------------------------------------
|
|
483
|
+
// Roots provider (advertises client roots capability)
|
|
484
|
+
// ---------------------------------------------------------------------------
|
|
485
|
+
setRootsProvider(provider) {
|
|
486
|
+
this.rootsProvider = provider;
|
|
487
|
+
}
|
|
488
|
+
wireRootsHandler(client) {
|
|
489
|
+
try {
|
|
490
|
+
client.setRequestHandler(ListRootsRequestSchema, async () => ({
|
|
491
|
+
roots: this.rootsProvider(),
|
|
492
|
+
}));
|
|
493
|
+
}
|
|
494
|
+
catch {
|
|
495
|
+
/* roots handler is best-effort; failures don't block activation */
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
wireNotificationHandler(client, serverName) {
|
|
499
|
+
const anyClient = client;
|
|
500
|
+
const logs = this.logService;
|
|
501
|
+
anyClient.fallbackNotificationHandler = async (n) => {
|
|
502
|
+
try {
|
|
503
|
+
if (!logs)
|
|
504
|
+
return;
|
|
505
|
+
if (n.method === 'notifications/progress' && n.params) {
|
|
506
|
+
const p = n.params;
|
|
507
|
+
logs.pushProgress(serverName, p.progressToken ?? 0, p.progress ?? 0, p.total, p.message);
|
|
508
|
+
}
|
|
509
|
+
else {
|
|
510
|
+
logs.pushNotification(serverName, n.method, (n.params ?? {}));
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
catch {
|
|
514
|
+
/* ignore */
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
requireActive(name) {
|
|
519
|
+
const server = this.activeServers.get(name);
|
|
520
|
+
if (!server)
|
|
521
|
+
throw new Error(`Server "${name}" is not active`);
|
|
522
|
+
return server;
|
|
523
|
+
}
|
|
524
|
+
// ---------------------------------------------------------------------------
|
|
525
|
+
// Elicitation — only wired on interactive (transient) clients
|
|
526
|
+
// ---------------------------------------------------------------------------
|
|
527
|
+
setElicitationListener(listener) {
|
|
528
|
+
this.elicitationListener = listener;
|
|
529
|
+
}
|
|
530
|
+
listPendingElicitations() {
|
|
531
|
+
return [...this.elicitations.values()].map((e) => e.request);
|
|
532
|
+
}
|
|
533
|
+
respondElicitation(id, response) {
|
|
534
|
+
const entry = this.elicitations.get(id);
|
|
535
|
+
if (!entry)
|
|
536
|
+
return false;
|
|
537
|
+
this.elicitations.delete(id);
|
|
538
|
+
clearTimeout(entry.timer);
|
|
539
|
+
entry.resolve(response);
|
|
540
|
+
return true;
|
|
541
|
+
}
|
|
542
|
+
wireElicitationHandler(client, serverName) {
|
|
543
|
+
client.setRequestHandler(ElicitRequestSchema, async (req) => {
|
|
544
|
+
const params = req.params;
|
|
545
|
+
const id = `elicit-${Date.now().toString(36)}-${(++this.elicitationSeq).toString(36)}`;
|
|
546
|
+
const pending = {
|
|
547
|
+
id,
|
|
548
|
+
serverName,
|
|
549
|
+
message: params.message ?? '',
|
|
550
|
+
requestedSchema: params.requestedSchema ?? { type: 'object', properties: {} },
|
|
551
|
+
createdAt: Date.now(),
|
|
552
|
+
};
|
|
553
|
+
this.logService?.push(serverName, 'elicitation/create', pending.requestedSchema, pending.message, 0, true, 'elicitation');
|
|
554
|
+
return new Promise((resolve) => {
|
|
555
|
+
const timer = setTimeout(() => {
|
|
556
|
+
if (this.elicitations.has(id)) {
|
|
557
|
+
this.elicitations.delete(id);
|
|
558
|
+
resolve({ action: 'cancel' });
|
|
559
|
+
}
|
|
560
|
+
}, ELICITATION_TIMEOUT_MS);
|
|
561
|
+
this.elicitations.set(id, { serverName, resolve, timer, request: pending });
|
|
562
|
+
try {
|
|
563
|
+
this.elicitationListener?.(pending);
|
|
564
|
+
}
|
|
565
|
+
catch {
|
|
566
|
+
/* ignore listener errors */
|
|
567
|
+
}
|
|
568
|
+
}).then((response) => {
|
|
569
|
+
return response.action === 'accept' && response.content
|
|
570
|
+
? { action: 'accept', content: response.content }
|
|
571
|
+
: { action: response.action };
|
|
572
|
+
});
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
// ---------------------------------------------------------------------------
|
|
576
|
+
// Sampling — only wired on interactive (transient) clients
|
|
577
|
+
// ---------------------------------------------------------------------------
|
|
578
|
+
setSamplingProvider(provider) {
|
|
579
|
+
this.samplingProvider = provider;
|
|
580
|
+
}
|
|
581
|
+
wireSamplingHandler(client, serverName) {
|
|
582
|
+
client.setRequestHandler(CreateMessageRequestSchema, async (req) => {
|
|
583
|
+
const params = req.params;
|
|
584
|
+
const start = Date.now();
|
|
585
|
+
if (!this.samplingProvider) {
|
|
586
|
+
const message = 'sampling/createMessage: no sampling provider configured (set AGENT_DISCOVER_OPENAI_API_KEY or OPENAI_API_KEY to enable)';
|
|
587
|
+
this.logService?.push(serverName, 'sampling/createMessage', params, message, 0, false, 'sampling');
|
|
588
|
+
throw new Error(message);
|
|
589
|
+
}
|
|
590
|
+
try {
|
|
591
|
+
const result = await this.samplingProvider.createMessage({
|
|
592
|
+
serverName,
|
|
593
|
+
messages: params.messages,
|
|
594
|
+
maxTokens: params.maxTokens,
|
|
595
|
+
temperature: params.temperature,
|
|
596
|
+
systemPrompt: params.systemPrompt,
|
|
597
|
+
modelPreferences: params.modelPreferences,
|
|
598
|
+
});
|
|
599
|
+
const latency = Date.now() - start;
|
|
600
|
+
this.logService?.push(serverName, 'sampling/createMessage', params, result.content.text, latency, true, 'sampling');
|
|
601
|
+
return result;
|
|
602
|
+
}
|
|
603
|
+
catch (err) {
|
|
604
|
+
const latency = Date.now() - start;
|
|
605
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
606
|
+
this.logService?.push(serverName, 'sampling/createMessage', params, msg, latency, false, 'sampling');
|
|
607
|
+
throw err;
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
}
|
|
218
611
|
createTransport(config) {
|
|
219
612
|
const transportType = config.transport ?? 'stdio';
|
|
220
613
|
if ((transportType === 'streamable-http' || transportType === 'sse') && config.url) {
|