agent-pool-mcp 1.2.1 → 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/README.md CHANGED
@@ -282,7 +282,7 @@ src/
282
282
  - **Live Events**: Progress polling uses a ring buffer to show the latest activity without overwhelming context.
283
283
  - **Depth Tracking**: Nested orchestration support with optional `AGENT_POOL_MAX_DEPTH` limit.
284
284
  - **Adaptive Polling**: Pipeline daemon uses 3s intervals when active, 30s when idle.
285
- - **File-Based Communication**: Pipeline agents communicate through `.agent/runs/` JSON files — each Gemini process has its own MCP server instance but shares state via filesystem.
285
+ - **File-Based Communication**: Pipeline agents communicate through `.agents/runs/` JSON files — each Gemini process has its own MCP server instance but shares state via filesystem.
286
286
 
287
287
  ## License
288
288
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-pool-mcp",
3
- "version": "1.2.1",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "description": "MCP Server for multi-agent task delegation and orchestration via Gemini CLI",
6
6
  "main": "index.js",
@@ -17,9 +17,9 @@ import { join, dirname } from 'node:path';
17
17
  import { matchesCron } from './cron.js';
18
18
 
19
19
  const POLL_INTERVAL_MS = 30_000; // Check schedules every 30 seconds
20
- const PID_FILE = '.agent/scheduler.pid';
21
- const SCHEDULE_FILE = '.agent/schedule.json';
22
- const RESULTS_DIR = '.agent/scheduled-results';
20
+ const PID_FILE = '.agents/scheduler.pid';
21
+ const SCHEDULE_FILE = '.agents/schedule.json';
22
+ const RESULTS_DIR = '.agents/scheduled-results';
23
23
 
24
24
  /** @type {string} */
25
25
  const cwd = process.argv[2] || process.cwd();
@@ -163,8 +163,8 @@ function executeSchedule(schedule) {
163
163
 
164
164
  import { readdirSync } from 'node:fs';
165
165
 
166
- const PIPELINES_DIR = '.agent/pipelines';
167
- const RUNS_DIR = '.agent/runs';
166
+ const PIPELINES_DIR = '.agents/pipelines';
167
+ const RUNS_DIR = '.agents/runs';
168
168
 
169
169
  /**
170
170
  * Spawn a Gemini CLI agent for a pipeline step.
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Pipeline management — CRUD for pipeline definitions and run state.
3
3
  *
4
- * Pipelines are stored as JSON templates in .agent/pipelines/.
5
- * Each execution creates a run state in .agent/runs/.
4
+ * Pipelines are stored as JSON templates in .agents/pipelines/.
5
+ * Each execution creates a run state in .agents/runs/.
6
6
  *
7
7
  * @module agent-pool/scheduler/pipeline
8
8
  */
@@ -12,8 +12,8 @@ import { join, dirname } from 'node:path';
12
12
  import { randomUUID } from 'node:crypto';
13
13
  import { ensureDaemon } from './scheduler.js';
14
14
 
15
- const PIPELINES_DIR = '.agent/pipelines';
16
- const RUNS_DIR = '.agent/runs';
15
+ const PIPELINES_DIR = '.agents/pipelines';
16
+ const RUNS_DIR = '.agents/runs';
17
17
 
18
18
  // ─── Helpers ────────────────────────────────────────────────
19
19
 
@@ -15,9 +15,9 @@ import { nextCronRun } from './cron.js';
15
15
  const __dirname = dirname(fileURLToPath(import.meta.url));
16
16
  const DAEMON_SCRIPT = join(__dirname, 'daemon.js');
17
17
 
18
- const SCHEDULE_FILE = '.agent/schedule.json';
19
- const RESULTS_DIR = '.agent/scheduled-results';
20
- const PID_FILE = '.agent/scheduler.pid';
18
+ const SCHEDULE_FILE = '.agents/schedule.json';
19
+ const RESULTS_DIR = '.agents/scheduled-results';
20
+ const PID_FILE = '.agents/scheduler.pid';
21
21
 
22
22
  // ─── Schedule CRUD ──────────────────────────────────────────
23
23
 
package/src/server.js CHANGED
@@ -6,9 +6,12 @@
6
6
  */
7
7
 
8
8
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
9
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
9
10
  import {
10
11
  ListToolsRequestSchema,
11
12
  CallToolRequestSchema,
13
+ ListResourcesRequestSchema,
14
+ ReadResourceRequestSchema,
12
15
  } from '@modelcontextprotocol/sdk/types.js';
13
16
  import { randomUUID } from 'node:crypto';
14
17
 
@@ -108,9 +111,33 @@ export function createServer() {
108
111
 
109
112
  const server = new Server(
110
113
  { name: 'agent-pool', version: '1.2.1' },
111
- { capabilities: { tools: {} } },
114
+ { capabilities: { tools: {}, resources: {} } },
112
115
  );
113
116
 
117
+ server.setRequestHandler(ListResourcesRequestSchema, async () => ({
118
+ resources: [{
119
+ uri: 'agent-pool://guide',
120
+ name: 'Usage Guide',
121
+ description: 'Comprehensive guide for agent-pool',
122
+ mimeType: 'text/markdown',
123
+ }],
124
+ }));
125
+
126
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
127
+ if (request.params.uri === 'agent-pool://guide') {
128
+ const guidePath = path.resolve(__dirname, '..', 'GUIDE.md');
129
+ const content = fs.readFileSync(guidePath, 'utf-8');
130
+ return {
131
+ contents: [{
132
+ uri: request.params.uri,
133
+ mimeType: 'text/markdown',
134
+ text: content,
135
+ }],
136
+ };
137
+ }
138
+ throw new Error(`Resource not found: ${request.params.uri}`);
139
+ });
140
+
114
141
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
115
142
  tools: TOOL_DEFINITIONS,
116
143
  }));
@@ -155,6 +182,8 @@ export function createServer() {
155
182
  response = handleCancelSchedule(args); break;
156
183
  case 'get_scheduled_results':
157
184
  response = handleGetScheduledResults(args); break;
185
+ case 'get_usage_guide':
186
+ response = handleGetUsageGuide(args); break;
158
187
  case 'create_pipeline':
159
188
  response = handleCreatePipeline(args); break;
160
189
  case 'run_pipeline':
@@ -169,6 +198,8 @@ export function createServer() {
169
198
  response = handleSignalStepComplete(args); break;
170
199
  case 'bounce_back':
171
200
  response = handleBounceBack(args); break;
201
+ case 'get_usage_guide':
202
+ response = handleGetUsageGuide(args); break;
172
203
  default:
173
204
  response = { content: [{ type: 'text', text: `Unknown tool: ${name}` }], isError: true };
174
205
  }
@@ -391,7 +422,7 @@ function handleScheduleTask(args) {
391
422
  return {
392
423
  content: [{
393
424
  type: 'text',
394
- text: `⏰ Task scheduled.\n\n- **Schedule ID**: \`${result.scheduleId}\`\n- **Cron**: \`${args.cron}\`\n- **Next run**: ${result.nextRun || 'unknown'}\n- **Prompt**: ${args.prompt.substring(0, 100)}...\n\nDaemon is running in the background. Results will be saved to \`.agent/scheduled-results/\`.\nUse \`list_schedules\` to see all schedules, \`get_scheduled_results\` to read outputs.`,
425
+ text: `⏰ Task scheduled.\n\n- **Schedule ID**: \`${result.scheduleId}\`\n- **Cron**: \`${args.cron}\`\n- **Next run**: ${result.nextRun || 'unknown'}\n- **Prompt**: ${args.prompt.substring(0, 100)}...\n\nDaemon is running in the background. Results will be saved to \`.agents/scheduled-results/\`.\nUse \`list_schedules\` to see all schedules, \`get_scheduled_results\` to read outputs.`,
395
426
  }],
396
427
  };
397
428
  } catch (error) {
@@ -616,3 +647,44 @@ function handleBounceBack(args) {
616
647
  }
617
648
  }
618
649
 
650
+ /** @param {object} args */
651
+ function handleGetUsageGuide(args) {
652
+ const guidePath = path.resolve(__dirname, '..', 'GUIDE.md');
653
+ if (!fs.existsSync(guidePath)) {
654
+ return { content: [{ type: 'text', text: 'Guide not found.' }], isError: true };
655
+ }
656
+
657
+ const fullContent = fs.readFileSync(guidePath, 'utf-8');
658
+
659
+ if (!args.topic) {
660
+ return { content: [{ type: 'text', text: fullContent }] };
661
+ }
662
+
663
+ const topicLower = args.topic.toLowerCase();
664
+ const lines = fullContent.split('\n');
665
+ let inTopic = false;
666
+ let topicContent = [];
667
+
668
+ for (const line of lines) {
669
+ if (line.toLowerCase().startsWith(`## ${topicLower}`)) {
670
+ inTopic = true;
671
+ topicContent.push(line);
672
+ continue;
673
+ }
674
+
675
+ if (inTopic && line.startsWith('## ')) {
676
+ break; // End of section
677
+ }
678
+
679
+ if (inTopic) {
680
+ topicContent.push(line);
681
+ }
682
+ }
683
+
684
+ if (topicContent.length === 0) {
685
+ return { content: [{ type: 'text', text: `Topic '${args.topic}' not found in the guide.\n\nAvailable topics: delegation, pipelines, scheduling, skills, peer-review, sessions.` }] };
686
+ }
687
+
688
+ return { content: [{ type: 'text', text: topicContent.join('\n').trim() }] };
689
+ }
690
+
@@ -6,6 +6,26 @@
6
6
  */
7
7
 
8
8
  export const TOOL_DEFINITIONS = [
9
+ {
10
+ name: 'get_usage_guide',
11
+ description: [
12
+ 'Get the comprehensive usage guide for agent-pool with examples and best practices.',
13
+ 'Call this FIRST when planning how to use agent-pool tools for parallel work, pipelines, or scheduling.',
14
+ 'Returns practical examples for each feature area.',
15
+ '',
16
+ 'Available topics: delegation, pipelines, scheduling, skills, peer-review, sessions.',
17
+ 'Omit topic to get the full guide.',
18
+ ].join('\n'),
19
+ inputSchema: {
20
+ type: 'object',
21
+ properties: {
22
+ topic: {
23
+ type: 'string',
24
+ description: 'Optional topic filter: delegation, pipelines, scheduling, skills, peer-review, sessions',
25
+ },
26
+ },
27
+ },
28
+ },
9
29
  {
10
30
  name: 'delegate_task',
11
31
  description: [
@@ -179,7 +199,7 @@ export const TOOL_DEFINITIONS = [
179
199
  description: [
180
200
  'Schedule a Gemini CLI agent to run on a cron schedule or as a delayed one-shot.',
181
201
  'Spawns a persistent daemon that survives IDE/CLI restarts.',
182
- 'Results are saved to .agent/scheduled-results/ and can be retrieved with get_scheduled_results.',
202
+ 'Results are saved to .agents/scheduled-results/ and can be retrieved with get_scheduled_results.',
183
203
  '',
184
204
  'Cron format: standard 5-field (minute hour day month weekday).',
185
205
  'Examples: "*/30 * * * *" (every 30 min), "0 9 * * MON-FRI" (9am weekdays), "0 */2 * * *" (every 2 hours).',