@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taiga-ai/mcp-server",
3
- "version": "0.6.0-rc.393",
3
+ "version": "0.7.0-dev.395",
4
4
  "description": "MCP server for Taiga -- gives AI assistants access to documents and products",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -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
- return this.request<{ data: unknown }>('GET', `/products/${seg(productId)}/documents/${seg(type)}`);
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));
@@ -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.taiga.app' });
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
- const DEFAULT_API_URL = 'https://api.taiga.app';
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 an API key at https://app.taiga.app/settings/api-keys');
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