@taiga-ai/mcp-server 0.6.0-rc.393 → 0.7.0-dev.395
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/dist/index.js +1151 -128
- package/package.json +1 -1
- package/src/client.test.ts +19 -0
- package/src/client.ts +11 -3
- package/src/config.test.ts +1 -1
- package/src/config.ts +4 -1
- package/src/index.ts +3 -30
- package/src/server.integration.test.ts +644 -9
- package/src/tools/catalogue.test.ts +109 -0
- package/src/tools/catalogue.ts +165 -0
- package/src/tools/documents.ts +115 -35
- package/src/tools/instructions.ts +65 -0
- package/src/tools/products.ts +234 -43
- package/src/tools/sections.test.ts +34 -1
- package/src/tools/sections.ts +23 -1
- package/src/tools/summarize.ts +3 -34
- package/taiga-ai-mcp-server-0.7.0-dev.395.tgz +0 -0
- package/src/tools/inputs.test.ts +0 -19
- package/src/tools/inputs.ts +0 -13
- package/taiga-ai-mcp-server-0.6.0-rc.393.tgz +0 -0
package/package.json
CHANGED
package/src/client.test.ts
CHANGED
|
@@ -338,6 +338,25 @@ describe('TaigaClient', () => {
|
|
|
338
338
|
expect(url.searchParams.get('repositoryHost')).toBe('https://github.com');
|
|
339
339
|
});
|
|
340
340
|
|
|
341
|
+
it('should read a product document from the asked timeline and list one timeline at a time', async () => {
|
|
342
|
+
const spy = stubFetch(200, { data: [] });
|
|
343
|
+
const client = makeClient();
|
|
344
|
+
|
|
345
|
+
await client.getProductDocument('p1', 'architecture', 'reality');
|
|
346
|
+
await client.getProductDocument('p1', 'architecture');
|
|
347
|
+
await client.listProductDocuments('p1', { origin: 'reality', limit: 100 });
|
|
348
|
+
|
|
349
|
+
const paths = spy.mock.calls.map((c) => {
|
|
350
|
+
const url = new URL(c[0] as string);
|
|
351
|
+
return url.pathname + url.search;
|
|
352
|
+
});
|
|
353
|
+
expect(paths).toEqual([
|
|
354
|
+
'/v1/products/p1/documents/architecture?origin=reality',
|
|
355
|
+
'/v1/products/p1/documents/architecture',
|
|
356
|
+
'/v1/products/p1/documents?origin=reality&limit=100',
|
|
357
|
+
]);
|
|
358
|
+
});
|
|
359
|
+
|
|
341
360
|
it('should GET a single backlog item by id (flat path)', async () => {
|
|
342
361
|
const spy = stubFetch(200, { data: { id: 'item-1' } });
|
|
343
362
|
|
package/src/client.ts
CHANGED
|
@@ -137,6 +137,7 @@ export class TaigaClient {
|
|
|
137
137
|
async listProducts(opts?: {
|
|
138
138
|
factoryId?: string | undefined;
|
|
139
139
|
status?: string | undefined;
|
|
140
|
+
slug?: string | undefined;
|
|
140
141
|
repository?: string | undefined;
|
|
141
142
|
repositoryHost?: string | undefined;
|
|
142
143
|
limit?: number | undefined;
|
|
@@ -145,6 +146,7 @@ export class TaigaClient {
|
|
|
145
146
|
const params = new URLSearchParams();
|
|
146
147
|
if (opts?.factoryId) params.set('factoryId', opts.factoryId);
|
|
147
148
|
if (opts?.status) params.set('status', opts.status);
|
|
149
|
+
if (opts?.slug) params.set('slug', opts.slug);
|
|
148
150
|
if (opts?.repository) params.set('repository', opts.repository);
|
|
149
151
|
if (opts?.repositoryHost) params.set('repositoryHost', opts.repositoryHost);
|
|
150
152
|
if (opts?.limit) params.set('limit', String(opts.limit));
|
|
@@ -230,8 +232,9 @@ export class TaigaClient {
|
|
|
230
232
|
// Product Documents
|
|
231
233
|
// ---------------------------------------------------------------------------
|
|
232
234
|
|
|
233
|
-
async listProductDocuments(productId: string, opts?: { limit?: number | undefined }) {
|
|
235
|
+
async listProductDocuments(productId: string, opts?: { origin?: string | undefined; limit?: number | undefined }) {
|
|
234
236
|
const params = new URLSearchParams();
|
|
237
|
+
if (opts?.origin) params.set('origin', opts.origin);
|
|
235
238
|
if (opts?.limit) params.set('limit', String(opts.limit));
|
|
236
239
|
const qs = params.toString();
|
|
237
240
|
return this.request<{ data: unknown[]; nextCursor: string | null }>(
|
|
@@ -240,8 +243,9 @@ export class TaigaClient {
|
|
|
240
243
|
);
|
|
241
244
|
}
|
|
242
245
|
|
|
243
|
-
async getProductDocument(productId: string, type: string) {
|
|
244
|
-
|
|
246
|
+
async getProductDocument(productId: string, type: string, origin?: string) {
|
|
247
|
+
const qs = origin ? `?${new URLSearchParams({ origin })}` : '';
|
|
248
|
+
return this.request<{ data: unknown }>('GET', `/products/${seg(productId)}/documents/${seg(type)}${qs}`);
|
|
245
249
|
}
|
|
246
250
|
|
|
247
251
|
// ---------------------------------------------------------------------------
|
|
@@ -307,6 +311,10 @@ export class TaigaClient {
|
|
|
307
311
|
// Factories
|
|
308
312
|
// ---------------------------------------------------------------------------
|
|
309
313
|
|
|
314
|
+
async getFactory(id: string) {
|
|
315
|
+
return this.request<{ data: unknown }>('GET', `/factories/${seg(id)}`);
|
|
316
|
+
}
|
|
317
|
+
|
|
310
318
|
async listFactories(opts?: { limit?: number | undefined }) {
|
|
311
319
|
const params = new URLSearchParams();
|
|
312
320
|
if (opts?.limit) params.set('limit', String(opts.limit));
|
package/src/config.test.ts
CHANGED
|
@@ -17,7 +17,7 @@ describe('readConfig', () => {
|
|
|
17
17
|
it('defaults the API URL', () => {
|
|
18
18
|
vi.stubEnv('TAIGA_API_KEY', 'taiga_sk_live_test');
|
|
19
19
|
vi.stubEnv('TAIGA_API_URL', undefined);
|
|
20
|
-
expect(readConfig()).toEqual({ apiKey: 'taiga_sk_live_test', apiUrl: 'https://api.
|
|
20
|
+
expect(readConfig()).toEqual({ apiKey: 'taiga_sk_live_test', apiUrl: 'https://api.eu.tai.ga' });
|
|
21
21
|
vi.stubEnv('TAIGA_API_URL', 'http://localhost:3001');
|
|
22
22
|
expect(readConfig()?.apiUrl).toBe('http://localhost:3001');
|
|
23
23
|
});
|
package/src/config.ts
CHANGED
|
@@ -5,7 +5,10 @@ import { z } from 'zod';
|
|
|
5
5
|
* at startup.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
// The production API behind the custom domain in infra/dns.tf. The old
|
|
9
|
+
// default, api.taiga.app, never resolved, so every install that followed the
|
|
10
|
+
// README without TAIGA_API_URL failed on its first call.
|
|
11
|
+
const DEFAULT_API_URL = 'https://api.eu.tai.ga';
|
|
9
12
|
|
|
10
13
|
const envSchema = z.object({
|
|
11
14
|
TAIGA_API_KEY: z.string().min(1),
|
package/src/index.ts
CHANGED
|
@@ -5,13 +5,14 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
|
5
5
|
import { TaigaClient } from './client.js';
|
|
6
6
|
import { readConfig } from './config.js';
|
|
7
7
|
import { registerAllTools } from './tools/index.js';
|
|
8
|
+
import { SERVER_INSTRUCTIONS } from './tools/instructions.js';
|
|
8
9
|
import { SERVER_VERSION } from './version.js';
|
|
9
10
|
|
|
10
11
|
async function main() {
|
|
11
12
|
const config = readConfig();
|
|
12
13
|
if (!config) {
|
|
13
14
|
console.error('Error: TAIGA_API_KEY environment variable is required.');
|
|
14
|
-
console.error('Create
|
|
15
|
+
console.error('Create one at https://eu.tai.ga under Settings > Account > API keys.');
|
|
15
16
|
process.exit(1);
|
|
16
17
|
}
|
|
17
18
|
|
|
@@ -32,35 +33,7 @@ async function main() {
|
|
|
32
33
|
version: SERVER_VERSION,
|
|
33
34
|
},
|
|
34
35
|
{
|
|
35
|
-
instructions:
|
|
36
|
-
'You have access to Taiga -- a policy-aware software development platform.',
|
|
37
|
-
"Taiga provides your organization's engineering knowledge base:",
|
|
38
|
-
'',
|
|
39
|
-
'**Company policies** (taiga_list_documents / taiga_get_document):',
|
|
40
|
-
'Security, data privacy, SDLC, architecture, and compliance rules that apply to all code.',
|
|
41
|
-
'Read the relevant policy BEFORE writing code that touches security, data handling, or infrastructure.',
|
|
42
|
-
'',
|
|
43
|
-
'**Factory instructions** (taiga_list_factory_documents / taiga_get_factory_document):',
|
|
44
|
-
"A factory's standing guidance: domain context (ubiquitous language, entities, business rules),",
|
|
45
|
-
'tech preferences (approved stack, patterns), and conventions. Read these to understand HOW this factory builds software.',
|
|
46
|
-
'',
|
|
47
|
-
'**Product documents** (taiga_list_product_documents / taiga_get_product_document):',
|
|
48
|
-
"Specification (what to build), architecture (how it's designed), threat model (security risks),",
|
|
49
|
-
'technology decisions, and data flow. Read these to understand the specific product.',
|
|
50
|
-
'',
|
|
51
|
-
'**Backlog and runs** (taiga_list_backlog_items / taiga_get_backlog_item / taiga_list_builds / taiga_get_build):',
|
|
52
|
-
"The product's initiatives with their acceptance criteria, and what Taiga's coding agent already built",
|
|
53
|
-
'for them: runs, steps, commits and pull requests.',
|
|
54
|
-
'',
|
|
55
|
-
'Workflow: Inside a git checkout, start with taiga_resolve_product on the remote URL to find the product.',
|
|
56
|
-
'Otherwise use taiga_list_factories and taiga_list_products. Then read the factory instructions,',
|
|
57
|
-
"the product's specification and architecture, and the backlog item you are working on.",
|
|
58
|
-
'',
|
|
59
|
-
'When you notice a policy or factory instructions are outdated, fix the section with',
|
|
60
|
-
'taiga_update_document or taiga_update_factory_document. That saves a draft nobody follows yet;',
|
|
61
|
-
'publish it with taiga_publish_document or taiga_publish_factory_document only when the person asks.',
|
|
62
|
-
'This keeps the knowledge base accurate for everyone.',
|
|
63
|
-
].join('\n'),
|
|
36
|
+
instructions: SERVER_INSTRUCTIONS,
|
|
64
37
|
}
|
|
65
38
|
);
|
|
66
39
|
|