@guildai/cli 0.5.7 → 0.5.9

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.
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { GuildAPIClient } from '../lib/api-client.js';
3
+ export declare function registerResources(server: McpServer, apiClient: GuildAPIClient, workspaceId: string): void;
4
+ //# sourceMappingURL=resources.d.ts.map
@@ -0,0 +1,67 @@
1
+ // Copyright 2026 Guild.ai
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ export function registerResources(server, apiClient, workspaceId) {
4
+ // guild://workspace — Current workspace info
5
+ server.resource('workspace', 'guild://workspace', async () => {
6
+ try {
7
+ const workspace = await apiClient.get(`/workspaces/${workspaceId}`);
8
+ const text = JSON.stringify({
9
+ id: workspace.id,
10
+ name: workspace.name,
11
+ full_name: workspace.full_name,
12
+ }, null, 2);
13
+ return {
14
+ contents: [
15
+ {
16
+ uri: 'guild://workspace',
17
+ mimeType: 'application/json',
18
+ text,
19
+ },
20
+ ],
21
+ };
22
+ }
23
+ catch {
24
+ return {
25
+ contents: [
26
+ {
27
+ uri: 'guild://workspace',
28
+ mimeType: 'application/json',
29
+ text: JSON.stringify({ id: workspaceId }),
30
+ },
31
+ ],
32
+ };
33
+ }
34
+ });
35
+ // guild://agents — Agent list
36
+ server.resource('agents', 'guild://agents', async () => {
37
+ try {
38
+ const agents = await apiClient.fetchAll(`/workspaces/${workspaceId}/workspace_agents`);
39
+ const text = JSON.stringify(agents.map((a) => ({
40
+ id: a.id,
41
+ name: a.full_name || a.name,
42
+ description: a.description,
43
+ })), null, 2);
44
+ return {
45
+ contents: [
46
+ {
47
+ uri: 'guild://agents',
48
+ mimeType: 'application/json',
49
+ text,
50
+ },
51
+ ],
52
+ };
53
+ }
54
+ catch {
55
+ return {
56
+ contents: [
57
+ {
58
+ uri: 'guild://agents',
59
+ mimeType: 'application/json',
60
+ text: '[]',
61
+ },
62
+ ],
63
+ };
64
+ }
65
+ });
66
+ }
67
+ //# sourceMappingURL=resources.js.map
@@ -0,0 +1,6 @@
1
+ export interface McpServerOptions {
2
+ workspace?: string;
3
+ debug?: boolean;
4
+ }
5
+ export declare function startMcpServer(options: McpServerOptions): Promise<void>;
6
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1,64 @@
1
+ // Copyright 2026 Guild.ai
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
4
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
5
+ import { readFileSync } from 'fs';
6
+ import path from 'path';
7
+ import { fileURLToPath } from 'url';
8
+ import { GuildAPIClient } from '../lib/api-client.js';
9
+ import { getAuthToken } from '../lib/auth.js';
10
+ import { getWorkspaceId } from '../lib/guild-config.js';
11
+ import { registerTools } from './tools.js';
12
+ import { registerResources } from './resources.js';
13
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
14
+ function debugLog(debug, message) {
15
+ if (debug) {
16
+ process.stderr.write(`[guild-mcp] ${message}\n`);
17
+ }
18
+ }
19
+ export async function startMcpServer(options) {
20
+ const { debug = false } = options;
21
+ // Read version from package.json
22
+ const packageJson = JSON.parse(readFileSync(path.join(__dirname, '../../package.json'), 'utf-8'));
23
+ // Resolve auth token
24
+ const token = await getAuthToken();
25
+ if (!token) {
26
+ process.stderr.write('Error: Not authenticated. Run: guild auth login\n');
27
+ process.exit(1);
28
+ }
29
+ // Resolve workspace ID
30
+ let workspaceId = options.workspace;
31
+ if (!workspaceId) {
32
+ const resolved = await getWorkspaceId();
33
+ if (!resolved) {
34
+ process.stderr.write('Error: No workspace configured. Run: guild workspace select\n');
35
+ process.exit(1);
36
+ }
37
+ workspaceId = resolved.workspaceId;
38
+ }
39
+ debugLog(debug, `Starting MCP server v${packageJson.version}`);
40
+ debugLog(debug, `Workspace: ${workspaceId}`);
41
+ // Create API client
42
+ const apiClient = new GuildAPIClient();
43
+ // Create MCP server
44
+ const server = new McpServer({
45
+ name: 'guild',
46
+ version: packageJson.version,
47
+ });
48
+ // Register tools and resources
49
+ registerTools(server, apiClient, workspaceId, debug);
50
+ registerResources(server, apiClient, workspaceId);
51
+ // Create stdio transport and connect
52
+ const transport = new StdioServerTransport();
53
+ await server.connect(transport);
54
+ debugLog(debug, 'MCP server connected via stdio');
55
+ // Graceful shutdown
56
+ const shutdown = async () => {
57
+ debugLog(debug, 'Shutting down MCP server');
58
+ await server.close();
59
+ process.exit(0);
60
+ };
61
+ process.on('SIGINT', () => void shutdown());
62
+ process.on('SIGTERM', () => void shutdown());
63
+ }
64
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { GuildAPIClient } from '../lib/api-client.js';
3
+ export declare function registerTools(server: McpServer, apiClient: GuildAPIClient, defaultWorkspaceId: string, debug: boolean): void;
4
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1,803 @@
1
+ // Copyright 2026 Guild.ai
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { z } from 'zod';
4
+ // ---------------------------------------------------------------------------
5
+ // Constants
6
+ // ---------------------------------------------------------------------------
7
+ const POLL_INTERVAL_MS = 500;
8
+ const POLL_TIMEOUT_MS = 120_000;
9
+ // ---------------------------------------------------------------------------
10
+ // Helpers
11
+ // ---------------------------------------------------------------------------
12
+ function debugLog(debug, message) {
13
+ if (debug) {
14
+ process.stderr.write(`[guild-mcp] ${message}\n`);
15
+ }
16
+ }
17
+ /**
18
+ * Poll session events until runtime_done or runtime_error.
19
+ * Returns collected agent messages.
20
+ */
21
+ async function pollForResponse(apiClient, sessionId, debug) {
22
+ const startTime = Date.now();
23
+ const messages = [];
24
+ let lastEventId;
25
+ while (Date.now() - startTime < POLL_TIMEOUT_MS) {
26
+ try {
27
+ const response = await apiClient.get(`/sessions/${sessionId}/events`);
28
+ const events = response.events || [];
29
+ // Find new events after last seen
30
+ let foundLast = !lastEventId;
31
+ for (const event of events) {
32
+ if (!foundLast) {
33
+ if (event.id === lastEventId) {
34
+ foundLast = true;
35
+ }
36
+ continue;
37
+ }
38
+ debugLog(debug, `Event: ${event.event_type}`);
39
+ if (event.event_type === 'agent_notification_message') {
40
+ const data = extractEventText(event);
41
+ if (data) {
42
+ messages.push(data);
43
+ }
44
+ }
45
+ if (event.event_type === 'runtime_error') {
46
+ const errorText = extractEventText(event);
47
+ if (errorText) {
48
+ return `Error: ${errorText}`;
49
+ }
50
+ return 'Error: Agent encountered an error';
51
+ }
52
+ if (event.event_type === 'runtime_done') {
53
+ debugLog(debug, 'Runtime done');
54
+ return messages.join('\n\n') || 'Agent completed without output.';
55
+ }
56
+ lastEventId = event.id;
57
+ }
58
+ // Update lastEventId to latest
59
+ if (events.length > 0) {
60
+ lastEventId = events[events.length - 1].id;
61
+ }
62
+ }
63
+ catch (error) {
64
+ debugLog(debug, `Poll error: ${String(error)}`);
65
+ }
66
+ await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
67
+ }
68
+ return messages.length > 0
69
+ ? messages.join('\n\n') + '\n\n(Timed out waiting for completion)'
70
+ : 'Timed out waiting for agent response.';
71
+ }
72
+ function extractEventText(event) {
73
+ if (!event.content)
74
+ return undefined;
75
+ if (typeof event.content === 'string') {
76
+ return event.content;
77
+ }
78
+ if (typeof event.content === 'object' && event.content.data) {
79
+ return event.content.data;
80
+ }
81
+ return undefined;
82
+ }
83
+ function errText(action, error) {
84
+ return `Failed to ${action}: ${error instanceof Error ? error.message : String(error)}`;
85
+ }
86
+ // ---------------------------------------------------------------------------
87
+ // Shared schema fragments
88
+ // ---------------------------------------------------------------------------
89
+ const workspaceIdParam = z
90
+ .string()
91
+ .optional()
92
+ .describe('Workspace ID (defaults to current workspace)');
93
+ // ---------------------------------------------------------------------------
94
+ // Tool registration
95
+ // ---------------------------------------------------------------------------
96
+ export function registerTools(server, apiClient, defaultWorkspaceId, debug) {
97
+ // =========================================================================
98
+ // User
99
+ // =========================================================================
100
+ server.tool('guild_whoami', 'Get current user info', {}, async () => {
101
+ debugLog(debug, 'guild_whoami');
102
+ try {
103
+ const me = await apiClient.get('/me');
104
+ const text = [`Name: ${me.name}`, `ID: ${me.id}`, `Type: ${me.type}`].join('\n');
105
+ return { content: [{ type: 'text', text }] };
106
+ }
107
+ catch (error) {
108
+ return {
109
+ content: [{ type: 'text', text: errText('get user info', error) }],
110
+ isError: true,
111
+ };
112
+ }
113
+ });
114
+ // =========================================================================
115
+ // Workspaces
116
+ // =========================================================================
117
+ server.tool('guild_list_workspaces', 'List workspaces the current user has access to', {
118
+ search: z.string().optional().describe('Filter workspaces by name'),
119
+ limit: z
120
+ .number()
121
+ .int()
122
+ .min(1)
123
+ .max(100)
124
+ .optional()
125
+ .describe('Max results (default 20)'),
126
+ }, async ({ search, limit }) => {
127
+ debugLog(debug, `guild_list_workspaces: search=${search || ''}`);
128
+ try {
129
+ const params = new URLSearchParams();
130
+ if (search)
131
+ params.set('search', search);
132
+ params.set('limit', String(limit || 20));
133
+ const response = await apiClient.get(`/me/workspaces?${params.toString()}`);
134
+ const text = response.items
135
+ .map((w) => `• ${w.full_name || w.name} (${w.id})`)
136
+ .join('\n');
137
+ return {
138
+ content: [{ type: 'text', text: text || 'No workspaces found.' }],
139
+ };
140
+ }
141
+ catch (error) {
142
+ return {
143
+ content: [{ type: 'text', text: errText('list workspaces', error) }],
144
+ isError: true,
145
+ };
146
+ }
147
+ });
148
+ server.tool('guild_get_workspace', 'Get workspace details including context', {
149
+ workspace_id: workspaceIdParam,
150
+ }, async ({ workspace_id }) => {
151
+ const wsId = workspace_id || defaultWorkspaceId;
152
+ debugLog(debug, `guild_get_workspace: ${wsId}`);
153
+ try {
154
+ const ws = await apiClient.get(`/workspaces/${wsId}`);
155
+ const ownerLine = ws.owner
156
+ ? `Owner: ${ws.owner.name} (${ws.owner.type})`
157
+ : null;
158
+ const text = [`Name: ${ws.full_name || ws.name}`, `ID: ${ws.id}`, ownerLine]
159
+ .filter(Boolean)
160
+ .join('\n');
161
+ return { content: [{ type: 'text', text }] };
162
+ }
163
+ catch (error) {
164
+ return {
165
+ content: [{ type: 'text', text: errText('get workspace', error) }],
166
+ isError: true,
167
+ };
168
+ }
169
+ });
170
+ server.tool('guild_list_workspace_agents', 'List agents installed in a workspace', {
171
+ workspace_id: workspaceIdParam,
172
+ search: z.string().optional().describe('Filter agents by name'),
173
+ }, async ({ workspace_id, search }) => {
174
+ const wsId = workspace_id || defaultWorkspaceId;
175
+ debugLog(debug, `guild_list_workspace_agents: ws=${wsId} search=${search || ''}`);
176
+ try {
177
+ let endpoint = `/workspaces/${wsId}/workspace_agents`;
178
+ if (search)
179
+ endpoint += `?search=${encodeURIComponent(search)}`;
180
+ const agents = await apiClient.fetchAll(endpoint);
181
+ const text = agents
182
+ .map((wa) => {
183
+ const name = wa.agent.full_name || wa.agent.name;
184
+ const version = wa.agent_version.version_number ||
185
+ wa.agent_version.sha?.slice(0, 7) ||
186
+ 'latest';
187
+ return `• ${name} (workspace_agent: ${wa.id}, agent: ${wa.agent.id}) — v${version}`;
188
+ })
189
+ .join('\n');
190
+ return {
191
+ content: [{ type: 'text', text: text || 'No agents in workspace.' }],
192
+ };
193
+ }
194
+ catch (error) {
195
+ return {
196
+ content: [
197
+ { type: 'text', text: errText('list workspace agents', error) },
198
+ ],
199
+ isError: true,
200
+ };
201
+ }
202
+ });
203
+ server.tool('guild_add_workspace_agent', 'Install an agent in a workspace', {
204
+ agent_id: z.string().describe('The agent ID to install'),
205
+ workspace_id: workspaceIdParam,
206
+ }, async ({ agent_id, workspace_id }) => {
207
+ const wsId = workspace_id || defaultWorkspaceId;
208
+ debugLog(debug, `guild_add_workspace_agent: ${agent_id} ws=${wsId}`);
209
+ try {
210
+ const wa = await apiClient.post(`/workspaces/${wsId}/workspace_agents`, { agent_id });
211
+ return {
212
+ content: [
213
+ {
214
+ type: 'text',
215
+ text: `Installed agent ${wa.agent.full_name || wa.agent.name} (workspace_agent: ${wa.id})`,
216
+ },
217
+ ],
218
+ };
219
+ }
220
+ catch (error) {
221
+ return {
222
+ content: [
223
+ { type: 'text', text: errText('add workspace agent', error) },
224
+ ],
225
+ isError: true,
226
+ };
227
+ }
228
+ });
229
+ server.tool('guild_remove_workspace_agent', 'Remove an agent from the workspace', {
230
+ workspace_agent_id: z.string().describe('The workspace agent ID to remove'),
231
+ }, async ({ workspace_agent_id }) => {
232
+ debugLog(debug, `guild_remove_workspace_agent: ${workspace_agent_id}`);
233
+ try {
234
+ await apiClient.delete(`/workspace_agents/${workspace_agent_id}`);
235
+ return {
236
+ content: [
237
+ {
238
+ type: 'text',
239
+ text: `Removed workspace agent ${workspace_agent_id}.`,
240
+ },
241
+ ],
242
+ };
243
+ }
244
+ catch (error) {
245
+ return {
246
+ content: [
247
+ { type: 'text', text: errText('remove workspace agent', error) },
248
+ ],
249
+ isError: true,
250
+ };
251
+ }
252
+ });
253
+ // =========================================================================
254
+ // Contexts
255
+ // =========================================================================
256
+ server.tool('guild_list_contexts', 'List context versions for a workspace', {
257
+ workspace_id: workspaceIdParam,
258
+ limit: z
259
+ .number()
260
+ .int()
261
+ .min(1)
262
+ .max(100)
263
+ .optional()
264
+ .describe('Max results (default 20)'),
265
+ }, async ({ workspace_id, limit }) => {
266
+ const wsId = workspace_id || defaultWorkspaceId;
267
+ debugLog(debug, `guild_list_contexts: ws=${wsId}`);
268
+ try {
269
+ const response = await apiClient.get(`/workspaces/${wsId}/contexts?limit=${limit || 20}`);
270
+ const text = response.items
271
+ .map((c) => {
272
+ const summary = c.summary ? ` — ${c.summary}` : '';
273
+ return `• ${c.id} [${c.status}] ${c.created_at}${summary}`;
274
+ })
275
+ .join('\n');
276
+ return {
277
+ content: [{ type: 'text', text: text || 'No contexts found.' }],
278
+ };
279
+ }
280
+ catch (error) {
281
+ return {
282
+ content: [{ type: 'text', text: errText('list contexts', error) }],
283
+ isError: true,
284
+ };
285
+ }
286
+ });
287
+ server.tool('guild_get_context', 'Get the content of a specific context version', {
288
+ context_id: z.string().describe('The context ID'),
289
+ }, async ({ context_id }) => {
290
+ debugLog(debug, `guild_get_context: ${context_id}`);
291
+ try {
292
+ const ctx = await apiClient.get(`/contexts/${context_id}`);
293
+ const sections = [
294
+ `Context: ${ctx.id}`,
295
+ `Status: ${ctx.status}`,
296
+ `Created: ${ctx.created_at}`,
297
+ ];
298
+ if (ctx.summary)
299
+ sections.push(`Summary: ${ctx.summary}`);
300
+ if (ctx.manual_context) {
301
+ sections.push('', '--- Manual Context ---', ctx.manual_context);
302
+ }
303
+ if (ctx.generated_context) {
304
+ sections.push('', '--- Generated Context ---', ctx.generated_context);
305
+ }
306
+ return { content: [{ type: 'text', text: sections.join('\n') }] };
307
+ }
308
+ catch (error) {
309
+ return {
310
+ content: [{ type: 'text', text: errText('get context', error) }],
311
+ isError: true,
312
+ };
313
+ }
314
+ });
315
+ server.tool('guild_publish_context', 'Create or publish a new context version for a workspace', {
316
+ content: z.string().describe('The context content to publish'),
317
+ workspace_id: workspaceIdParam,
318
+ status: z
319
+ .enum(['ACTIVE', 'ARCHIVED'])
320
+ .optional()
321
+ .describe('Context status (default ACTIVE)'),
322
+ summary: z.string().optional().describe('Short summary of the context'),
323
+ }, async ({ content, workspace_id, status, summary }) => {
324
+ const wsId = workspace_id || defaultWorkspaceId;
325
+ debugLog(debug, `guild_publish_context: ws=${wsId}`);
326
+ try {
327
+ const body = { manual_context: content };
328
+ if (status)
329
+ body.status = status;
330
+ if (summary)
331
+ body.summary = summary;
332
+ const ctx = await apiClient.post(`/workspaces/${wsId}/contexts`, body);
333
+ return {
334
+ content: [
335
+ {
336
+ type: 'text',
337
+ text: `Published context ${ctx.id} [${ctx.status}]`,
338
+ },
339
+ ],
340
+ };
341
+ }
342
+ catch (error) {
343
+ return {
344
+ content: [{ type: 'text', text: errText('publish context', error) }],
345
+ isError: true,
346
+ };
347
+ }
348
+ });
349
+ // =========================================================================
350
+ // Agents (catalog)
351
+ // =========================================================================
352
+ server.tool('guild_search_agents', 'Search or list agents in the Guild catalog', {
353
+ search: z.string().optional().describe('Search query to filter agents by name'),
354
+ published_only: z
355
+ .boolean()
356
+ .optional()
357
+ .describe('Only show published agents (default true)'),
358
+ limit: z
359
+ .number()
360
+ .int()
361
+ .min(1)
362
+ .max(100)
363
+ .optional()
364
+ .describe('Max results (default 20)'),
365
+ }, async ({ search, published_only, limit }) => {
366
+ debugLog(debug, `guild_search_agents: search=${search || ''}`);
367
+ try {
368
+ const params = new URLSearchParams();
369
+ if (search)
370
+ params.set('search', search);
371
+ if (published_only !== undefined)
372
+ params.set('published_only', String(published_only));
373
+ params.set('limit', String(limit || 20));
374
+ const response = await apiClient.get(`/agents?${params.toString()}`);
375
+ const text = response.items
376
+ .map((a) => {
377
+ const name = a.full_name || a.name;
378
+ const desc = a.description ? ` — ${a.description}` : '';
379
+ return `• ${name} (${a.id})${desc}`;
380
+ })
381
+ .join('\n');
382
+ return {
383
+ content: [{ type: 'text', text: text || 'No agents found.' }],
384
+ };
385
+ }
386
+ catch (error) {
387
+ return {
388
+ content: [{ type: 'text', text: errText('search agents', error) }],
389
+ isError: true,
390
+ };
391
+ }
392
+ });
393
+ server.tool('guild_get_agent', 'Get details for a specific Guild agent', {
394
+ agent_id: z
395
+ .string()
396
+ .describe('The agent ID or full name (e.g. owner/agent-name)'),
397
+ }, async ({ agent_id }) => {
398
+ debugLog(debug, `guild_get_agent: ${agent_id}`);
399
+ try {
400
+ const agent = await apiClient.get(`/agents/${agent_id}`);
401
+ const lines = [
402
+ `Name: ${agent.full_name || agent.name}`,
403
+ `ID: ${agent.id}`,
404
+ `Status: ${agent.status}`,
405
+ agent.description ? `Description: ${agent.description}` : null,
406
+ agent.owner ? `Owner: ${agent.owner.name}` : null,
407
+ agent.is_public !== undefined ? `Public: ${agent.is_public}` : null,
408
+ ];
409
+ return {
410
+ content: [{ type: 'text', text: lines.filter(Boolean).join('\n') }],
411
+ };
412
+ }
413
+ catch (error) {
414
+ return {
415
+ content: [{ type: 'text', text: errText('get agent', error) }],
416
+ isError: true,
417
+ };
418
+ }
419
+ });
420
+ server.tool('guild_get_agent_readme', 'Get the README for a Guild agent', {
421
+ agent_id: z.string().describe('The agent ID or full name'),
422
+ }, async ({ agent_id }) => {
423
+ debugLog(debug, `guild_get_agent_readme: ${agent_id}`);
424
+ try {
425
+ const readme = await apiClient.get(`/agents/${agent_id}/readme`);
426
+ return { content: [{ type: 'text', text: readme.content }] };
427
+ }
428
+ catch (error) {
429
+ return {
430
+ content: [
431
+ { type: 'text', text: errText('get agent readme', error) },
432
+ ],
433
+ isError: true,
434
+ };
435
+ }
436
+ });
437
+ server.tool('guild_get_agent_code', 'Get the source code files for a Guild agent', {
438
+ agent_id: z.string().describe('The agent ID or full name'),
439
+ }, async ({ agent_id }) => {
440
+ debugLog(debug, `guild_get_agent_code: ${agent_id}`);
441
+ try {
442
+ const files = await apiClient.get(`/agents/${agent_id}/code`);
443
+ if (files.length === 0) {
444
+ return {
445
+ content: [{ type: 'text', text: 'No source files found.' }],
446
+ };
447
+ }
448
+ const text = files.map((f) => `--- ${f.path} ---\n${f.content}`).join('\n\n');
449
+ return { content: [{ type: 'text', text }] };
450
+ }
451
+ catch (error) {
452
+ return {
453
+ content: [{ type: 'text', text: errText('get agent code', error) }],
454
+ isError: true,
455
+ };
456
+ }
457
+ });
458
+ server.tool('guild_list_agent_versions', 'List versions of a Guild agent', {
459
+ agent_id: z.string().describe('The agent ID or full name'),
460
+ limit: z
461
+ .number()
462
+ .int()
463
+ .min(1)
464
+ .max(100)
465
+ .optional()
466
+ .describe('Max results (default 20)'),
467
+ }, async ({ agent_id, limit }) => {
468
+ debugLog(debug, `guild_list_agent_versions: ${agent_id}`);
469
+ try {
470
+ const response = await apiClient.get(`/agents/${agent_id}/versions?limit=${limit || 20}`);
471
+ const text = response.items
472
+ .map((v) => {
473
+ const version = v.version_number || v.sha?.slice(0, 7) || 'ephemeral';
474
+ return `• ${version} (${v.id}) [${v.status}] — ${v.summary} — ${v.created_at}`;
475
+ })
476
+ .join('\n');
477
+ return {
478
+ content: [{ type: 'text', text: text || 'No versions found.' }],
479
+ };
480
+ }
481
+ catch (error) {
482
+ return {
483
+ content: [
484
+ { type: 'text', text: errText('list agent versions', error) },
485
+ ],
486
+ isError: true,
487
+ };
488
+ }
489
+ });
490
+ // =========================================================================
491
+ // Sessions
492
+ // =========================================================================
493
+ server.tool('guild_chat', 'Start a new chat session with a Guild agent and get a response', {
494
+ message: z.string().describe('The message to send to the agent'),
495
+ agent: z
496
+ .string()
497
+ .optional()
498
+ .describe('Agent identifier (e.g. owner/agent-name). Uses workspace default if not specified'),
499
+ workspace_id: workspaceIdParam,
500
+ }, async ({ message, agent, workspace_id }) => {
501
+ const wsId = workspace_id || defaultWorkspaceId;
502
+ debugLog(debug, `guild_chat: message="${message}", agent=${agent || 'default'}, ws=${wsId}`);
503
+ try {
504
+ const body = {
505
+ session_type: 'chat',
506
+ initial_prompt: message,
507
+ };
508
+ if (agent) {
509
+ body.agent_id = agent;
510
+ }
511
+ const session = await apiClient.post(`/workspaces/${wsId}/sessions`, body);
512
+ debugLog(debug, `Session created: ${session.id}`);
513
+ const response = await pollForResponse(apiClient, session.id, debug);
514
+ return {
515
+ content: [{ type: 'text', text: response }],
516
+ };
517
+ }
518
+ catch (error) {
519
+ return {
520
+ content: [{ type: 'text', text: errText('chat', error) }],
521
+ isError: true,
522
+ };
523
+ }
524
+ });
525
+ server.tool('guild_send_message', 'Send a follow-up message to an existing Guild session', {
526
+ session_id: z.string().describe('The session ID to send the message to'),
527
+ message: z.string().describe('The message to send'),
528
+ }, async ({ session_id, message }) => {
529
+ debugLog(debug, `guild_send_message: session=${session_id}`);
530
+ try {
531
+ await apiClient.post(`/sessions/${session_id}/events`, {
532
+ event_type: 'user_message',
533
+ content: { type: 'text', data: message },
534
+ });
535
+ const response = await pollForResponse(apiClient, session_id, debug);
536
+ return {
537
+ content: [{ type: 'text', text: response }],
538
+ };
539
+ }
540
+ catch (error) {
541
+ return {
542
+ content: [{ type: 'text', text: errText('send message', error) }],
543
+ isError: true,
544
+ };
545
+ }
546
+ });
547
+ server.tool('guild_list_sessions', 'List recent sessions in a Guild workspace', {
548
+ workspace_id: workspaceIdParam,
549
+ limit: z
550
+ .number()
551
+ .int()
552
+ .min(1)
553
+ .max(100)
554
+ .optional()
555
+ .describe('Number of sessions to return (default 20)'),
556
+ }, async ({ workspace_id, limit }) => {
557
+ const wsId = workspace_id || defaultWorkspaceId;
558
+ debugLog(debug, `guild_list_sessions: ws=${wsId}`);
559
+ try {
560
+ const queryLimit = limit || 20;
561
+ const response = await apiClient.get(`/workspaces/${wsId}/sessions?limit=${queryLimit}`);
562
+ const text = response.items
563
+ .map((s) => `• ${s.id} (${s.session_type}) — ${s.created_at}`)
564
+ .join('\n');
565
+ return {
566
+ content: [{ type: 'text', text: text || 'No sessions found.' }],
567
+ };
568
+ }
569
+ catch (error) {
570
+ return {
571
+ content: [{ type: 'text', text: errText('list sessions', error) }],
572
+ isError: true,
573
+ };
574
+ }
575
+ });
576
+ server.tool('guild_get_session', 'Get session details and recent events from a Guild session', {
577
+ session_id: z.string().describe('The session ID'),
578
+ }, async ({ session_id }) => {
579
+ debugLog(debug, `guild_get_session: ${session_id}`);
580
+ try {
581
+ const [session, eventsResponse] = await Promise.all([
582
+ apiClient.get(`/sessions/${session_id}`),
583
+ apiClient.get(`/sessions/${session_id}/events`),
584
+ ]);
585
+ const events = eventsResponse.events || [];
586
+ const recentEvents = events.slice(-20);
587
+ const eventLines = recentEvents.map((e) => {
588
+ const text = extractEventText(e);
589
+ const preview = text
590
+ ? `: ${text.slice(0, 100)}${text.length > 100 ? '...' : ''}`
591
+ : '';
592
+ return ` [${e.event_type}]${preview}`;
593
+ });
594
+ const text = [
595
+ `Session: ${session.id}`,
596
+ `Type: ${session.session_type}`,
597
+ `Created: ${session.created_at}`,
598
+ `Updated: ${session.updated_at}`,
599
+ '',
600
+ `Recent events (${recentEvents.length} of ${events.length}):`,
601
+ ...eventLines,
602
+ ].join('\n');
603
+ return {
604
+ content: [{ type: 'text', text }],
605
+ };
606
+ }
607
+ catch (error) {
608
+ return {
609
+ content: [{ type: 'text', text: errText('get session', error) }],
610
+ isError: true,
611
+ };
612
+ }
613
+ });
614
+ server.tool('guild_get_session_events', 'Get events from a Guild session with pagination', {
615
+ session_id: z.string().describe('The session ID'),
616
+ limit: z
617
+ .number()
618
+ .int()
619
+ .min(1)
620
+ .max(200)
621
+ .optional()
622
+ .describe('Max events to return (default 50)'),
623
+ }, async ({ session_id, limit }) => {
624
+ debugLog(debug, `guild_get_session_events: ${session_id}`);
625
+ try {
626
+ const response = await apiClient.get(`/sessions/${session_id}/events`);
627
+ const events = response.events || [];
628
+ const maxEvents = limit || 50;
629
+ const displayed = events.slice(-maxEvents);
630
+ const lines = displayed.map((e) => {
631
+ const text = extractEventText(e);
632
+ const preview = text
633
+ ? `: ${text.slice(0, 200)}${text.length > 200 ? '...' : ''}`
634
+ : '';
635
+ return `[${e.created_at}] ${e.event_type}${preview}`;
636
+ });
637
+ const header = `Events (${displayed.length} of ${events.length}):`;
638
+ return {
639
+ content: [{ type: 'text', text: [header, ...lines].join('\n') }],
640
+ };
641
+ }
642
+ catch (error) {
643
+ return {
644
+ content: [
645
+ { type: 'text', text: errText('get session events', error) },
646
+ ],
647
+ isError: true,
648
+ };
649
+ }
650
+ });
651
+ server.tool('guild_interrupt_session', 'Interrupt a running Guild session', {
652
+ session_id: z.string().describe('The session ID to interrupt'),
653
+ }, async ({ session_id }) => {
654
+ debugLog(debug, `guild_interrupt_session: ${session_id}`);
655
+ try {
656
+ await apiClient.post(`/sessions/${session_id}/interrupt`);
657
+ return {
658
+ content: [
659
+ {
660
+ type: 'text',
661
+ text: `Interrupted session ${session_id}.`,
662
+ },
663
+ ],
664
+ };
665
+ }
666
+ catch (error) {
667
+ return {
668
+ content: [
669
+ { type: 'text', text: errText('interrupt session', error) },
670
+ ],
671
+ isError: true,
672
+ };
673
+ }
674
+ });
675
+ // =========================================================================
676
+ // Triggers
677
+ // =========================================================================
678
+ server.tool('guild_list_triggers', 'List triggers configured in a workspace', {
679
+ workspace_id: workspaceIdParam,
680
+ limit: z
681
+ .number()
682
+ .int()
683
+ .min(1)
684
+ .max(100)
685
+ .optional()
686
+ .describe('Max results (default 20)'),
687
+ }, async ({ workspace_id, limit }) => {
688
+ const wsId = workspace_id || defaultWorkspaceId;
689
+ debugLog(debug, `guild_list_triggers: ws=${wsId}`);
690
+ try {
691
+ const response = await apiClient.get(`/workspaces/${wsId}/triggers?limit=${limit || 20}`);
692
+ const text = response.items
693
+ .map((t) => {
694
+ const agent = t.agent.full_name || t.agent.name;
695
+ const disabled = t.deactivated_at ? ' [DISABLED]' : '';
696
+ if (t.type === 'webhook') {
697
+ return `• ${t.id} [webhook] ${t.service}/${t.event_type || '*'} → ${agent}${disabled}`;
698
+ }
699
+ return `• ${t.id} [time] ${t.frequency} → ${agent}${disabled}`;
700
+ })
701
+ .join('\n');
702
+ return {
703
+ content: [{ type: 'text', text: text || 'No triggers found.' }],
704
+ };
705
+ }
706
+ catch (error) {
707
+ return {
708
+ content: [{ type: 'text', text: errText('list triggers', error) }],
709
+ isError: true,
710
+ };
711
+ }
712
+ });
713
+ server.tool('guild_get_trigger_sessions', 'List sessions spawned by a specific trigger', {
714
+ trigger_id: z.string().describe('The trigger ID'),
715
+ workspace_id: workspaceIdParam,
716
+ limit: z
717
+ .number()
718
+ .int()
719
+ .min(1)
720
+ .max(100)
721
+ .optional()
722
+ .describe('Max results (default 20)'),
723
+ }, async ({ trigger_id, workspace_id, limit }) => {
724
+ const wsId = workspace_id || defaultWorkspaceId;
725
+ debugLog(debug, `guild_get_trigger_sessions: ${trigger_id} ws=${wsId}`);
726
+ try {
727
+ const response = await apiClient.get(`/workspaces/${wsId}/sessions?trigger_id=${trigger_id}&limit=${limit || 20}`);
728
+ const text = response.items
729
+ .map((s) => `• ${s.id} (${s.session_type}) — ${s.created_at}`)
730
+ .join('\n');
731
+ return {
732
+ content: [
733
+ { type: 'text', text: text || 'No trigger sessions found.' },
734
+ ],
735
+ };
736
+ }
737
+ catch (error) {
738
+ return {
739
+ content: [
740
+ { type: 'text', text: errText('get trigger sessions', error) },
741
+ ],
742
+ isError: true,
743
+ };
744
+ }
745
+ });
746
+ // =========================================================================
747
+ // Credentials / Integrations
748
+ // =========================================================================
749
+ server.tool('guild_list_credentials', 'List connected integration credentials', {}, async () => {
750
+ debugLog(debug, 'guild_list_credentials');
751
+ try {
752
+ const me = await apiClient.get('/me');
753
+ const response = await apiClient.get(`/credentials?account_id=${me.id}`);
754
+ const text = response.items
755
+ .map((c) => {
756
+ const status = c.status ? ` [${c.status}]` : '';
757
+ return `• ${c.service} (${c.id})${status}`;
758
+ })
759
+ .join('\n');
760
+ return {
761
+ content: [{ type: 'text', text: text || 'No credentials found.' }],
762
+ };
763
+ }
764
+ catch (error) {
765
+ return {
766
+ content: [
767
+ { type: 'text', text: errText('list credentials', error) },
768
+ ],
769
+ isError: true,
770
+ };
771
+ }
772
+ });
773
+ server.tool('guild_list_available_integrations', 'List available integrations that can be connected', {}, async () => {
774
+ debugLog(debug, 'guild_list_available_integrations');
775
+ try {
776
+ const integrations = await apiClient.get('/credentials/available');
777
+ const items = Array.isArray(integrations) ? integrations : [];
778
+ const text = items
779
+ .map((i) => {
780
+ const desc = i.description ? ` — ${i.description}` : '';
781
+ return `• ${i.name || i.service} (${i.service})${desc}`;
782
+ })
783
+ .join('\n');
784
+ return {
785
+ content: [
786
+ { type: 'text', text: text || 'No integrations available.' },
787
+ ],
788
+ };
789
+ }
790
+ catch (error) {
791
+ return {
792
+ content: [
793
+ {
794
+ type: 'text',
795
+ text: errText('list available integrations', error),
796
+ },
797
+ ],
798
+ isError: true,
799
+ };
800
+ }
801
+ });
802
+ }
803
+ //# sourceMappingURL=tools.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guildai/cli",
3
- "version": "0.5.7",
3
+ "version": "0.5.9",
4
4
  "description": "Guild.ai CLI - Build, test, and deploy AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -18,6 +18,8 @@
18
18
  "dist/components/**/*.d.ts",
19
19
  "dist/lib/**/*.js",
20
20
  "dist/lib/**/*.d.ts",
21
+ "dist/mcp/**/*.js",
22
+ "dist/mcp/**/*.d.ts",
21
23
  "dist/assets/",
22
24
  "docs/"
23
25
  ],