@hanhnd/agent-kit 1.0.42 → 1.0.44
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 +23 -0
- package/dist/mcp/bitbucket.test.d.ts +1 -0
- package/dist/mcp/bitbucket.test.js +335 -0
- package/dist/mcp/confluence.test.d.ts +1 -0
- package/dist/mcp/confluence.test.js +258 -0
- package/dist/mcp/integration.d.ts +154 -2
- package/dist/mcp/integration.js +751 -36
- package/dist/mcp/jira.test.d.ts +1 -0
- package/dist/mcp/jira.test.js +37 -0
- package/dist/mcp/registration.test.js +46 -1
- package/dist/server.js +1108 -48
- package/dist/services/integration/credentials.d.ts +1 -1
- package/dist/services/integration/credentials.js +1 -1
- package/dist/services/integration/parser/storage.d.ts +18 -0
- package/dist/services/integration/parser/storage.js +508 -0
- package/dist/services/integration/parser/storage.test.d.ts +1 -0
- package/dist/services/integration/parser/storage.test.js +211 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as assert from 'node:assert/strict';
|
|
2
|
+
import { describe, test } from 'node:test';
|
|
3
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
4
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
5
|
+
import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
|
|
6
|
+
import { buildAtlassianContext, registerIntegrationTools } from './integration.js';
|
|
7
|
+
// Both products' tokens are present so J1 can prove they share an email but not a token.
|
|
8
|
+
process.env.ATLASSIAN_CLOUD_ID = 'cloud-a';
|
|
9
|
+
process.env.ATLASSIAN_USER_EMAIL = 'dev@acme.test';
|
|
10
|
+
process.env.JIRA_API_TOKEN = 'token-123';
|
|
11
|
+
process.env.CONFLUENCE_API_TOKEN = 'confluence-token';
|
|
12
|
+
async function buildClient() {
|
|
13
|
+
const server = new McpServer({ name: 'test-kit', version: '0.0.0' });
|
|
14
|
+
registerIntegrationTools(server);
|
|
15
|
+
const [serverTransport, clientTransport] = InMemoryTransport.createLinkedPair();
|
|
16
|
+
const client = new Client({ name: 'test-client', version: '0.0.0' });
|
|
17
|
+
await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]);
|
|
18
|
+
return client;
|
|
19
|
+
}
|
|
20
|
+
describe('kit_jira_get_ticket regression after the buildAtlassianContext refactor (BC21)', () => {
|
|
21
|
+
test('J1: jira and confluence share the cloud id and email but not the token', () => {
|
|
22
|
+
const jira = buildAtlassianContext('jira');
|
|
23
|
+
const confluence = buildAtlassianContext('confluence');
|
|
24
|
+
const decode = (auth) => Buffer.from(auth.replace('Basic ', ''), 'base64').toString('utf8');
|
|
25
|
+
assert.equal(jira.cloudId, 'cloud-a');
|
|
26
|
+
assert.equal(confluence.cloudId, 'cloud-a', 'both products must use the same ATLASSIAN_CLOUD_ID');
|
|
27
|
+
assert.equal(decode(jira.auth), 'dev@acme.test:token-123');
|
|
28
|
+
assert.equal(decode(confluence.auth), 'dev@acme.test:confluence-token');
|
|
29
|
+
assert.notEqual(jira.auth, confluence.auth, 'a per-app scoped token must never cross products');
|
|
30
|
+
});
|
|
31
|
+
test('J2: an invalid ticket ID still returns the pre-existing format message', async () => {
|
|
32
|
+
const client = await buildClient();
|
|
33
|
+
const result = await client.callTool({ name: 'kit_jira_get_ticket', arguments: { ticketId: 'not-a-ticket' } });
|
|
34
|
+
const content = result.content;
|
|
35
|
+
assert.equal(content[0].text, '❌ Invalid ticket ID format: not-a-ticket\n\nExpected format: PROJ-123');
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -10,7 +10,11 @@ const EXPECTED_NON_MEMORY_TOOLS = [
|
|
|
10
10
|
'kit_save_handoff',
|
|
11
11
|
'kit_trigger_agent',
|
|
12
12
|
'kit_get_bitbucket_pr',
|
|
13
|
+
'kit_create_bitbucket_pr',
|
|
14
|
+
'kit_find_bitbucket_reviewers',
|
|
15
|
+
'kit_get_bitbucket_pr_comments',
|
|
13
16
|
'kit_jira_get_ticket',
|
|
17
|
+
'kit_confluence_get_page',
|
|
14
18
|
];
|
|
15
19
|
async function buildClientWithTools() {
|
|
16
20
|
const server = new McpServer({ name: 'test-kit', version: '0.0.0' });
|
|
@@ -23,7 +27,7 @@ async function buildClientWithTools() {
|
|
|
23
27
|
return client;
|
|
24
28
|
}
|
|
25
29
|
describe('MCP tool registration smoke tests', () => {
|
|
26
|
-
test('R1: all
|
|
30
|
+
test('R1: all 8 non-memory tool names are registered', async () => {
|
|
27
31
|
const client = await buildClientWithTools();
|
|
28
32
|
const { tools } = await client.listTools();
|
|
29
33
|
const names = tools.map((t) => t.name);
|
|
@@ -74,4 +78,45 @@ describe('MCP tool registration smoke tests', () => {
|
|
|
74
78
|
assert.equal(tool.annotations.idempotentHint, true, 'idempotentHint must be true');
|
|
75
79
|
assert.equal(tool.annotations.openWorldHint, true, 'openWorldHint must be true');
|
|
76
80
|
});
|
|
81
|
+
test('R6: kit_confluence_get_page (readOnlyHint:true) has correct annotations (BC1)', async () => {
|
|
82
|
+
const client = await buildClientWithTools();
|
|
83
|
+
const { tools } = await client.listTools();
|
|
84
|
+
const tool = tools.find((t) => t.name === 'kit_confluence_get_page');
|
|
85
|
+
assert.ok(tool, 'kit_confluence_get_page must be registered');
|
|
86
|
+
assert.ok(tool.annotations, 'kit_confluence_get_page must have annotations');
|
|
87
|
+
assert.equal(tool.annotations.readOnlyHint, true, 'readOnlyHint must be true');
|
|
88
|
+
assert.equal(tool.annotations.idempotentHint, true, 'idempotentHint must be true');
|
|
89
|
+
assert.equal(tool.annotations.openWorldHint, true, 'openWorldHint must be true');
|
|
90
|
+
});
|
|
91
|
+
test('R7: kit_create_bitbucket_pr (readOnlyHint:false) has correct annotations', async () => {
|
|
92
|
+
const client = await buildClientWithTools();
|
|
93
|
+
const { tools } = await client.listTools();
|
|
94
|
+
const tool = tools.find((t) => t.name === 'kit_create_bitbucket_pr');
|
|
95
|
+
assert.ok(tool, 'kit_create_bitbucket_pr must be registered');
|
|
96
|
+
assert.ok(tool.annotations, 'kit_create_bitbucket_pr must have annotations');
|
|
97
|
+
assert.equal(tool.annotations.readOnlyHint, false, 'readOnlyHint must be false');
|
|
98
|
+
assert.equal(tool.annotations.destructiveHint, false, 'destructiveHint must be false');
|
|
99
|
+
assert.equal(tool.annotations.idempotentHint, false, 'idempotentHint must be false');
|
|
100
|
+
assert.equal(tool.annotations.openWorldHint, true, 'openWorldHint must be true');
|
|
101
|
+
});
|
|
102
|
+
test('R8: kit_get_bitbucket_pr_comments (readOnlyHint:true) has correct annotations', async () => {
|
|
103
|
+
const client = await buildClientWithTools();
|
|
104
|
+
const { tools } = await client.listTools();
|
|
105
|
+
const tool = tools.find((t) => t.name === 'kit_get_bitbucket_pr_comments');
|
|
106
|
+
assert.ok(tool, 'kit_get_bitbucket_pr_comments must be registered');
|
|
107
|
+
assert.ok(tool.annotations, 'kit_get_bitbucket_pr_comments must have annotations');
|
|
108
|
+
assert.equal(tool.annotations.readOnlyHint, true, 'readOnlyHint must be true');
|
|
109
|
+
assert.equal(tool.annotations.idempotentHint, true, 'idempotentHint must be true');
|
|
110
|
+
assert.equal(tool.annotations.openWorldHint, true, 'openWorldHint must be true');
|
|
111
|
+
});
|
|
112
|
+
test('R9: kit_find_bitbucket_reviewers (readOnlyHint:true) has correct annotations', async () => {
|
|
113
|
+
const client = await buildClientWithTools();
|
|
114
|
+
const { tools } = await client.listTools();
|
|
115
|
+
const tool = tools.find((t) => t.name === 'kit_find_bitbucket_reviewers');
|
|
116
|
+
assert.ok(tool, 'kit_find_bitbucket_reviewers must be registered');
|
|
117
|
+
assert.ok(tool.annotations, 'kit_find_bitbucket_reviewers must have annotations');
|
|
118
|
+
assert.equal(tool.annotations.readOnlyHint, true, 'readOnlyHint must be true');
|
|
119
|
+
assert.equal(tool.annotations.idempotentHint, true, 'idempotentHint must be true');
|
|
120
|
+
assert.equal(tool.annotations.openWorldHint, true, 'openWorldHint must be true');
|
|
121
|
+
});
|
|
77
122
|
});
|