@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.
- package/README.md +305 -0
- package/config/development.js +20 -0
- package/config/endpoint-map.js +351 -0
- package/config/index.js +34 -0
- package/config/production.js +18 -0
- package/config/staging.js +18 -0
- package/handlers/access.js +141 -0
- package/handlers/activity.js +112 -0
- package/handlers/agents.js +95 -0
- package/handlers/ai-intelligence.js +55 -0
- package/handlers/attachments.js +30 -0
- package/handlers/catalogs.js +169 -0
- package/handlers/components.js +282 -0
- package/handlers/context-manifest.js +1150 -0
- package/handlers/decisions.js +114 -0
- package/handlers/designs.js +118 -0
- package/handlers/documents.js +227 -0
- package/handlers/entities.js +95 -0
- package/handlers/epics.js +190 -0
- package/handlers/facts.js +62 -0
- package/handlers/feature-flags.js +142 -0
- package/handlers/features.js +137 -0
- package/handlers/folders.js +127 -0
- package/handlers/git-context.js +917 -0
- package/handlers/github.js +72 -0
- package/handlers/graph.js +23 -0
- package/handlers/index.js +205 -0
- package/handlers/links.js +156 -0
- package/handlers/milestones.js +131 -0
- package/handlers/organizations.js +14 -0
- package/handlers/projects.js +122 -0
- package/handlers/recurring-tasks.js +33 -0
- package/handlers/tags.js +124 -0
- package/handlers/tasks.js +561 -0
- package/handlers/testing.js +116 -0
- package/handlers/todos.js +43 -0
- package/handlers/watchers.js +54 -0
- package/handlers/work-templates.js +32 -0
- package/index.js +175 -0
- package/lib/active-session.js +86 -0
- package/lib/auto-assign.js +93 -0
- package/lib/autolink.js +176 -0
- package/lib/changed-files.js +22 -0
- package/lib/env.js +45 -0
- package/lib/git-helpers.js +553 -0
- package/lib/git-utils.js +73 -0
- package/lib/http-client.js +164 -0
- package/lib/links-at-create.js +94 -0
- package/lib/local-cache.js +140 -0
- package/lib/logger.js +109 -0
- package/lib/manifest-loader.js +182 -0
- package/lib/manifest-query.js +686 -0
- package/lib/repo-config-dir.js +118 -0
- package/lib/version.js +10 -0
- package/lib/web-url.js +69 -0
- package/lib/worktree-tools.js +950 -0
- package/package.json +62 -0
- package/prompts/ai-workflow-automation.js +96 -0
- package/prompts/index.js +39 -0
- package/prompts/zephly-usage-guide-content.txt +631 -0
- package/prompts/zephly-usage-guide.js +119 -0
- package/tools/access-entity-types.js +28 -0
- package/tools/access.js +152 -0
- package/tools/activity.js +38 -0
- package/tools/agents.js +208 -0
- package/tools/ai-intelligence.js +111 -0
- package/tools/attachments.js +92 -0
- package/tools/catalogs.js +341 -0
- package/tools/components.js +249 -0
- package/tools/context-manifest.js +236 -0
- package/tools/decisions.js +168 -0
- package/tools/designs.js +222 -0
- package/tools/documents.js +287 -0
- package/tools/entities.js +223 -0
- package/tools/epics.js +267 -0
- package/tools/facts.js +70 -0
- package/tools/feature-flags.js +300 -0
- package/tools/features.js +246 -0
- package/tools/folders.js +122 -0
- package/tools/git-context.js +109 -0
- package/tools/github.js +172 -0
- package/tools/graph.js +70 -0
- package/tools/index.js +77 -0
- package/tools/link-params.js +93 -0
- package/tools/linkable-types.js +36 -0
- package/tools/links.js +199 -0
- package/tools/milestones.js +176 -0
- package/tools/organizations.js +23 -0
- package/tools/projects.js +172 -0
- package/tools/recurring-tasks.js +115 -0
- package/tools/tags.js +219 -0
- package/tools/task-item-schema.js +57 -0
- package/tools/task-type.js +33 -0
- package/tools/tasks.js +680 -0
- package/tools/testing.js +344 -0
- package/tools/todos.js +69 -0
- package/tools/watchers.js +81 -0
- 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'];
|
package/tools/access.js
ADDED
|
@@ -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
|
+
];
|
package/tools/agents.js
ADDED
|
@@ -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
|
+
];
|