@taiga-ai/mcp-server 0.0.1-rc.71 → 0.0.1-rc.72
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/client.d.ts +36 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +102 -0
- package/dist/index.js +30 -1
- package/dist/server.integration.test.js +66 -56
- package/dist/tools/backlogs.d.ts +1 -1
- package/dist/tools/backlogs.d.ts.map +1 -1
- package/dist/tools/backlogs.js +5 -32
- package/dist/tools/documents.d.ts.map +1 -1
- package/dist/tools/documents.js +74 -12
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +3 -0
- package/dist/tools/projects.d.ts.map +1 -1
- package/dist/tools/projects.js +46 -15
- package/dist/tools/skills.d.ts.map +1 -1
- package/dist/tools/skills.js +30 -10
- package/dist/tools/summarize.d.ts +15 -0
- package/dist/tools/summarize.d.ts.map +1 -0
- package/dist/tools/summarize.js +26 -0
- package/package.json +2 -2
- package/src/client.ts +130 -0
- package/src/index.ts +37 -5
- package/src/server.integration.test.ts +68 -56
- package/src/tools/backlogs.ts +6 -49
- package/src/tools/documents.ts +101 -9
- package/src/tools/index.ts +3 -0
- package/src/tools/projects.ts +57 -14
- package/src/tools/skills.ts +37 -8
- package/src/tools/summarize.ts +30 -0
package/dist/client.d.ts
CHANGED
|
@@ -40,6 +40,29 @@ export declare class TaigaClient {
|
|
|
40
40
|
}): Promise<{
|
|
41
41
|
data: unknown;
|
|
42
42
|
}>;
|
|
43
|
+
listTeamDocuments(teamId: string, opts?: {
|
|
44
|
+
limit?: number;
|
|
45
|
+
}): Promise<{
|
|
46
|
+
data: unknown[];
|
|
47
|
+
nextCursor: string | null;
|
|
48
|
+
}>;
|
|
49
|
+
getTeamDocument(teamId: string, type: string): Promise<{
|
|
50
|
+
data: unknown;
|
|
51
|
+
}>;
|
|
52
|
+
saveTeamDocumentDraft(teamId: string, type: string, body: {
|
|
53
|
+
data: Record<string, unknown>;
|
|
54
|
+
}): Promise<{
|
|
55
|
+
data: unknown;
|
|
56
|
+
}>;
|
|
57
|
+
listProjectDocuments(projectId: string, opts?: {
|
|
58
|
+
limit?: number;
|
|
59
|
+
}): Promise<{
|
|
60
|
+
data: unknown[];
|
|
61
|
+
nextCursor: string | null;
|
|
62
|
+
}>;
|
|
63
|
+
getProjectDocument(projectId: string, type: string): Promise<{
|
|
64
|
+
data: unknown;
|
|
65
|
+
}>;
|
|
43
66
|
listSkills(opts?: {
|
|
44
67
|
scope?: string;
|
|
45
68
|
scopeId?: string;
|
|
@@ -51,6 +74,19 @@ export declare class TaigaClient {
|
|
|
51
74
|
getSkill(id: string): Promise<{
|
|
52
75
|
data: unknown;
|
|
53
76
|
}>;
|
|
77
|
+
updateSkill(id: string, body: {
|
|
78
|
+
name?: string;
|
|
79
|
+
description?: string;
|
|
80
|
+
content?: string;
|
|
81
|
+
}): Promise<{
|
|
82
|
+
data: unknown;
|
|
83
|
+
}>;
|
|
84
|
+
/**
|
|
85
|
+
* Fetch the full context for a project in parallel: project metadata,
|
|
86
|
+
* team documents, project documents, and team skills.
|
|
87
|
+
* Returns a structured bundle optimized for coding agent consumption.
|
|
88
|
+
*/
|
|
89
|
+
getProjectContext(projectId: string): Promise<Record<string, unknown>>;
|
|
54
90
|
listBacklogItems(projectId: string, opts?: {
|
|
55
91
|
limit?: number;
|
|
56
92
|
}): Promise<{
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,aAAa,CAAoC;gBAE7C,IAAI,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;YAKvC,OAAO;IA0Bf,UAAU,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAMhD,gBAAgB,IAAI,mBAAmB,GAAG,IAAI;IAI9C,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IASpC,YAAY,CAAC,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;cAMhD,OAAO,EAAE;oBAAc,MAAM,GAAG,IAAI;;IAG5D,UAAU,CAAC,EAAE,EAAE,MAAM;cACG,OAAO;;IAO/B,mBAAmB,CAAC,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;cAIrB,OAAO,EAAE;oBAAc,MAAM,GAAG,IAAI;;IAM5D,iBAAiB,CAAC,IAAI,EAAE,MAAM;cACN,OAAO;;IAG/B,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE;cACrD,OAAO;;IAO/B,UAAU,CAAC,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE;cAM9C,OAAO,EAAE;oBAAc,MAAM,GAAG,IAAI;;IAG5D,QAAQ,CAAC,EAAE,EAAE,MAAM;cACK,OAAO;;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
CHANGED
|
@@ -78,6 +78,35 @@ export class TaigaClient {
|
|
|
78
78
|
return this.request('PUT', `/tenants/current/documents/${type}/draft`, body);
|
|
79
79
|
}
|
|
80
80
|
// ---------------------------------------------------------------------------
|
|
81
|
+
// Team Documents
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
async listTeamDocuments(teamId, opts) {
|
|
84
|
+
const params = new URLSearchParams();
|
|
85
|
+
if (opts?.limit)
|
|
86
|
+
params.set('limit', String(opts.limit));
|
|
87
|
+
const qs = params.toString();
|
|
88
|
+
return this.request('GET', `/teams/${teamId}/documents${qs ? `?${qs}` : ''}`);
|
|
89
|
+
}
|
|
90
|
+
async getTeamDocument(teamId, type) {
|
|
91
|
+
return this.request('GET', `/teams/${teamId}/documents/${type}`);
|
|
92
|
+
}
|
|
93
|
+
async saveTeamDocumentDraft(teamId, type, body) {
|
|
94
|
+
return this.request('PUT', `/teams/${teamId}/documents/${type}/draft`, body);
|
|
95
|
+
}
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// Project Documents
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
async listProjectDocuments(projectId, opts) {
|
|
100
|
+
const params = new URLSearchParams();
|
|
101
|
+
if (opts?.limit)
|
|
102
|
+
params.set('limit', String(opts.limit));
|
|
103
|
+
const qs = params.toString();
|
|
104
|
+
return this.request('GET', `/projects/${projectId}/documents${qs ? `?${qs}` : ''}`);
|
|
105
|
+
}
|
|
106
|
+
async getProjectDocument(projectId, type) {
|
|
107
|
+
return this.request('GET', `/projects/${projectId}/documents/${type}`);
|
|
108
|
+
}
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
81
110
|
// Skills (agent skills)
|
|
82
111
|
// ---------------------------------------------------------------------------
|
|
83
112
|
async listSkills(opts) {
|
|
@@ -94,6 +123,79 @@ export class TaigaClient {
|
|
|
94
123
|
async getSkill(id) {
|
|
95
124
|
return this.request('GET', `/agent-skills/${id}`);
|
|
96
125
|
}
|
|
126
|
+
async updateSkill(id, body) {
|
|
127
|
+
return this.request('PATCH', `/agent-skills/${id}`, body);
|
|
128
|
+
}
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// Team Documents
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
/**
|
|
133
|
+
* Fetch the full context for a project in parallel: project metadata,
|
|
134
|
+
* team documents, project documents, and team skills.
|
|
135
|
+
* Returns a structured bundle optimized for coding agent consumption.
|
|
136
|
+
*/
|
|
137
|
+
async getProjectContext(projectId) {
|
|
138
|
+
// First fetch the project to get the teamId
|
|
139
|
+
const project = await this.request('GET', `/projects/${projectId}`);
|
|
140
|
+
const teamId = project.data.teamId;
|
|
141
|
+
// Fetch everything in parallel
|
|
142
|
+
const [projectDocs, teamDocs, skills] = await Promise.all([
|
|
143
|
+
this.listProjectDocuments(projectId, { limit: 20 }).catch(() => ({ data: [] })),
|
|
144
|
+
teamId
|
|
145
|
+
? this.listTeamDocuments(teamId, { limit: 20 }).catch(() => ({ data: [] }))
|
|
146
|
+
: Promise.resolve({ data: [] }),
|
|
147
|
+
this.listSkills({ limit: 100 }).catch(() => ({ data: [] })),
|
|
148
|
+
]);
|
|
149
|
+
// Fetch full content for key documents (in parallel)
|
|
150
|
+
const keyProjectDocTypes = ['specification', 'architecture', 'technology_decisions'];
|
|
151
|
+
const keyTeamDocTypes = ['domain_context', 'tech_preferences', 'architecture_constraints'];
|
|
152
|
+
const docFetches = [];
|
|
153
|
+
for (const docType of keyProjectDocTypes) {
|
|
154
|
+
const exists = projectDocs.data.some((d) => d.type === docType && !d.isDraft);
|
|
155
|
+
if (exists) {
|
|
156
|
+
docFetches.push(this.getProjectDocument(projectId, docType)
|
|
157
|
+
.then((r) => ({ type: docType, scope: 'project', data: r.data }))
|
|
158
|
+
.catch(() => ({ type: docType, scope: 'project', data: null })));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (teamId) {
|
|
162
|
+
for (const docType of keyTeamDocTypes) {
|
|
163
|
+
const exists = teamDocs.data.some((d) => d.type === docType && !d.isDraft);
|
|
164
|
+
if (exists) {
|
|
165
|
+
docFetches.push(this.getTeamDocument(teamId, docType)
|
|
166
|
+
.then((r) => ({ type: docType, scope: 'team', data: r.data }))
|
|
167
|
+
.catch(() => ({ type: docType, scope: 'team', data: null })));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const fetchedDocs = await Promise.all(docFetches);
|
|
172
|
+
// Assemble context bundle
|
|
173
|
+
const context = {
|
|
174
|
+
project: project.data,
|
|
175
|
+
documents: {
|
|
176
|
+
project: Object.fromEntries(fetchedDocs.filter((d) => d.scope === 'project' && d.data).map((d) => [d.type, d.data])),
|
|
177
|
+
team: Object.fromEntries(fetchedDocs.filter((d) => d.scope === 'team' && d.data).map((d) => [d.type, d.data])),
|
|
178
|
+
},
|
|
179
|
+
available_documents: {
|
|
180
|
+
project: projectDocs.data.map((d) => ({
|
|
181
|
+
type: d.type,
|
|
182
|
+
name: d.name,
|
|
183
|
+
version: d.version,
|
|
184
|
+
isDraft: d.isDraft,
|
|
185
|
+
})),
|
|
186
|
+
team: teamDocs.data.map((d) => ({
|
|
187
|
+
type: d.type,
|
|
188
|
+
name: d.name,
|
|
189
|
+
version: d.version,
|
|
190
|
+
isDraft: d.isDraft,
|
|
191
|
+
})),
|
|
192
|
+
},
|
|
193
|
+
skills_summary: skills.data
|
|
194
|
+
.filter((s) => !s.teamId || s.teamId === teamId)
|
|
195
|
+
.map((s) => ({ id: s.id, name: s.name, slug: s.slug, description: s.description })),
|
|
196
|
+
};
|
|
197
|
+
return context;
|
|
198
|
+
}
|
|
97
199
|
// ---------------------------------------------------------------------------
|
|
98
200
|
// Backlog
|
|
99
201
|
// ---------------------------------------------------------------------------
|
package/dist/index.js
CHANGED
|
@@ -20,10 +20,39 @@ async function main() {
|
|
|
20
20
|
console.error('Check that your TAIGA_API_KEY is valid and not expired.');
|
|
21
21
|
process.exit(1);
|
|
22
22
|
});
|
|
23
|
-
// Create MCP server with dynamic tool registration
|
|
23
|
+
// Create MCP server with dynamic tool registration and instructions
|
|
24
24
|
const server = new McpServer({
|
|
25
25
|
name: 'taiga',
|
|
26
26
|
version: '0.0.1',
|
|
27
|
+
}, {
|
|
28
|
+
instructions: [
|
|
29
|
+
'You have access to Taiga -- a policy-aware software development platform.',
|
|
30
|
+
"Taiga provides your organization's engineering knowledge base:",
|
|
31
|
+
'',
|
|
32
|
+
'**Company policies** (taiga_list_documents / taiga_get_document):',
|
|
33
|
+
'Security, data privacy, SDLC, architecture, and compliance rules that apply to all code.',
|
|
34
|
+
'Read the relevant policy BEFORE writing code that touches security, data handling, or infrastructure.',
|
|
35
|
+
'',
|
|
36
|
+
'**Team documents** (taiga_list_team_documents / taiga_get_team_document):',
|
|
37
|
+
'Domain context (ubiquitous language, entities, business rules), tech preferences (approved stack, patterns),',
|
|
38
|
+
'architecture constraints, and SLO targets. Read these to understand HOW this team builds software.',
|
|
39
|
+
'',
|
|
40
|
+
'**Project documents** (taiga_list_project_documents / taiga_get_project_document):',
|
|
41
|
+
"Specification (what to build), architecture (how it's designed), threat model (security risks),",
|
|
42
|
+
'technology decisions, and data flow. Read these to understand the specific project context.',
|
|
43
|
+
'',
|
|
44
|
+
'**Skills** (taiga_list_skills / taiga_get_skill):',
|
|
45
|
+
'Coding standards, security requirements, API design patterns, testing strategy, database patterns,',
|
|
46
|
+
'and more. These are detailed engineering guidelines with code examples.',
|
|
47
|
+
'',
|
|
48
|
+
"Workflow: Start with taiga_list_teams to find your team, then read the team's domain_context",
|
|
49
|
+
'and tech_preferences. For project-specific work, use taiga_list_projects to find the project,',
|
|
50
|
+
'then read its specification and architecture. Use skills for coding patterns.',
|
|
51
|
+
'',
|
|
52
|
+
'When you notice a policy, skill, or team document is outdated, use the update tools',
|
|
53
|
+
'(taiga_update_document, taiga_update_skill, taiga_update_team_document) to fix it.',
|
|
54
|
+
'This keeps the knowledge base accurate for everyone.',
|
|
55
|
+
].join('\n'),
|
|
27
56
|
});
|
|
28
57
|
registerAllTools(server, client);
|
|
29
58
|
const toolCount = introspection.capabilities.length;
|
|
@@ -17,17 +17,19 @@ const ALL_CAPABILITIES = [
|
|
|
17
17
|
];
|
|
18
18
|
/** All tool names the server can register (sorted for deterministic comparison). */
|
|
19
19
|
const ALL_TOOL_NAMES = [
|
|
20
|
-
'taiga_get_backlog_item',
|
|
21
20
|
'taiga_get_document',
|
|
22
|
-
'
|
|
21
|
+
'taiga_get_project_document',
|
|
23
22
|
'taiga_get_skill',
|
|
24
|
-
'
|
|
23
|
+
'taiga_get_team_document',
|
|
25
24
|
'taiga_list_documents',
|
|
26
|
-
'
|
|
25
|
+
'taiga_list_project_documents',
|
|
27
26
|
'taiga_list_projects',
|
|
28
27
|
'taiga_list_skills',
|
|
28
|
+
'taiga_list_team_documents',
|
|
29
29
|
'taiga_list_teams',
|
|
30
30
|
'taiga_update_document',
|
|
31
|
+
'taiga_update_skill',
|
|
32
|
+
'taiga_update_team_document',
|
|
31
33
|
];
|
|
32
34
|
function makeFetchRouter(routes) {
|
|
33
35
|
return vi.fn().mockImplementation(async (url, init) => {
|
|
@@ -110,7 +112,7 @@ describe('MCP server integration', () => {
|
|
|
110
112
|
// the API key's capabilities. This is the primary security contract.
|
|
111
113
|
// -------------------------------------------------------------------------
|
|
112
114
|
describe('tool discovery', () => {
|
|
113
|
-
it('should expose all
|
|
115
|
+
it('should expose all 13 tools when API key has full capabilities', async () => {
|
|
114
116
|
const { client } = await bootMcpPair({ capabilities: ALL_CAPABILITIES });
|
|
115
117
|
const { tools } = await client.listTools();
|
|
116
118
|
expect(toolNames(tools)).toEqual(ALL_TOOL_NAMES);
|
|
@@ -122,15 +124,15 @@ describe('MCP server integration', () => {
|
|
|
122
124
|
const { client } = await bootMcpPair({ capabilities: [] });
|
|
123
125
|
await expect(client.listTools()).rejects.toThrow(/Method not found/);
|
|
124
126
|
});
|
|
125
|
-
it('should expose only
|
|
126
|
-
const { client } = await bootMcpPair({ capabilities: ['
|
|
127
|
+
it('should expose only team tools for a teams:read-only key', async () => {
|
|
128
|
+
const { client } = await bootMcpPair({ capabilities: ['teams:read'] });
|
|
127
129
|
const { tools } = await client.listTools();
|
|
128
130
|
const names = toolNames(tools);
|
|
129
|
-
expect(names).toContain('
|
|
130
|
-
expect(names).toContain('
|
|
131
|
-
expect(names).toContain('
|
|
132
|
-
expect(names).not.toContain('taiga_list_teams');
|
|
131
|
+
expect(names).toContain('taiga_list_teams');
|
|
132
|
+
expect(names).toContain('taiga_list_team_documents');
|
|
133
|
+
expect(names).toContain('taiga_get_team_document');
|
|
133
134
|
expect(names).not.toContain('taiga_list_documents');
|
|
135
|
+
expect(names).not.toContain('taiga_update_document');
|
|
134
136
|
});
|
|
135
137
|
it('should expose read-only document tools without write capability', async () => {
|
|
136
138
|
const { client } = await bootMcpPair({ capabilities: ['tenant:documents:read'] });
|
|
@@ -142,35 +144,39 @@ describe('MCP server integration', () => {
|
|
|
142
144
|
expect(names).toContain('taiga_get_skill');
|
|
143
145
|
expect(names).not.toContain('taiga_update_document');
|
|
144
146
|
});
|
|
145
|
-
it('should expose
|
|
147
|
+
it('should expose write tools when documents:write is also granted', async () => {
|
|
146
148
|
const { client } = await bootMcpPair({
|
|
147
149
|
capabilities: ['tenant:documents:read', 'tenant:documents:write'],
|
|
148
150
|
});
|
|
149
151
|
const { tools } = await client.listTools();
|
|
150
|
-
|
|
152
|
+
const names = toolNames(tools);
|
|
153
|
+
expect(names).toContain('taiga_update_document');
|
|
154
|
+
expect(names).toContain('taiga_update_skill');
|
|
151
155
|
});
|
|
152
|
-
it('should expose
|
|
153
|
-
const { client } = await bootMcpPair({
|
|
156
|
+
it('should expose team document write when both teams:read and documents:write are granted', async () => {
|
|
157
|
+
const { client } = await bootMcpPair({
|
|
158
|
+
capabilities: ['teams:read', 'tenant:documents:write'],
|
|
159
|
+
});
|
|
154
160
|
const { tools } = await client.listTools();
|
|
155
161
|
const names = toolNames(tools);
|
|
156
|
-
expect(names).toContain('
|
|
157
|
-
expect(names).toContain('
|
|
158
|
-
expect(names).not.toContain('taiga_list_environments');
|
|
162
|
+
expect(names).toContain('taiga_update_team_document');
|
|
163
|
+
expect(names).toContain('taiga_list_teams');
|
|
159
164
|
});
|
|
160
165
|
it('should combine capabilities additively', async () => {
|
|
161
166
|
const { client } = await bootMcpPair({
|
|
162
|
-
capabilities: ['
|
|
167
|
+
capabilities: ['teams:read', 'tenant:documents:read'],
|
|
163
168
|
});
|
|
164
169
|
const { tools } = await client.listTools();
|
|
165
170
|
const names = toolNames(tools);
|
|
166
|
-
//
|
|
167
|
-
expect(names).toContain('
|
|
168
|
-
expect(names).toContain('
|
|
169
|
-
//
|
|
170
|
-
expect(names).toContain('
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
expect(names).not.toContain('
|
|
171
|
+
// teams:read tools present
|
|
172
|
+
expect(names).toContain('taiga_list_teams');
|
|
173
|
+
expect(names).toContain('taiga_list_team_documents');
|
|
174
|
+
// tenant:documents:read tools present
|
|
175
|
+
expect(names).toContain('taiga_list_documents');
|
|
176
|
+
expect(names).toContain('taiga_list_skills');
|
|
177
|
+
// write tools absent
|
|
178
|
+
expect(names).not.toContain('taiga_update_document');
|
|
179
|
+
expect(names).not.toContain('taiga_update_skill');
|
|
174
180
|
});
|
|
175
181
|
it('should provide a description and input schema for every tool', async () => {
|
|
176
182
|
const { client } = await bootMcpPair({ capabilities: ALL_CAPABILITIES });
|
|
@@ -189,11 +195,10 @@ describe('MCP server integration', () => {
|
|
|
189
195
|
// -------------------------------------------------------------------------
|
|
190
196
|
describe('capability-tool contract', () => {
|
|
191
197
|
const CONTRACT = {
|
|
192
|
-
'projects:read': ['taiga_list_projects', '
|
|
193
|
-
'teams:read': ['taiga_list_teams'],
|
|
198
|
+
'projects:read': ['taiga_list_projects', 'taiga_list_project_documents', 'taiga_get_project_document'],
|
|
199
|
+
'teams:read': ['taiga_list_teams', 'taiga_list_team_documents', 'taiga_get_team_document'],
|
|
194
200
|
'tenant:documents:read': ['taiga_list_documents', 'taiga_get_document', 'taiga_list_skills', 'taiga_get_skill'],
|
|
195
|
-
'tenant:documents:write': ['taiga_update_document'],
|
|
196
|
-
'backlog:read': ['taiga_list_backlog_items', 'taiga_get_backlog_item'],
|
|
201
|
+
'tenant:documents:write': ['taiga_update_document', 'taiga_update_skill'],
|
|
197
202
|
};
|
|
198
203
|
for (const [capability, expectedTools] of Object.entries(CONTRACT)) {
|
|
199
204
|
it(`${capability} should gate: ${expectedTools.join(', ')}`, async () => {
|
|
@@ -212,31 +217,33 @@ describe('MCP server integration', () => {
|
|
|
212
217
|
// -> (mocked) API -> response back through MCP protocol.
|
|
213
218
|
// -------------------------------------------------------------------------
|
|
214
219
|
describe('tool execution', () => {
|
|
215
|
-
it('should return
|
|
216
|
-
const
|
|
217
|
-
{ id: '
|
|
218
|
-
{ id: '
|
|
220
|
+
it('should return team list as JSON text content', async () => {
|
|
221
|
+
const teams = [
|
|
222
|
+
{ id: 't1', name: 'Product' },
|
|
223
|
+
{ id: 't2', name: 'Platform' },
|
|
219
224
|
];
|
|
220
225
|
const { client } = await bootMcpPair({
|
|
221
226
|
capabilities: ALL_CAPABILITIES,
|
|
222
|
-
routes: { 'GET /v1/
|
|
227
|
+
routes: { 'GET /v1/teams': { data: teams, nextCursor: null } },
|
|
223
228
|
});
|
|
224
|
-
const result = await client.callTool({ name: '
|
|
229
|
+
const result = await client.callTool({ name: 'taiga_list_teams', arguments: {} });
|
|
225
230
|
expect(result.content).toHaveLength(1);
|
|
226
|
-
expect(parseToolResult(result)).toEqual(
|
|
231
|
+
expect(parseToolResult(result)).toEqual(teams);
|
|
227
232
|
});
|
|
228
|
-
it('should
|
|
229
|
-
const
|
|
230
|
-
const
|
|
231
|
-
const { client } = await bootMcpPair({
|
|
233
|
+
it('should send PATCH when updating a skill', async () => {
|
|
234
|
+
const skillId = '00000000-0000-0000-0000-000000000001';
|
|
235
|
+
const updated = { id: skillId, name: 'Updated Skill', content: '# Updated' };
|
|
236
|
+
const { client, fetchSpy } = await bootMcpPair({
|
|
232
237
|
capabilities: ALL_CAPABILITIES,
|
|
233
|
-
routes: { [`
|
|
238
|
+
routes: { [`PATCH /v1/agent-skills/${skillId}`]: { data: updated } },
|
|
234
239
|
});
|
|
235
|
-
|
|
236
|
-
name: '
|
|
237
|
-
arguments: { id:
|
|
240
|
+
await client.callTool({
|
|
241
|
+
name: 'taiga_update_skill',
|
|
242
|
+
arguments: { id: skillId, content: '# Updated' },
|
|
238
243
|
});
|
|
239
|
-
|
|
244
|
+
const patchCall = fetchSpy.mock.calls.find((c) => c[1]?.method === 'PATCH');
|
|
245
|
+
expect(patchCall).toBeDefined();
|
|
246
|
+
expect(patchCall[0]).toContain(`/v1/agent-skills/${skillId}`);
|
|
240
247
|
});
|
|
241
248
|
it('should return document content through MCP protocol', async () => {
|
|
242
249
|
const docs = [{ id: 'd1', title: 'Security Policy' }];
|
|
@@ -262,18 +269,21 @@ describe('MCP server integration', () => {
|
|
|
262
269
|
expect(putCall).toBeDefined();
|
|
263
270
|
expect(putCall[0]).toContain(`/v1/tenants/current/documents/${docType}/draft`);
|
|
264
271
|
});
|
|
265
|
-
it('should
|
|
266
|
-
const
|
|
267
|
-
const
|
|
268
|
-
const {
|
|
272
|
+
it('should send PUT when updating a team document draft', async () => {
|
|
273
|
+
const teamId = '00000000-0000-0000-0000-000000000001';
|
|
274
|
+
const docType = 'domain_context';
|
|
275
|
+
const updated = { type: docType, name: 'Domain Context' };
|
|
276
|
+
const { client, fetchSpy } = await bootMcpPair({
|
|
269
277
|
capabilities: ALL_CAPABILITIES,
|
|
270
|
-
routes: { [`
|
|
278
|
+
routes: { [`PUT /v1/teams/${teamId}/documents/${docType}/draft`]: { data: updated } },
|
|
271
279
|
});
|
|
272
|
-
|
|
273
|
-
name: '
|
|
274
|
-
arguments: {
|
|
280
|
+
await client.callTool({
|
|
281
|
+
name: 'taiga_update_team_document',
|
|
282
|
+
arguments: { teamId, type: docType, data: { sections: { overview: 'Updated' } } },
|
|
275
283
|
});
|
|
276
|
-
|
|
284
|
+
const putCall = fetchSpy.mock.calls.find((c) => c[1]?.method === 'PUT' && c[0].includes('/teams/'));
|
|
285
|
+
expect(putCall).toBeDefined();
|
|
286
|
+
expect(putCall[0]).toContain(`/v1/teams/${teamId}/documents/${docType}/draft`);
|
|
277
287
|
});
|
|
278
288
|
it('should return skills through MCP protocol', async () => {
|
|
279
289
|
const skills = [{ id: 's1', name: 'React Standards' }];
|
package/dist/tools/backlogs.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import type { TaigaClient } from '../client.js';
|
|
3
|
-
export declare function registerBacklogTools(
|
|
3
|
+
export declare function registerBacklogTools(_server: McpServer, _client: TaigaClient): void;
|
|
4
4
|
//# sourceMappingURL=backlogs.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backlogs.d.ts","sourceRoot":"","sources":["../../src/tools/backlogs.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"backlogs.d.ts","sourceRoot":"","sources":["../../src/tools/backlogs.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,QAG5E"}
|
package/dist/tools/backlogs.js
CHANGED
|
@@ -1,33 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
projectId: z.string().uuid().describe('Project ID'),
|
|
7
|
-
limit: z.number().min(1).max(100).optional().describe('Max results (default 25)'),
|
|
8
|
-
}, async (params) => {
|
|
9
|
-
const result = await client.listBacklogItems(params.projectId, { limit: params.limit });
|
|
10
|
-
return {
|
|
11
|
-
content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
|
|
12
|
-
};
|
|
13
|
-
});
|
|
14
|
-
server.tool('taiga_get_backlog_item', 'Get detailed information about a specific backlog item, including its active plan and steps.', {
|
|
15
|
-
itemId: z.string().uuid().describe('Backlog item ID'),
|
|
16
|
-
}, async (params) => {
|
|
17
|
-
const result = await client.getBacklogItem(params.itemId);
|
|
18
|
-
return {
|
|
19
|
-
content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
|
|
20
|
-
};
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
if (client.hasCapability('projects:read')) {
|
|
24
|
-
server.tool('taiga_list_environments', 'List deployment environments (dev, staging, production) for a project.', {
|
|
25
|
-
projectId: z.string().uuid().describe('Project ID'),
|
|
26
|
-
}, async (params) => {
|
|
27
|
-
const result = await client.listEnvironments(params.projectId);
|
|
28
|
-
return {
|
|
29
|
-
content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
|
|
30
|
-
};
|
|
31
|
-
});
|
|
32
|
-
}
|
|
1
|
+
// Backlog tools are reserved for post-beta.
|
|
2
|
+
// The beta MCP server focuses on the knowledge base (policies, skills, team docs).
|
|
3
|
+
export function registerBacklogTools(_server, _client) {
|
|
4
|
+
// No backlog tools in beta -- will be added when the MCP server
|
|
5
|
+
// expands beyond the knowledge base use case.
|
|
33
6
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../src/tools/documents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../src/tools/documents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,QA6I3E"}
|
package/dist/tools/documents.js
CHANGED
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { summarizeList } from './summarize.js';
|
|
2
3
|
export function registerDocumentTools(server, client) {
|
|
4
|
+
// ── Company-level policy documents ──────────────────────────────────
|
|
3
5
|
if (client.hasCapability('tenant:documents:read')) {
|
|
4
|
-
server.tool('taiga_list_documents', 'List company-level policy documents (
|
|
5
|
-
'
|
|
6
|
+
server.tool('taiga_list_documents', 'List company-level policy documents (names and types only). ' +
|
|
7
|
+
'Policies define security, data privacy, SDLC, operations, architecture, and compliance rules ' +
|
|
8
|
+
'that apply across all teams and projects. ' +
|
|
9
|
+
'Use taiga_get_document with the document type to read the full policy content.', {
|
|
6
10
|
limit: z.number().min(1).max(100).optional().describe('Max results (default 25)'),
|
|
7
|
-
}, async (params) => {
|
|
11
|
+
}, { readOnlyHint: true, openWorldHint: false }, async (params) => {
|
|
8
12
|
const result = await client.listTenantDocuments(params);
|
|
13
|
+
const summaries = summarizeList(result.data);
|
|
9
14
|
return {
|
|
10
|
-
content: [{ type: 'text', text: JSON.stringify(
|
|
15
|
+
content: [{ type: 'text', text: JSON.stringify(summaries, null, 2) }],
|
|
11
16
|
};
|
|
12
17
|
});
|
|
13
|
-
server.tool('taiga_get_document', 'Get the full content of a
|
|
14
|
-
'
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
server.tool('taiga_get_document', 'Get the full content of a company policy document. ' +
|
|
19
|
+
'Use this when you need to understand security requirements, data handling rules, ' +
|
|
20
|
+
'architecture standards, or compliance controls that apply to your code. ' +
|
|
21
|
+
'Types: policy_security, policy_data, policy_sdlc, policy_ops, policy_tic, ' +
|
|
22
|
+
'policy_risk, policy_architecture, policy_supply_chain, policy_acceptable_use, policy_ip.', {
|
|
23
|
+
type: z
|
|
24
|
+
.string()
|
|
25
|
+
.describe('Document type -- get available types from taiga_list_documents. ' +
|
|
26
|
+
'Common: policy_security, policy_data, policy_sdlc, policy_architecture'),
|
|
27
|
+
}, { readOnlyHint: true, openWorldHint: false }, async (params) => {
|
|
17
28
|
const result = await client.getTenantDocument(params.type);
|
|
18
29
|
return {
|
|
19
30
|
content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
|
|
@@ -21,10 +32,12 @@ export function registerDocumentTools(server, client) {
|
|
|
21
32
|
});
|
|
22
33
|
}
|
|
23
34
|
if (client.hasCapability('tenant:documents:write')) {
|
|
24
|
-
server.tool('taiga_update_document', 'Update the draft content of a policy document.
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
35
|
+
server.tool('taiga_update_document', 'Update the draft content of a company policy document. ' +
|
|
36
|
+
'Only updates the draft -- does not publish. Use this when you notice a policy ' +
|
|
37
|
+
'is outdated or needs corrections while reviewing code.', {
|
|
38
|
+
type: z.string().describe('Document type (e.g. policy_security, policy_sdlc)'),
|
|
39
|
+
data: z.record(z.string(), z.unknown()).describe('Document content to save as JSON'),
|
|
40
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
28
41
|
const { type, ...body } = params;
|
|
29
42
|
const result = await client.saveTenantDocumentDraft(type, body);
|
|
30
43
|
return {
|
|
@@ -32,4 +45,53 @@ export function registerDocumentTools(server, client) {
|
|
|
32
45
|
};
|
|
33
46
|
});
|
|
34
47
|
}
|
|
48
|
+
// ── Team documents ──────────────────────────────────────────────────
|
|
49
|
+
if (client.hasCapability('teams:read')) {
|
|
50
|
+
server.tool('taiga_list_team_documents', 'List documents for a specific team (names and types only). ' +
|
|
51
|
+
'Team documents define how the team works: domain context (entities, ubiquitous language), ' +
|
|
52
|
+
'tech preferences (approved stack), architecture constraints, SLO targets, ' +
|
|
53
|
+
'definition of done, and team charter. ' +
|
|
54
|
+
'Use taiga_get_team_document to read the full content.', {
|
|
55
|
+
teamId: z.string().uuid().describe('Team ID -- get from taiga_list_teams'),
|
|
56
|
+
limit: z.number().min(1).max(100).optional().describe('Max results (default 25)'),
|
|
57
|
+
}, { readOnlyHint: true, openWorldHint: false }, async (params) => {
|
|
58
|
+
const result = await client.listTeamDocuments(params.teamId, { limit: params.limit });
|
|
59
|
+
const summaries = summarizeList(result.data);
|
|
60
|
+
return {
|
|
61
|
+
content: [{ type: 'text', text: JSON.stringify(summaries, null, 2) }],
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
server.tool('taiga_get_team_document', 'Get the full content of a specific team document. ' +
|
|
65
|
+
'Use this when you need the team domain context (ubiquitous language, entities, business rules), ' +
|
|
66
|
+
'tech preferences (approved stack, patterns), or architecture constraints. ' +
|
|
67
|
+
'Types: team_charter, definition_of_done, tech_preferences, ' +
|
|
68
|
+
'architecture_constraints, slo_targets, domain_context.', {
|
|
69
|
+
teamId: z.string().uuid().describe('Team ID -- get from taiga_list_teams'),
|
|
70
|
+
type: z
|
|
71
|
+
.string()
|
|
72
|
+
.describe('Document type -- get available types from taiga_list_team_documents. ' +
|
|
73
|
+
'Most useful: domain_context (entities, language), tech_preferences (stack, patterns)'),
|
|
74
|
+
}, { readOnlyHint: true, openWorldHint: false }, async (params) => {
|
|
75
|
+
const result = await client.getTeamDocument(params.teamId, params.type);
|
|
76
|
+
return {
|
|
77
|
+
content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
// Team document write requires both teams:read (to find the team) and tenant:documents:write
|
|
82
|
+
if (client.hasCapability('teams:read') && client.hasCapability('tenant:documents:write')) {
|
|
83
|
+
server.tool('taiga_update_team_document', 'Update the draft content of a team document. ' +
|
|
84
|
+
'Only updates the draft -- does not publish. Use this when you notice team conventions, ' +
|
|
85
|
+
'domain context, or tech preferences need updating while working on the codebase.', {
|
|
86
|
+
teamId: z.string().uuid().describe('Team ID -- get from taiga_list_teams'),
|
|
87
|
+
type: z.string().describe('Document type (e.g. domain_context, tech_preferences)'),
|
|
88
|
+
data: z.record(z.string(), z.unknown()).describe('Document content to save as JSON'),
|
|
89
|
+
}, { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false }, async (params) => {
|
|
90
|
+
const { teamId, type, ...body } = params;
|
|
91
|
+
const result = await client.saveTeamDocumentDraft(teamId, type, body);
|
|
92
|
+
return {
|
|
93
|
+
content: [{ type: 'text', text: JSON.stringify(result.data, null, 2) }],
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
}
|
|
35
97
|
}
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -4,6 +4,9 @@ import type { TaigaClient } from '../client.js';
|
|
|
4
4
|
* Register all MCP tools based on the API key's effective capabilities.
|
|
5
5
|
* Only tools matching the key's scopes are registered -- the AI assistant
|
|
6
6
|
* never sees tools it can't use.
|
|
7
|
+
*
|
|
8
|
+
* Beta scope: Knowledge base access (policies, skills, team documents).
|
|
9
|
+
* Post-beta: Projects, backlog items, environments, composite tools.
|
|
7
10
|
*/
|
|
8
11
|
export declare function registerAllTools(server: McpServer, client: TaigaClient): void;
|
|
9
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAMhD
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAMhD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAK7E"}
|
package/dist/tools/index.js
CHANGED
|
@@ -6,6 +6,9 @@ import { registerSkillTools } from './skills.js';
|
|
|
6
6
|
* Register all MCP tools based on the API key's effective capabilities.
|
|
7
7
|
* Only tools matching the key's scopes are registered -- the AI assistant
|
|
8
8
|
* never sees tools it can't use.
|
|
9
|
+
*
|
|
10
|
+
* Beta scope: Knowledge base access (policies, skills, team documents).
|
|
11
|
+
* Post-beta: Projects, backlog items, environments, composite tools.
|
|
9
12
|
*/
|
|
10
13
|
export function registerAllTools(server, client) {
|
|
11
14
|
registerProjectTools(server, client);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/tools/projects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/tools/projects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,QA0F1E"}
|