@guildai/cli 0.5.8 → 0.5.10

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 CHANGED
@@ -210,8 +210,35 @@ guild version # Show version info
210
210
  ### Coding Assistant Skills
211
211
 
212
212
  ```bash
213
- guild setup # Install Guild skills for coding assistants
213
+ guild setup # Install skills + configure MCP server
214
214
  guild setup --claude-md # Also create a CLAUDE.md template
215
+ guild setup --no-mcp # Install skills only, skip MCP configuration
216
+ guild mcp # Start MCP server (used by Claude Code, etc.)
217
+ ```
218
+
219
+ ### MCP Server
220
+
221
+ The CLI includes an [MCP](https://modelcontextprotocol.io/) server that exposes Guild's API to AI coding assistants like Claude Code.
222
+
223
+ **Setup:**
224
+
225
+ ```bash
226
+ guild setup
227
+ ```
228
+
229
+ This installs Claude Code skills and adds a `guild` entry to `.mcp.json` in your project. Claude Code (and other MCP-compatible tools) will automatically connect when they detect it.
230
+
231
+ **What it provides:**
232
+
233
+ - 24 tools: workspaces, agents, sessions, triggers, contexts, credentials
234
+ - 2 resources: current workspace info and installed agents
235
+ - All tools use your `guild auth` credentials automatically
236
+
237
+ **Manual start (for debugging):**
238
+
239
+ ```bash
240
+ guild mcp
241
+ guild mcp --debug # Verbose logging to stderr
215
242
  ```
216
243
 
217
244
  ## Configuration
@@ -60,8 +60,8 @@ async function setupMcp(options) {
60
60
  const content = await fs.readFile(mcpPath, 'utf-8');
61
61
  existing = JSON.parse(content);
62
62
  if (existing.mcpServers && 'guild' in existing.mcpServers && !options.force) {
63
- output.progress('Guild MCP server already configured in .mcp.json');
64
- return;
63
+ output.progress('.mcp.json already has Guild server (use --force to overwrite)');
64
+ return 'skipped';
65
65
  }
66
66
  }
67
67
  const updated = {
@@ -78,6 +78,7 @@ async function setupMcp(options) {
78
78
  else {
79
79
  output.success('Created .mcp.json with Guild MCP server');
80
80
  }
81
+ return 'created';
81
82
  }
82
83
  async function setup(options) {
83
84
  const output = createOutputWriter();
@@ -116,7 +117,13 @@ async function setup(options) {
116
117
  }
117
118
  // Handle --mcp flag
118
119
  if (options.mcp) {
119
- await setupMcp({ force: options.force });
120
+ const result = await setupMcp({ force: options.force });
121
+ if (result === 'created') {
122
+ filesCreated++;
123
+ }
124
+ else {
125
+ filesSkipped++;
126
+ }
120
127
  }
121
128
  // Handle CLAUDE.md template
122
129
  if (options.claudeMd) {
@@ -155,7 +162,7 @@ export function createSetupCommand() {
155
162
  .description('Set up Guild CLI skills for coding assistants (Claude Code, etc.)')
156
163
  .option('--force', 'Overwrite existing skill files', false)
157
164
  .option('--claude-md', 'Also create a CLAUDE.md template in the project root', false)
158
- .option('--mcp', 'Configure Guild MCP server in .mcp.json', false)
165
+ .option('--no-mcp', 'Skip MCP server configuration')
159
166
  .action(async (options) => {
160
167
  await setup(options);
161
168
  });
@@ -1,4 +1,4 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import type { GuildAPIClient } from '../lib/api-client.js';
3
- export declare function registerTools(server: McpServer, apiClient: GuildAPIClient, workspaceId: string, debug: boolean): void;
3
+ export declare function registerTools(server: McpServer, apiClient: GuildAPIClient, defaultWorkspaceId: string, debug: boolean): void;
4
4
  //# sourceMappingURL=tools.d.ts.map
package/dist/mcp/tools.js CHANGED
@@ -84,9 +84,16 @@ function errText(action, error) {
84
84
  return `Failed to ${action}: ${error instanceof Error ? error.message : String(error)}`;
85
85
  }
86
86
  // ---------------------------------------------------------------------------
87
+ // Shared schema fragments
88
+ // ---------------------------------------------------------------------------
89
+ const workspaceIdParam = z
90
+ .string()
91
+ .optional()
92
+ .describe('Workspace ID (defaults to current workspace)');
93
+ // ---------------------------------------------------------------------------
87
94
  // Tool registration
88
95
  // ---------------------------------------------------------------------------
89
- export function registerTools(server, apiClient, workspaceId, debug) {
96
+ export function registerTools(server, apiClient, defaultWorkspaceId, debug) {
90
97
  // =========================================================================
91
98
  // User
92
99
  // =========================================================================
@@ -139,12 +146,9 @@ export function registerTools(server, apiClient, workspaceId, debug) {
139
146
  }
140
147
  });
141
148
  server.tool('guild_get_workspace', 'Get workspace details including context', {
142
- workspace_id: z
143
- .string()
144
- .optional()
145
- .describe('Workspace ID (defaults to current workspace)'),
149
+ workspace_id: workspaceIdParam,
146
150
  }, async ({ workspace_id }) => {
147
- const wsId = workspace_id || workspaceId;
151
+ const wsId = workspace_id || defaultWorkspaceId;
148
152
  debugLog(debug, `guild_get_workspace: ${wsId}`);
149
153
  try {
150
154
  const ws = await apiClient.get(`/workspaces/${wsId}`);
@@ -163,12 +167,14 @@ export function registerTools(server, apiClient, workspaceId, debug) {
163
167
  };
164
168
  }
165
169
  });
166
- server.tool('guild_list_workspace_agents', 'List agents installed in the current workspace', {
170
+ server.tool('guild_list_workspace_agents', 'List agents installed in a workspace', {
171
+ workspace_id: workspaceIdParam,
167
172
  search: z.string().optional().describe('Filter agents by name'),
168
- }, async ({ search }) => {
169
- debugLog(debug, `guild_list_workspace_agents: search=${search || ''}`);
173
+ }, async ({ workspace_id, search }) => {
174
+ const wsId = workspace_id || defaultWorkspaceId;
175
+ debugLog(debug, `guild_list_workspace_agents: ws=${wsId} search=${search || ''}`);
170
176
  try {
171
- let endpoint = `/workspaces/${workspaceId}/workspace_agents`;
177
+ let endpoint = `/workspaces/${wsId}/workspace_agents`;
172
178
  if (search)
173
179
  endpoint += `?search=${encodeURIComponent(search)}`;
174
180
  const agents = await apiClient.fetchAll(endpoint);
@@ -194,12 +200,14 @@ export function registerTools(server, apiClient, workspaceId, debug) {
194
200
  };
195
201
  }
196
202
  });
197
- server.tool('guild_add_workspace_agent', 'Install an agent in the current workspace', {
203
+ server.tool('guild_add_workspace_agent', 'Install an agent in a workspace', {
198
204
  agent_id: z.string().describe('The agent ID to install'),
199
- }, async ({ agent_id }) => {
200
- debugLog(debug, `guild_add_workspace_agent: ${agent_id}`);
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}`);
201
209
  try {
202
- const wa = await apiClient.post(`/workspaces/${workspaceId}/workspace_agents`, { agent_id });
210
+ const wa = await apiClient.post(`/workspaces/${wsId}/workspace_agents`, { agent_id });
203
211
  return {
204
212
  content: [
205
213
  {
@@ -245,7 +253,8 @@ export function registerTools(server, apiClient, workspaceId, debug) {
245
253
  // =========================================================================
246
254
  // Contexts
247
255
  // =========================================================================
248
- server.tool('guild_list_contexts', 'List context versions for the current workspace', {
256
+ server.tool('guild_list_contexts', 'List context versions for a workspace', {
257
+ workspace_id: workspaceIdParam,
249
258
  limit: z
250
259
  .number()
251
260
  .int()
@@ -253,10 +262,11 @@ export function registerTools(server, apiClient, workspaceId, debug) {
253
262
  .max(100)
254
263
  .optional()
255
264
  .describe('Max results (default 20)'),
256
- }, async ({ limit }) => {
257
- debugLog(debug, 'guild_list_contexts');
265
+ }, async ({ workspace_id, limit }) => {
266
+ const wsId = workspace_id || defaultWorkspaceId;
267
+ debugLog(debug, `guild_list_contexts: ws=${wsId}`);
258
268
  try {
259
- const response = await apiClient.get(`/workspaces/${workspaceId}/contexts?limit=${limit || 20}`);
269
+ const response = await apiClient.get(`/workspaces/${wsId}/contexts?limit=${limit || 20}`);
260
270
  const text = response.items
261
271
  .map((c) => {
262
272
  const summary = c.summary ? ` — ${c.summary}` : '';
@@ -302,22 +312,24 @@ export function registerTools(server, apiClient, workspaceId, debug) {
302
312
  };
303
313
  }
304
314
  });
305
- server.tool('guild_publish_context', 'Create or publish a new context version for the workspace', {
315
+ server.tool('guild_publish_context', 'Create or publish a new context version for a workspace', {
306
316
  content: z.string().describe('The context content to publish'),
317
+ workspace_id: workspaceIdParam,
307
318
  status: z
308
319
  .enum(['ACTIVE', 'ARCHIVED'])
309
320
  .optional()
310
321
  .describe('Context status (default ACTIVE)'),
311
322
  summary: z.string().optional().describe('Short summary of the context'),
312
- }, async ({ content, status, summary }) => {
313
- debugLog(debug, 'guild_publish_context');
323
+ }, async ({ content, workspace_id, status, summary }) => {
324
+ const wsId = workspace_id || defaultWorkspaceId;
325
+ debugLog(debug, `guild_publish_context: ws=${wsId}`);
314
326
  try {
315
327
  const body = { manual_context: content };
316
328
  if (status)
317
329
  body.status = status;
318
330
  if (summary)
319
331
  body.summary = summary;
320
- const ctx = await apiClient.post(`/workspaces/${workspaceId}/contexts`, body);
332
+ const ctx = await apiClient.post(`/workspaces/${wsId}/contexts`, body);
321
333
  return {
322
334
  content: [
323
335
  {
@@ -484,8 +496,10 @@ export function registerTools(server, apiClient, workspaceId, debug) {
484
496
  .string()
485
497
  .optional()
486
498
  .describe('Agent identifier (e.g. owner/agent-name). Uses workspace default if not specified'),
487
- }, async ({ message, agent }) => {
488
- debugLog(debug, `guild_chat: message="${message}", agent=${agent || 'default'}`);
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}`);
489
503
  try {
490
504
  const body = {
491
505
  session_type: 'chat',
@@ -494,7 +508,7 @@ export function registerTools(server, apiClient, workspaceId, debug) {
494
508
  if (agent) {
495
509
  body.agent_id = agent;
496
510
  }
497
- const session = await apiClient.post(`/workspaces/${workspaceId}/sessions`, body);
511
+ const session = await apiClient.post(`/workspaces/${wsId}/sessions`, body);
498
512
  debugLog(debug, `Session created: ${session.id}`);
499
513
  const response = await pollForResponse(apiClient, session.id, debug);
500
514
  return {
@@ -530,7 +544,8 @@ export function registerTools(server, apiClient, workspaceId, debug) {
530
544
  };
531
545
  }
532
546
  });
533
- server.tool('guild_list_sessions', 'List recent sessions in the current Guild workspace', {
547
+ server.tool('guild_list_sessions', 'List recent sessions in a Guild workspace', {
548
+ workspace_id: workspaceIdParam,
534
549
  limit: z
535
550
  .number()
536
551
  .int()
@@ -538,11 +553,12 @@ export function registerTools(server, apiClient, workspaceId, debug) {
538
553
  .max(100)
539
554
  .optional()
540
555
  .describe('Number of sessions to return (default 20)'),
541
- }, async ({ limit }) => {
542
- debugLog(debug, 'guild_list_sessions');
556
+ }, async ({ workspace_id, limit }) => {
557
+ const wsId = workspace_id || defaultWorkspaceId;
558
+ debugLog(debug, `guild_list_sessions: ws=${wsId}`);
543
559
  try {
544
560
  const queryLimit = limit || 20;
545
- const response = await apiClient.get(`/workspaces/${workspaceId}/sessions?limit=${queryLimit}`);
561
+ const response = await apiClient.get(`/workspaces/${wsId}/sessions?limit=${queryLimit}`);
546
562
  const text = response.items
547
563
  .map((s) => `• ${s.id} (${s.session_type}) — ${s.created_at}`)
548
564
  .join('\n');
@@ -659,7 +675,8 @@ export function registerTools(server, apiClient, workspaceId, debug) {
659
675
  // =========================================================================
660
676
  // Triggers
661
677
  // =========================================================================
662
- server.tool('guild_list_triggers', 'List triggers configured in the current workspace', {
678
+ server.tool('guild_list_triggers', 'List triggers configured in a workspace', {
679
+ workspace_id: workspaceIdParam,
663
680
  limit: z
664
681
  .number()
665
682
  .int()
@@ -667,10 +684,11 @@ export function registerTools(server, apiClient, workspaceId, debug) {
667
684
  .max(100)
668
685
  .optional()
669
686
  .describe('Max results (default 20)'),
670
- }, async ({ limit }) => {
671
- debugLog(debug, 'guild_list_triggers');
687
+ }, async ({ workspace_id, limit }) => {
688
+ const wsId = workspace_id || defaultWorkspaceId;
689
+ debugLog(debug, `guild_list_triggers: ws=${wsId}`);
672
690
  try {
673
- const response = await apiClient.get(`/workspaces/${workspaceId}/triggers?limit=${limit || 20}`);
691
+ const response = await apiClient.get(`/workspaces/${wsId}/triggers?limit=${limit || 20}`);
674
692
  const text = response.items
675
693
  .map((t) => {
676
694
  const agent = t.agent.full_name || t.agent.name;
@@ -694,6 +712,7 @@ export function registerTools(server, apiClient, workspaceId, debug) {
694
712
  });
695
713
  server.tool('guild_get_trigger_sessions', 'List sessions spawned by a specific trigger', {
696
714
  trigger_id: z.string().describe('The trigger ID'),
715
+ workspace_id: workspaceIdParam,
697
716
  limit: z
698
717
  .number()
699
718
  .int()
@@ -701,10 +720,11 @@ export function registerTools(server, apiClient, workspaceId, debug) {
701
720
  .max(100)
702
721
  .optional()
703
722
  .describe('Max results (default 20)'),
704
- }, async ({ trigger_id, limit }) => {
705
- debugLog(debug, `guild_get_trigger_sessions: ${trigger_id}`);
723
+ }, async ({ trigger_id, workspace_id, limit }) => {
724
+ const wsId = workspace_id || defaultWorkspaceId;
725
+ debugLog(debug, `guild_get_trigger_sessions: ${trigger_id} ws=${wsId}`);
706
726
  try {
707
- const response = await apiClient.get(`/workspaces/${workspaceId}/sessions?trigger_id=${trigger_id}&limit=${limit || 20}`);
727
+ const response = await apiClient.get(`/workspaces/${wsId}/sessions?trigger_id=${trigger_id}&limit=${limit || 20}`);
708
728
  const text = response.items
709
729
  .map((s) => `• ${s.id} (${s.session_type}) — ${s.created_at}`)
710
730
  .join('\n');
@@ -7,6 +7,12 @@ description: Agent development using the Guild CLI. Activated when user mentions
7
7
 
8
8
  For local agent development using the Guild CLI. This workflow manages agent code via the Guild git server.
9
9
 
10
+ ## MCP vs CLI
11
+
12
+ If Guild MCP tools are available (check for tools prefixed with `guild_`), use them for **read operations**: searching agents, listing workspaces, reading contexts, checking sessions, viewing credentials. MCP tools are faster and don't require shell execution.
13
+
14
+ Use the **CLI** (via Bash) for **local development operations**: `guild agent create`, `guild agent save`, `guild agent test`, `guild agent pull`, `guild agent clone`. These involve the local filesystem and git, which MCP can't do.
15
+
10
16
  ## CRITICAL: Always Use the Guild CLI
11
17
 
12
18
  **NEVER manually create agent files or use raw git commands.**
package/docs/DESIGN.md CHANGED
@@ -190,6 +190,8 @@ Environments are Docker containers managed by GuildCore. The CLI provides a simp
190
190
 
191
191
  The CLI integrates with AI coding assistants like Claude Code, Cursor, and others. Run `guild setup` to install Guild skills into your project.
192
192
 
193
+ The CLI also exposes a [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server via `guild mcp`. This gives coding assistants direct access to Guild's API — searching agents, managing workspaces, reading contexts, and starting sessions — without leaving the editor. `guild setup` configures it by default; use `--no-mcp` to skip.
194
+
193
195
  **Typical Workflow:**
194
196
 
195
197
  1. Initialize agent: `guild agent init --name my-agent --template LLM`
@@ -7,6 +7,12 @@ description: Local agent development using the Guild CLI. Activated when user me
7
7
 
8
8
  Build agents for Guild using the CLI. **Always use the Guild CLI for agent operations - never use raw git commands.**
9
9
 
10
+ ## MCP vs CLI
11
+
12
+ If Guild MCP tools are available (check for tools prefixed with `guild_`), use them for **read operations**: searching agents, listing workspaces, reading contexts, checking sessions, viewing credentials. MCP tools are faster and don't require shell execution.
13
+
14
+ Use the **CLI** (via Bash) for **local development operations**: `guild agent create`, `guild agent save`, `guild agent test`, `guild agent pull`, `guild agent clone`. These involve the local filesystem and git, which MCP can't do.
15
+
10
16
  ## When to Use This
11
17
 
12
18
  Activate when user:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@guildai/cli",
3
- "version": "0.5.8",
3
+ "version": "0.5.10",
4
4
  "description": "Guild.ai CLI - Build, test, and deploy AI agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",