@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,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component Tools
|
|
3
|
+
* MCP tools for the unified UI inventory (E-168).
|
|
4
|
+
*
|
|
5
|
+
* NAMING (E-107): a project's type renames the `area` kind only — a marketing
|
|
6
|
+
* project calls an area a "Channel", a sales project a "Segment". The screen,
|
|
7
|
+
* page and component kinds keep their literal names, because "Channel: screen"
|
|
8
|
+
* is nonsense. Read the word from `get_current_project_context().terminology`.
|
|
9
|
+
*
|
|
10
|
+
* A Component is ONE concept that spans four kinds:
|
|
11
|
+
* - area — coarse codebase module / domain (api, web, mcp-server); the
|
|
12
|
+
* legacy meaning. The task component-picker uses kind=area.
|
|
13
|
+
* - screen — a mobile / Flutter screen
|
|
14
|
+
* - page — a web route / page
|
|
15
|
+
* - component — a reusable UI component
|
|
16
|
+
* There is NO separate "UI surface" entity — surfaces ARE components. Components
|
|
17
|
+
* self-nest via parentComponentId (e.g. web → Sprint Board → TaskCard) and carry
|
|
18
|
+
* sourcePath / route / framework. They can be discovered from the Context
|
|
19
|
+
* Manifest and bulk-imported.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { LINKS_ARRAY_SCHEMA } from './link-params.js';
|
|
23
|
+
|
|
24
|
+
export const COMPONENT_TOOLS = [
|
|
25
|
+
{
|
|
26
|
+
name: 'manage_component',
|
|
27
|
+
description: 'Create, update, delete components, manage component dependencies and screen ' +
|
|
28
|
+
'navigation edges, or discover/import ' +
|
|
29
|
+
'UI surfaces. A Component is the unified UI inventory entry — ONE concept spanning kinds ' +
|
|
30
|
+
'area|screen|page|component (there is no separate "UI surface" entity). "area" is the legacy ' +
|
|
31
|
+
'coarse codebase module (api, web, mobile) and is what the task component-picker uses; ' +
|
|
32
|
+
'"screen"/"page"/"component" describe mobile screens, web pages, and reusable UI components. ' +
|
|
33
|
+
'Components self-nest via parentComponentId and carry sourcePath/route/framework. ' +
|
|
34
|
+
'"discover" proposes page/component surfaces from the Context Manifest not yet in the inventory; ' +
|
|
35
|
+
'"import" bulk-creates surfaces (optionally nested under a parent and/or linked to a feature).',
|
|
36
|
+
inputSchema: {
|
|
37
|
+
type: 'object',
|
|
38
|
+
properties: {
|
|
39
|
+
action: {
|
|
40
|
+
type: 'string',
|
|
41
|
+
enum: ['create', 'update', 'delete', 'add_dependency', 'remove_dependency',
|
|
42
|
+
'add_navigation', 'remove_navigation', 'derive_navigation', 'discover', 'import'],
|
|
43
|
+
description: 'Action to perform. "discover" (pass projectId) returns candidate UI surfaces ' +
|
|
44
|
+
'from the Context Manifest not yet in the inventory. "import" (pass projectId + surfaces, ' +
|
|
45
|
+
'optionally parentComponentId + featureId) bulk-creates components from surfaces. ' +
|
|
46
|
+
'"add_navigation"/"remove_navigation" (pass projectId + sourceComponentId + ' +
|
|
47
|
+
'targetComponentId) manage screen\u2192screen navigation edges for the screen-flow map ' +
|
|
48
|
+
'(E-223) \u2014 a DIFFERENT relation from add_dependency: navigation is "you can get ' +
|
|
49
|
+
'there from here" and only valid between screens/pages, whereas a dependency is a code ' +
|
|
50
|
+
'relationship. Read the current flow with list_components include:["navigation"]. ' +
|
|
51
|
+
'"derive_navigation" (pass projectId) RE-DERIVES the whole flow map from the synced ' +
|
|
52
|
+
'Context Manifest \u2014 prefer it to drawing edges by hand, because a derived map stays ' +
|
|
53
|
+
'true for free while an asserted one decays from the moment it is written (E-239). It is ' +
|
|
54
|
+
'idempotent and cannot delete a human\u2019s edge: it reconciles only edges still at ' +
|
|
55
|
+
'origin auto/inferred under its own rules, reporting the rest as `spared`. Check the ' +
|
|
56
|
+
'`unresolved` list in the response \u2014 references no component matched mean the ' +
|
|
57
|
+
'inventory is missing a screen, not that the code has no navigation.',
|
|
58
|
+
},
|
|
59
|
+
// --- Identifiers ---
|
|
60
|
+
projectId: {
|
|
61
|
+
type: 'string',
|
|
62
|
+
description: 'Project ID (required for create, delete, add_dependency, remove_dependency)',
|
|
63
|
+
},
|
|
64
|
+
componentId: {
|
|
65
|
+
type: 'string',
|
|
66
|
+
description: 'Component ID (required for update, delete, add_dependency, remove_dependency)',
|
|
67
|
+
},
|
|
68
|
+
componentSlug: {
|
|
69
|
+
type: 'string',
|
|
70
|
+
description: 'URL-friendly slug of the component (alternative to componentId for update, delete, add_dependency, remove_dependency)',
|
|
71
|
+
},
|
|
72
|
+
// --- Create / Update fields ---
|
|
73
|
+
name: {
|
|
74
|
+
type: 'string',
|
|
75
|
+
description: 'Component name (required for create, e.g., "api", "web", "mcp-server", "functions")',
|
|
76
|
+
},
|
|
77
|
+
description: {
|
|
78
|
+
type: 'string',
|
|
79
|
+
description: 'Description of what this component covers (create, update). ' +
|
|
80
|
+
'Writing this stays plain text; it does not create a backing document.',
|
|
81
|
+
},
|
|
82
|
+
color: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
description: 'Hex color for UI display (e.g., "#3B82F6"). Defaults to blue if not provided. (create, update)',
|
|
85
|
+
},
|
|
86
|
+
icon: {
|
|
87
|
+
type: 'string',
|
|
88
|
+
description: 'Icon name for the component (create, update)',
|
|
89
|
+
},
|
|
90
|
+
// --- Unified UI-inventory fields (E-168) (create, update) ---
|
|
91
|
+
kind: {
|
|
92
|
+
type: 'string',
|
|
93
|
+
enum: ['area', 'screen', 'page', 'component'],
|
|
94
|
+
description: 'Kind of inventory entry (default "area"). "area" = coarse codebase module ' +
|
|
95
|
+
'(api/web/mobile — the legacy meaning, used by the task component-picker); "screen" = ' +
|
|
96
|
+
'mobile/Flutter screen; "page" = web route/page; "component" = reusable UI component. ' +
|
|
97
|
+
'(create, update)',
|
|
98
|
+
},
|
|
99
|
+
parentComponentId: {
|
|
100
|
+
type: 'string',
|
|
101
|
+
description: 'Parent component ID for self-nesting (e.g. web → Sprint Board → TaskCard). ' +
|
|
102
|
+
'On update, pass an empty string to clear it (make top-level). (create, update)',
|
|
103
|
+
},
|
|
104
|
+
sourcePath: {
|
|
105
|
+
type: 'string',
|
|
106
|
+
description: 'Repo file/dir path this surface maps to (create, update)',
|
|
107
|
+
},
|
|
108
|
+
route: {
|
|
109
|
+
type: 'string',
|
|
110
|
+
description: 'Route this surface serves, for page/screen kinds (create, update)',
|
|
111
|
+
},
|
|
112
|
+
framework: {
|
|
113
|
+
type: 'string',
|
|
114
|
+
description: 'Framework, e.g. "nextjs", "flutter", "react" (create, update)',
|
|
115
|
+
},
|
|
116
|
+
// --- import fields ---
|
|
117
|
+
featureId: {
|
|
118
|
+
type: 'string',
|
|
119
|
+
description: 'Optionally link every imported component to this feature (import only)',
|
|
120
|
+
},
|
|
121
|
+
surfaces: {
|
|
122
|
+
type: 'array',
|
|
123
|
+
description: 'UI surfaces to import as components (required for import)',
|
|
124
|
+
items: {
|
|
125
|
+
type: 'object',
|
|
126
|
+
properties: {
|
|
127
|
+
kind: {
|
|
128
|
+
type: 'string',
|
|
129
|
+
enum: ['area', 'screen', 'page', 'component'],
|
|
130
|
+
description: 'Kind of surface',
|
|
131
|
+
},
|
|
132
|
+
name: { type: 'string', description: 'Surface / component name' },
|
|
133
|
+
sourcePath: { type: 'string', description: 'Repo file/dir path it maps to' },
|
|
134
|
+
route: { type: 'string', description: 'Route it serves (page/screen kinds)' },
|
|
135
|
+
framework: { type: 'string', description: 'Framework (nextjs, flutter, react, ...)' },
|
|
136
|
+
links: LINKS_ARRAY_SCHEMA,
|
|
137
|
+
},
|
|
138
|
+
required: ['kind', 'name'],
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
links: LINKS_ARRAY_SCHEMA,
|
|
142
|
+
// --- Create-only fields ---
|
|
143
|
+
ownerId: {
|
|
144
|
+
type: 'string',
|
|
145
|
+
description: 'Owner user ID — who maintains this component (create only)',
|
|
146
|
+
},
|
|
147
|
+
ownerName: {
|
|
148
|
+
type: 'string',
|
|
149
|
+
description: 'Display name of the owner (required if ownerId is set, create only)',
|
|
150
|
+
},
|
|
151
|
+
teamId: {
|
|
152
|
+
type: 'string',
|
|
153
|
+
description: 'Team ID — which team is responsible (create, update)',
|
|
154
|
+
},
|
|
155
|
+
// --- Update-only fields ---
|
|
156
|
+
order: {
|
|
157
|
+
type: 'number',
|
|
158
|
+
description: 'Display order, lower = first (update only)',
|
|
159
|
+
},
|
|
160
|
+
owner: {
|
|
161
|
+
type: 'object',
|
|
162
|
+
description: 'Component owner object (set to null to clear). Object with id and name fields. (update only)',
|
|
163
|
+
properties: {
|
|
164
|
+
id: { type: 'string', description: 'Owner user ID' },
|
|
165
|
+
name: { type: 'string', description: 'Owner display name' },
|
|
166
|
+
},
|
|
167
|
+
nullable: true,
|
|
168
|
+
},
|
|
169
|
+
// --- Dependency fields (add_dependency, remove_dependency) ---
|
|
170
|
+
targetComponentId: {
|
|
171
|
+
type: 'string',
|
|
172
|
+
description: 'The other end of the edge. For add_dependency/remove_dependency: the ' +
|
|
173
|
+
'component depended on. For add_navigation/remove_navigation: the screen navigated TO ' +
|
|
174
|
+
'(must be kind screen or page).',
|
|
175
|
+
},
|
|
176
|
+
type: {
|
|
177
|
+
type: 'string',
|
|
178
|
+
enum: ['depends_on', 'blocks'],
|
|
179
|
+
description: 'Dependency type: "depends_on" (source needs target) or "blocks" ' +
|
|
180
|
+
'(source blocks target). Required for add_dependency. Cycles are ALLOWED \u2014 code ' +
|
|
181
|
+
'imports are legitimately mutual \u2014 but a dependency that closes one comes back with ' +
|
|
182
|
+
'a `warning` and the `cyclePath` naming the loop. Re-adding an existing dependency is ' +
|
|
183
|
+
'an idempotent no-op that returns `alreadyExisted: true`.',
|
|
184
|
+
},
|
|
185
|
+
// --- Navigation fields (add_navigation, remove_navigation) — E-223 ---
|
|
186
|
+
sourceComponentId: {
|
|
187
|
+
type: 'string',
|
|
188
|
+
description: 'Screen the user navigates FROM (required for add_navigation/remove_navigation, ' +
|
|
189
|
+
'unless sourceComponentSlug is given). Must be kind screen or page.',
|
|
190
|
+
},
|
|
191
|
+
sourceComponentSlug: {
|
|
192
|
+
type: 'string',
|
|
193
|
+
description: 'Slug alternative to sourceComponentId (add_navigation, remove_navigation)',
|
|
194
|
+
},
|
|
195
|
+
targetComponentSlug: {
|
|
196
|
+
type: 'string',
|
|
197
|
+
description: 'Slug alternative to targetComponentId (add_navigation, remove_navigation)',
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
required: ['action'],
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
name: 'list_components',
|
|
205
|
+
description: 'List components in a project, optionally with stats, dependency graph, or navigation data. ' +
|
|
206
|
+
'Provide componentId (or componentSlug) to get data for a single component — the response is the ' +
|
|
207
|
+
'same shape as a list, with `components` holding just that one; an identifier that matches nothing ' +
|
|
208
|
+
'is an error, never the full inventory. ' +
|
|
209
|
+
'Responses include `descriptionDocumentId` — the id of the backing rich-description Document ' +
|
|
210
|
+
'when the description has been promoted to one (E-189), otherwise omitted.',
|
|
211
|
+
inputSchema: {
|
|
212
|
+
type: 'object',
|
|
213
|
+
properties: {
|
|
214
|
+
projectId: {
|
|
215
|
+
type: 'string',
|
|
216
|
+
description: 'The project ID (required)',
|
|
217
|
+
},
|
|
218
|
+
componentId: {
|
|
219
|
+
type: 'string',
|
|
220
|
+
description: 'Optional component ID — narrows the listing to that one component',
|
|
221
|
+
},
|
|
222
|
+
componentSlug: {
|
|
223
|
+
type: 'string',
|
|
224
|
+
description: 'Optional component slug (alternative to componentId; the slug wins if both are given)',
|
|
225
|
+
},
|
|
226
|
+
kind: {
|
|
227
|
+
type: 'string',
|
|
228
|
+
enum: ['area', 'screen', 'page', 'component'],
|
|
229
|
+
description: 'Optional filter — only return components of this kind. Use kind="area" for ' +
|
|
230
|
+
'the coarse codebase modules the task component-picker uses.',
|
|
231
|
+
},
|
|
232
|
+
include: {
|
|
233
|
+
type: 'array',
|
|
234
|
+
items: {
|
|
235
|
+
type: 'string',
|
|
236
|
+
enum: ['stats', 'dependency_graph', 'navigation'],
|
|
237
|
+
},
|
|
238
|
+
description: 'Optional additional data to include: stats (task counts), dependency_graph ' +
|
|
239
|
+
'(all dependencies; honours the kind filter), ' +
|
|
240
|
+
'navigation (screen\u2192screen navigates_to edges for the screen-flow map, E-223). ' +
|
|
241
|
+
'Note: "timeline" is NOT available \u2014 component timeline data is not computed by the ' +
|
|
242
|
+
'API (nothing populates it, so it read back as all zeros on every path). Use ' +
|
|
243
|
+
'"stats" for task counts.',
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
required: ['projectId'],
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
];
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Manifest Tools
|
|
3
|
+
* MCP tools for querying the project's context manifest — a structured index
|
|
4
|
+
* of all files, their roles, dependencies, and AI-useful summaries.
|
|
5
|
+
*
|
|
6
|
+
* `get_context` is the unified query tool replacing search_project_context,
|
|
7
|
+
* get_related_files, get_project_overview, get_critical_files,
|
|
8
|
+
* query_project_graph, analyze_impact, get_graph_stats, and
|
|
9
|
+
* analyze_project_organization.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
export const CONTEXT_MANIFEST_TOOLS = [
|
|
13
|
+
{
|
|
14
|
+
name: 'get_context',
|
|
15
|
+
description:
|
|
16
|
+
'Get contextual information about any entity (project, task, epic, component, file, tag). ' +
|
|
17
|
+
'Replaces search_project_context, get_related_files, get_project_overview, get_critical_files, ' +
|
|
18
|
+
'query_project_graph, analyze_impact, get_graph_stats, analyze_project_organization. ' +
|
|
19
|
+
'Use `query` for keyword search, or `entityType` + `entityId` for entity-specific context. ' +
|
|
20
|
+
'Control what\'s returned via `include` array.',
|
|
21
|
+
inputSchema: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
properties: {
|
|
24
|
+
projectId: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
description: 'Project ID (required)',
|
|
27
|
+
},
|
|
28
|
+
entityType: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
enum: ['project', 'task', 'epic', 'component', 'file', 'tag'],
|
|
31
|
+
description: 'Type of entity to get context for',
|
|
32
|
+
},
|
|
33
|
+
entityId: {
|
|
34
|
+
type: 'string',
|
|
35
|
+
description:
|
|
36
|
+
'Entity ID or file path (required when entityType is not project)',
|
|
37
|
+
},
|
|
38
|
+
query: {
|
|
39
|
+
type: 'string',
|
|
40
|
+
description:
|
|
41
|
+
'Search query for keyword-based context search (alternative to entityType+entityId)',
|
|
42
|
+
},
|
|
43
|
+
include: {
|
|
44
|
+
type: 'array',
|
|
45
|
+
items: {
|
|
46
|
+
type: 'string',
|
|
47
|
+
enum: [
|
|
48
|
+
'graph',
|
|
49
|
+
'files',
|
|
50
|
+
'dependencies',
|
|
51
|
+
'impact',
|
|
52
|
+
'overview',
|
|
53
|
+
'critical_files',
|
|
54
|
+
'graph_stats',
|
|
55
|
+
'organization',
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
description:
|
|
59
|
+
'What to include in response. Defaults to all relevant sections for the entityType.',
|
|
60
|
+
},
|
|
61
|
+
queryType: {
|
|
62
|
+
type: 'string',
|
|
63
|
+
enum: ['context', 'impact', 'feature', 'task_context', 'connection'],
|
|
64
|
+
description: 'Graph query type (when include contains "graph")',
|
|
65
|
+
},
|
|
66
|
+
depth: {
|
|
67
|
+
type: 'number',
|
|
68
|
+
description: 'Graph traversal depth (default: 2)',
|
|
69
|
+
},
|
|
70
|
+
format: {
|
|
71
|
+
type: 'string',
|
|
72
|
+
enum: ['compact', 'detailed', 'structured'],
|
|
73
|
+
description: 'Output format for file context',
|
|
74
|
+
},
|
|
75
|
+
limit: {
|
|
76
|
+
type: 'number',
|
|
77
|
+
description: 'Max results for search queries',
|
|
78
|
+
},
|
|
79
|
+
tags: {
|
|
80
|
+
type: 'array',
|
|
81
|
+
items: { type: 'string' },
|
|
82
|
+
description: 'Filter by tags (for context search)',
|
|
83
|
+
},
|
|
84
|
+
direction: {
|
|
85
|
+
type: 'string',
|
|
86
|
+
enum: ['forward', 'reverse', 'both'],
|
|
87
|
+
description: 'Dependency traversal direction (for file context)',
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
required: ['projectId'],
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
name: 'rebuild_manifest',
|
|
95
|
+
description:
|
|
96
|
+
'Trigger regeneration of the project context manifest. ' +
|
|
97
|
+
'"incremental" re-analyzes only files changed since last generation (fast). ' +
|
|
98
|
+
'"full" regenerates everything with static analysis.',
|
|
99
|
+
inputSchema: {
|
|
100
|
+
type: 'object',
|
|
101
|
+
properties: {
|
|
102
|
+
mode: {
|
|
103
|
+
type: 'string',
|
|
104
|
+
enum: ['incremental', 'full'],
|
|
105
|
+
description:
|
|
106
|
+
'Regeneration mode. "incremental" = git diff-based (fast). ' +
|
|
107
|
+
'"full" = re-analyze all files (slower). Default: "incremental"',
|
|
108
|
+
default: 'incremental',
|
|
109
|
+
},
|
|
110
|
+
target_paths: {
|
|
111
|
+
type: 'array',
|
|
112
|
+
items: { type: 'string' },
|
|
113
|
+
description: 'Limit regeneration to specific paths or directories (optional)',
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
name: 'update_manifest_entries',
|
|
120
|
+
description:
|
|
121
|
+
'Write AI-enriched summaries back to the context manifest. ' +
|
|
122
|
+
'After reading critical files and generating better summaries, ' +
|
|
123
|
+
'use this tool to persist them. Marks entries as LLM-enriched ' +
|
|
124
|
+
'and saves to disk.',
|
|
125
|
+
inputSchema: {
|
|
126
|
+
type: 'object',
|
|
127
|
+
properties: {
|
|
128
|
+
project_id: {
|
|
129
|
+
type: 'string',
|
|
130
|
+
description:
|
|
131
|
+
'Project ID for remote manifest access. Required when no local manifest is available.',
|
|
132
|
+
},
|
|
133
|
+
updates: {
|
|
134
|
+
type: 'array',
|
|
135
|
+
description: 'Array of entries to update with enriched summaries',
|
|
136
|
+
items: {
|
|
137
|
+
type: 'object',
|
|
138
|
+
properties: {
|
|
139
|
+
path: {
|
|
140
|
+
type: 'string',
|
|
141
|
+
description: 'File path relative to project root',
|
|
142
|
+
},
|
|
143
|
+
summary: {
|
|
144
|
+
type: 'string',
|
|
145
|
+
description:
|
|
146
|
+
'New AI-enriched summary. Should capture intent, ' +
|
|
147
|
+
'key behaviors, integrations, and gotchas. ' +
|
|
148
|
+
'Keep under 200 words.',
|
|
149
|
+
},
|
|
150
|
+
criticality_score: {
|
|
151
|
+
type: 'number',
|
|
152
|
+
description: 'Criticality score 0-1 (optional)',
|
|
153
|
+
},
|
|
154
|
+
criticality_signals: {
|
|
155
|
+
type: 'array',
|
|
156
|
+
items: { type: 'string' },
|
|
157
|
+
description: 'Criticality signals (optional)',
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
required: ['path', 'summary'],
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
required: ['updates'],
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: 'get_manifest_schema',
|
|
169
|
+
description:
|
|
170
|
+
'Get the full context manifest JSON schema with documentation and examples. ' +
|
|
171
|
+
'Use this when you need to generate a manifest for a language or project that ' +
|
|
172
|
+
'the built-in generator doesn\'t support. The schema includes field descriptions, ' +
|
|
173
|
+
'valid enum values, example entries, and a reusable prompt template for AI agents. ' +
|
|
174
|
+
'Supported natively: TypeScript/JavaScript, Go, Python, Rust, Java, Kotlin, Dart, ' +
|
|
175
|
+
'C#, Swift, PHP, Ruby, C/C++. For any other language, use this schema to generate ' +
|
|
176
|
+
'a valid manifest yourself.',
|
|
177
|
+
inputSchema: {
|
|
178
|
+
type: 'object',
|
|
179
|
+
properties: {
|
|
180
|
+
includeExamples: {
|
|
181
|
+
type: 'boolean',
|
|
182
|
+
description: 'Include annotated example entries for common patterns (default: true)',
|
|
183
|
+
default: true,
|
|
184
|
+
},
|
|
185
|
+
language: {
|
|
186
|
+
type: 'string',
|
|
187
|
+
description:
|
|
188
|
+
'If provided, tailor examples to this language (e.g., "scala", "elixir", "haskell"). ' +
|
|
189
|
+
'The schema itself is language-agnostic — this only affects examples.',
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
name: 'resolve_concepts',
|
|
196
|
+
description:
|
|
197
|
+
'Resolve user-facing product terms to code locations. Use this when a user ' +
|
|
198
|
+
'refers to a feature by its product name (e.g., "dashboard", "board", "settings") ' +
|
|
199
|
+
'and you need to find the corresponding code files. Returns matching concept aliases ' +
|
|
200
|
+
'from the manifest, plus get_context results for broader matching.',
|
|
201
|
+
inputSchema: {
|
|
202
|
+
type: 'object',
|
|
203
|
+
properties: {
|
|
204
|
+
projectId: {
|
|
205
|
+
type: 'string',
|
|
206
|
+
description: 'Project ID (required)',
|
|
207
|
+
},
|
|
208
|
+
terms: {
|
|
209
|
+
type: 'array',
|
|
210
|
+
items: { type: 'string' },
|
|
211
|
+
description:
|
|
212
|
+
'User-facing terms to resolve (e.g., ["dashboard", "tour", "sprint board"])',
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
required: ['projectId', 'terms'],
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
name: 'validate_manifest',
|
|
220
|
+
description:
|
|
221
|
+
'Validate a manifest JSON against the schema. Returns errors and warnings. ' +
|
|
222
|
+
'Use this after generating a manifest to check it before uploading. ' +
|
|
223
|
+
'Checks: required fields, valid enum values, dependency paths exist in manifest, ' +
|
|
224
|
+
'entry count matches metadata, and common issues.',
|
|
225
|
+
inputSchema: {
|
|
226
|
+
type: 'object',
|
|
227
|
+
properties: {
|
|
228
|
+
manifest: {
|
|
229
|
+
type: 'object',
|
|
230
|
+
description: 'The full ContextManifest JSON object to validate',
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
required: ['manifest'],
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
];
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decision Tools
|
|
3
|
+
* MCP tools for Decisions / ADRs (E-170).
|
|
4
|
+
*
|
|
5
|
+
* A Decision is a durable, org-level ADR-style record of a choice and its
|
|
6
|
+
* rationale (title, context, options, decision, consequences, status). Decisions
|
|
7
|
+
* live on the capability/knowledge axis: they LINK to features, epics, tasks,
|
|
8
|
+
* milestones, and other artifacts via the generic link graph — they do not own
|
|
9
|
+
* them.
|
|
10
|
+
*
|
|
11
|
+
* Decisions capture "why we built it this way" so the rationale survives the work
|
|
12
|
+
* that produced it. A task's decision-type knowledge item can be elevated into a
|
|
13
|
+
* durable Decision via promote_from_knowledge.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { LINKABLE_TYPES } from './linkable-types.js';
|
|
17
|
+
import { LINKS_ARRAY_SCHEMA } from './link-params.js';
|
|
18
|
+
|
|
19
|
+
export const DECISION_TOOLS = [
|
|
20
|
+
{
|
|
21
|
+
name: 'manage_decision',
|
|
22
|
+
description: 'Create, update, or delete a Decision (a durable ADR-style record: title, context, ' +
|
|
23
|
+
'options, decision, consequences, status), link/unlink it to existing artifacts, mark it ' +
|
|
24
|
+
'superseded by another decision, or promote a task\'s decision-type knowledge item into a ' +
|
|
25
|
+
'durable Decision. Decisions are org-level and LINK to features/epics/tasks/milestones/etc., ' +
|
|
26
|
+
'they do not contain them.',
|
|
27
|
+
inputSchema: {
|
|
28
|
+
type: 'object',
|
|
29
|
+
properties: {
|
|
30
|
+
action: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
enum: ['create', 'update', 'delete', 'link', 'unlink', 'supersede', 'promote_from_knowledge'],
|
|
33
|
+
description: 'Action to perform. "supersede" marks a decision as superseded by another ' +
|
|
34
|
+
'(pass decisionId + supersededById). "promote_from_knowledge" elevates a task\'s ' +
|
|
35
|
+
'decision-type knowledge item into a durable Decision (pass organizationId + taskId + ' +
|
|
36
|
+
'knowledgeId, optionally title + linkToType/linkToId to link it on creation).',
|
|
37
|
+
},
|
|
38
|
+
// --- Identifiers ---
|
|
39
|
+
organizationId: {
|
|
40
|
+
type: 'string',
|
|
41
|
+
description: 'Organization ID (required for create and promote_from_knowledge)',
|
|
42
|
+
},
|
|
43
|
+
decisionId: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
description: 'Decision ID (required for update, delete, link, unlink, supersede)',
|
|
46
|
+
},
|
|
47
|
+
supersededById: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
description: 'ID of the decision that supersedes this one (required for supersede)',
|
|
50
|
+
},
|
|
51
|
+
// --- Create / update fields ---
|
|
52
|
+
title: {
|
|
53
|
+
type: 'string',
|
|
54
|
+
description: 'Decision title (required for create), e.g. "Use PostgreSQL over Firestore". ' +
|
|
55
|
+
'Optional for promote_from_knowledge (defaults from the knowledge item).',
|
|
56
|
+
},
|
|
57
|
+
context: {
|
|
58
|
+
type: 'string',
|
|
59
|
+
description: 'The situation / forces that motivated the decision, supports markdown ' +
|
|
60
|
+
'(create, update)',
|
|
61
|
+
},
|
|
62
|
+
options: {
|
|
63
|
+
type: 'string',
|
|
64
|
+
description: 'The options considered, supports markdown (create, update)',
|
|
65
|
+
},
|
|
66
|
+
decision: {
|
|
67
|
+
type: 'string',
|
|
68
|
+
description: 'The decision that was made, supports markdown (create, update)',
|
|
69
|
+
},
|
|
70
|
+
consequences: {
|
|
71
|
+
type: 'string',
|
|
72
|
+
description: 'The resulting consequences / trade-offs, supports markdown (create, update)',
|
|
73
|
+
},
|
|
74
|
+
status: {
|
|
75
|
+
type: 'string',
|
|
76
|
+
enum: ['proposed', 'accepted', 'rejected', 'superseded', 'deprecated'],
|
|
77
|
+
description: 'Decision lifecycle status (default: "proposed") (create, update)',
|
|
78
|
+
},
|
|
79
|
+
projectId: {
|
|
80
|
+
type: 'string',
|
|
81
|
+
description: 'Scope the decision to a project. Omit/empty = cross-project / org-wide ' +
|
|
82
|
+
'(create, update)',
|
|
83
|
+
},
|
|
84
|
+
// --- link / unlink fields ---
|
|
85
|
+
targetType: {
|
|
86
|
+
type: 'string',
|
|
87
|
+
enum: LINKABLE_TYPES,
|
|
88
|
+
description: 'Type of artifact to link/unlink (required for link, unlink)',
|
|
89
|
+
},
|
|
90
|
+
targetId: {
|
|
91
|
+
type: 'string',
|
|
92
|
+
description: 'ID of the artifact to link/unlink (required for link, unlink)',
|
|
93
|
+
},
|
|
94
|
+
links: LINKS_ARRAY_SCHEMA,
|
|
95
|
+
// --- promote_from_knowledge fields ---
|
|
96
|
+
taskId: {
|
|
97
|
+
type: 'string',
|
|
98
|
+
description: 'Task whose knowledge item to promote (required for promote_from_knowledge)',
|
|
99
|
+
},
|
|
100
|
+
knowledgeId: {
|
|
101
|
+
type: 'string',
|
|
102
|
+
description: 'ID of the decision-type knowledge item to promote ' +
|
|
103
|
+
'(required for promote_from_knowledge)',
|
|
104
|
+
},
|
|
105
|
+
linkToType: {
|
|
106
|
+
type: 'string',
|
|
107
|
+
enum: LINKABLE_TYPES,
|
|
108
|
+
description: 'Optionally link the new decision to this artifact type on creation ' +
|
|
109
|
+
'(create, promote_from_knowledge)',
|
|
110
|
+
},
|
|
111
|
+
linkToId: {
|
|
112
|
+
type: 'string',
|
|
113
|
+
description: 'ID of the artifact to link the new decision to on creation ' +
|
|
114
|
+
'(create, promote_from_knowledge; requires linkToType)',
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
required: ['action'],
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: 'get_decision',
|
|
122
|
+
description: 'Retrieve a single Decision, list an organization\'s decisions, or list the decisions ' +
|
|
123
|
+
'linked to a given entity (e.g. all decisions on a feature). Provide decisionId for a single ' +
|
|
124
|
+
'lookup; provide linkedType + linkedId to list decisions linked to that entity; otherwise ' +
|
|
125
|
+
'provide organizationId to list.',
|
|
126
|
+
inputSchema: {
|
|
127
|
+
type: 'object',
|
|
128
|
+
properties: {
|
|
129
|
+
decisionId: {
|
|
130
|
+
type: 'string',
|
|
131
|
+
description: 'Decision ID for a single lookup',
|
|
132
|
+
},
|
|
133
|
+
organizationId: {
|
|
134
|
+
type: 'string',
|
|
135
|
+
description: 'Organization ID (required for list, unless using linkedType + linkedId)',
|
|
136
|
+
},
|
|
137
|
+
linkedType: {
|
|
138
|
+
type: 'string',
|
|
139
|
+
enum: LINKABLE_TYPES,
|
|
140
|
+
description: 'List decisions linked to this entity type (requires linkedId), ' +
|
|
141
|
+
'e.g. all decisions on a feature',
|
|
142
|
+
},
|
|
143
|
+
linkedId: {
|
|
144
|
+
type: 'string',
|
|
145
|
+
description: 'ID of the entity to list linked decisions for (requires linkedType)',
|
|
146
|
+
},
|
|
147
|
+
includeLinks: {
|
|
148
|
+
type: 'boolean',
|
|
149
|
+
description: 'If true (single lookup), also return the decision\'s linked artifacts',
|
|
150
|
+
},
|
|
151
|
+
// --- List filters ---
|
|
152
|
+
projectId: {
|
|
153
|
+
type: 'string',
|
|
154
|
+
description: 'Filter to a single project\'s decisions (list mode)',
|
|
155
|
+
},
|
|
156
|
+
status: {
|
|
157
|
+
type: 'string',
|
|
158
|
+
enum: ['proposed', 'accepted', 'rejected', 'superseded', 'deprecated'],
|
|
159
|
+
description: 'Filter by status (list mode)',
|
|
160
|
+
},
|
|
161
|
+
limit: {
|
|
162
|
+
type: 'number',
|
|
163
|
+
description: 'Maximum number of results (list mode)',
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
];
|