@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,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature Flag Tools
|
|
3
|
+
* MCP tools for Feature Flags (E-149) — PM-aware, lifecycle-tracked runtime gates.
|
|
4
|
+
*
|
|
5
|
+
* A Feature Flag is an org-level (projectId nullable) runtime gate with a
|
|
6
|
+
* lifecycle (draft → … → enabled/disabled → sunset → archived), a served value
|
|
7
|
+
* (boolean | multivariate | config), optional prerequisite nesting
|
|
8
|
+
* (parentFeatureFlagId — a child only serves "on" when its parent chain is on
|
|
9
|
+
* for the same subject), and targeting rules + percentage rollout. Flags LINK to
|
|
10
|
+
* the feature(s) they gate via the generic link graph — they do not contain them.
|
|
11
|
+
*
|
|
12
|
+
* Prefer the polymorphic manage_link (sourceType "feature", targetType
|
|
13
|
+
* "feature_flag") to attach a flag to a feature; the link/unlink actions here are
|
|
14
|
+
* a convenience that go through the flag's own link surface.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { LINKABLE_TYPES } from './linkable-types.js';
|
|
18
|
+
import { LINKS_ARRAY_SCHEMA } from './link-params.js';
|
|
19
|
+
|
|
20
|
+
export const FEATURE_FLAG_TOOLS = [
|
|
21
|
+
{
|
|
22
|
+
name: 'manage_feature_flag',
|
|
23
|
+
description: 'Create, update, or delete a Feature Flag (a PM-aware runtime gate: key, name, ' +
|
|
24
|
+
'kind boolean|multivariate|config, rollout %, prerequisite parent, governance properties), ' +
|
|
25
|
+
'advance its lifecycle status (action "transition"), or link/unlink it to the feature(s) it ' +
|
|
26
|
+
'gates. Flags are org-level and LINK to features/epics/tasks/etc., they do not contain them. ' +
|
|
27
|
+
'Status changes go through action "transition" (recorded in history), NOT update.',
|
|
28
|
+
inputSchema: {
|
|
29
|
+
type: 'object',
|
|
30
|
+
properties: {
|
|
31
|
+
action: {
|
|
32
|
+
type: 'string',
|
|
33
|
+
enum: ['create', 'update', 'delete', 'transition', 'link', 'unlink', 'set_environment_config'],
|
|
34
|
+
description: 'Action to perform. "transition" advances lifecycle status (pass flagId + ' +
|
|
35
|
+
'status + reason). "link"/"unlink" attach/detach the flag to an artifact (pass flagId + ' +
|
|
36
|
+
'targetType + targetId). "set_environment_config" sets the flag\'s served state in ONE ' +
|
|
37
|
+
'environment (pass flagId + environmentId + enabled + rolloutPercentage [+ defaultVariantId]) — ' +
|
|
38
|
+
'this is how you turn a flag on in dev but off in prod (E-186).',
|
|
39
|
+
},
|
|
40
|
+
// --- per-environment served state (E-186, action set_environment_config) ---
|
|
41
|
+
environmentId: {
|
|
42
|
+
type: 'string',
|
|
43
|
+
description: 'Environment ID whose served state to set (set_environment_config). Get ids ' +
|
|
44
|
+
'from manage_environment action "list".',
|
|
45
|
+
},
|
|
46
|
+
enabled: {
|
|
47
|
+
type: 'boolean',
|
|
48
|
+
description: 'Per-environment kill switch — when false the flag serves off in this ' +
|
|
49
|
+
'environment regardless of rules/rollout (set_environment_config)',
|
|
50
|
+
},
|
|
51
|
+
// --- Identifiers ---
|
|
52
|
+
organizationId: {
|
|
53
|
+
type: 'string',
|
|
54
|
+
description: 'Organization ID (required for create)',
|
|
55
|
+
},
|
|
56
|
+
flagId: {
|
|
57
|
+
type: 'string',
|
|
58
|
+
description: 'Feature flag ID (required for update, delete, transition, link, unlink)',
|
|
59
|
+
},
|
|
60
|
+
// --- Create / update fields ---
|
|
61
|
+
key: {
|
|
62
|
+
type: 'string',
|
|
63
|
+
description: 'Stable programmatic identifier used by code gates and the evaluator ' +
|
|
64
|
+
'(e.g. "analytics.behavioral_source"). Unique per organization. Required for create.',
|
|
65
|
+
},
|
|
66
|
+
name: {
|
|
67
|
+
type: 'string',
|
|
68
|
+
description: 'Human-friendly flag name (required for create) (create, update)',
|
|
69
|
+
},
|
|
70
|
+
description: {
|
|
71
|
+
type: 'string',
|
|
72
|
+
description: 'What the flag gates and when it can be removed, supports markdown (create, update)',
|
|
73
|
+
},
|
|
74
|
+
kind: {
|
|
75
|
+
type: 'string',
|
|
76
|
+
enum: ['boolean', 'multivariate', 'config'],
|
|
77
|
+
description: 'What the flag serves: "boolean" on/off (default), "multivariate" named ' +
|
|
78
|
+
'weighted variants, or "config" a JSON payload (create, update)',
|
|
79
|
+
},
|
|
80
|
+
rolloutPercentage: {
|
|
81
|
+
type: 'number',
|
|
82
|
+
description: 'Percentage rollout 0–100 (default 0). Subjects are bucketed by a consistent ' +
|
|
83
|
+
'hash of (key, subjectId); those below the cutoff are served on (create, update)',
|
|
84
|
+
},
|
|
85
|
+
projectId: {
|
|
86
|
+
type: 'string',
|
|
87
|
+
description: 'Scope the flag to a project. Omit/empty = org-wide / system flag ' +
|
|
88
|
+
'(e.g. a backend gate) (create, update)',
|
|
89
|
+
},
|
|
90
|
+
parentFeatureFlagId: {
|
|
91
|
+
type: 'string',
|
|
92
|
+
description: 'Prerequisite parent flag ID — this flag serves "on" for a subject only if ' +
|
|
93
|
+
'the parent chain is also on for that subject. Omit/empty = root flag. Cycles are ' +
|
|
94
|
+
'rejected (create, update)',
|
|
95
|
+
},
|
|
96
|
+
defaultVariantId: {
|
|
97
|
+
type: 'string',
|
|
98
|
+
description: 'Variant served when the flag is on and no rule matched (fallthrough). ' +
|
|
99
|
+
'Empty string clears it (update)',
|
|
100
|
+
},
|
|
101
|
+
properties: {
|
|
102
|
+
type: 'object',
|
|
103
|
+
description: 'Governance metadata (owner, expiry/ttl, ticket link, environment, custom ' +
|
|
104
|
+
'k/v). Does NOT affect evaluation (create, update)',
|
|
105
|
+
},
|
|
106
|
+
// --- transition fields ---
|
|
107
|
+
status: {
|
|
108
|
+
type: 'string',
|
|
109
|
+
enum: ['draft', 'in_development', 'rolling_out', 'enabled', 'disabled',
|
|
110
|
+
'sunset', 'archived', 'cancelled'],
|
|
111
|
+
description: 'For action "create": the initial lifecycle status (default "draft"). For ' +
|
|
112
|
+
'action "transition": the target status to move to.',
|
|
113
|
+
},
|
|
114
|
+
reason: {
|
|
115
|
+
type: 'string',
|
|
116
|
+
description: 'Why the status changed — recorded in the flag\'s history (transition)',
|
|
117
|
+
},
|
|
118
|
+
// --- link / unlink fields ---
|
|
119
|
+
targetType: {
|
|
120
|
+
type: 'string',
|
|
121
|
+
enum: LINKABLE_TYPES,
|
|
122
|
+
description: 'Type of artifact to link/unlink — usually "feature" (required for link, unlink)',
|
|
123
|
+
},
|
|
124
|
+
targetId: {
|
|
125
|
+
type: 'string',
|
|
126
|
+
description: 'ID of the artifact to link/unlink (required for link, unlink)',
|
|
127
|
+
},
|
|
128
|
+
// --- create-time link fields ---
|
|
129
|
+
linkToType: {
|
|
130
|
+
type: 'string',
|
|
131
|
+
enum: LINKABLE_TYPES,
|
|
132
|
+
description: 'Optionally link the new flag to this artifact type on creation (create)',
|
|
133
|
+
},
|
|
134
|
+
linkToId: {
|
|
135
|
+
type: 'string',
|
|
136
|
+
description: 'ID of the artifact to link the new flag to on creation (create; requires linkToType)',
|
|
137
|
+
},
|
|
138
|
+
links: LINKS_ARRAY_SCHEMA,
|
|
139
|
+
},
|
|
140
|
+
required: ['action'],
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: 'get_feature_flag',
|
|
145
|
+
description: 'Retrieve a single Feature Flag (with its variants + rules) by ID, or by ' +
|
|
146
|
+
'organizationId + key (key is unique per org). Provide flagId, OR organizationId + key.',
|
|
147
|
+
inputSchema: {
|
|
148
|
+
type: 'object',
|
|
149
|
+
properties: {
|
|
150
|
+
flagId: {
|
|
151
|
+
type: 'string',
|
|
152
|
+
description: 'Feature flag ID for a single lookup',
|
|
153
|
+
},
|
|
154
|
+
organizationId: {
|
|
155
|
+
type: 'string',
|
|
156
|
+
description: 'Organization ID (with key, for a lookup by key)',
|
|
157
|
+
},
|
|
158
|
+
key: {
|
|
159
|
+
type: 'string',
|
|
160
|
+
description: 'Flag key (with organizationId, for a lookup by key)',
|
|
161
|
+
},
|
|
162
|
+
includeLinks: {
|
|
163
|
+
type: 'boolean',
|
|
164
|
+
description: 'If true, also return the flag\'s linked artifacts',
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: 'list_feature_flags',
|
|
171
|
+
description: 'List an organization\'s Feature Flags, optionally filtered by project, status, or ' +
|
|
172
|
+
'kind — or list the flags linked to a given entity (e.g. all flags on a feature) via ' +
|
|
173
|
+
'linkedType + linkedId.',
|
|
174
|
+
inputSchema: {
|
|
175
|
+
type: 'object',
|
|
176
|
+
properties: {
|
|
177
|
+
organizationId: {
|
|
178
|
+
type: 'string',
|
|
179
|
+
description: 'Organization ID (required)',
|
|
180
|
+
},
|
|
181
|
+
projectId: {
|
|
182
|
+
type: 'string',
|
|
183
|
+
description: 'Filter to a single project\'s flags',
|
|
184
|
+
},
|
|
185
|
+
status: {
|
|
186
|
+
type: 'string',
|
|
187
|
+
enum: ['draft', 'in_development', 'rolling_out', 'enabled', 'disabled',
|
|
188
|
+
'sunset', 'archived', 'cancelled'],
|
|
189
|
+
description: 'Filter by lifecycle status',
|
|
190
|
+
},
|
|
191
|
+
kind: {
|
|
192
|
+
type: 'string',
|
|
193
|
+
enum: ['boolean', 'multivariate', 'config'],
|
|
194
|
+
description: 'Filter by flag kind',
|
|
195
|
+
},
|
|
196
|
+
includeOrgWide: {
|
|
197
|
+
type: 'boolean',
|
|
198
|
+
description: 'When filtering by projectId, also include org-wide (project-less) flags',
|
|
199
|
+
},
|
|
200
|
+
linkedType: {
|
|
201
|
+
type: 'string',
|
|
202
|
+
enum: LINKABLE_TYPES,
|
|
203
|
+
description: 'List flags linked to this entity type (requires linkedId), e.g. all flags on a feature',
|
|
204
|
+
},
|
|
205
|
+
linkedId: {
|
|
206
|
+
type: 'string',
|
|
207
|
+
description: 'ID of the entity to list linked flags for (requires linkedType)',
|
|
208
|
+
},
|
|
209
|
+
limit: {
|
|
210
|
+
type: 'number',
|
|
211
|
+
description: 'Maximum number of results',
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
required: ['organizationId'],
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
name: 'evaluate_feature_flag',
|
|
219
|
+
description: 'Evaluate a Feature Flag for a subject and return the served Result ({ on, ' +
|
|
220
|
+
'variantKey, value, reason }) — for debugging a flag\'s behavior from chat. Resolves the ' +
|
|
221
|
+
'prerequisite chain and runs the deterministic evaluator (status → targeting rules → ' +
|
|
222
|
+
'percentage rollout). Look up by organizationId + key.',
|
|
223
|
+
inputSchema: {
|
|
224
|
+
type: 'object',
|
|
225
|
+
properties: {
|
|
226
|
+
organizationId: {
|
|
227
|
+
type: 'string',
|
|
228
|
+
description: 'Organization ID (required)',
|
|
229
|
+
},
|
|
230
|
+
key: {
|
|
231
|
+
type: 'string',
|
|
232
|
+
description: 'Flag key to evaluate (required)',
|
|
233
|
+
},
|
|
234
|
+
subjectId: {
|
|
235
|
+
type: 'string',
|
|
236
|
+
description: 'Stable subject identifier for percentage bucketing (e.g. a userId). ' +
|
|
237
|
+
'Same subject always lands in the same bucket per flag.',
|
|
238
|
+
},
|
|
239
|
+
environment: {
|
|
240
|
+
type: 'string',
|
|
241
|
+
description: 'Environment KEY to evaluate in (e.g. "production", "development"). ' +
|
|
242
|
+
'Omit to use the flag scope\'s default environment (E-186).',
|
|
243
|
+
},
|
|
244
|
+
attributes: {
|
|
245
|
+
type: 'object',
|
|
246
|
+
description: 'Targeting facts the rules test against (e.g. { plan: "pro", country: "US" })',
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
required: ['organizationId', 'key'],
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
name: 'manage_environment',
|
|
254
|
+
description: 'Manage the configurable ENVIRONMENT registry (E-186): the named environments ' +
|
|
255
|
+
'(e.g. development/staging/production) a flag can be served differently in. Environments are ' +
|
|
256
|
+
'per-scope: org-wide (omit projectId) or project-scoped (set projectId). Exactly one per scope ' +
|
|
257
|
+
'is the default (used when an evaluation does not name an environment). To set a flag\'s value ' +
|
|
258
|
+
'IN an environment, use manage_feature_flag action "set_environment_config".',
|
|
259
|
+
inputSchema: {
|
|
260
|
+
type: 'object',
|
|
261
|
+
properties: {
|
|
262
|
+
action: {
|
|
263
|
+
type: 'string',
|
|
264
|
+
enum: ['list', 'create', 'update', 'delete', 'set_default'],
|
|
265
|
+
description: 'list (by organizationId [+projectId]); create; update (name/order); delete; ' +
|
|
266
|
+
'set_default (make this the scope\'s default environment).',
|
|
267
|
+
},
|
|
268
|
+
organizationId: {
|
|
269
|
+
type: 'string',
|
|
270
|
+
description: 'Organization ID (required for list and create)',
|
|
271
|
+
},
|
|
272
|
+
projectId: {
|
|
273
|
+
type: 'string',
|
|
274
|
+
description: 'Project scope. Omit/empty = the org-wide environment set (used by org-wide flags).',
|
|
275
|
+
},
|
|
276
|
+
environmentId: {
|
|
277
|
+
type: 'string',
|
|
278
|
+
description: 'Environment ID (required for update, delete, set_default)',
|
|
279
|
+
},
|
|
280
|
+
key: {
|
|
281
|
+
type: 'string',
|
|
282
|
+
description: 'Stable environment key, lowercase (e.g. "production"). Immutable. Required for create.',
|
|
283
|
+
},
|
|
284
|
+
name: {
|
|
285
|
+
type: 'string',
|
|
286
|
+
description: 'Human-friendly environment name (create, update)',
|
|
287
|
+
},
|
|
288
|
+
order: {
|
|
289
|
+
type: 'number',
|
|
290
|
+
description: 'Display order within the scope (create, update)',
|
|
291
|
+
},
|
|
292
|
+
isDefault: {
|
|
293
|
+
type: 'boolean',
|
|
294
|
+
description: 'Make this the scope\'s default environment on create (create)',
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
required: ['action'],
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
];
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature Tools
|
|
3
|
+
* MCP tools for the Feature Compendium (E-162).
|
|
4
|
+
*
|
|
5
|
+
* A Feature is a durable, user-facing product CAPABILITY — a NOUN, on a
|
|
6
|
+
* separate axis from work. Epics/tasks are VERBS (work); features LINK to work,
|
|
7
|
+
* they do not own it. Features are ORG-LEVEL, and a feature SPANS MULTIPLE
|
|
8
|
+
* PROJECTS (E-242) — a real capability like "Push notifications" lives in api +
|
|
9
|
+
* web + mobile at once:
|
|
10
|
+
* - projectIds [] → every project the capability spans; the FIRST is the
|
|
11
|
+
* primary/owner. An empty set = cross-project / org-wide,
|
|
12
|
+
* which is in scope for every project.
|
|
13
|
+
* - projectId → DEPRECATED single-project form, treated as a
|
|
14
|
+
* one-element projectIds. Still accepted everywhere.
|
|
15
|
+
* - parent_feature_id builds a sub-feature tree.
|
|
16
|
+
*
|
|
17
|
+
* The "is this a feature?" test: would a PM/user call it "a feature of the app"?
|
|
18
|
+
* (push notifications = yes; "refactor auth middleware" = no, that's an epic).
|
|
19
|
+
* Discipline: features track the product-capability map, NOT every change — do
|
|
20
|
+
* not create a feature per task.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { LINKABLE_TYPES } from './linkable-types.js';
|
|
24
|
+
|
|
25
|
+
export const FEATURE_TOOLS = [
|
|
26
|
+
{
|
|
27
|
+
name: 'manage_feature',
|
|
28
|
+
description: 'Create, update, or delete a Feature (a durable product capability), or link/unlink it ' +
|
|
29
|
+
'to existing work artifacts. Features are org-level and live on a separate axis from work — they ' +
|
|
30
|
+
'LINK to epics/tasks/milestones/etc., they do not contain them.',
|
|
31
|
+
inputSchema: {
|
|
32
|
+
type: 'object',
|
|
33
|
+
properties: {
|
|
34
|
+
action: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
enum: ['create', 'update', 'delete', 'link', 'unlink', 'promote_epic', 'generate_how_it_works', 'apply_how_it_works', 'apply_init'],
|
|
37
|
+
description: 'Action to perform. "promote_epic" creates a feature from an existing epic ' +
|
|
38
|
+
'(inheriting its title/description/scope) and links the epic to it. ' +
|
|
39
|
+
'"generate_how_it_works" (re)generates the feature\'s grounded, source-attributed ' +
|
|
40
|
+
'"how it works" living description from its linked work + code (requires featureId; ' +
|
|
41
|
+
'AI-quota gated). "apply_how_it_works" (BYO-AI) persists a summary YOU authored ' +
|
|
42
|
+
'(markdown + sources); the server validates your cited sources against the real ' +
|
|
43
|
+
'grounded context before saving — no server model call. Read the result back via ' +
|
|
44
|
+
'get_feature with includeDetail. ' +
|
|
45
|
+
'"apply_init" commits a human-approved init/backfill proposal (E-167): pass ' +
|
|
46
|
+
'organizationId + nodes (a candidate-feature tree) to create features parents→children, ' +
|
|
47
|
+
'backfill links, and persist any agent-authored "how it works". Inference itself runs ' +
|
|
48
|
+
'locally with the user\'s AI — this only applies the approved result.',
|
|
49
|
+
},
|
|
50
|
+
// --- Identifiers ---
|
|
51
|
+
organizationId: {
|
|
52
|
+
type: 'string',
|
|
53
|
+
description: 'Organization ID (required for create)',
|
|
54
|
+
},
|
|
55
|
+
featureId: {
|
|
56
|
+
type: 'string',
|
|
57
|
+
description: 'Feature ID (required for update, delete, link, unlink, generate_how_it_works, apply_how_it_works)',
|
|
58
|
+
},
|
|
59
|
+
// --- apply_how_it_works (BYO-AI) ---
|
|
60
|
+
markdown: {
|
|
61
|
+
type: 'string',
|
|
62
|
+
description: 'Rendered markdown body for apply_how_it_works (the how-it-works YOU authored).',
|
|
63
|
+
},
|
|
64
|
+
sources: {
|
|
65
|
+
type: 'object',
|
|
66
|
+
description: 'Structured backing for apply_how_it_works: { claims: [{ text, sources: [ref...], ' +
|
|
67
|
+
'confidence: "grounded"|"unverified" }], divergences: [{ intent, reality, severity }] }. Cite ' +
|
|
68
|
+
'real source refs from the feature\'s grounded context; the server drops fabricated ones.',
|
|
69
|
+
},
|
|
70
|
+
epicId: {
|
|
71
|
+
type: 'string',
|
|
72
|
+
description: 'Epic ID to promote into a feature (required for promote_epic)',
|
|
73
|
+
},
|
|
74
|
+
// --- Create / update fields ---
|
|
75
|
+
title: {
|
|
76
|
+
type: 'string',
|
|
77
|
+
description: 'Feature title (required for create), e.g. "Push Notifications"',
|
|
78
|
+
},
|
|
79
|
+
description: {
|
|
80
|
+
type: 'string',
|
|
81
|
+
description: 'Feature description, supports markdown (create, update). ' +
|
|
82
|
+
'Writing this stays plain text; it does not create a backing document.',
|
|
83
|
+
},
|
|
84
|
+
status: {
|
|
85
|
+
type: 'string',
|
|
86
|
+
enum: ['proposed', 'active', 'deprecated', 'removed'],
|
|
87
|
+
description: 'Capability lifecycle status (default: "active") (create, update)',
|
|
88
|
+
},
|
|
89
|
+
projectId: {
|
|
90
|
+
type: 'string',
|
|
91
|
+
description: 'DEPRECATED single-project form — prefer projectIds. Treated as a ' +
|
|
92
|
+
'one-element projectIds. Omit/empty = cross-project / org-wide; on update an empty ' +
|
|
93
|
+
'string clears the scope back to org-wide.',
|
|
94
|
+
},
|
|
95
|
+
projectIds: {
|
|
96
|
+
type: 'array',
|
|
97
|
+
items: { type: 'string' },
|
|
98
|
+
description: 'Every project this capability spans (create, update). The FIRST id is ' +
|
|
99
|
+
'the primary/owner. On UPDATE this REPLACES the whole set — pass the full list, not ' +
|
|
100
|
+
'just additions — and an empty array makes the feature org-wide. Omitting it on an ' +
|
|
101
|
+
'update leaves the existing projects alone. Wins over projectId.',
|
|
102
|
+
},
|
|
103
|
+
parentFeatureId: {
|
|
104
|
+
type: 'string',
|
|
105
|
+
description: 'Parent feature ID for the sub-feature tree. Omit/empty = root feature. ' +
|
|
106
|
+
'On update, an empty string makes it a root.',
|
|
107
|
+
},
|
|
108
|
+
// --- link / unlink fields ---
|
|
109
|
+
targetType: {
|
|
110
|
+
type: 'string',
|
|
111
|
+
enum: LINKABLE_TYPES,
|
|
112
|
+
description: 'Type of artifact to link/unlink (required for link, unlink). ' +
|
|
113
|
+
'test_suite surfaces read-only pass/fail coverage on the feature (E-173).',
|
|
114
|
+
},
|
|
115
|
+
targetId: {
|
|
116
|
+
type: 'string',
|
|
117
|
+
description: 'ID of the artifact to link/unlink (required for link, unlink)',
|
|
118
|
+
},
|
|
119
|
+
// --- apply_init fields (E-167) ---
|
|
120
|
+
nodes: {
|
|
121
|
+
type: 'array',
|
|
122
|
+
description: 'Approved candidate-feature tree to commit (required for apply_init). Each node: ' +
|
|
123
|
+
'{ tempId, title, description?, status?, parentTempId?|parentFeatureId?, mergeIntoFeatureId?, ' +
|
|
124
|
+
'projectId?, links?:[{targetType,targetId}], howItWorks?:{markdown, sources, validSources?} }. ' +
|
|
125
|
+
'tempId lets nodes reference each other before creation; mergeIntoFeatureId picks the dedup path.',
|
|
126
|
+
items: { type: 'object' },
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
required: ['action'],
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: 'get_feature',
|
|
134
|
+
description: 'Retrieve a single Feature, list features for a project, view the feature tree, ' +
|
|
135
|
+
'or list a feature\'s links. Provide featureId (or organizationId + featureSlug) for a single ' +
|
|
136
|
+
'lookup; for list/tree provide organizationId AND a project scope (projectId, or ' +
|
|
137
|
+
'projectIds for several at once) — an org can span several products, so list/tree is ' +
|
|
138
|
+
'project-scoped (it still includes org-wide capabilities, i.e. features spanning no ' +
|
|
139
|
+
'project). List mode is PAGINATED: the response carries total/hasMore alongside features, ' +
|
|
140
|
+
'so use offset to page rather than assuming you got everything. ' +
|
|
141
|
+
'Responses include `descriptionDocumentId` — the id of the backing rich-description Document ' +
|
|
142
|
+
'when the description has been promoted to one (E-189), otherwise omitted.',
|
|
143
|
+
inputSchema: {
|
|
144
|
+
type: 'object',
|
|
145
|
+
properties: {
|
|
146
|
+
organizationId: {
|
|
147
|
+
type: 'string',
|
|
148
|
+
description: 'Organization ID (required for list/tree, alongside projectId; ' +
|
|
149
|
+
'with featureSlug for slug lookup)',
|
|
150
|
+
},
|
|
151
|
+
featureId: {
|
|
152
|
+
type: 'string',
|
|
153
|
+
description: 'Feature ID for a single lookup',
|
|
154
|
+
},
|
|
155
|
+
featureSlug: {
|
|
156
|
+
type: 'string',
|
|
157
|
+
description: 'Feature slug for a single lookup (requires organizationId)',
|
|
158
|
+
},
|
|
159
|
+
tree: {
|
|
160
|
+
type: 'boolean',
|
|
161
|
+
description: 'If true, return the nested feature forest instead of a flat list',
|
|
162
|
+
},
|
|
163
|
+
includeLinks: {
|
|
164
|
+
type: 'boolean',
|
|
165
|
+
description: 'If true (single lookup), also return the feature\'s linked artifacts',
|
|
166
|
+
},
|
|
167
|
+
includeDetail: {
|
|
168
|
+
type: 'boolean',
|
|
169
|
+
description: 'If true (single lookup), return the aggregated detail: linked artifacts ' +
|
|
170
|
+
'hydrated + grouped by type + a progress rollup over linked epics/tasks, plus the ' +
|
|
171
|
+
'generated "how it works" summary (howItWorks/howItWorksSources/generatedAt/model on ' +
|
|
172
|
+
'the feature) and a coarse howItWorksStale flag. Supersedes includeLinks.',
|
|
173
|
+
},
|
|
174
|
+
// --- List/tree filters ---
|
|
175
|
+
projectId: {
|
|
176
|
+
type: 'string',
|
|
177
|
+
description: 'Scope the listing to one project. Either this or projectIds is REQUIRED ' +
|
|
178
|
+
'for list/tree mode. Returns features spanning that project PLUS org-wide ' +
|
|
179
|
+
'(cross-project) ones. Ignored for a single lookup by featureId/featureSlug.',
|
|
180
|
+
},
|
|
181
|
+
projectIds: {
|
|
182
|
+
type: 'array',
|
|
183
|
+
items: { type: 'string' },
|
|
184
|
+
description: 'Scope the listing to several projects at once — satisfies the list/tree ' +
|
|
185
|
+
'scope requirement in place of projectId. Use it when working across projects ' +
|
|
186
|
+
'(e.g. api + web) to get one call instead of two. Wins over projectId.',
|
|
187
|
+
},
|
|
188
|
+
status: {
|
|
189
|
+
type: 'string',
|
|
190
|
+
enum: ['proposed', 'active', 'deprecated', 'removed'],
|
|
191
|
+
description: 'Filter by status (list/tree mode)',
|
|
192
|
+
},
|
|
193
|
+
search: {
|
|
194
|
+
type: 'string',
|
|
195
|
+
description: 'Substring filter over title, description and slug (list mode). This is a ' +
|
|
196
|
+
'literal text match — for "does this capability already exist?" use search_features, ' +
|
|
197
|
+
'which ranks by meaning.',
|
|
198
|
+
},
|
|
199
|
+
sortBy: {
|
|
200
|
+
type: 'string',
|
|
201
|
+
enum: ['title', 'status', 'createdAt', 'updatedAt', 'howItWorksGeneratedAt'],
|
|
202
|
+
description: 'Sort column (list mode, default "title"). An unrecognised value is an error.',
|
|
203
|
+
},
|
|
204
|
+
sortDir: {
|
|
205
|
+
type: 'string',
|
|
206
|
+
enum: ['asc', 'desc'],
|
|
207
|
+
description: 'Sort direction (list mode, default "asc")',
|
|
208
|
+
},
|
|
209
|
+
limit: {
|
|
210
|
+
type: 'number',
|
|
211
|
+
description: 'Page size (list mode, default 25, max 500)',
|
|
212
|
+
},
|
|
213
|
+
offset: {
|
|
214
|
+
type: 'number',
|
|
215
|
+
description: 'Rows to skip (list mode, default 0). Page with this while hasMore is true.',
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
name: 'search_features',
|
|
222
|
+
description: 'Semantic search over an organization\'s Features. Returns existing features ' +
|
|
223
|
+
'ranked by meaning-similarity to a query — use this BEFORE creating a new feature to find ' +
|
|
224
|
+
'an existing capability the work belongs to, so the compendium stays small and free of ' +
|
|
225
|
+
'duplicates (capture-at-build, E-164). Each result is {feature, similarity}.',
|
|
226
|
+
inputSchema: {
|
|
227
|
+
type: 'object',
|
|
228
|
+
properties: {
|
|
229
|
+
organizationId: {
|
|
230
|
+
type: 'string',
|
|
231
|
+
description: 'Organization ID to search within (required)',
|
|
232
|
+
},
|
|
233
|
+
query: {
|
|
234
|
+
type: 'string',
|
|
235
|
+
description: 'Natural-language description of the capability to find ' +
|
|
236
|
+
'(e.g. "let users get notified about activity"). Required.',
|
|
237
|
+
},
|
|
238
|
+
limit: {
|
|
239
|
+
type: 'number',
|
|
240
|
+
description: 'Maximum number of results (default: 10)',
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
required: ['organizationId', 'query'],
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
];
|
package/tools/folders.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Folder Tools
|
|
3
|
+
* MCP tools for managing document folders within projects
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const FOLDER_TOOLS = [
|
|
7
|
+
{
|
|
8
|
+
name: 'manage_folder',
|
|
9
|
+
description: 'Create, update, or delete document folders. Folders are usually ' +
|
|
10
|
+
'project-scoped (pass projectId), but a folder can also be ORG-SCOPED ' +
|
|
11
|
+
'(project-less) by passing organizationId with NO projectId — exactly one of the two. ' +
|
|
12
|
+
'Org-scoped folders are the org\'s document "areas"; the reserved areas (Goals, ' +
|
|
13
|
+
'Features, ADRs, How it works) are managed via get_org_areas. (E-195)',
|
|
14
|
+
inputSchema: {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
action: {
|
|
18
|
+
type: 'string',
|
|
19
|
+
enum: ['create', 'update', 'delete'],
|
|
20
|
+
description: 'Action to perform',
|
|
21
|
+
},
|
|
22
|
+
// --- Identifiers ---
|
|
23
|
+
projectId: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
description: 'Project ID. Provide for a PROJECT-SCOPED folder. ' +
|
|
26
|
+
'Mutually exclusive with organizationId — supply exactly one when creating.',
|
|
27
|
+
},
|
|
28
|
+
organizationId: {
|
|
29
|
+
type: 'string',
|
|
30
|
+
description: 'Org scope — provide organizationId with NO projectId to create/list an ' +
|
|
31
|
+
'ORG-SCOPED (project-less) folder (an org document "area"). Exactly one of projectId ' +
|
|
32
|
+
'or organizationId. (E-195)',
|
|
33
|
+
},
|
|
34
|
+
folderId: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
description: 'Folder ID (required for update, delete)',
|
|
37
|
+
},
|
|
38
|
+
// --- Create / Update fields ---
|
|
39
|
+
name: {
|
|
40
|
+
type: 'string',
|
|
41
|
+
description: 'Folder name (required for create, optional for update)',
|
|
42
|
+
},
|
|
43
|
+
color: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
description: 'Folder color (e.g., "blue", "red", "#FF0000") (create, update)',
|
|
46
|
+
},
|
|
47
|
+
icon: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
description: 'Folder icon identifier (create, update)',
|
|
50
|
+
},
|
|
51
|
+
// NOTE: there is deliberately no `access` parameter. Folder access
|
|
52
|
+
// control is real, but it is generic across entity types rather than a
|
|
53
|
+
// property of folders — folders.CreateFolderRequest /
|
|
54
|
+
// UpdateFolderRequest carry no access field, so a previously-advertised
|
|
55
|
+
// `access` object was decoded away to nothing on both create and update
|
|
56
|
+
// (#2168). Use the `manage_access` / `get_access` tools with
|
|
57
|
+
// entityType:"folder" instead; passing `access` here is reported back as
|
|
58
|
+
// a warning rather than silently accepted, see handlers/folders.js.
|
|
59
|
+
// Note that only ROOT folders carry their own access — nested folders
|
|
60
|
+
// inherit from their root, and manage_access rejects them accordingly.
|
|
61
|
+
// --- Create-only fields ---
|
|
62
|
+
parentFolderId: {
|
|
63
|
+
type: 'string',
|
|
64
|
+
description: 'Parent folder ID for nested folders (create only). For update, use this to move the folder. Use "root" or empty string to move to root level.',
|
|
65
|
+
},
|
|
66
|
+
// --- Delete-only fields ---
|
|
67
|
+
cascade: {
|
|
68
|
+
type: 'boolean',
|
|
69
|
+
description: 'If true, delete all contents recursively. If false (default), move contents to root. (delete only)',
|
|
70
|
+
default: false,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
// projectId OR organizationId is required for create (see scope descriptions);
|
|
74
|
+
// update/delete require folderId. Enforced server-side.
|
|
75
|
+
required: ['action'],
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'list_folders',
|
|
80
|
+
description: 'List document folders. Provide projectId for a project\'s folders, OR ' +
|
|
81
|
+
'organizationId (with no projectId) for the org\'s ORG-SCOPED (project-less) folders / ' +
|
|
82
|
+
'document areas (E-195). Use mode "tree" for hierarchical parent-child view, or "flat" ' +
|
|
83
|
+
'(default) for a flat list with document counts.',
|
|
84
|
+
inputSchema: {
|
|
85
|
+
type: 'object',
|
|
86
|
+
properties: {
|
|
87
|
+
projectId: {
|
|
88
|
+
type: 'string',
|
|
89
|
+
description: 'The project ID. Mutually exclusive with organizationId.',
|
|
90
|
+
},
|
|
91
|
+
organizationId: {
|
|
92
|
+
type: 'string',
|
|
93
|
+
description: 'Organization ID — list the org\'s ORG-SCOPED (project-less) folders ' +
|
|
94
|
+
'instead of a project\'s. Mutually exclusive with projectId. (E-195)',
|
|
95
|
+
},
|
|
96
|
+
mode: {
|
|
97
|
+
type: 'string',
|
|
98
|
+
enum: ['flat', 'tree'],
|
|
99
|
+
description: 'Output mode: "flat" (default) for list with document counts, "tree" for hierarchical parent-child view',
|
|
100
|
+
default: 'flat',
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'get_org_areas',
|
|
107
|
+
description: 'List the org\'s reserved document areas (Goals, Features, ADRs, How it works), ' +
|
|
108
|
+
'creating any missing ones. Areas are org-scoped (project-less) system folders that ' +
|
|
109
|
+
'organize cross-project documents — e.g. org-scoped "adr" and "how-it-works" documents ' +
|
|
110
|
+
'are auto-filed into the ADRs / How it works areas. (E-195)',
|
|
111
|
+
inputSchema: {
|
|
112
|
+
type: 'object',
|
|
113
|
+
properties: {
|
|
114
|
+
organizationId: {
|
|
115
|
+
type: 'string',
|
|
116
|
+
description: 'Organization ID (required)',
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
required: ['organizationId'],
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
];
|