@taiga-ai/mcp-server 0.25.0-rc.474 → 0.26.0-dev.481

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +111 -0
  2. package/dist/index.js +292 -115
  3. package/package.json +15 -2
  4. package/scripts/build.mjs +0 -37
  5. package/scripts/prepare-publish.cjs +0 -49
  6. package/src/client.test.ts +0 -424
  7. package/src/client.ts +0 -977
  8. package/src/config.test.ts +0 -24
  9. package/src/config.ts +0 -28
  10. package/src/index.ts +0 -45
  11. package/src/modern.integration.test.ts +0 -153
  12. package/src/server.integration.test.ts +0 -9214
  13. package/src/server.ts +0 -18
  14. package/src/tools/annotations.ts +0 -38
  15. package/src/tools/autonomy.ts +0 -86
  16. package/src/tools/backlogs.ts +0 -802
  17. package/src/tools/builds.ts +0 -668
  18. package/src/tools/catalogue.test.ts +0 -170
  19. package/src/tools/catalogue.ts +0 -223
  20. package/src/tools/context.ts +0 -513
  21. package/src/tools/documents.ts +0 -375
  22. package/src/tools/errors.ts +0 -172
  23. package/src/tools/hints.ts +0 -99
  24. package/src/tools/inbox.ts +0 -546
  25. package/src/tools/index.ts +0 -239
  26. package/src/tools/inputs.ts +0 -47
  27. package/src/tools/instructions.ts +0 -41
  28. package/src/tools/jobs.ts +0 -90
  29. package/src/tools/knowledge.ts +0 -249
  30. package/src/tools/maintenance.ts +0 -547
  31. package/src/tools/markdown.test.ts +0 -249
  32. package/src/tools/markdown.ts +0 -151
  33. package/src/tools/observe.ts +0 -311
  34. package/src/tools/product-documents.ts +0 -184
  35. package/src/tools/products.ts +0 -529
  36. package/src/tools/prompts.ts +0 -265
  37. package/src/tools/queue.ts +0 -250
  38. package/src/tools/readiness.ts +0 -177
  39. package/src/tools/remote.test.ts +0 -44
  40. package/src/tools/remote.ts +0 -107
  41. package/src/tools/repositories.ts +0 -360
  42. package/src/tools/request-prompt.test.ts +0 -32
  43. package/src/tools/request-prompt.ts +0 -28
  44. package/src/tools/resources.ts +0 -217
  45. package/src/tools/sections.test.ts +0 -143
  46. package/src/tools/sections.ts +0 -287
  47. package/src/tools/setup.ts +0 -455
  48. package/src/tools/summarize.test.ts +0 -20
  49. package/src/tools/summarize.ts +0 -96
  50. package/src/tools/wait.ts +0 -490
  51. package/src/version.test.ts +0 -10
  52. package/src/version.ts +0 -14
  53. package/taiga-ai-mcp-server-0.25.0-rc.474.tgz +0 -0
  54. package/tsconfig.json +0 -21
  55. package/vitest.config.ts +0 -9
@@ -1,311 +0,0 @@
1
- import type { McpServer } from '@modelcontextprotocol/server';
2
- import { ENVIRONMENT_TYPES } from '@taiga/types';
3
- import { z } from 'zod';
4
- import type { Deployment, Environment } from '@taiga/types';
5
- import { TaigaApiError, type TaigaClient, type WithoutTenant } from '../client.js';
6
- import { OPERATE, OPERATE_SETTING, READ_ONLY } from './annotations.js';
7
- import { isNetworkFailure, runTool, toolError, toolResult } from './errors.js';
8
- import { withNotFoundHint } from './hints.js';
9
- import { idInput, pagination, productId } from './inputs.js';
10
- import { page, pickFields } from './summarize.js';
11
-
12
- /**
13
- * What runs where and how it is doing (docs.tai.ga, Deliver: Deployments;
14
- * Operate: Monitoring). Taiga observes deployments, it does not perform them:
15
- * the history is mirrored from the provider, so these tools read and never
16
- * deploy, approve or cancel. Importing history reaches into the connected
17
- * provider and is an administrator's action in the web.
18
- */
19
-
20
- /** A deployment as a line of history: what shipped where, how it ended, and who shipped it. */
21
- const DEPLOYMENT_FIELDS = [
22
- 'id',
23
- 'environmentId',
24
- 'status',
25
- 'commitSha',
26
- 'commitSubject',
27
- 'version',
28
- 'tag',
29
- 'ref',
30
- 'prNumber',
31
- 'buildRunId',
32
- 'actorLogin',
33
- 'error',
34
- 'runUrl',
35
- 'createdAt',
36
- 'completedAt',
37
- ] as const;
38
-
39
- const ENVIRONMENT_FIELDS = ['id', 'name', 'slug', 'type', 'ordinal', 'status', 'isProtected', 'url'] as const;
40
-
41
- /**
42
- * Deployments as lines, each naming the repository that deployed it: every
43
- * repository runs its own deployment in an environment, so two running in
44
- * production are two repositories, not a contradiction (PRO-2528).
45
- */
46
- function deploymentLines(rows: WithoutTenant<Deployment>[]) {
47
- return rows.map((row) => {
48
- // `metadata` is an untyped jsonb column until PRO-2515 types it.
49
- const repository = row.metadata?.['repositoryFullName'];
50
- return {
51
- ...pickFields([row], DEPLOYMENT_FIELDS)[0],
52
- repository: typeof repository === 'string' ? repository : null,
53
- };
54
- });
55
- }
56
-
57
- const environmentId = idInput('environment', 'taiga_list_environments lists them; a product ID is not one');
58
- /** The windows the pages offer, as the schema's own values rather than a number checked afterwards. */
59
- const windowDays = z.literal([30, 60, 90]).optional().describe('Days to look back: 30, 60 or 90 (default 30)');
60
-
61
- /** Whether a failure is the API's (refused, missing, unreachable) rather than a bug here. */
62
- const isApiFailure = (error: unknown) => error instanceof TaigaApiError || isNetworkFailure(error);
63
-
64
- /** A part that may fail on its own without failing the read: null and the reason, or the value. */
65
- async function part<T>(read: () => Promise<T>): Promise<{ value: T } | { unavailable: string }> {
66
- try {
67
- return { value: await read() };
68
- } catch (error) {
69
- if (!isApiFailure(error)) throw error;
70
- return {
71
- unavailable: error instanceof TaigaApiError ? `${error.status}: ${error.apiMessage ?? ''}`.trim() : 'unreachable',
72
- };
73
- }
74
- }
75
-
76
- /** Environment pages read for one answer; a product has a handful, so this is a guard, not a page size. */
77
- const ENVIRONMENT_PAGES = 5;
78
-
79
- /** Every environment of a product, page by page, and whether any were left past the guard. */
80
- async function allEnvironments(
81
- client: TaigaClient,
82
- product: string
83
- ): Promise<{ rows: WithoutTenant<Environment>[]; more: boolean }> {
84
- const rows: WithoutTenant<Environment>[] = [];
85
- let cursor: string | undefined;
86
- for (let pageNo = 0; pageNo < ENVIRONMENT_PAGES; pageNo++) {
87
- const result = await client.listEnvironments(product, { limit: 100, cursor });
88
- rows.push(...result.data);
89
- if (!result.nextCursor) return { rows, more: false };
90
- cursor = result.nextCursor;
91
- }
92
- return { rows, more: true };
93
- }
94
-
95
- export function registerObserveTools(server: McpServer, client: TaigaClient) {
96
- if (!client.hasCapability('products:read')) return;
97
-
98
- server.registerTool(
99
- 'taiga_get_deployments',
100
- {
101
- title: 'Get what runs where',
102
- description:
103
- "Read what runs in each of a product's environments and its recent deployments, newest first: commit, " +
104
- "pull request, status, deployer and, on failure, the provider's error. What runs is the latest " +
105
- 'successful deployment, so a newer failure shows beside it. History is mirrored from the provider, ' +
106
- 'including deployments made outside Taiga; syncStatus says when it last synced. environmentId narrows to ' +
107
- 'one environment. Taiga never deploys.',
108
- inputSchema: z.object({ productId, environmentId: environmentId.optional(), ...pagination }),
109
- annotations: READ_ONLY,
110
- },
111
- (params) =>
112
- runTool(async () => {
113
- const [environments, current, history, sync] = await Promise.all([
114
- allEnvironments(client, params.productId),
115
- client.getCurrentDeployments(params.productId),
116
- client.listDeployments(params.productId, {
117
- environmentId: params.environmentId,
118
- limit: params.limit ?? 10,
119
- cursor: params.cursor,
120
- }),
121
- part(() => client.getDeploymentSyncStatus(params.productId)),
122
- ]);
123
- const now = current.data;
124
- // An empty answer says why, as the maintenance read does: no
125
- // environment, or none deployed to yet, is not "nothing is wrong".
126
- const note =
127
- environments.rows.length === 0
128
- ? 'This product has no environments yet: an environment is defined with taiga_create_environment, ' +
129
- 'and its deployments are mirrored from the provider once it is.'
130
- : history.data.length === 0 && !params.cursor
131
- ? 'No deployments recorded yet: none was mirrored from the provider (syncStatus says when it last ' +
132
- 'synced), or nothing has been deployed.'
133
- : null;
134
- return toolResult({
135
- environments: pickFields(environments.rows, ENVIRONMENT_FIELDS),
136
- ...(environments.more ? { moreEnvironments: true } : {}),
137
- running: deploymentLines(now.current ?? []),
138
- deploying: deploymentLines(now.deploying ?? []),
139
- history: page(deploymentLines(history.data), history.nextCursor),
140
- ...('value' in sync
141
- ? { syncStatus: sync.value.data }
142
- : { syncStatus: null, syncUnavailable: sync.unavailable }),
143
- ...(note ? { note } : {}),
144
- });
145
- })
146
- );
147
-
148
- server.registerTool(
149
- 'taiga_list_environments',
150
- {
151
- title: "List a product's environments",
152
- description:
153
- "List a product's environments with ID, type, order and App URL. These are the environment IDs " +
154
- 'taiga_get_delivery_metrics, taiga_get_monitoring and taiga_update_environment take. ' +
155
- 'taiga_get_deployments lists them too, with what runs where.',
156
- inputSchema: z.object({ productId }),
157
- annotations: READ_ONLY,
158
- },
159
- (params) =>
160
- runTool(async () => {
161
- const { rows, more } = await allEnvironments(client, params.productId);
162
- return toolResult({
163
- data: pickFields(rows, ENVIRONMENT_FIELDS),
164
- ...(more ? { more: 'More environments than this answer reads; the rest were left out.' } : {}),
165
- ...(rows.length === 0 ? { note: 'No environment is defined yet; taiga_create_environment adds one.' } : {}),
166
- });
167
- })
168
- );
169
-
170
- server.registerTool(
171
- 'taiga_get_delivery_metrics',
172
- {
173
- title: 'Get delivery metrics',
174
- description:
175
- "Read DORA's five delivery metrics for one environment (the page shows production) over 30, 60 or 90 " +
176
- 'days: deployment frequency, lead time, failed deployment recovery time, change-failure rate and rework ' +
177
- 'rate, each with its trend against the window before and a performance band (none for rework rate). ' +
178
- 'Computed from deployments, not incidents; previews and checks do not count. Under ten deployments a ' +
179
- 'trend is approximate; a metric with no data says so instead of a number.',
180
- inputSchema: z.object({ productId, environmentId, windowDays }),
181
- annotations: READ_ONLY,
182
- },
183
- (params) =>
184
- runTool(async () => {
185
- const days = params.windowDays ?? 30;
186
- return toolResult((await client.getDeliveryMetrics(params.productId, params.environmentId, days)).data);
187
- })
188
- );
189
-
190
- server.registerTool(
191
- 'taiga_get_monitoring',
192
- {
193
- title: "Get a product's monitoring",
194
- description:
195
- "How a product's environments are doing: each one's health from Taiga's checks of its App URL, uptime " +
196
- 'and last check (not checked when unverifiable now, baseline learning when new). With environmentId: ' +
197
- 'uptime over 30, 60 or 90 days and the beacon signals (Core Web Vitals, JavaScript errors, API health); ' +
198
- "not set up means no data. Setting up the beacon raises an initiative from the environment's settings in " +
199
- 'the web.',
200
- inputSchema: z.object({
201
- productId,
202
- environmentId: environmentId.optional(),
203
- windowDays,
204
- }),
205
- annotations: READ_ONLY,
206
- },
207
- (params) =>
208
- runTool(async () => {
209
- const health = await client.getMonitoringHealth(params.productId);
210
- if (!params.environmentId) {
211
- return toolResult({
212
- health: health.data,
213
- ...(health.data.length === 0
214
- ? {
215
- note:
216
- 'No environment is monitored: monitoring starts when an environment has its App URL ' +
217
- '(taiga_create_environment, taiga_update_environment). No health is not good health.',
218
- }
219
- : {}),
220
- });
221
- }
222
- const days = params.windowDays ?? 30;
223
- const env = params.environmentId;
224
- const [uptime, experience, clientHealth] = await Promise.all([
225
- part(() => client.getMonitoringSignal(params.productId, 'uptime', env, days)),
226
- part(() => client.getMonitoringSignal(params.productId, 'rum', env, days)),
227
- part(() => client.getMonitoringSignal(params.productId, 'client-health', env, days)),
228
- ]);
229
- // The API refuses an environment that is not the product's with 404
230
- // on every signal: that is a wrong ID, not three signals missing.
231
- if (
232
- 'unavailable' in uptime &&
233
- [uptime, experience, clientHealth].every((p) => 'unavailable' in p && p.unavailable.startsWith('404'))
234
- ) {
235
- // The API's own word, with the environmentId hint, as runTool gives any 404.
236
- const said = uptime.unavailable.replace(/^404:\s*/, '') || 'Environment not found';
237
- return toolError('NOT_FOUND', withNotFoundHint(said));
238
- }
239
- const value = (p: { value: { data: unknown } } | { unavailable: string }) =>
240
- 'value' in p ? p.value.data : { unavailable: p.unavailable };
241
- const envHealth = health.data.filter((row) => row.environmentId === env);
242
- return toolResult({
243
- health: envHealth,
244
- ...(envHealth.length === 0
245
- ? {
246
- note:
247
- 'No health for this environment: it has no App URL to check yet (taiga_update_environment ' +
248
- 'sets one). No health is not good health.',
249
- }
250
- : {}),
251
- windowDays: days,
252
- uptime: value(uptime),
253
- realUserExperience: value(experience),
254
- clientHealth: value(clientHealth),
255
- });
256
- })
257
- );
258
-
259
- if (!client.hasCapability('products:write')) return;
260
-
261
- server.registerTool(
262
- 'taiga_create_environment',
263
- {
264
- title: 'Create an environment',
265
- description:
266
- "Add an environment a product's software runs in (development, staging, production or its own). " +
267
- 'Deployments, monitoring and plans are tracked per environment. Taiga gets no access to it: the pipeline ' +
268
- 'deploys and Taiga learns what happened from source control. Members can do this. Then set its App URL ' +
269
- "with taiga_update_environment so monitoring starts. Changes the product's setup for everybody.",
270
- inputSchema: z.object({
271
- productId,
272
- name: z.string().trim().min(1).max(100).describe('What the team calls it, e.g. staging'),
273
- type: z.enum(ENVIRONMENT_TYPES).describe('Its kind; production is the one delivery metrics report on'),
274
- }),
275
- annotations: OPERATE,
276
- },
277
- (params) =>
278
- runTool(async () => {
279
- const created = (await client.createEnvironment(params.productId, { name: params.name, type: params.type }))
280
- .data;
281
- return toolResult(pickFields([created], ENVIRONMENT_FIELDS)[0]);
282
- })
283
- );
284
-
285
- server.registerTool(
286
- 'taiga_update_environment',
287
- {
288
- title: 'Update an environment',
289
- description:
290
- 'Rename an environment, change its kind, or set its public App URL (null clears it). Once an App URL is ' +
291
- 'saved, Taiga checks availability every few minutes. Marking one production makes it the one delivery ' +
292
- "metrics report on. Changes the product's setup for everybody.",
293
- inputSchema: z.object({
294
- environmentId,
295
- name: z.string().trim().min(1).max(100).optional().describe('A new name'),
296
- type: z.enum(ENVIRONMENT_TYPES).optional().describe('A new kind'),
297
- url: z.string().trim().max(500).url().nullable().optional().describe('The public App URL; null clears it'),
298
- }),
299
- annotations: OPERATE_SETTING,
300
- },
301
- (params) =>
302
- runTool(async () => {
303
- const { environmentId: id, ...changes } = params;
304
- if (Object.values(changes).every((value) => value === undefined)) {
305
- return toolError('VALIDATION_ERROR', 'Change at least one of name, type or url.');
306
- }
307
- const updated = (await client.updateEnvironment(id, changes)).data;
308
- return toolResult(pickFields([updated], ENVIRONMENT_FIELDS)[0]);
309
- })
310
- );
311
- }
@@ -1,184 +0,0 @@
1
- import type { McpServer } from '@modelcontextprotocol/server';
2
- import {
3
- DOCUMENT_INPUTS,
4
- type GeneratedDocumentType,
5
- PRODUCT_DOCUMENT_TYPES,
6
- type ProductDocumentType,
7
- REVIEWABLE_PRODUCT_DOCUMENT_TYPES,
8
- SETUP_REQUIRED_DOCUMENT_TYPES,
9
- } from '@taiga/types';
10
- import { z } from 'zod';
11
- import type { TaigaClient } from '../client.js';
12
- import { OPERATE, WRITE } from './annotations.js';
13
- import { type DocumentScope, publishDraft, sectionContentInput, sectionIdFrom, updateSection } from './documents.js';
14
- import { runTool, toolError, toolResult } from './errors.js';
15
- import { productId } from './inputs.js';
16
- import { jobReport } from './jobs.js';
17
-
18
- /**
19
- * A product's own documents (docs.tai.ga, Learn: Product documents): drafts,
20
- * versions and publishing on the plan timeline, the side people and the
21
- * discovery agents write. A draft changes nothing downstream until it is
22
- * published; documents generated from one that changed are marked outdated
23
- * and regenerated, never rewritten in place; and finishing Discovery locks
24
- * the set, which the API enforces. The reality timeline is derived from the
25
- * code and is not edited.
26
- */
27
-
28
- /** The plan-side documents people edit; the codebase snapshot is derived from the code, never written. */
29
- type EditableType = Exclude<ProductDocumentType, 'codebase_snapshot'>;
30
- const EDITABLE_TYPES = PRODUCT_DOCUMENT_TYPES.filter((type): type is EditableType => type !== 'codebase_snapshot') as [
31
- EditableType,
32
- ...EditableType[],
33
- ];
34
-
35
- const documentType = z
36
- .enum(EDITABLE_TYPES)
37
- .describe('Document type -- taiga_get_product_document without type shows which ones the product has');
38
-
39
- /** The documents a person reviews: the discovery chain, not the snapshot or the product's own instructions. */
40
- const reviewableType = z
41
- .enum(REVIEWABLE_PRODUCT_DOCUMENT_TYPES)
42
- .describe('Document type -- one of the discovery documents a person reviews');
43
-
44
- /** The documents an agent writes from other documents; the same table the worker reads its inputs from. */
45
- const generatedType = z
46
- .enum(Object.keys(DOCUMENT_INPUTS) as [GeneratedDocumentType, ...GeneratedDocumentType[]])
47
- .describe('Document type -- one generated from the documents above it');
48
-
49
- export function registerProductDocumentWrites(server: McpServer, client: TaigaClient) {
50
- if (!client.hasCapability('products:write')) return;
51
- // The section edit reads the draft and the published version, and the
52
- // regenerate reads the product's Discovery state, before they write.
53
- const canRead = client.hasCapability('products:read');
54
-
55
- const productScope = (product: string, type: string): DocumentScope => ({
56
- getDraft: () => client.getProductDocumentDraft(product, type),
57
- getPublished: () => client.getProductDocument(product, type, 'plan'),
58
- saveDraft: (data) => client.saveProductDocumentDraft(product, type, { data }),
59
- publish: () => client.publishProductDocument(product, type),
60
- });
61
-
62
- if (canRead) {
63
- server.registerTool(
64
- 'taiga_update_product_document',
65
- {
66
- title: 'Update a section of a product document draft',
67
- description:
68
- "Replace one section's text in a plan-timeline product document's draft; other sections stay. Agents " +
69
- 'read the published version until taiga_publish_product_document. Refused once Discovery is finished and ' +
70
- 'the set is locked (reopen it with taiga_reopen_discovery or in the web). Reality documents come from ' +
71
- 'the code and are not edited.',
72
- inputSchema: z.object({
73
- productId,
74
- type: documentType,
75
- sectionId: sectionIdFrom('taiga_get_product_document (the plan timeline)'),
76
- content: sectionContentInput,
77
- }),
78
- annotations: WRITE,
79
- },
80
- (params) =>
81
- runTool(() =>
82
- updateSection(productScope(params.productId, params.type), params.type, params.sectionId, params.content)
83
- )
84
- );
85
- }
86
-
87
- server.registerTool(
88
- 'taiga_publish_product_document',
89
- {
90
- title: 'Publish a product document draft',
91
- description:
92
- "Publish a product document's draft as its new version, the one agents work from. Documents generated " +
93
- 'from it are marked outdated, not rewritten; regenerate them with taiga_regenerate_product_document, or ' +
94
- 'taiga_generate_product_documents for every outdated and missing one.',
95
- inputSchema: z.object({ productId, type: documentType }),
96
- annotations: OPERATE,
97
- },
98
- (params) => runTool(() => publishDraft(productScope(params.productId, params.type)))
99
- );
100
-
101
- server.registerTool(
102
- 'taiga_mark_product_document_reviewed',
103
- {
104
- title: 'Mark a product document reviewed',
105
- description:
106
- "Record that a person reviewed a product document's latest published version. Once every published " +
107
- "document is reviewed, the product's review item in Action Required resolves. Only when the person says " +
108
- 'they read it; your own reading is not a review.',
109
- inputSchema: z.object({ productId, type: reviewableType }),
110
- annotations: OPERATE,
111
- },
112
- (params) =>
113
- runTool(async () => toolResult((await client.markProductDocumentReviewed(params.productId, params.type)).data))
114
- );
115
-
116
- if (canRead) {
117
- server.registerTool(
118
- 'taiga_regenerate_product_document',
119
- {
120
- title: 'Regenerate a product document',
121
- description:
122
- 'Regenerate one product document from the documents it derives from, when it is outdated or needs ' +
123
- 'another pass, and return the job. The result is published and documents derived from it are marked ' +
124
- 'outdated. The Specification (from the Discovery conversation) and the Look & Feel (from its concepts) ' +
125
- 'are made in the web. Documents Discovery requires regenerate only while Discovery is open; the optional ' +
126
- 'Service Blueprint any time. taiga_wait_for_job says when it is done.',
127
- inputSchema: z.object({ productId, type: generatedType }),
128
- annotations: OPERATE,
129
- },
130
- (params) =>
131
- runTool(async () => {
132
- // The lock guards the draft and publish routes; a generated document
133
- // is published by the worker directly, so the check is made here.
134
- // It holds the documents setup requires, as the API's lock does; the
135
- // optional blueprint stays open after setup.
136
- const locked = (SETUP_REQUIRED_DOCUMENT_TYPES as readonly string[]).includes(params.type);
137
- const product = locked ? ((await client.getProduct(params.productId)).data as { status?: unknown }) : null;
138
- if (product && product.status !== 'draft') {
139
- return toolError(
140
- 'CONFLICT',
141
- 'Discovery is finished for this product, so its documents are locked. Reopen Discovery in the web to regenerate one.'
142
- );
143
- }
144
- const job = (
145
- await client.createAgentJob({
146
- scope: 'product',
147
- type: 'generate_document',
148
- targetId: params.productId,
149
- documentType: params.type,
150
- })
151
- ).data;
152
- return toolResult(jobReport(job));
153
- })
154
- );
155
- }
156
-
157
- server.registerTool(
158
- 'taiga_generate_product_documents',
159
- {
160
- title: 'Generate the remaining product documents',
161
- description:
162
- 'Generate every missing or outdated product document (Generate remaining in the web), one after another ' +
163
- 'in the order they build on each other; on an imported product, every unpublished one. Returns the jobs ' +
164
- 'it started (jobIds). Refused (CONFLICT) while a document is already being generated. ' +
165
- 'taiga_stop_generating_documents stops it.',
166
- inputSchema: z.object({ productId }),
167
- annotations: OPERATE,
168
- },
169
- (params) => runTool(async () => toolResult((await client.generateRemainingDocuments(params.productId)).data))
170
- );
171
-
172
- server.registerTool(
173
- 'taiga_stop_generating_documents',
174
- {
175
- title: 'Stop generating product documents',
176
- description:
177
- 'Stop a Generate remaining run (taiga_generate_product_documents): documents still being generated are ' +
178
- 'cancelled and nothing after them starts; published ones stay. An empty list means none was running.',
179
- inputSchema: z.object({ productId }),
180
- annotations: OPERATE,
181
- },
182
- (params) => runTool(async () => toolResult((await client.stopGeneratingDocuments(params.productId)).data))
183
- );
184
- }