@opvs-ai/mcp 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -176,7 +176,7 @@ const TOOLS = [
176
176
  },
177
177
  {
178
178
  name: "get_task",
179
- description: "Get full details of a single task including description, agent instructions, comments, assignees, labels, and metadata. If the task has stages (has_stages=true), use list_stages to see the stage workflow and check the active stage for your current instructions.",
179
+ description: "Get full details of a single task including description, agent instructions, comments, assignees, labels, and metadata.",
180
180
  inputSchema: {
181
181
  type: "object",
182
182
  properties: {
@@ -284,405 +284,669 @@ const TOOLS = [
284
284
  required: ["task_id"],
285
285
  },
286
286
  },
287
- // ── Stages & Handoff ──
287
+ // ── Comments ──
288
288
  {
289
- name: "list_stages",
290
- description: "List all stages for a task, ordered by position. Stages are sequential in-card steps. Check this BEFORE starting work on a task to see if it has a multi-stage workflow. Returns stage IDs, titles, statuses (pending/active/done/skipped), agent instructions, and handoff reports from previous stages.",
289
+ name: "add_comment",
290
+ description: "Add a comment to a task. Use for progress updates, notes, questions, or deliverables. Supports markdown formatting.",
291
291
  inputSchema: {
292
292
  type: "object",
293
293
  properties: {
294
294
  task_id: { type: "string", description: "Task UUID" },
295
+ content: {
296
+ type: "string",
297
+ description: "Comment text (markdown supported)",
298
+ },
295
299
  ...WORKSPACE_PROP,
296
300
  },
297
- required: ["task_id"],
301
+ required: ["task_id", "content"],
298
302
  },
299
303
  },
300
304
  {
301
- name: "create_stage",
302
- description: "Create a stage inside a task. Stages define sequential steps within a single card. The FIRST stage created on a task auto-activates immediately. Subsequent stages start as 'pending' and activate when the previous stage hands off.",
305
+ name: "list_comments",
306
+ description: "List comments on a task, ordered newest first. Returns comment content, author, and timestamps.",
303
307
  inputSchema: {
304
308
  type: "object",
305
309
  properties: {
306
310
  task_id: { type: "string", description: "Task UUID" },
307
- title: { type: "string", description: "Stage title" },
308
- description: { type: "string", description: "Stage description" },
309
- assignee_user_id: { type: "string", description: "User UUID to assign this stage to" },
310
- assignee_agent_id: { type: "string", description: "Agent UUID to assign this stage to" },
311
- agent_instructions: { type: "string", description: "Detailed instructions for the agent working this stage" },
312
- agent_context: { type: "object", description: "Structured context data for the agent (key-value pairs)" },
313
- position: { type: "number", description: "Position in stage order (auto-assigned if omitted)" },
311
+ limit: { type: "number", description: "Max results (default 25)" },
314
312
  ...WORKSPACE_PROP,
315
313
  },
316
- required: ["task_id", "title"],
314
+ required: ["task_id"],
317
315
  },
318
316
  },
317
+ // ── Views (agent-optimized) ──
319
318
  {
320
- name: "update_stage",
321
- description: "Update a stage's fields. Only pending or active stages can be updated done and skipped stages are immutable. Provide only the fields you want to change.",
319
+ name: "get_board_session",
320
+ description: "RECOMMENDED FIRST CALL when starting work on a board. Returns everything in one call: board info, all columns with their UUIDs and names (needed for move_task), and your assigned tasks. Much more efficient than calling get_board + list_tasks separately.",
322
321
  inputSchema: {
323
322
  type: "object",
324
323
  properties: {
325
- task_id: { type: "string", description: "Task UUID" },
326
- stage_id: { type: "string", description: "Stage UUID" },
327
- title: { type: "string", description: "New title" },
328
- description: { type: "string", description: "New description" },
329
- assignee_user_id: { type: "string", description: "New user assignee UUID" },
330
- assignee_agent_id: { type: "string", description: "New agent assignee UUID" },
331
- agent_instructions: { type: "string", description: "New agent instructions" },
332
- agent_context: { type: "object", description: "New structured context data" },
324
+ board_id: { type: "string", description: "Board UUID" },
333
325
  ...WORKSPACE_PROP,
334
326
  },
335
- required: ["task_id", "stage_id"],
327
+ required: ["board_id"],
336
328
  },
337
329
  },
338
330
  {
339
- name: "delete_stage",
340
- description: "Delete a pending stage from a task. Cannot delete active or completed stages.",
331
+ name: "get_board_overview",
332
+ description: "Get board overview with column structure, task counts per column, and board metadata. Lighter than get_board_session (no task details).",
341
333
  inputSchema: {
342
334
  type: "object",
343
335
  properties: {
344
- task_id: { type: "string", description: "Task UUID" },
345
- stage_id: { type: "string", description: "Stage UUID" },
336
+ board_id: { type: "string", description: "Board UUID" },
346
337
  ...WORKSPACE_PROP,
347
338
  },
348
- required: ["task_id", "stage_id"],
339
+ required: ["board_id"],
349
340
  },
350
341
  },
342
+ // ── Session ──
351
343
  {
352
- name: "reorder_stages",
353
- description: "Reorder the pending stages within a task. Pass all pending stage UUIDs in the desired order. Active and completed stages cannot be reordered.",
344
+ name: "get_session",
345
+ description: "Get your assigned tasks across all boards. Use this to find what you should work on. For a specific board's full context (columns, tasks), use get_board_session instead.",
354
346
  inputSchema: {
355
347
  type: "object",
356
348
  properties: {
357
- task_id: { type: "string", description: "Task UUID" },
358
- order: {
349
+ board_id: {
350
+ type: "string",
351
+ description: "Optional: scope to a specific board",
352
+ },
353
+ ...WORKSPACE_PROP,
354
+ },
355
+ },
356
+ },
357
+ // ── Activity ──
358
+ {
359
+ name: "list_activity",
360
+ description: "Get recent activity feed (who did what, when). Provide exactly ONE of board_id or task_id. Shows task creation, status changes, comments, assignments, and moves. Ordered newest first.",
361
+ inputSchema: {
362
+ type: "object",
363
+ properties: {
364
+ board_id: { type: "string", description: "Board UUID — activity for the whole board" },
365
+ task_id: { type: "string", description: "Task UUID — activity for a single task" },
366
+ limit: { type: "number", description: "Max results (default 25)" },
367
+ ...WORKSPACE_PROP,
368
+ },
369
+ },
370
+ },
371
+ // ── Metrics ──
372
+ {
373
+ name: "get_board_summary",
374
+ description: "Get board KPIs: task counts by status, workload by assignee, priority distribution, and recent activity stats. Useful for reporting and understanding board health.",
375
+ inputSchema: {
376
+ type: "object",
377
+ properties: {
378
+ board_id: { type: "string", description: "Board UUID" },
379
+ days: { type: "number", description: "Time window in days (default 7)" },
380
+ ...WORKSPACE_PROP,
381
+ },
382
+ required: ["board_id"],
383
+ },
384
+ },
385
+ {
386
+ name: "get_task_velocity",
387
+ description: "Get task velocity: tasks created vs completed per day over time. Useful for tracking team throughput and trends.",
388
+ inputSchema: {
389
+ type: "object",
390
+ properties: {
391
+ days: { type: "number", description: "Time window in days (default 30)" },
392
+ ...WORKSPACE_PROP,
393
+ },
394
+ },
395
+ },
396
+ // ── Columns ──
397
+ {
398
+ name: "list_columns",
399
+ description: "List all columns on a board with their IDs, names, and positions. Use this to find column IDs needed by move_task and create_task (or just pass column names directly).",
400
+ inputSchema: {
401
+ type: "object",
402
+ properties: {
403
+ board_id: { type: "string", description: "Board UUID" },
404
+ ...WORKSPACE_PROP,
405
+ },
406
+ required: ["board_id"],
407
+ },
408
+ },
409
+ {
410
+ name: "create_column",
411
+ description: "Create a new column on a board. New column is added at the end. Use reorder_columns to change position.",
412
+ inputSchema: {
413
+ type: "object",
414
+ properties: {
415
+ board_id: { type: "string", description: "Board UUID" },
416
+ name: { type: "string", description: "Column name (e.g. 'In Review', 'Blocked')" },
417
+ color: { type: "string", description: "Column color hex (e.g. '#3B82F6')" },
418
+ wip_limit: { type: "number", description: "Max tasks allowed in this column" },
419
+ ...WORKSPACE_PROP,
420
+ },
421
+ required: ["board_id", "name"],
422
+ },
423
+ },
424
+ {
425
+ name: "reorder_columns",
426
+ description: "Set the order of columns on a board. Pass ALL column UUIDs in the desired order — any omitted columns will be removed.",
427
+ inputSchema: {
428
+ type: "object",
429
+ properties: {
430
+ board_id: { type: "string", description: "Board UUID" },
431
+ column_ids: {
359
432
  type: "array",
360
433
  items: { type: "string" },
361
- description: "Stage UUIDs in desired order",
434
+ description: "ALL column UUIDs in desired left-to-right order",
362
435
  },
363
436
  ...WORKSPACE_PROP,
364
437
  },
365
- required: ["task_id", "order"],
438
+ required: ["board_id", "column_ids"],
366
439
  },
367
440
  },
441
+ // ── Files ──
368
442
  {
369
- name: "submit_handoff",
370
- description: "Submit a handoff report for the currently ACTIVE stage of a task. This is how you complete your current stage and pass work to the next owner.\n\nWORKFLOW: When working on a task with stages, call this after finishing your stage's work.\n- resolution='hand_off' (default): Marks your stage as done, activates the NEXT pending stage. You MUST provide next_owner_context to brief the next person.\n- resolution='resolve': Marks your stage AND the entire task as done. Use when you're on the last stage or want to finish early.\n\nIMPORTANT: Always include detailed what_was_done (min 10 chars) and output. The next_owner_context field is critical for knowledge transfer — explain what the next person needs to know to continue.",
443
+ name: "list_files",
444
+ description: "List file attachments on a task. Returns file names, sizes, types, and IDs. Use get_file for download URLs.",
371
445
  inputSchema: {
372
446
  type: "object",
373
447
  properties: {
374
448
  task_id: { type: "string", description: "Task UUID" },
375
- stage_id: { type: "string", description: "Stage UUID (must be the currently active stage)" },
376
- what_was_done: { type: "string", description: "Summary of work completed (minimum 10 characters)" },
377
- output: { type: "string", description: "Deliverable or output from this stage" },
378
- next_owner_context: { type: "string", description: "Context for the next stage owner — what they need to know to continue. Required when resolution is 'hand_off'." },
379
- resolution: { type: "string", description: "hand_off (pass to next stage, default) or resolve (complete entire task)" },
380
449
  ...WORKSPACE_PROP,
381
450
  },
382
- required: ["task_id", "stage_id", "what_was_done", "output"],
451
+ required: ["task_id"],
383
452
  },
384
453
  },
385
454
  {
386
- name: "resolve_task",
387
- description: "Resolve a task with a final handoff report. Works with or without stages. Use this to formally complete a task with a structured report, instead of just setting status='done'.\n\n- resolution='resolve' (default): Marks the task as done with your final report.\n- resolution='spawn_linked_card': Marks the task as done AND creates a new follow-up task linked to this one with a 'spawned' link. The next_owner_context becomes the new task's description.\n\nReturns the task status and, if spawned, the new spawned_task_id.",
455
+ name: "get_file",
456
+ description: "Get file metadata including name, size, MIME type, and download URL. Note: file upload is only available via the CLI (opvs files upload).",
388
457
  inputSchema: {
389
458
  type: "object",
390
459
  properties: {
391
- task_id: { type: "string", description: "Task UUID" },
392
- what_was_done: { type: "string", description: "Summary of all work completed (minimum 10 characters)" },
393
- output: { type: "string", description: "Final deliverable or output" },
394
- next_owner_context: { type: "string", description: "Context for follow-up work. Required when resolution is 'spawn_linked_card'." },
395
- resolution: { type: "string", description: "resolve (complete task, default) or spawn_linked_card (complete + create follow-up task)" },
460
+ file_id: { type: "string", description: "File UUID" },
396
461
  ...WORKSPACE_PROP,
397
462
  },
398
- required: ["task_id", "what_was_done", "output"],
463
+ required: ["file_id"],
399
464
  },
400
465
  },
401
- // ── Task Links ──
466
+ // ── Docs ──
402
467
  {
403
- name: "list_task_links",
404
- description: "List all links for a task both incoming and outgoing. Returns link type (spawned, blocked_by, related), source/target task IDs and titles. Use to understand task dependencies and relationships.",
468
+ name: "list_docs",
469
+ description: "List all AgentDocs documentation projects in your workspace. Returns project names, slugs, and page counts.",
470
+ inputSchema: {
471
+ type: "object",
472
+ properties: { ...WORKSPACE_PROP },
473
+ },
474
+ },
475
+ {
476
+ name: "get_doc",
477
+ description: "Get a documentation page by project and slug. The project parameter accepts a slug (e.g. 'platform-core-docs') or UUID.",
405
478
  inputSchema: {
406
479
  type: "object",
407
480
  properties: {
408
- task_id: { type: "string", description: "Task UUID" },
481
+ project: { type: "string", description: "Project slug or UUID (e.g. 'platform-core-docs')" },
482
+ slug: { type: "string", description: "Page slug" },
483
+ version: { type: "number", description: "Specific version number (optional, defaults to latest)" },
409
484
  ...WORKSPACE_PROP,
410
485
  },
411
- required: ["task_id"],
486
+ required: ["project", "slug"],
412
487
  },
413
488
  },
414
489
  {
415
- name: "create_task_link",
416
- description: "Create a typed link between two tasks. Link types: 'spawned' (target was created from source), 'blocked_by' (source blocked until target completes), 'related' (informational cross-reference). The source is the task_id you provide, the target is the other task.",
490
+ name: "create_doc",
491
+ description: "Create a new documentation page in a project. Content supports full markdown. Each page has a unique slug within its project.",
417
492
  inputSchema: {
418
493
  type: "object",
419
494
  properties: {
420
- task_id: { type: "string", description: "Source task UUID" },
421
- target_task_id: { type: "string", description: "Target task UUID to link to" },
422
- link_type: { type: "string", description: "Link type: spawned, blocked_by, or related (default: related)" },
495
+ project: { type: "string", description: "Project slug or UUID" },
496
+ title: { type: "string", description: "Page title" },
497
+ slug: { type: "string", description: "Page slug (URL-friendly, must be unique in project)" },
498
+ content: { type: "string", description: "Page content (markdown)" },
499
+ message: { type: "string", description: "Commit message (default: 'Created via MCP')" },
423
500
  ...WORKSPACE_PROP,
424
501
  },
425
- required: ["task_id", "target_task_id"],
502
+ required: ["project", "title", "slug"],
426
503
  },
427
504
  },
428
505
  {
429
- name: "delete_task_link",
430
- description: "Delete a task link by its link ID. Use list_task_links to find link IDs.",
506
+ name: "update_doc",
507
+ description: "Update a documentation page's content. Creates a new version previous versions are preserved and accessible by version number.",
431
508
  inputSchema: {
432
509
  type: "object",
433
510
  properties: {
434
- link_id: { type: "string", description: "Link UUID" },
511
+ project: { type: "string", description: "Project slug or UUID" },
512
+ slug: { type: "string", description: "Page slug" },
513
+ content: { type: "string", description: "New content (markdown)" },
514
+ title: { type: "string", description: "New title (optional)" },
515
+ message: { type: "string", description: "Commit message (default: 'Updated via MCP')" },
435
516
  ...WORKSPACE_PROP,
436
517
  },
437
- required: ["link_id"],
518
+ required: ["project", "slug", "content"],
438
519
  },
439
520
  },
440
- // ── Comments ──
441
521
  {
442
- name: "add_comment",
443
- description: "Add a comment to a task. Use for progress updates, notes, questions, or deliverables. Supports markdown formatting.",
522
+ name: "search_docs",
523
+ description: "Full-text search across documentation. Searches page titles and content. Optionally scope to a single project.",
444
524
  inputSchema: {
445
525
  type: "object",
446
526
  properties: {
447
- task_id: { type: "string", description: "Task UUID" },
448
- content: {
449
- type: "string",
450
- description: "Comment text (markdown supported)",
451
- },
527
+ query: { type: "string", description: "Search query (searches titles and content)" },
528
+ project: { type: "string", description: "Project slug or UUID to scope search (optional)" },
529
+ limit: { type: "number", description: "Max results (default 10)" },
452
530
  ...WORKSPACE_PROP,
453
531
  },
454
- required: ["task_id", "content"],
532
+ required: ["query"],
455
533
  },
456
534
  },
535
+ // ── Docs: Project CRUD ──
457
536
  {
458
- name: "list_comments",
459
- description: "List comments on a task, ordered newest first. Returns comment content, author, and timestamps.",
537
+ name: "create_project",
538
+ description: "Create a new documentation project. Returns the project with its ID and slug.",
460
539
  inputSchema: {
461
540
  type: "object",
462
541
  properties: {
463
- task_id: { type: "string", description: "Task UUID" },
542
+ name: { type: "string", description: "Project name" },
543
+ description: { type: "string", description: "Project description" },
544
+ visibility: { type: "string", description: "public or private (default: public)" },
545
+ ...WORKSPACE_PROP,
546
+ },
547
+ required: ["name"],
548
+ },
549
+ },
550
+ {
551
+ name: "update_project",
552
+ description: "Update a documentation project's name, description, or visibility. Brand admin only.",
553
+ inputSchema: {
554
+ type: "object",
555
+ properties: {
556
+ project: { type: "string", description: "Project slug or UUID" },
557
+ name: { type: "string", description: "New name" },
558
+ description: { type: "string", description: "New description" },
559
+ visibility: { type: "string", description: "public or private" },
560
+ ...WORKSPACE_PROP,
561
+ },
562
+ required: ["project"],
563
+ },
564
+ },
565
+ {
566
+ name: "delete_project",
567
+ description: "Soft-delete a documentation project. Brand admin only.",
568
+ inputSchema: {
569
+ type: "object",
570
+ properties: {
571
+ project: { type: "string", description: "Project slug or UUID" },
572
+ ...WORKSPACE_PROP,
573
+ },
574
+ required: ["project"],
575
+ },
576
+ },
577
+ // ── Docs: Page Operations ──
578
+ {
579
+ name: "list_pages",
580
+ description: "List pages in a documentation project. Use view='tree' for nested structure with children.",
581
+ inputSchema: {
582
+ type: "object",
583
+ properties: {
584
+ project: { type: "string", description: "Project slug or UUID" },
585
+ view: { type: "string", description: "flat or tree (default: flat)" },
586
+ limit: { type: "number", description: "Max results (default 100)" },
587
+ ...WORKSPACE_PROP,
588
+ },
589
+ required: ["project"],
590
+ },
591
+ },
592
+ {
593
+ name: "move_page",
594
+ description: "Move a page to a new path or change sort order within its folder. Does not create a revision.",
595
+ inputSchema: {
596
+ type: "object",
597
+ properties: {
598
+ project: { type: "string", description: "Project slug or UUID" },
599
+ slug: { type: "string", description: "Page slug" },
600
+ path: { type: "string", description: "New tree path (e.g. '/guides')" },
601
+ sort_order: { type: "number", description: "New sort order within folder" },
602
+ ...WORKSPACE_PROP,
603
+ },
604
+ required: ["project", "slug"],
605
+ },
606
+ },
607
+ {
608
+ name: "delete_page",
609
+ description: "Soft-delete a documentation page.",
610
+ inputSchema: {
611
+ type: "object",
612
+ properties: {
613
+ project: { type: "string", description: "Project slug or UUID" },
614
+ slug: { type: "string", description: "Page slug" },
615
+ ...WORKSPACE_PROP,
616
+ },
617
+ required: ["project", "slug"],
618
+ },
619
+ },
620
+ // ── Docs: Revision History ──
621
+ {
622
+ name: "page_history",
623
+ description: "Get revision history for a page. Returns all past versions with dates and authors.",
624
+ inputSchema: {
625
+ type: "object",
626
+ properties: {
627
+ page_id: { type: "string", description: "Page UUID" },
464
628
  limit: { type: "number", description: "Max results (default 25)" },
465
629
  ...WORKSPACE_PROP,
466
630
  },
467
- required: ["task_id"],
631
+ required: ["page_id"],
468
632
  },
469
633
  },
470
- // ── Views (agent-optimized) ──
471
634
  {
472
- name: "get_board_session",
473
- description: "RECOMMENDED FIRST CALL when starting work on a board. Returns everything in one call: board info, all columns with their UUIDs and names (needed for move_task), and your assigned tasks. Much more efficient than calling get_board + list_tasks separately.",
635
+ name: "page_diff",
636
+ description: "Compute unified diff between two revisions. Omit 'from' for parent comparison.",
474
637
  inputSchema: {
475
638
  type: "object",
476
639
  properties: {
477
- board_id: { type: "string", description: "Board UUID" },
640
+ page_id: { type: "string", description: "Page UUID" },
641
+ from_rev: { type: "string", description: "From revision ID (optional — defaults to parent)" },
642
+ to_rev: { type: "string", description: "To revision ID (optional — defaults to latest)" },
478
643
  ...WORKSPACE_PROP,
479
644
  },
480
- required: ["board_id"],
645
+ required: ["page_id"],
481
646
  },
482
647
  },
483
648
  {
484
- name: "get_board_overview",
485
- description: "Get board overview with column structure, task counts per column, and board metadata. Lighter than get_board_session (no task details).",
649
+ name: "page_rollback",
650
+ description: "Rollback a page to a previous revision. Non-destructive creates a new revision with the old content.",
486
651
  inputSchema: {
487
652
  type: "object",
488
653
  properties: {
489
- board_id: { type: "string", description: "Board UUID" },
654
+ page_id: { type: "string", description: "Page UUID" },
655
+ revision_id: { type: "string", description: "Target revision ID to restore" },
656
+ message: { type: "string", description: "Commit message (default: 'Rollback via MCP')" },
490
657
  ...WORKSPACE_PROP,
491
658
  },
492
- required: ["board_id"],
659
+ required: ["page_id", "revision_id"],
493
660
  },
494
661
  },
495
- // ── Session ──
662
+ // ── Docs: Media ──
496
663
  {
497
- name: "get_session",
498
- description: "Get your assigned tasks across all boards. Use this to find what you should work on. For a specific board's full context (columns, tasks), use get_board_session instead.",
664
+ name: "list_media",
665
+ description: "List media files in a documentation project. Returns filenames, sizes, URLs, and markdown embed snippets.",
499
666
  inputSchema: {
500
667
  type: "object",
501
668
  properties: {
502
- board_id: {
503
- type: "string",
504
- description: "Optional: scope to a specific board",
669
+ project: { type: "string", description: "Project slug or UUID" },
670
+ limit: { type: "number", description: "Max results (default 25)" },
671
+ ...WORKSPACE_PROP,
672
+ },
673
+ required: ["project"],
674
+ },
675
+ },
676
+ // ── Docs: Bulk & Export ──
677
+ {
678
+ name: "bulk_create_pages",
679
+ description: "Bulk create or update multiple pages at once. Used for multi-page writes. Each page needs title, slug, content_md, commit_message.",
680
+ inputSchema: {
681
+ type: "object",
682
+ properties: {
683
+ project: { type: "string", description: "Project slug or UUID" },
684
+ pages: {
685
+ type: "array",
686
+ items: {
687
+ type: "object",
688
+ properties: {
689
+ title: { type: "string" },
690
+ slug: { type: "string" },
691
+ content_md: { type: "string" },
692
+ commit_message: { type: "string" },
693
+ path: { type: "string" },
694
+ },
695
+ required: ["title", "slug", "content_md", "commit_message"],
696
+ },
697
+ description: "Array of page objects",
505
698
  },
699
+ branch: { type: "string", description: "Target branch (default: main)" },
506
700
  ...WORKSPACE_PROP,
507
701
  },
702
+ required: ["project", "pages"],
508
703
  },
509
704
  },
510
- // ── Activity ──
705
+ // ── Agent Optimization ──
511
706
  {
512
- name: "list_activity",
513
- description: "Get recent activity feed (who did what, when). Provide exactly ONE of board_id or task_id. Shows task creation, status changes, comments, assignments, and moves. Ordered newest first.",
707
+ name: "agent_my_tasks",
708
+ description: "Get tasks assigned to you across ALL boards in one call. More comprehensive than list_tasks with self=true aggregates from every board and includes board names.",
514
709
  inputSchema: {
515
710
  type: "object",
516
711
  properties: {
517
- board_id: { type: "string", description: "Board UUID activity for the whole board" },
518
- task_id: { type: "string", description: "Task UUID activity for a single task" },
519
- limit: { type: "number", description: "Max results (default 25)" },
712
+ board_id: { type: "string", description: "Scope to a specific board (optional)" },
713
+ status: { type: "string", description: "Filter: pending, assigned, in_progress, review, done, failed" },
714
+ limit: { type: "number", description: "Max results" },
520
715
  ...WORKSPACE_PROP,
521
716
  },
522
717
  },
523
718
  },
524
- // ── Metrics ──
525
719
  {
526
- name: "get_board_summary",
527
- description: "Get board KPIs: task counts by status, workload by assignee, priority distribution, and recent activity stats. Useful for reporting and understanding board health.",
720
+ name: "agent_my_delegations",
721
+ description: "List tasks you delegated to other agents. Complement to agent_my_tasks shows tasks you handed off, not tasks assigned to you.",
528
722
  inputSchema: {
529
723
  type: "object",
530
724
  properties: {
531
- board_id: { type: "string", description: "Board UUID" },
532
- days: { type: "number", description: "Time window in days (default 7)" },
725
+ status: { type: "string", description: "Filter: pending, assigned, in_progress, review, done, failed" },
726
+ limit: { type: "number", description: "Max results" },
533
727
  ...WORKSPACE_PROP,
534
728
  },
535
- required: ["board_id"],
536
729
  },
537
730
  },
538
731
  {
539
- name: "get_task_velocity",
540
- description: "Get task velocity: tasks created vs completed per day over time. Useful for tracking team throughput and trends.",
732
+ name: "agent_batch_create_tasks",
733
+ description: "Create multiple tasks at once. Each task needs board_id and title. Returns list of created IDs and any errors.",
541
734
  inputSchema: {
542
735
  type: "object",
543
736
  properties: {
544
- days: { type: "number", description: "Time window in days (default 30)" },
737
+ tasks: {
738
+ type: "array",
739
+ items: {
740
+ type: "object",
741
+ properties: {
742
+ board_id: { type: "string", description: "Board UUID" },
743
+ title: { type: "string", description: "Task title" },
744
+ description: { type: "string", description: "Task description" },
745
+ priority: { type: "string", description: "low, medium, high, critical" },
746
+ column_id: { type: "string", description: "Column UUID or name" },
747
+ agent_instructions: { type: "string", description: "Agent instructions" },
748
+ },
749
+ required: ["board_id", "title"],
750
+ },
751
+ description: "Array of task objects to create",
752
+ },
545
753
  ...WORKSPACE_PROP,
546
754
  },
755
+ required: ["tasks"],
547
756
  },
548
757
  },
549
- // ── Columns ──
550
758
  {
551
- name: "list_columns",
552
- description: "List all columns on a board with their IDs, names, and positions. Use this to find column IDs needed by move_task and create_task (or just pass column names directly).",
759
+ name: "agent_report_progress",
760
+ description: "Report progress on a task. Updates metadata and adds a progress comment. Use this for long-running tasks to keep stakeholders informed.",
553
761
  inputSchema: {
554
762
  type: "object",
555
763
  properties: {
556
- board_id: { type: "string", description: "Board UUID" },
764
+ task_id: { type: "string", description: "Task UUID" },
765
+ percent: { type: "number", description: "Progress percentage (0-100)" },
766
+ message: { type: "string", description: "Progress message" },
767
+ current_operation: { type: "string", description: "What you're currently doing" },
557
768
  ...WORKSPACE_PROP,
558
769
  },
559
- required: ["board_id"],
770
+ required: ["task_id", "percent"],
560
771
  },
561
772
  },
562
773
  {
563
- name: "create_column",
564
- description: "Create a new column on a board. New column is added at the end. Use reorder_columns to change position.",
774
+ name: "agent_complete_task",
775
+ description: "Mark a task as done or failed. Automatically walks through intermediate status transitions (pending→assigned→in_progress→done). Adds a completion comment.",
565
776
  inputSchema: {
566
777
  type: "object",
567
778
  properties: {
568
- board_id: { type: "string", description: "Board UUID" },
569
- name: { type: "string", description: "Column name (e.g. 'In Review', 'Blocked')" },
570
- color: { type: "string", description: "Column color hex (e.g. '#3B82F6')" },
571
- wip_limit: { type: "number", description: "Max tasks allowed in this column" },
779
+ task_id: { type: "string", description: "Task UUID" },
780
+ status: { type: "string", description: "done or failed (default: done)" },
781
+ summary: { type: "string", description: "Completion summary (added as comment)" },
782
+ result_data: {
783
+ type: "object",
784
+ description: "Structured result data (JSON object)",
785
+ },
572
786
  ...WORKSPACE_PROP,
573
787
  },
574
- required: ["board_id", "name"],
788
+ required: ["task_id"],
575
789
  },
576
790
  },
577
791
  {
578
- name: "reorder_columns",
579
- description: "Set the order of columns on a board. Pass ALL column UUIDs in the desired order any omitted columns will be removed.",
792
+ name: "agent_delegate_task",
793
+ description: "Reassign a task to another agent by their slug (e.g. 'maya', 'grant'). Resolves the slug to a UUID, updates assignment, and adds a delegation comment.",
580
794
  inputSchema: {
581
795
  type: "object",
582
796
  properties: {
583
- board_id: { type: "string", description: "Board UUID" },
584
- column_ids: {
797
+ task_id: { type: "string", description: "Task UUID" },
798
+ agent_slug: { type: "string", description: "Target agent's slug (e.g. 'maya')" },
799
+ instructions: { type: "string", description: "Instructions for the target agent" },
800
+ ...WORKSPACE_PROP,
801
+ },
802
+ required: ["task_id", "agent_slug"],
803
+ },
804
+ },
805
+ {
806
+ name: "search_tasks",
807
+ description: "Full-text search across all tasks/cards. Searches titles, descriptions, and comments.",
808
+ inputSchema: {
809
+ type: "object",
810
+ properties: {
811
+ query: { type: "string", description: "Search query" },
812
+ board_id: { type: "string", description: "Scope to a specific board (optional)" },
813
+ limit: { type: "number", description: "Max results (default 25)" },
814
+ ...WORKSPACE_PROP,
815
+ },
816
+ required: ["query"],
817
+ },
818
+ },
819
+ {
820
+ name: "batch_get_tasks",
821
+ description: "Get multiple tasks by IDs in one call (max 50). More efficient than calling get_task multiple times.",
822
+ inputSchema: {
823
+ type: "object",
824
+ properties: {
825
+ ids: {
585
826
  type: "array",
586
827
  items: { type: "string" },
587
- description: "ALL column UUIDs in desired left-to-right order",
828
+ description: "Array of task UUIDs (max 50)",
588
829
  },
589
830
  ...WORKSPACE_PROP,
590
831
  },
591
- required: ["board_id", "column_ids"],
832
+ required: ["ids"],
833
+ },
834
+ },
835
+ // ── Stages ──
836
+ {
837
+ name: "list_stages",
838
+ description: "List stages (sequential in-card steps) for a task. Stages enable multi-agent handoff workflows within a single task.",
839
+ inputSchema: {
840
+ type: "object",
841
+ properties: {
842
+ task_id: { type: "string", description: "Task UUID" },
843
+ ...WORKSPACE_PROP,
844
+ },
845
+ required: ["task_id"],
592
846
  },
593
847
  },
594
- // ── Files ──
595
848
  {
596
- name: "list_files",
597
- description: "List file attachments on a task. Returns file names, sizes, types, and IDs. Use get_file for download URLs.",
849
+ name: "create_stage",
850
+ description: "Create a stage on a task. The first stage auto-activates. Subsequent stages stay pending until the previous one is completed via handoff.",
598
851
  inputSchema: {
599
852
  type: "object",
600
853
  properties: {
601
854
  task_id: { type: "string", description: "Task UUID" },
855
+ title: { type: "string", description: "Stage title" },
856
+ description: { type: "string", description: "Stage description" },
857
+ assignee_agent_id: { type: "string", description: "Agent UUID to assign this stage to" },
858
+ agent_instructions: { type: "string", description: "Instructions for the agent handling this stage" },
859
+ position: { type: "number", description: "Position in stage order" },
602
860
  ...WORKSPACE_PROP,
603
861
  },
604
- required: ["task_id"],
862
+ required: ["task_id", "title"],
605
863
  },
606
864
  },
607
865
  {
608
- name: "get_file",
609
- description: "Get file metadata including name, size, MIME type, and download URL. Note: file upload is only available via the CLI (opvs files upload).",
866
+ name: "update_stage",
867
+ description: "Update a stage (pending or active only). Provide only the fields you want to change.",
610
868
  inputSchema: {
611
869
  type: "object",
612
870
  properties: {
613
- file_id: { type: "string", description: "File UUID" },
871
+ task_id: { type: "string", description: "Task UUID" },
872
+ stage_id: { type: "string", description: "Stage UUID" },
873
+ title: { type: "string", description: "New title" },
874
+ description: { type: "string", description: "New description" },
875
+ assignee_agent_id: { type: "string", description: "New agent assignment" },
876
+ agent_instructions: { type: "string", description: "New agent instructions" },
614
877
  ...WORKSPACE_PROP,
615
878
  },
616
- required: ["file_id"],
879
+ required: ["task_id", "stage_id"],
617
880
  },
618
881
  },
619
- // ── Docs ──
620
882
  {
621
- name: "list_docs",
622
- description: "List all AgentDocs documentation projects in your workspace. Returns project names, slugs, and page counts.",
883
+ name: "complete_stage",
884
+ description: "Complete a stage and hand off to the next one. Adds a handoff comment. If this is the last stage, the task can be completed.",
623
885
  inputSchema: {
624
886
  type: "object",
625
- properties: { ...WORKSPACE_PROP },
887
+ properties: {
888
+ task_id: { type: "string", description: "Task UUID" },
889
+ stage_id: { type: "string", description: "Stage UUID to complete" },
890
+ comment: { type: "string", description: "Handoff comment for the next stage's assignee" },
891
+ ...WORKSPACE_PROP,
892
+ },
893
+ required: ["task_id", "stage_id"],
626
894
  },
627
895
  },
628
896
  {
629
- name: "get_doc",
630
- description: "Get a documentation page by project and slug. The project parameter accepts a slug (e.g. 'platform-core-docs') or UUID.",
897
+ name: "reorder_stages",
898
+ description: "Reorder pending stages on a task. Active and completed stages cannot be reordered.",
631
899
  inputSchema: {
632
900
  type: "object",
633
901
  properties: {
634
- project: { type: "string", description: "Project slug or UUID (e.g. 'platform-core-docs')" },
635
- slug: { type: "string", description: "Page slug" },
636
- version: { type: "number", description: "Specific version number (optional, defaults to latest)" },
902
+ task_id: { type: "string", description: "Task UUID" },
903
+ order: {
904
+ type: "array",
905
+ items: { type: "string" },
906
+ description: "Stage UUIDs in desired order",
907
+ },
637
908
  ...WORKSPACE_PROP,
638
909
  },
639
- required: ["project", "slug"],
910
+ required: ["task_id", "order"],
640
911
  },
641
912
  },
913
+ // ── Task Links ──
642
914
  {
643
- name: "create_doc",
644
- description: "Create a new documentation page in a project. Content supports full markdown. Each page has a unique slug within its project.",
915
+ name: "list_task_links",
916
+ description: "List all links for a task (incoming and outgoing). Link types: spawned, blocked_by, related.",
645
917
  inputSchema: {
646
918
  type: "object",
647
919
  properties: {
648
- project: { type: "string", description: "Project slug or UUID" },
649
- title: { type: "string", description: "Page title" },
650
- slug: { type: "string", description: "Page slug (URL-friendly, must be unique in project)" },
651
- content: { type: "string", description: "Page content (markdown)" },
652
- message: { type: "string", description: "Commit message (default: 'Created via MCP')" },
920
+ task_id: { type: "string", description: "Task UUID" },
653
921
  ...WORKSPACE_PROP,
654
922
  },
655
- required: ["project", "title", "slug"],
923
+ required: ["task_id"],
656
924
  },
657
925
  },
658
926
  {
659
- name: "update_doc",
660
- description: "Update a documentation page's content. Creates a new version previous versions are preserved and accessible by version number.",
927
+ name: "create_task_link",
928
+ description: "Create a link between two tasks. Types: 'spawned' (this task created the target), 'blocked_by' (this task is blocked by target), 'related' (general relation).",
661
929
  inputSchema: {
662
930
  type: "object",
663
931
  properties: {
664
- project: { type: "string", description: "Project slug or UUID" },
665
- slug: { type: "string", description: "Page slug" },
666
- content: { type: "string", description: "New content (markdown)" },
667
- title: { type: "string", description: "New title (optional)" },
668
- message: { type: "string", description: "Commit message (default: 'Updated via MCP')" },
932
+ task_id: { type: "string", description: "Source task UUID" },
933
+ target_task_id: { type: "string", description: "Target task UUID" },
934
+ link_type: { type: "string", description: "spawned, blocked_by, or related (default: related)" },
669
935
  ...WORKSPACE_PROP,
670
936
  },
671
- required: ["project", "slug", "content"],
937
+ required: ["task_id", "target_task_id"],
672
938
  },
673
939
  },
674
940
  {
675
- name: "search_docs",
676
- description: "Full-text search across documentation. Searches page titles and content. Optionally scope to a single project.",
941
+ name: "delete_task_link",
942
+ description: "Delete a task link by its ID.",
677
943
  inputSchema: {
678
944
  type: "object",
679
945
  properties: {
680
- query: { type: "string", description: "Search query (searches titles and content)" },
681
- project: { type: "string", description: "Project slug or UUID to scope search (optional)" },
682
- limit: { type: "number", description: "Max results (default 10)" },
946
+ link_id: { type: "string", description: "Link UUID" },
683
947
  ...WORKSPACE_PROP,
684
948
  },
685
- required: ["query"],
949
+ required: ["link_id"],
686
950
  },
687
951
  },
688
952
  // ── Auth ──
@@ -846,92 +1110,6 @@ async function handleTool(name, args) {
846
1110
  const url = buildUrl(`/api/v1/board/tasks/${args.task_id}/subtasks`, undefined, fmt);
847
1111
  return ok(await callApi("GET", url, ws));
848
1112
  }
849
- // ── Stages & Handoff ──
850
- case "list_stages": {
851
- const url = buildUrl(`/api/v1/board/tasks/${args.task_id}/stages`, undefined, fmt);
852
- return ok(await callApi("GET", url, ws));
853
- }
854
- case "create_stage": {
855
- const body = { title: args.title };
856
- if (args.description)
857
- body.description = args.description;
858
- if (args.assignee_user_id)
859
- body.assignee_user_id = args.assignee_user_id;
860
- if (args.assignee_agent_id)
861
- body.assignee_agent_id = args.assignee_agent_id;
862
- if (args.agent_instructions)
863
- body.agent_instructions = args.agent_instructions;
864
- if (args.agent_context)
865
- body.agent_context = args.agent_context;
866
- if (args.position !== undefined)
867
- body.position = args.position;
868
- return ok(await callApi("POST", `/api/v1/board/tasks/${args.task_id}/stages`, ws, body));
869
- }
870
- case "update_stage": {
871
- const body = {};
872
- if (args.title)
873
- body.title = args.title;
874
- if (args.description)
875
- body.description = args.description;
876
- if (args.assignee_user_id)
877
- body.assignee_user_id = args.assignee_user_id;
878
- if (args.assignee_agent_id)
879
- body.assignee_agent_id = args.assignee_agent_id;
880
- if (args.agent_instructions)
881
- body.agent_instructions = args.agent_instructions;
882
- if (args.agent_context)
883
- body.agent_context = args.agent_context;
884
- if (Object.keys(body).length === 0) {
885
- return err("Nothing to update. Provide title, description, assignee_user_id, assignee_agent_id, agent_instructions, or agent_context.");
886
- }
887
- return ok(await callApi("PATCH", `/api/v1/board/tasks/${args.task_id}/stages/${args.stage_id}`, ws, body));
888
- }
889
- case "delete_stage": {
890
- await callApi("DELETE", `/api/v1/board/tasks/${args.task_id}/stages/${args.stage_id}`, ws);
891
- return ok(`Deleted stage ${args.stage_id}`);
892
- }
893
- case "reorder_stages": {
894
- return ok(await callApi("POST", `/api/v1/board/tasks/${args.task_id}/stages/reorder`, ws, { order: args.order }));
895
- }
896
- case "submit_handoff": {
897
- const body = {
898
- what_was_done: args.what_was_done,
899
- output: args.output,
900
- };
901
- if (args.next_owner_context)
902
- body.next_owner_context = args.next_owner_context;
903
- if (args.resolution)
904
- body.resolution = args.resolution;
905
- return ok(await callApi("POST", `/api/v1/board/tasks/${args.task_id}/stages/${args.stage_id}/handoff`, ws, body));
906
- }
907
- case "resolve_task": {
908
- const body = {
909
- what_was_done: args.what_was_done,
910
- output: args.output,
911
- };
912
- if (args.next_owner_context)
913
- body.next_owner_context = args.next_owner_context;
914
- if (args.resolution)
915
- body.resolution = args.resolution;
916
- return ok(await callApi("POST", `/api/v1/board/tasks/${args.task_id}/resolve`, ws, body));
917
- }
918
- // ── Task Links ──
919
- case "list_task_links": {
920
- const url = buildUrl(`/api/v1/board/tasks/${args.task_id}/links`, undefined, fmt);
921
- return ok(await callApi("GET", url, ws));
922
- }
923
- case "create_task_link": {
924
- const body = {
925
- target_task_id: args.target_task_id,
926
- };
927
- if (args.link_type)
928
- body.link_type = args.link_type;
929
- return ok(await callApi("POST", `/api/v1/board/tasks/${args.task_id}/links`, ws, body));
930
- }
931
- case "delete_task_link": {
932
- await callApi("DELETE", `/api/v1/board/task-links/${args.link_id}`, ws);
933
- return ok(`Deleted task link ${args.link_id}`);
934
- }
935
1113
  // ── Comments ──
936
1114
  case "add_comment": {
937
1115
  return ok(await callApi("POST", `/api/v1/board/tasks/${args.task_id}/comments`, ws, { content: args.content }));
@@ -1055,6 +1233,215 @@ async function handleTool(name, args) {
1055
1233
  const url = buildUrl("/api/v1/docs/search", params, fmt);
1056
1234
  return ok(await callApi("GET", url, ws));
1057
1235
  }
1236
+ // ── Docs: Project CRUD ──
1237
+ case "create_project": {
1238
+ const body = { name: args.name };
1239
+ if (args.description)
1240
+ body.description = args.description;
1241
+ if (args.visibility)
1242
+ body.visibility = args.visibility;
1243
+ return ok(await callApi("POST", "/api/v1/docs/projects", ws, body));
1244
+ }
1245
+ case "update_project": {
1246
+ const body = {};
1247
+ if (args.name)
1248
+ body.name = args.name;
1249
+ if (args.description)
1250
+ body.description = args.description;
1251
+ if (args.visibility)
1252
+ body.visibility = args.visibility;
1253
+ if (Object.keys(body).length === 0) {
1254
+ return err("Nothing to update. Provide name, description, or visibility.");
1255
+ }
1256
+ return ok(await callApi("PATCH", `/api/v1/docs/projects/${args.project}`, ws, body));
1257
+ }
1258
+ case "delete_project": {
1259
+ await callApi("DELETE", `/api/v1/docs/projects/${args.project}`, ws);
1260
+ return ok(`Deleted project ${args.project}`);
1261
+ }
1262
+ // ── Docs: Page Operations ──
1263
+ case "list_pages": {
1264
+ const params = {};
1265
+ if (args.view)
1266
+ params.view = String(args.view);
1267
+ if (args.limit)
1268
+ params.limit = String(args.limit);
1269
+ const url = buildUrl(`/api/v1/docs/projects/${args.project}/pages`, params, fmt);
1270
+ return ok(await callApi("GET", url, ws));
1271
+ }
1272
+ case "move_page": {
1273
+ const body = {};
1274
+ if (args.path)
1275
+ body.path = args.path;
1276
+ if (args.sort_order !== undefined)
1277
+ body.sort_order = args.sort_order;
1278
+ if (Object.keys(body).length === 0) {
1279
+ return err("Provide path or sort_order.");
1280
+ }
1281
+ return ok(await callApi("PATCH", `/api/v1/docs/projects/${args.project}/pages/${args.slug}/move`, ws, body));
1282
+ }
1283
+ case "delete_page": {
1284
+ await callApi("DELETE", `/api/v1/docs/projects/${args.project}/pages/${args.slug}`, ws);
1285
+ return ok(`Deleted page ${args.slug}`);
1286
+ }
1287
+ // ── Docs: Revision History ──
1288
+ case "page_history": {
1289
+ const params = {};
1290
+ if (args.limit)
1291
+ params.limit = String(args.limit);
1292
+ const url = buildUrl(`/api/v1/docs/pages/${args.page_id}/history`, params, fmt);
1293
+ return ok(await callApi("GET", url, ws));
1294
+ }
1295
+ case "page_diff": {
1296
+ const params = {};
1297
+ if (args.from_rev)
1298
+ params.from = String(args.from_rev);
1299
+ if (args.to_rev)
1300
+ params.to = String(args.to_rev);
1301
+ const url = buildUrl(`/api/v1/docs/pages/${args.page_id}/diff`, params, fmt);
1302
+ return ok(await callApi("GET", url, ws));
1303
+ }
1304
+ case "page_rollback": {
1305
+ const body = {
1306
+ revision_id: args.revision_id,
1307
+ commit_message: String(args.message || "Rollback via MCP"),
1308
+ };
1309
+ return ok(await callApi("POST", `/api/v1/docs/pages/${args.page_id}/rollback`, ws, body));
1310
+ }
1311
+ // ── Docs: Media ──
1312
+ case "list_media": {
1313
+ const params = {};
1314
+ if (args.limit)
1315
+ params.limit = String(args.limit);
1316
+ const url = buildUrl(`/api/v1/docs/projects/${args.project}/media`, params, fmt);
1317
+ return ok(await callApi("GET", url, ws));
1318
+ }
1319
+ // ── Docs: Bulk ──
1320
+ case "bulk_create_pages": {
1321
+ const body = { pages: args.pages };
1322
+ if (args.branch)
1323
+ body.branch = args.branch;
1324
+ return ok(await callApi("POST", `/api/v1/docs/projects/${args.project}/pages/bulk`, ws, body));
1325
+ }
1326
+ // ── Agent Optimization ──
1327
+ case "agent_my_tasks": {
1328
+ const params = {};
1329
+ if (args.board_id)
1330
+ params.board_id = String(args.board_id);
1331
+ if (args.status)
1332
+ params.status = String(args.status);
1333
+ if (args.limit)
1334
+ params.limit = String(args.limit);
1335
+ const url = buildUrl("/api/v1/board/agent-api/my-tasks", params, fmt);
1336
+ return ok(await callApi("GET", url, ws));
1337
+ }
1338
+ case "agent_my_delegations": {
1339
+ const params = {};
1340
+ if (args.status)
1341
+ params.status = String(args.status);
1342
+ if (args.limit)
1343
+ params.limit = String(args.limit);
1344
+ const url = buildUrl("/api/v1/board/agent-api/my-delegations", params, fmt);
1345
+ return ok(await callApi("GET", url, ws));
1346
+ }
1347
+ case "agent_batch_create_tasks": {
1348
+ return ok(await callApi("POST", "/api/v1/board/agent-api/tasks/batch", ws, { tasks: args.tasks }));
1349
+ }
1350
+ case "agent_report_progress": {
1351
+ const body = { percent: args.percent };
1352
+ if (args.message)
1353
+ body.message = args.message;
1354
+ if (args.current_operation)
1355
+ body.current_operation = args.current_operation;
1356
+ return ok(await callApi("POST", `/api/v1/board/agent-api/tasks/${args.task_id}/progress`, ws, body));
1357
+ }
1358
+ case "agent_complete_task": {
1359
+ const body = {};
1360
+ if (args.status)
1361
+ body.status = args.status;
1362
+ if (args.summary)
1363
+ body.summary = args.summary;
1364
+ if (args.result_data)
1365
+ body.result_data = args.result_data;
1366
+ return ok(await callApi("POST", `/api/v1/board/agent-api/tasks/${args.task_id}/complete`, ws, body));
1367
+ }
1368
+ case "agent_delegate_task": {
1369
+ const body = { agent_slug: args.agent_slug };
1370
+ if (args.instructions)
1371
+ body.instructions = args.instructions;
1372
+ return ok(await callApi("POST", `/api/v1/board/agent-api/tasks/${args.task_id}/delegate`, ws, body));
1373
+ }
1374
+ case "search_tasks": {
1375
+ const params = { q: String(args.query) };
1376
+ if (args.board_id)
1377
+ params.board_id = String(args.board_id);
1378
+ if (args.limit)
1379
+ params.limit = String(args.limit);
1380
+ const url = buildUrl("/api/v1/board/cards/search", params, fmt);
1381
+ return ok(await callApi("GET", url, ws));
1382
+ }
1383
+ case "batch_get_tasks": {
1384
+ const ids = args.ids.join(",");
1385
+ const url = buildUrl("/api/v1/board/tasks/batch", { ids }, fmt);
1386
+ return ok(await callApi("GET", url, ws));
1387
+ }
1388
+ // ── Stages ──
1389
+ case "list_stages": {
1390
+ const url = buildUrl(`/api/v1/board/tasks/${args.task_id}/stages`, undefined, fmt);
1391
+ return ok(await callApi("GET", url, ws));
1392
+ }
1393
+ case "create_stage": {
1394
+ const body = { title: args.title };
1395
+ if (args.description)
1396
+ body.description = args.description;
1397
+ if (args.assignee_agent_id)
1398
+ body.assignee_agent_id = args.assignee_agent_id;
1399
+ if (args.agent_instructions)
1400
+ body.agent_instructions = args.agent_instructions;
1401
+ if (args.position !== undefined)
1402
+ body.position = args.position;
1403
+ return ok(await callApi("POST", `/api/v1/board/tasks/${args.task_id}/stages`, ws, body));
1404
+ }
1405
+ case "update_stage": {
1406
+ const body = {};
1407
+ if (args.title)
1408
+ body.title = args.title;
1409
+ if (args.description)
1410
+ body.description = args.description;
1411
+ if (args.assignee_agent_id)
1412
+ body.assignee_agent_id = args.assignee_agent_id;
1413
+ if (args.agent_instructions)
1414
+ body.agent_instructions = args.agent_instructions;
1415
+ if (Object.keys(body).length === 0) {
1416
+ return err("Nothing to update. Provide title, description, assignee_agent_id, or agent_instructions.");
1417
+ }
1418
+ return ok(await callApi("PATCH", `/api/v1/board/tasks/${args.task_id}/stages/${args.stage_id}`, ws, body));
1419
+ }
1420
+ case "complete_stage": {
1421
+ const body = {};
1422
+ if (args.comment)
1423
+ body.comment = args.comment;
1424
+ return ok(await callApi("POST", `/api/v1/board/tasks/${args.task_id}/stages/${args.stage_id}/handoff`, ws, body));
1425
+ }
1426
+ case "reorder_stages": {
1427
+ return ok(await callApi("POST", `/api/v1/board/tasks/${args.task_id}/stages/reorder`, ws, { order: args.order }));
1428
+ }
1429
+ // ── Task Links ──
1430
+ case "list_task_links": {
1431
+ const url = buildUrl(`/api/v1/board/tasks/${args.task_id}/links`, undefined, fmt);
1432
+ return ok(await callApi("GET", url, ws));
1433
+ }
1434
+ case "create_task_link": {
1435
+ const body = {
1436
+ target_task_id: args.target_task_id,
1437
+ link_type: args.link_type || "related",
1438
+ };
1439
+ return ok(await callApi("POST", `/api/v1/board/tasks/${args.task_id}/links`, ws, body));
1440
+ }
1441
+ case "delete_task_link": {
1442
+ await callApi("DELETE", `/api/v1/board/task-links/${args.link_id}`, ws);
1443
+ return ok(`Deleted link ${args.link_id}`);
1444
+ }
1058
1445
  // ── Auth ──
1059
1446
  case "request_access": {
1060
1447
  const baseUrl = args.api_url || DEFAULT_WORKSPACE.api_url;
@@ -1134,13 +1521,20 @@ async function handleTool(name, args) {
1134
1521
  }
1135
1522
  }
1136
1523
  // ── Server Setup ─────────────────────────────────────────────────
1137
- const server = new Server({ name: "opvs", version: "0.5.0" }, { capabilities: { tools: {} } });
1524
+ const server = new Server({ name: "opvs", version: "0.5.2" }, { capabilities: { tools: {} } });
1525
+ // ── opvsHUB Generated Tools ──────────────────────────────────────
1526
+ import { GENERATED_TOOLS, handleGeneratedTool } from "./generated-tools.js";
1138
1527
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
1139
- tools: TOOLS,
1528
+ tools: [...TOOLS, ...GENERATED_TOOLS],
1140
1529
  }));
1141
1530
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
1142
1531
  const { name, arguments: args } = request.params;
1143
1532
  try {
1533
+ // Try generated tools first (opvsHUB skills)
1534
+ const generatedResult = await handleGeneratedTool(name, (args ?? {}), callApi, buildUrl, ok);
1535
+ if (generatedResult !== null)
1536
+ return generatedResult;
1537
+ // Fall back to hand-written tools
1144
1538
  return await handleTool(name, (args ?? {}));
1145
1539
  }
1146
1540
  catch (e) {