@ezmodo/mcp-server 0.13.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.
Files changed (98) hide show
  1. package/README.md +305 -0
  2. package/config/development.js +20 -0
  3. package/config/endpoint-map.js +351 -0
  4. package/config/index.js +34 -0
  5. package/config/production.js +18 -0
  6. package/config/staging.js +18 -0
  7. package/handlers/access.js +141 -0
  8. package/handlers/activity.js +112 -0
  9. package/handlers/agents.js +95 -0
  10. package/handlers/ai-intelligence.js +55 -0
  11. package/handlers/attachments.js +30 -0
  12. package/handlers/catalogs.js +169 -0
  13. package/handlers/components.js +282 -0
  14. package/handlers/context-manifest.js +1150 -0
  15. package/handlers/decisions.js +114 -0
  16. package/handlers/designs.js +118 -0
  17. package/handlers/documents.js +227 -0
  18. package/handlers/entities.js +95 -0
  19. package/handlers/epics.js +190 -0
  20. package/handlers/facts.js +62 -0
  21. package/handlers/feature-flags.js +142 -0
  22. package/handlers/features.js +137 -0
  23. package/handlers/folders.js +127 -0
  24. package/handlers/git-context.js +917 -0
  25. package/handlers/github.js +72 -0
  26. package/handlers/graph.js +23 -0
  27. package/handlers/index.js +205 -0
  28. package/handlers/links.js +156 -0
  29. package/handlers/milestones.js +131 -0
  30. package/handlers/organizations.js +14 -0
  31. package/handlers/projects.js +122 -0
  32. package/handlers/recurring-tasks.js +33 -0
  33. package/handlers/tags.js +124 -0
  34. package/handlers/tasks.js +561 -0
  35. package/handlers/testing.js +116 -0
  36. package/handlers/todos.js +43 -0
  37. package/handlers/watchers.js +54 -0
  38. package/handlers/work-templates.js +32 -0
  39. package/index.js +175 -0
  40. package/lib/active-session.js +86 -0
  41. package/lib/auto-assign.js +93 -0
  42. package/lib/autolink.js +176 -0
  43. package/lib/changed-files.js +22 -0
  44. package/lib/env.js +45 -0
  45. package/lib/git-helpers.js +553 -0
  46. package/lib/git-utils.js +73 -0
  47. package/lib/http-client.js +164 -0
  48. package/lib/links-at-create.js +94 -0
  49. package/lib/local-cache.js +140 -0
  50. package/lib/logger.js +109 -0
  51. package/lib/manifest-loader.js +182 -0
  52. package/lib/manifest-query.js +686 -0
  53. package/lib/repo-config-dir.js +118 -0
  54. package/lib/version.js +10 -0
  55. package/lib/web-url.js +69 -0
  56. package/lib/worktree-tools.js +950 -0
  57. package/package.json +62 -0
  58. package/prompts/ai-workflow-automation.js +96 -0
  59. package/prompts/index.js +39 -0
  60. package/prompts/zephly-usage-guide-content.txt +631 -0
  61. package/prompts/zephly-usage-guide.js +119 -0
  62. package/tools/access-entity-types.js +28 -0
  63. package/tools/access.js +152 -0
  64. package/tools/activity.js +38 -0
  65. package/tools/agents.js +208 -0
  66. package/tools/ai-intelligence.js +111 -0
  67. package/tools/attachments.js +92 -0
  68. package/tools/catalogs.js +341 -0
  69. package/tools/components.js +249 -0
  70. package/tools/context-manifest.js +236 -0
  71. package/tools/decisions.js +168 -0
  72. package/tools/designs.js +222 -0
  73. package/tools/documents.js +287 -0
  74. package/tools/entities.js +223 -0
  75. package/tools/epics.js +267 -0
  76. package/tools/facts.js +70 -0
  77. package/tools/feature-flags.js +300 -0
  78. package/tools/features.js +246 -0
  79. package/tools/folders.js +122 -0
  80. package/tools/git-context.js +109 -0
  81. package/tools/github.js +172 -0
  82. package/tools/graph.js +70 -0
  83. package/tools/index.js +77 -0
  84. package/tools/link-params.js +93 -0
  85. package/tools/linkable-types.js +36 -0
  86. package/tools/links.js +199 -0
  87. package/tools/milestones.js +176 -0
  88. package/tools/organizations.js +23 -0
  89. package/tools/projects.js +172 -0
  90. package/tools/recurring-tasks.js +115 -0
  91. package/tools/tags.js +219 -0
  92. package/tools/task-item-schema.js +57 -0
  93. package/tools/task-type.js +33 -0
  94. package/tools/tasks.js +680 -0
  95. package/tools/testing.js +344 -0
  96. package/tools/todos.js +69 -0
  97. package/tools/watchers.js +81 -0
  98. package/tools/work-templates.js +96 -0
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Zephly Usage Guide Prompt
3
+ * Guidelines for using Zephly MCP tools effectively
4
+ */
5
+
6
+ export const ZEPHLY_USAGE_GUIDE = `# Zephly MCP Integration Guide
7
+
8
+ You have access to Zephly's intelligent project management tools.
9
+ Zephly uses a **project-first** model where projects are the primary
10
+ work containers.
11
+
12
+ ## Session Start - Discover Context
13
+
14
+ At the start of each session, discover the user's context:
15
+
16
+ \`\`\`
17
+ 1. list_organizations() # Get user's workspaces (usually one)
18
+ 2. list_projects({ organizationId }) # Get projects
19
+ \`\`\`
20
+
21
+ This gives you the organizationId and projects needed for all other operations.
22
+
23
+ ## Project-First Hierarchy
24
+
25
+ \`\`\`
26
+ Organization
27
+ └── Projects (primary work containers)
28
+ └── Epics (milestones within projects)
29
+ └── Tasks (individual work items)
30
+ └── Goals (strategic alignment, links to epics)
31
+ \`\`\`
32
+
33
+ **Key points:**
34
+ - Tasks belong to **projects** (projectId is required)
35
+ - Epics are project-scoped milestones
36
+ - Goals provide strategic alignment and can link to epics
37
+
38
+ ## When to Use Zephly Tools
39
+
40
+ **Proactively use these tools when:**
41
+ - User mentions tasks, projects, epics, sprints, or team coordination
42
+ - User asks about project status, health, or blockers
43
+ - User needs help prioritizing work or deciding what to work on next
44
+ - User is planning team assignments or workload distribution
45
+ - User is breaking down features into tasks
46
+ - User asks about timelines or estimates
47
+ - User mentions dependencies, blockers, or handoffs
48
+
49
+ ## Core Tools
50
+
51
+ ### Discovery
52
+ - \`list_organizations\` - List all workspaces
53
+ - \`list_projects\` - List projects for an organization
54
+ - \`search_projects\` - Search/filter projects
55
+
56
+ ### Project Management
57
+ - \`create_project\` - Create new project
58
+ - \`get_project_context\` - Get project details with progress
59
+
60
+ ### Task Operations
61
+ - \`create_task\` - Create task in a project (requires projectId)
62
+ - \`update_task\` - Update task properties and steps
63
+ - \`complete_task\` - Mark task completed
64
+ - \`search_tasks\` - Semantic search or filter tasks
65
+ - \`get_task\` - Get task by ID or number
66
+
67
+ ### Epic Management
68
+ - \`create_epic\` - Create epic in project
69
+ - \`update_epic\` - Update epic
70
+ - \`list_epics\` - List epics for project
71
+ - \`get_epic\` - Get epic details
72
+
73
+ ### Goal Management
74
+ - \`create_goal\` - Create strategic goal
75
+ - \`update_goal\` - Update goal
76
+ - \`list_goals\` - List goals for organization
77
+ - \`link_epic_to_goal\` - Link epic to goal for alignment
78
+
79
+ ### AI Intelligence
80
+ - \`get_project_insights\` - Project health analysis
81
+ - \`suggest_next_actions\` - Task recommendations
82
+ - \`analyze_dependency_graph\` - Critical path analysis
83
+ - \`estimate_task_duration\` - AI time estimates
84
+
85
+ ### Team Coordination
86
+ - \`analyze_team_capacity\` - Resource allocation
87
+ - \`suggest_task_assignments\` - Smart task matching
88
+ - \`bulk_task_operations\` - Batch operations
89
+ - \`identify_handoff_needs\` - Detect blocked tasks
90
+ - \`pull_ai_task_from_queue\` - AI agent task queue
91
+
92
+ ## Example Workflow
93
+
94
+ \`\`\`javascript
95
+ // 1. Discover context
96
+ const orgs = await list_organizations();
97
+ const orgId = orgs.organizations[0].id;
98
+
99
+ const projects = await list_projects({ organizationId: orgId });
100
+ const projectId = projects.projects[0].id;
101
+
102
+ // 2. Create a task
103
+ await create_task({
104
+ projectId,
105
+ title: 'Implement user authentication',
106
+ description: 'Add login/logout functionality',
107
+ priority: 'high'
108
+ });
109
+
110
+ // 3. Search existing tasks
111
+ await search_tasks({ projectId, status: 'in_progress' });
112
+ \`\`\`
113
+
114
+ ## Best Practices
115
+
116
+ 1. **Discover context first** - Call list_organizations + list_projects at session start
117
+ 2. **Project-first** - Always have a projectId before creating tasks
118
+ 3. **Check health proactively** - Use get_project_insights to identify issues
119
+ 4. **Track AI work** - Create tasks for significant work you're doing`;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The entity types that support access control, declared once.
3
+ *
4
+ * This mirrors `access.IsValidEntityType` in the Go API (api/internal/core/
5
+ * access/models.go), which is the authority. The API side exposes the same list
6
+ * via `handlers.SupportedAccessEntityTypes()` and a test
7
+ * (TestSupportedAccessEntityTypes_MatchesService) fails if access.EntityType
8
+ * gains or loses a member without that list being updated.
9
+ *
10
+ * Getting this wrong in either direction is the bug this tool exists downstream
11
+ * of (#2168): advertising a type the service rejects turns a clear schema error
12
+ * into a confusing 400 — or worse, reads as a capability that silently does
13
+ * nothing — while omitting a supported type hides real capability from agents.
14
+ *
15
+ * Adding a type: add it to access.EntityType and IsValidEntityType in Go, to
16
+ * SupportedAccessEntityTypes, then here.
17
+ */
18
+ export const ACCESS_ENTITY_TYPES = [
19
+ 'goal',
20
+ 'project',
21
+ 'epic',
22
+ 'task',
23
+ 'document',
24
+ 'folder',
25
+ ];
26
+
27
+ /** The roles an access entry can grant, most permissive first. */
28
+ export const ACCESS_ROLES = ['owner', 'admin', 'member', 'viewer'];
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Entity Access Tools (#2170)
3
+ *
4
+ * Polymorphic access control — one read tool and one write tool covering every
5
+ * entity type the access service supports, mirroring the generic REST shape at
6
+ * /api/v1/access/{entityType}/{id} and following manage_link's precedent.
7
+ *
8
+ * Deliberately NOT modelled as an `access` field on each manage_* tool: that
9
+ * would duplicate the same object across a dozen schemas and invite exactly the
10
+ * drift that produced #2168, where manage_folder advertised an `access`
11
+ * parameter that no code path implemented.
12
+ *
13
+ * Permissions, twice over. Reading requires viewer access to the entity, so an
14
+ * agent cannot enumerate permissions on something it cannot already see. Every
15
+ * mutation requires admin on the entity AND an API key holding the dedicated
16
+ * `write:access` scope — an ordinary write:tasks key cannot change who can see
17
+ * a task, because granting visibility is a larger privilege than editing.
18
+ */
19
+
20
+ import { ACCESS_ENTITY_TYPES, ACCESS_ROLES } from './access-entity-types.js';
21
+
22
+ const entityTypeProperty = {
23
+ type: 'string',
24
+ enum: ACCESS_ENTITY_TYPES,
25
+ description:
26
+ 'The type of entity whose access is being read or changed. Only these ' +
27
+ 'types support access control; anything else is rejected rather than ' +
28
+ 'accepted and ignored.',
29
+ };
30
+
31
+ const entityIdProperty = {
32
+ type: 'string',
33
+ description: 'ID of the entity (required)',
34
+ };
35
+
36
+ const organizationIdProperty = {
37
+ type: 'string',
38
+ description:
39
+ 'Organization the entity belongs to (required). Also guards against ' +
40
+ 'cross-org lookups: an entity in a different org resolves to no access.',
41
+ };
42
+
43
+ export const ACCESS_TOOLS = [
44
+ {
45
+ name: 'get_access',
46
+ description:
47
+ 'Read who can access an entity. Returns `resolvedAccess` — the effective ' +
48
+ 'entries after inheritance, with the source of each — plus `rawAccess`, the ' +
49
+ 'entity\'s own unresolved settings, which is included only when you hold ' +
50
+ 'admin on the entity. Requires at least viewer access to the entity itself. ' +
51
+ 'Supported entity types: ' + ACCESS_ENTITY_TYPES.join(', ') + '. ' +
52
+ 'To ask whether a specific role is held, use manage_access action:"check".',
53
+ inputSchema: {
54
+ type: 'object',
55
+ properties: {
56
+ entityType: entityTypeProperty,
57
+ entityId: entityIdProperty,
58
+ organizationId: organizationIdProperty,
59
+ },
60
+ required: ['entityType', 'entityId', 'organizationId'],
61
+ },
62
+ },
63
+ {
64
+ name: 'manage_access',
65
+ description:
66
+ 'Change or test an entity\'s access control. Actions: ' +
67
+ '"update_settings" replaces the access configuration wholesale ' +
68
+ '(inheritFromParent / accessList / publicAccess); ' +
69
+ '"add_entry" grants one user or team a role; ' +
70
+ '"remove_entry" revokes a single entry by its id; ' +
71
+ '"check" reports whether you currently hold a given role (a denial is a ' +
72
+ 'normal result, not an error). ' +
73
+ 'The three mutating actions require admin on the entity AND an API key ' +
74
+ 'with the `write:access` scope — a key that can edit an entity cannot ' +
75
+ 'change who may see it unless it was issued that scope explicitly. ' +
76
+ 'Note that some entities cannot carry their own access: projects do not ' +
77
+ 'support publicAccess, nested folders inherit from their root folder, and ' +
78
+ 'documents inside a folder inherit from that folder.',
79
+ inputSchema: {
80
+ type: 'object',
81
+ properties: {
82
+ action: {
83
+ type: 'string',
84
+ enum: ['update_settings', 'add_entry', 'remove_entry', 'check'],
85
+ description: 'Action to perform',
86
+ },
87
+ entityType: entityTypeProperty,
88
+ entityId: entityIdProperty,
89
+ organizationId: organizationIdProperty,
90
+
91
+ // --- update_settings ---
92
+ inheritFromParent: {
93
+ type: 'boolean',
94
+ description:
95
+ 'If true the entity inherits access from its parent and accessList is ' +
96
+ 'ignored; if false it uses its own accessList. (update_settings only)',
97
+ },
98
+ accessList: {
99
+ type: 'array',
100
+ description:
101
+ 'The complete access list, replacing any existing one. Each entry sets ' +
102
+ 'exactly one of userId or teamId, plus a role. (update_settings only)',
103
+ items: {
104
+ type: 'object',
105
+ properties: {
106
+ userId: { type: 'string', description: 'Grant to this user (mutually exclusive with teamId)' },
107
+ teamId: { type: 'string', description: 'Grant to this team (mutually exclusive with userId)' },
108
+ role: { type: 'string', enum: ACCESS_ROLES, description: 'Role granted to this user or team' },
109
+ },
110
+ required: ['role'],
111
+ },
112
+ },
113
+ publicAccess: {
114
+ type: 'boolean',
115
+ description:
116
+ 'Enable public read-only access. Not supported for projects. (update_settings only)',
117
+ },
118
+
119
+ // --- add_entry ---
120
+ userId: {
121
+ type: 'string',
122
+ description: 'User to grant a role to (mutually exclusive with teamId). (add_entry only)',
123
+ },
124
+ teamId: {
125
+ type: 'string',
126
+ description: 'Team to grant a role to (mutually exclusive with userId). (add_entry only)',
127
+ },
128
+ role: {
129
+ type: 'string',
130
+ enum: ACCESS_ROLES,
131
+ description: 'Role to grant. (add_entry only)',
132
+ },
133
+
134
+ // --- remove_entry ---
135
+ entryId: {
136
+ type: 'string',
137
+ description:
138
+ 'ID of the access entry to revoke, as returned in get_access rawAccess ' +
139
+ 'entries. (remove_entry only)',
140
+ },
141
+
142
+ // --- check ---
143
+ requiredRole: {
144
+ type: 'string',
145
+ enum: ACCESS_ROLES,
146
+ description: 'Role to test for; defaults to viewer. (check only)',
147
+ },
148
+ },
149
+ required: ['action', 'entityType', 'entityId', 'organizationId'],
150
+ },
151
+ },
152
+ ];
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Activity Timeline Tools
3
+ * MCP tools for querying project activity/changes
4
+ */
5
+
6
+ export const ACTIVITY_TOOLS = [
7
+ {
8
+ name: 'get_project_changes',
9
+ description: 'Get recent activity and changes for a project. Returns structured events (task created/completed, epic progress, doc updates, etc.) with an aggregate summary. Use this to understand what happened in a project since a given date.',
10
+ inputSchema: {
11
+ type: 'object',
12
+ properties: {
13
+ projectId: {
14
+ type: 'string',
15
+ description: 'The project ID to get changes for (required)',
16
+ },
17
+ since: {
18
+ type: 'string',
19
+ description: 'ISO 8601 date or relative duration. Examples: "2026-04-01T00:00:00Z", "7d" (last 7 days), "2w" (last 2 weeks), "30d" (last 30 days). Default: 7 days ago.',
20
+ },
21
+ entityTypes: {
22
+ type: 'string',
23
+ description: 'Comma-separated entity types to filter by. Options: task, epic, goal, document, project, comment. Example: "task,epic"',
24
+ },
25
+ eventTypes: {
26
+ type: 'string',
27
+ description: 'Comma-separated event types to filter by. Examples: "task_completed,task_created", "epic_status_changed"',
28
+ },
29
+ limit: {
30
+ type: 'number',
31
+ description: 'Maximum number of events to return (default: 20, max: 100)',
32
+ default: 20,
33
+ },
34
+ },
35
+ required: ['projectId'],
36
+ },
37
+ },
38
+ ];
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Background Agents Tools (E-150)
3
+ *
4
+ * Control-plane tools for EzModo's background hygiene agents. The agents
5
+ * themselves (Stale Sentinel, Dependency Mapper, Related Linker, Duplicate
6
+ * Hunter) run on EzModo's infra; these tools let an MCP client (e.g. the
7
+ * user's Claude) review and act on what they produced.
8
+ */
9
+
10
+ export const AGENT_TOOLS = [
11
+ {
12
+ name: 'list_agent_suggestions',
13
+ description:
14
+ 'List pending background-agent suggestions for the current organization. ' +
15
+ 'Returns the newest first — review and either accept_agent_suggestion or ' +
16
+ 'reject_agent_suggestion each one. Action types: \'link\' (create entity_link), ' +
17
+ '\'archive\' (set tasks.archived=true), \'merge\' / \'unblock_check\' / \'enrich\' ' +
18
+ '(no destructive side effect on accept — intent only).',
19
+ inputSchema: {
20
+ type: 'object',
21
+ properties: {
22
+ limit: {
23
+ type: 'integer',
24
+ minimum: 1,
25
+ maximum: 500,
26
+ description: 'Max suggestions to return (default 100).',
27
+ },
28
+ entityType: {
29
+ type: 'string',
30
+ description:
31
+ 'Narrow to one entity, e.g. entityType="task" with entityId. ' +
32
+ 'Use this to ask "what is pending on THIS task?" instead of ' +
33
+ 'scanning the whole organization. Matches EITHER end of the ' +
34
+ 'suggestion — you get it whether your entity is what the proposal ' +
35
+ 'is about or what it points at, so a PR-link suggestion keyed on ' +
36
+ 'the pull request still shows up under its target task.',
37
+ },
38
+ entityId: {
39
+ type: 'string',
40
+ description: 'The entity id. Only meaningful together with entityType.',
41
+ },
42
+ action: {
43
+ type: 'string',
44
+ enum: ['link', 'archive', 'merge', 'unblock_check', 'enrich', 'status_change', 'verify_link', 'regenerate_how_it_works'],
45
+ description:
46
+ 'Narrow to one suggestion verb. action="link" is what a ' +
47
+ 'links-focused review asks for — the queue is shared with every ' +
48
+ 'other agent, so without this you page through their findings too.',
49
+ },
50
+ agentType: {
51
+ type: 'string',
52
+ description: 'Narrow to one producing agent, e.g. "autolink" or "related_linker".',
53
+ },
54
+ minConfidence: {
55
+ type: 'number',
56
+ minimum: 0,
57
+ maximum: 1,
58
+ description:
59
+ 'Drop findings below this confidence. Raise it when the queue is ' +
60
+ 'noisy — past three or four items people stop reading and start ' +
61
+ 'bulk-accepting, which is worse than seeing fewer.',
62
+ },
63
+ },
64
+ },
65
+ },
66
+
67
+ {
68
+ name: 'accept_agent_suggestion',
69
+ description:
70
+ 'Accept a pending suggestion. The framework runs the side effect tied ' +
71
+ 'to the suggestion\'s action (e.g. action=\'link\' inserts the entity_link, ' +
72
+ 'action=\'archive\' archives the task) BEFORE flipping the status to ' +
73
+ 'accepted, so a failed side effect leaves the suggestion pending.',
74
+ inputSchema: {
75
+ type: 'object',
76
+ required: ['id'],
77
+ properties: {
78
+ id: {
79
+ type: 'string',
80
+ description: 'The agent_suggestions.id returned by list_agent_suggestions.',
81
+ },
82
+ reviewNote: {
83
+ type: 'string',
84
+ description: 'Optional free-text note recorded with the acceptance.',
85
+ },
86
+ },
87
+ },
88
+ },
89
+
90
+ {
91
+ name: 'reject_agent_suggestion',
92
+ description:
93
+ 'Reject a pending suggestion. Flips status to rejected and frees the ' +
94
+ 'dedup slot so the agent may re-propose the same idea in a future run ' +
95
+ 'if conditions change. Use a reviewNote to teach future judgement.',
96
+ inputSchema: {
97
+ type: 'object',
98
+ required: ['id'],
99
+ properties: {
100
+ id: { type: 'string' },
101
+ reviewNote: { type: 'string' },
102
+ },
103
+ },
104
+ },
105
+
106
+ {
107
+ name: 'run_agent_now',
108
+ description:
109
+ 'Manually enqueue an agent run, bypassing the scheduler\'s cadence. ' +
110
+ 'Useful for testing or for \'check this entity for duplicates now\' ' +
111
+ 'flows. The agent type must be registered server-side. Quota is ' +
112
+ 'respected — if the org has exhausted its monthly suggestion cap the ' +
113
+ 'run completes with status=\'quota_exhausted\' and zero new suggestions.',
114
+ inputSchema: {
115
+ type: 'object',
116
+ required: ['agentType'],
117
+ properties: {
118
+ agentType: {
119
+ type: 'string',
120
+ enum: ['stale_sentinel', 'dependency_mapper', 'related_linker', 'duplicate_hunter'],
121
+ },
122
+ scope: {
123
+ type: 'object',
124
+ description:
125
+ 'Optional narrowing of the run to a single entity. Omit for a ' +
126
+ 'full org/project sweep.',
127
+ properties: {
128
+ entity_type: { type: 'string', enum: ['task', 'epic', 'goal', 'doc'] },
129
+ entity_id: { type: 'string' },
130
+ },
131
+ required: ['entity_type', 'entity_id'],
132
+ },
133
+ },
134
+ },
135
+ },
136
+
137
+ {
138
+ name: 'configure_agent',
139
+ description:
140
+ 'Enable, disable, or change cadence for an agent in the current org. ' +
141
+ 'First enable on a fresh org schedules the agent\'s first run for NOW() ' +
142
+ 'so initial suggestions arrive within a scheduler tick (~60s).',
143
+ inputSchema: {
144
+ type: 'object',
145
+ required: ['agentType'],
146
+ properties: {
147
+ agentType: {
148
+ type: 'string',
149
+ enum: ['stale_sentinel', 'dependency_mapper', 'related_linker', 'duplicate_hunter'],
150
+ },
151
+ enabled: { type: 'boolean' },
152
+ cadenceSeconds: {
153
+ type: 'integer',
154
+ minimum: 60,
155
+ description:
156
+ 'Run interval in seconds. Omit to use the agent\'s default cadence ' +
157
+ '(typically 24h). Minimum 60s to prevent abuse.',
158
+ },
159
+ },
160
+ },
161
+ },
162
+
163
+ {
164
+ name: 'resolve_link_suggestions',
165
+ description:
166
+ 'Accept and/or reject several pending suggestions in ONE call.\n\n' +
167
+ 'This exists because clearing a queue item-by-item costs a call each, and ' +
168
+ 'anything that expensive gets skipped — leaving suggestions to pile up until ' +
169
+ 'someone bulk-dismisses them unread. Pass the ids you agree with in `accept` ' +
170
+ 'and the ones you do not in `reject`.\n\n' +
171
+ 'Rejecting is a real answer, not a failure: a rejection with a reason is how ' +
172
+ 'the linker learns. Leaving items pending is the only wrong outcome.\n\n' +
173
+ 'WHERE THE IDS COME FROM: the `suggestionId` on each entry of a manage_task / ' +
174
+ 'manage_epic response\'s `linkSuggestions`, or — authoritatively — ' +
175
+ 'list_agent_suggestions with action:"link" plus entityType/entityId. Prefer ' +
176
+ 'list_agent_suggestions when a response says its list may be partial: the ' +
177
+ 'engine\'s semantic rules finish a beat after the deterministic ones, so an ' +
178
+ 'inline list can legitimately show fewer than are actually queued.\n\n' +
179
+ 'Partial failure is reported per id rather than aborting — one bad id must not ' +
180
+ 'cost the rest of the batch.',
181
+ inputSchema: {
182
+ type: 'object',
183
+ properties: {
184
+ accept: {
185
+ type: 'array',
186
+ items: { type: 'string' },
187
+ description: 'Suggestion ids to accept (the side effect runs for each).',
188
+ },
189
+ reject: {
190
+ type: 'array',
191
+ items: {
192
+ type: 'object',
193
+ properties: {
194
+ id: { type: 'string' },
195
+ reason: { type: 'string', description: 'Why — recorded to teach future judgement.' },
196
+ },
197
+ required: ['id'],
198
+ },
199
+ description: 'Suggestions to reject, each with an optional reason.',
200
+ },
201
+ reviewNote: {
202
+ type: 'string',
203
+ description: 'Note applied to every acceptance in this batch.',
204
+ },
205
+ },
206
+ },
207
+ },
208
+ ];
@@ -0,0 +1,111 @@
1
+ /**
2
+ * AI Intelligence Tools
3
+ * MCP tools for project insights and intelligent analysis
4
+ *
5
+ * Consolidated: get_ai_insights (project_insights/suggest_next/dependency_graph)
6
+ */
7
+
8
+ export const AI_INTELLIGENCE_TOOLS = [
9
+ {
10
+ name: 'get_ai_insights',
11
+ description: 'Get AI-powered project analysis. ' +
12
+ 'Types: "project_insights" for health analysis (blockers, velocity, workload), ' +
13
+ '"suggest_next" for personalized task recommendations, ' +
14
+ '"dependency_graph" for critical path and bottleneck analysis, ' +
15
+ '"build_failure" for why CI is red (failing checks with their output, plus which checks are ' +
16
+ 'consistently broken vs merely flaky), ' +
17
+ '"deployment_risk" for how risky a deploy is (CI state on the commit + the environment\'s ' +
18
+ 'recent history, returned with the signals behind the score). ' +
19
+ 'build_failure and deployment_risk are DETERMINISTIC — computed from captured CI/CD data, ' +
20
+ 'no model call and no AI quota. They return evidence for you to reason over, not a verdict.',
21
+ inputSchema: {
22
+ type: 'object',
23
+ properties: {
24
+ type: {
25
+ type: 'string',
26
+ enum: ['project_insights', 'suggest_next', 'dependency_graph', 'build_failure', 'deployment_risk'],
27
+ description: 'Type of AI insight to retrieve',
28
+ },
29
+ projectId: {
30
+ type: 'string',
31
+ description: 'Project ID (required for all types)',
32
+ },
33
+ // --- suggest_next fields ---
34
+ userId: {
35
+ type: 'string',
36
+ description: 'User ID — defaults to API key owner (suggest_next only)',
37
+ },
38
+ limit: {
39
+ type: 'number',
40
+ description: 'Maximum number of recommendations (suggest_next only, default: 10). ' +
41
+ 'For build_failure and deployment_risk this is the ANALYSIS WINDOW — how many recent ' +
42
+ 'runs/deployments to read (default: 50). Results report the window they used.',
43
+ },
44
+ // --- build_failure fields ---
45
+ headSha: {
46
+ type: 'string',
47
+ description: 'Narrow the analysis to one commit (build_failure only)',
48
+ },
49
+ taskId: {
50
+ type: 'string',
51
+ description: 'Narrow to the CI that ran on a task\'s linked commits (build_failure only)',
52
+ },
53
+ kind: {
54
+ type: 'string',
55
+ enum: ['check_run', 'workflow_run'],
56
+ description: 'Analyse individual CI jobs ("check_run") or whole runs ("workflow_run"). ' +
57
+ 'Omit for both. Use workflow_run for "did CI pass"; check_run to see which job broke. ' +
58
+ '(build_failure only)',
59
+ },
60
+ // --- deployment_risk fields ---
61
+ environment: {
62
+ type: 'string',
63
+ description: 'Environment being deployed to, e.g. "production" (REQUIRED for ' +
64
+ 'deployment_risk — it is not defaulted, since assuming production would answer a ' +
65
+ 'different question than the one asked)',
66
+ },
67
+ sha: {
68
+ type: 'string',
69
+ description: 'Commit being deployed (deployment_risk). Without it the assessment cannot ' +
70
+ 'check CI and reports that as an unverified-change risk rather than borrowing another ' +
71
+ 'commit\'s result.',
72
+ },
73
+ },
74
+ required: ['type', 'projectId'],
75
+ },
76
+ },
77
+ {
78
+ name: 'estimate_task',
79
+ description: 'Get a Bayesian AI estimate for how long a task will take, based on similar completed tasks. ' +
80
+ 'Returns median and P80 (80% confidence) hour estimates, confidence level, and the similar tasks used as reference. ' +
81
+ 'Automatically adjusts for the assignee\'s historical accuracy if calibration data exists.',
82
+ inputSchema: {
83
+ type: 'object',
84
+ properties: {
85
+ taskId: {
86
+ type: 'string',
87
+ description: 'Task ID to estimate (required)',
88
+ },
89
+ },
90
+ required: ['taskId'],
91
+ },
92
+ },
93
+ {
94
+ name: 'infer_dependencies',
95
+ description: 'Infer task-to-task dependencies from file-level import graphs. ' +
96
+ 'Uses the project\'s context manifest (file dependencies) and task-to-file links (linkedFiles) ' +
97
+ 'to deterministically suggest which tasks depend on which. No AI required. ' +
98
+ 'Returns suggestions only — does not auto-create dependencies. ' +
99
+ 'Requires tasks to have linkedFiles populated (via addLinkedFile or git commit linking).',
100
+ inputSchema: {
101
+ type: 'object',
102
+ properties: {
103
+ projectId: {
104
+ type: 'string',
105
+ description: 'Project ID (required)',
106
+ },
107
+ },
108
+ required: ['projectId'],
109
+ },
110
+ },
111
+ ];