@hanhnd/agent-kit 1.0.40 → 1.0.41
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/core/handoffs/index.d.ts +2 -2
- package/dist/core/handoffs/index.js +0 -1
- package/dist/mcp/agent.js +12 -5
- package/dist/mcp/core.js +13 -8
- package/dist/mcp/integration.js +20 -10
- package/dist/mcp/memory.js +31 -11
- package/dist/mcp/registration.test.d.ts +1 -0
- package/dist/mcp/registration.test.js +77 -0
- package/dist/server.js +69 -38
- package/dist/services/memory/memory.test.js +3 -2
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export declare const HANDOFF_TYPES: readonly ["brainstorm", "clarification", "plan", "ticket", "research", "
|
|
1
|
+
export declare const HANDOFF_TYPES: readonly ["brainstorm", "clarification", "plan", "ticket", "research", "investigation", "code"];
|
|
2
2
|
type HandoffType = (typeof HANDOFF_TYPES)[number];
|
|
3
|
-
type CanonicalHandoffType = 'brainstorm' | 'clarification' | 'plan' | 'ticket' | 'research' | '
|
|
3
|
+
type CanonicalHandoffType = 'brainstorm' | 'clarification' | 'plan' | 'ticket' | 'research' | 'investigation' | 'code';
|
|
4
4
|
export interface SavedHandoffFolderLocation {
|
|
5
5
|
featureSlug: string;
|
|
6
6
|
canonicalType: CanonicalHandoffType;
|
package/dist/mcp/agent.js
CHANGED
|
@@ -49,11 +49,18 @@ function initAgentLog(workspaceRoot, slug, agent) {
|
|
|
49
49
|
return { logPath: path.relative(workspaceRoot, logFile), logStream };
|
|
50
50
|
}
|
|
51
51
|
export function registerAgentTools(server) {
|
|
52
|
-
server.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
server.registerTool('kit_trigger_agent', {
|
|
53
|
+
title: 'Delegate to External Agent',
|
|
54
|
+
description: '!Important: Trigger only when user explicitly asks to delegate a task to an external agent CLI (gemini, claude, or codex). The task can be a direct message or a path to a handoff folder (.agent-kit/handoffs/feature-slug/plan).',
|
|
55
|
+
inputSchema: {
|
|
56
|
+
agent: z
|
|
57
|
+
.enum(['gemini', 'claude', 'codex'])
|
|
58
|
+
.describe('The agent CLI to invoke: "gemini", "claude", or "codex"'),
|
|
59
|
+
task: z
|
|
60
|
+
.string()
|
|
61
|
+
.describe('Task message or path to a handoff folder (e.g., ".agent-kit/handoffs/feature-slug/plan")'),
|
|
62
|
+
},
|
|
63
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
|
|
57
64
|
}, async ({ agent, task }, extra) => {
|
|
58
65
|
const workspaceRoot = getWorkspaceRoot();
|
|
59
66
|
let job;
|
package/dist/mcp/core.js
CHANGED
|
@@ -46,14 +46,19 @@ export function registerCoreTools(server) {
|
|
|
46
46
|
// Writes handoff artifacts to the workspace as a folder of files
|
|
47
47
|
// Returns the saved folder path to use in next-step instructions
|
|
48
48
|
// ═══════════════════════════════════════════════════════════════
|
|
49
|
-
server.
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
.describe('
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
server.registerTool('kit_save_handoff', {
|
|
50
|
+
title: 'Save Handoff Artifact',
|
|
51
|
+
description: `Save a handoff artifact to .agent-kit/handoffs/. Returns the saved folder path to use in next-step instructions. Do NOT append version numbers (v2, v3, etc.) to the slug.`,
|
|
52
|
+
inputSchema: {
|
|
53
|
+
type: z.enum(HANDOFF_TYPES).describe('Handoff type'),
|
|
54
|
+
files: z
|
|
55
|
+
.record(z.string(), z.string())
|
|
56
|
+
.describe('Markdown files to write into the handoff folder. May include one or many files per call; repeated calls with the same type and slug add or overwrite the provided files. Filenames must match /^[A-Za-z0-9_-]+\\.md$/.'),
|
|
57
|
+
slug: z
|
|
58
|
+
.string()
|
|
59
|
+
.describe('Short identifier for the folder, e.g. "user-auth" or "PROJ-123". Do NOT append version numbers (v2, v3, etc.).'),
|
|
60
|
+
},
|
|
61
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
57
62
|
}, async (args) => handleSaveHandoff(args, getWorkspaceRoot()));
|
|
58
63
|
}
|
|
59
64
|
// Export DEFAULT_EXTENSIONS for backward compatibility
|
package/dist/mcp/integration.js
CHANGED
|
@@ -74,14 +74,19 @@ async function callRestApi(url, auth, accept = 'application/json') {
|
|
|
74
74
|
}
|
|
75
75
|
export function registerIntegrationTools(server) {
|
|
76
76
|
// TOOL: GET BITBUCKET PR
|
|
77
|
-
server.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
77
|
+
server.registerTool('kit_get_bitbucket_pr', {
|
|
78
|
+
title: 'Get Bitbucket PR',
|
|
79
|
+
description: 'Get Bitbucket PR details and optionally the diff. Accepts a full PR URL or a numeric PR ID with workspace + repoSlug.',
|
|
80
|
+
inputSchema: {
|
|
81
|
+
input: z.string().describe('Bitbucket PR URL or numeric PR ID'),
|
|
82
|
+
workspace: z
|
|
83
|
+
.string()
|
|
84
|
+
.optional()
|
|
85
|
+
.describe('Bitbucket workspace slug (required for numeric ID if BITBUCKET_DEFAULT_WORKSPACE not set)'),
|
|
86
|
+
repoSlug: z.string().optional().describe('Bitbucket repo slug (required for numeric ID)'),
|
|
87
|
+
includeDiff: z.boolean().optional().default(true).describe('Include unified diff in response'),
|
|
88
|
+
},
|
|
89
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
85
90
|
}, async ({ input, workspace, repoSlug, includeDiff }) => {
|
|
86
91
|
try {
|
|
87
92
|
let ws;
|
|
@@ -145,8 +150,13 @@ ${pr.description || 'No description'}`;
|
|
|
145
150
|
}
|
|
146
151
|
});
|
|
147
152
|
// TOOL: JIRA GET TICKET
|
|
148
|
-
server.
|
|
149
|
-
|
|
153
|
+
server.registerTool('kit_jira_get_ticket', {
|
|
154
|
+
title: 'Get Jira Ticket',
|
|
155
|
+
description: 'Get ticket details from Jira using the Atlassian REST API',
|
|
156
|
+
inputSchema: {
|
|
157
|
+
ticketId: z.string().describe('Jira ticket ID (e.g., PROJ-123)'),
|
|
158
|
+
},
|
|
159
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
150
160
|
}, async ({ ticketId }) => {
|
|
151
161
|
try {
|
|
152
162
|
const safeTicketId = ticketId.match(/^[A-Z]+-\d+$/)?.[0];
|
package/dist/mcp/memory.js
CHANGED
|
@@ -12,9 +12,14 @@ import { loadGlobalSettings, resolveConversationDigestConfig } from '../core/con
|
|
|
12
12
|
*/
|
|
13
13
|
function registerMemoryToolHandlers(server, subsystem, workspaceRoot = process.cwd()) {
|
|
14
14
|
const { config } = subsystem;
|
|
15
|
-
server.
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
server.registerTool('kit_memory_search', {
|
|
16
|
+
title: 'Search Memory',
|
|
17
|
+
description: 'Search persistent memory for factual or semantic matches (decisions, concepts, entities). Extract concise keywords only, removing stopwords and filler words from the user request before querying. Use kit_memory_recent for temporal or recency questions.',
|
|
18
|
+
inputSchema: {
|
|
19
|
+
query: z.string().min(1).describe('Keyword-only search query with stopwords removed'),
|
|
20
|
+
top_k: z.number().int().positive().optional().describe('Number of results to return'),
|
|
21
|
+
},
|
|
22
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
18
23
|
}, async ({ query, top_k }) => {
|
|
19
24
|
try {
|
|
20
25
|
if (!subsystem.indexer || !subsystem.store) {
|
|
@@ -44,9 +49,14 @@ function registerMemoryToolHandlers(server, subsystem, workspaceRoot = process.c
|
|
|
44
49
|
return mcpText(`kit_memory_search failed: ${formatError(err)}`);
|
|
45
50
|
}
|
|
46
51
|
});
|
|
47
|
-
server.
|
|
48
|
-
|
|
49
|
-
|
|
52
|
+
server.registerTool('kit_memory_recent', {
|
|
53
|
+
title: 'Recent Memory Sources',
|
|
54
|
+
description: 'Return the N most recently updated memory sources. Optionally filter by source type. Use for temporal questions like "what did we do last session" or "recent".',
|
|
55
|
+
inputSchema: {
|
|
56
|
+
n: z.number().int().positive().max(50).optional().describe('How many recent sources to return (default 5)'),
|
|
57
|
+
source_type: z.enum(SOURCE_TYPES).optional().describe('Optional source type filter'),
|
|
58
|
+
},
|
|
59
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false },
|
|
50
60
|
}, async ({ n, source_type }) => {
|
|
51
61
|
try {
|
|
52
62
|
if (!subsystem.store) {
|
|
@@ -75,8 +85,13 @@ function registerMemoryToolHandlers(server, subsystem, workspaceRoot = process.c
|
|
|
75
85
|
return mcpText(`kit_memory_recent failed: ${formatError(err)}`);
|
|
76
86
|
}
|
|
77
87
|
});
|
|
78
|
-
server.
|
|
79
|
-
|
|
88
|
+
server.registerTool('kit_memory_save', {
|
|
89
|
+
title: 'Save to Memory',
|
|
90
|
+
description: 'Save content to wiki/raw for inclusion after the next /wiki compile.',
|
|
91
|
+
inputSchema: {
|
|
92
|
+
content: z.string().min(1).describe('Content to save to memory'),
|
|
93
|
+
},
|
|
94
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
80
95
|
}, async ({ content }) => {
|
|
81
96
|
try {
|
|
82
97
|
if (!subsystem.indexer) {
|
|
@@ -100,9 +115,14 @@ function registerMemoryToolHandlers(server, subsystem, workspaceRoot = process.c
|
|
|
100
115
|
});
|
|
101
116
|
}
|
|
102
117
|
});
|
|
103
|
-
server.
|
|
104
|
-
|
|
105
|
-
|
|
118
|
+
server.registerTool('kit_memory_digest_init', {
|
|
119
|
+
title: 'Initialize Conversation Digest',
|
|
120
|
+
description: 'Initialize or toggle local conversation digesting. Downloads/cache-loads the pinned local model only when explicitly invoked.',
|
|
121
|
+
inputSchema: {
|
|
122
|
+
model_id: z.string().optional().describe('Digest model id'),
|
|
123
|
+
enabled: z.boolean().optional().describe('Enable or disable conversation digesting'),
|
|
124
|
+
},
|
|
125
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
106
126
|
}, async ({ model_id, enabled }) => {
|
|
107
127
|
try {
|
|
108
128
|
const existingConfig = resolveConversationDigestConfig(loadGlobalSettings());
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
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 { registerCoreTools } from './core.js';
|
|
7
|
+
import { registerAgentTools } from './agent.js';
|
|
8
|
+
import { registerIntegrationTools } from './integration.js';
|
|
9
|
+
const EXPECTED_NON_MEMORY_TOOLS = [
|
|
10
|
+
'kit_save_handoff',
|
|
11
|
+
'kit_trigger_agent',
|
|
12
|
+
'kit_get_bitbucket_pr',
|
|
13
|
+
'kit_jira_get_ticket',
|
|
14
|
+
];
|
|
15
|
+
async function buildClientWithTools() {
|
|
16
|
+
const server = new McpServer({ name: 'test-kit', version: '0.0.0' });
|
|
17
|
+
registerIntegrationTools(server);
|
|
18
|
+
registerCoreTools(server);
|
|
19
|
+
registerAgentTools(server);
|
|
20
|
+
const [serverTransport, clientTransport] = InMemoryTransport.createLinkedPair();
|
|
21
|
+
const client = new Client({ name: 'test-client', version: '0.0.0' });
|
|
22
|
+
await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]);
|
|
23
|
+
return client;
|
|
24
|
+
}
|
|
25
|
+
describe('MCP tool registration smoke tests', () => {
|
|
26
|
+
test('R1: all 4 non-memory tool names are registered', async () => {
|
|
27
|
+
const client = await buildClientWithTools();
|
|
28
|
+
const { tools } = await client.listTools();
|
|
29
|
+
const names = tools.map((t) => t.name);
|
|
30
|
+
for (const expected of EXPECTED_NON_MEMORY_TOOLS) {
|
|
31
|
+
assert.ok(names.includes(expected), `expected tool "${expected}" to be registered, got: ${names.join(', ')}`);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
test('R2: each non-memory tool has a non-empty description and inputSchema (BC3)', async () => {
|
|
35
|
+
const client = await buildClientWithTools();
|
|
36
|
+
const { tools } = await client.listTools();
|
|
37
|
+
const byName = Object.fromEntries(tools.map((t) => [t.name, t]));
|
|
38
|
+
for (const name of EXPECTED_NON_MEMORY_TOOLS) {
|
|
39
|
+
const tool = byName[name];
|
|
40
|
+
assert.ok(tool, `tool "${name}" not found`);
|
|
41
|
+
assert.ok(tool.description && tool.description.length > 0, `tool "${name}" must have a non-empty description`);
|
|
42
|
+
assert.ok(tool.inputSchema, `tool "${name}" must have an inputSchema`);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
test('R3: kit_trigger_agent (readOnlyHint:false) has correct annotations (BC5)', async () => {
|
|
46
|
+
const client = await buildClientWithTools();
|
|
47
|
+
const { tools } = await client.listTools();
|
|
48
|
+
const tool = tools.find((t) => t.name === 'kit_trigger_agent');
|
|
49
|
+
assert.ok(tool, 'kit_trigger_agent must be registered');
|
|
50
|
+
assert.ok(tool.annotations, 'kit_trigger_agent must have annotations');
|
|
51
|
+
assert.equal(tool.annotations.readOnlyHint, false, 'readOnlyHint must be false');
|
|
52
|
+
assert.equal(tool.annotations.destructiveHint, true, 'destructiveHint must be true');
|
|
53
|
+
assert.equal(tool.annotations.idempotentHint, false, 'idempotentHint must be false');
|
|
54
|
+
assert.equal(tool.annotations.openWorldHint, true, 'openWorldHint must be true');
|
|
55
|
+
});
|
|
56
|
+
test('R4: kit_save_handoff (readOnlyHint:false) has correct annotations (BC5)', async () => {
|
|
57
|
+
const client = await buildClientWithTools();
|
|
58
|
+
const { tools } = await client.listTools();
|
|
59
|
+
const tool = tools.find((t) => t.name === 'kit_save_handoff');
|
|
60
|
+
assert.ok(tool, 'kit_save_handoff must be registered');
|
|
61
|
+
assert.ok(tool.annotations, 'kit_save_handoff must have annotations');
|
|
62
|
+
assert.equal(tool.annotations.readOnlyHint, false, 'readOnlyHint must be false');
|
|
63
|
+
assert.equal(tool.annotations.destructiveHint, false, 'destructiveHint must be false');
|
|
64
|
+
assert.equal(tool.annotations.idempotentHint, true, 'idempotentHint must be true');
|
|
65
|
+
assert.equal(tool.annotations.openWorldHint, false, 'openWorldHint must be false');
|
|
66
|
+
});
|
|
67
|
+
test('R5: kit_get_bitbucket_pr (readOnlyHint:true) has correct annotations (BC5)', async () => {
|
|
68
|
+
const client = await buildClientWithTools();
|
|
69
|
+
const { tools } = await client.listTools();
|
|
70
|
+
const tool = tools.find((t) => t.name === 'kit_get_bitbucket_pr');
|
|
71
|
+
assert.ok(tool, 'kit_get_bitbucket_pr must be registered');
|
|
72
|
+
assert.ok(tool.annotations, 'kit_get_bitbucket_pr must have annotations');
|
|
73
|
+
assert.equal(tool.annotations.readOnlyHint, true, 'readOnlyHint must be true');
|
|
74
|
+
assert.equal(tool.annotations.idempotentHint, true, 'idempotentHint must be true');
|
|
75
|
+
assert.equal(tool.annotations.openWorldHint, true, 'openWorldHint must be true');
|
|
76
|
+
});
|
|
77
|
+
});
|
package/dist/server.js
CHANGED
|
@@ -36078,7 +36078,6 @@ var HANDOFF_TYPES = [
|
|
|
36078
36078
|
"plan",
|
|
36079
36079
|
"ticket",
|
|
36080
36080
|
"research",
|
|
36081
|
-
"scenario",
|
|
36082
36081
|
"investigation",
|
|
36083
36082
|
"code"
|
|
36084
36083
|
];
|
|
@@ -36161,17 +36160,21 @@ function handleSaveHandoff(args, workspaceRoot2) {
|
|
|
36161
36160
|
}
|
|
36162
36161
|
}
|
|
36163
36162
|
function registerCoreTools(server2) {
|
|
36164
|
-
server2.
|
|
36163
|
+
server2.registerTool(
|
|
36165
36164
|
"kit_save_handoff",
|
|
36166
|
-
`Save a handoff artifact to .agent-kit/handoffs/. Returns the saved folder path to use in next-step instructions. Do NOT append version numbers (v2, v3, etc.) to the slug.`,
|
|
36167
36165
|
{
|
|
36168
|
-
|
|
36169
|
-
|
|
36170
|
-
|
|
36171
|
-
|
|
36172
|
-
|
|
36173
|
-
|
|
36174
|
-
|
|
36166
|
+
title: "Save Handoff Artifact",
|
|
36167
|
+
description: `Save a handoff artifact to .agent-kit/handoffs/. Returns the saved folder path to use in next-step instructions. Do NOT append version numbers (v2, v3, etc.) to the slug.`,
|
|
36168
|
+
inputSchema: {
|
|
36169
|
+
type: external_exports.enum(HANDOFF_TYPES).describe("Handoff type"),
|
|
36170
|
+
files: external_exports.record(external_exports.string(), external_exports.string()).describe(
|
|
36171
|
+
"Markdown files to write into the handoff folder. May include one or many files per call; repeated calls with the same type and slug add or overwrite the provided files. Filenames must match /^[A-Za-z0-9_-]+\\.md$/."
|
|
36172
|
+
),
|
|
36173
|
+
slug: external_exports.string().describe(
|
|
36174
|
+
'Short identifier for the folder, e.g. "user-auth" or "PROJ-123". Do NOT append version numbers (v2, v3, etc.).'
|
|
36175
|
+
)
|
|
36176
|
+
},
|
|
36177
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false }
|
|
36175
36178
|
},
|
|
36176
36179
|
async (args) => handleSaveHandoff(args, getWorkspaceRoot())
|
|
36177
36180
|
);
|
|
@@ -36281,12 +36284,16 @@ ${"\u2500".repeat(60)}
|
|
|
36281
36284
|
return { logPath: path6.relative(workspaceRoot2, logFile), logStream };
|
|
36282
36285
|
}
|
|
36283
36286
|
function registerAgentTools(server2) {
|
|
36284
|
-
server2.
|
|
36287
|
+
server2.registerTool(
|
|
36285
36288
|
"kit_trigger_agent",
|
|
36286
|
-
"!Important: Trigger only when user explicitly asks to delegate a task to an external agent CLI (gemini, claude, or codex). The task can be a direct message or a path to a handoff folder (.agent-kit/handoffs/feature-slug/plan).",
|
|
36287
36289
|
{
|
|
36288
|
-
|
|
36289
|
-
|
|
36290
|
+
title: "Delegate to External Agent",
|
|
36291
|
+
description: "!Important: Trigger only when user explicitly asks to delegate a task to an external agent CLI (gemini, claude, or codex). The task can be a direct message or a path to a handoff folder (.agent-kit/handoffs/feature-slug/plan).",
|
|
36292
|
+
inputSchema: {
|
|
36293
|
+
agent: external_exports.enum(["gemini", "claude", "codex"]).describe('The agent CLI to invoke: "gemini", "claude", or "codex"'),
|
|
36294
|
+
task: external_exports.string().describe('Task message or path to a handoff folder (e.g., ".agent-kit/handoffs/feature-slug/plan")')
|
|
36295
|
+
},
|
|
36296
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true }
|
|
36290
36297
|
},
|
|
36291
36298
|
async ({ agent, task }, extra) => {
|
|
36292
36299
|
const workspaceRoot2 = getWorkspaceRoot();
|
|
@@ -36641,14 +36648,18 @@ async function callRestApi(url, auth, accept = "application/json") {
|
|
|
36641
36648
|
return accept === "text/plain" ? resp.text() : resp.json();
|
|
36642
36649
|
}
|
|
36643
36650
|
function registerIntegrationTools(server2) {
|
|
36644
|
-
server2.
|
|
36651
|
+
server2.registerTool(
|
|
36645
36652
|
"kit_get_bitbucket_pr",
|
|
36646
|
-
"Get Bitbucket PR details and optionally the diff. Accepts a full PR URL or a numeric PR ID with workspace + repoSlug.",
|
|
36647
36653
|
{
|
|
36648
|
-
|
|
36649
|
-
|
|
36650
|
-
|
|
36651
|
-
|
|
36654
|
+
title: "Get Bitbucket PR",
|
|
36655
|
+
description: "Get Bitbucket PR details and optionally the diff. Accepts a full PR URL or a numeric PR ID with workspace + repoSlug.",
|
|
36656
|
+
inputSchema: {
|
|
36657
|
+
input: external_exports.string().describe("Bitbucket PR URL or numeric PR ID"),
|
|
36658
|
+
workspace: external_exports.string().optional().describe("Bitbucket workspace slug (required for numeric ID if BITBUCKET_DEFAULT_WORKSPACE not set)"),
|
|
36659
|
+
repoSlug: external_exports.string().optional().describe("Bitbucket repo slug (required for numeric ID)"),
|
|
36660
|
+
includeDiff: external_exports.boolean().optional().default(true).describe("Include unified diff in response")
|
|
36661
|
+
},
|
|
36662
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true }
|
|
36652
36663
|
},
|
|
36653
36664
|
async ({ input, workspace, repoSlug, includeDiff }) => {
|
|
36654
36665
|
try {
|
|
@@ -36725,11 +36736,15 @@ ${diff}
|
|
|
36725
36736
|
}
|
|
36726
36737
|
}
|
|
36727
36738
|
);
|
|
36728
|
-
server2.
|
|
36739
|
+
server2.registerTool(
|
|
36729
36740
|
"kit_jira_get_ticket",
|
|
36730
|
-
"Get ticket details from Jira using the Atlassian REST API",
|
|
36731
36741
|
{
|
|
36732
|
-
|
|
36742
|
+
title: "Get Jira Ticket",
|
|
36743
|
+
description: "Get ticket details from Jira using the Atlassian REST API",
|
|
36744
|
+
inputSchema: {
|
|
36745
|
+
ticketId: external_exports.string().describe("Jira ticket ID (e.g., PROJ-123)")
|
|
36746
|
+
},
|
|
36747
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true }
|
|
36733
36748
|
},
|
|
36734
36749
|
async ({ ticketId }) => {
|
|
36735
36750
|
try {
|
|
@@ -38143,12 +38158,16 @@ async function initializeConversationDigestModel(input) {
|
|
|
38143
38158
|
// src/mcp/memory.ts
|
|
38144
38159
|
function registerMemoryToolHandlers(server2, subsystem, workspaceRoot2 = process.cwd()) {
|
|
38145
38160
|
const { config: config2 } = subsystem;
|
|
38146
|
-
server2.
|
|
38161
|
+
server2.registerTool(
|
|
38147
38162
|
"kit_memory_search",
|
|
38148
|
-
"Search persistent memory for factual or semantic matches (decisions, concepts, entities). Extract concise keywords only, removing stopwords and filler words from the user request before querying. Use kit_memory_recent for temporal or recency questions.",
|
|
38149
38163
|
{
|
|
38150
|
-
|
|
38151
|
-
|
|
38164
|
+
title: "Search Memory",
|
|
38165
|
+
description: "Search persistent memory for factual or semantic matches (decisions, concepts, entities). Extract concise keywords only, removing stopwords and filler words from the user request before querying. Use kit_memory_recent for temporal or recency questions.",
|
|
38166
|
+
inputSchema: {
|
|
38167
|
+
query: external_exports.string().min(1).describe("Keyword-only search query with stopwords removed"),
|
|
38168
|
+
top_k: external_exports.number().int().positive().optional().describe("Number of results to return")
|
|
38169
|
+
},
|
|
38170
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
|
|
38152
38171
|
},
|
|
38153
38172
|
async ({ query, top_k }) => {
|
|
38154
38173
|
try {
|
|
@@ -38175,12 +38194,16 @@ ${content}`;
|
|
|
38175
38194
|
}
|
|
38176
38195
|
}
|
|
38177
38196
|
);
|
|
38178
|
-
server2.
|
|
38197
|
+
server2.registerTool(
|
|
38179
38198
|
"kit_memory_recent",
|
|
38180
|
-
'Return the N most recently updated memory sources. Optionally filter by source type. Use for temporal questions like "what did we do last session" or "recent".',
|
|
38181
38199
|
{
|
|
38182
|
-
|
|
38183
|
-
|
|
38200
|
+
title: "Recent Memory Sources",
|
|
38201
|
+
description: 'Return the N most recently updated memory sources. Optionally filter by source type. Use for temporal questions like "what did we do last session" or "recent".',
|
|
38202
|
+
inputSchema: {
|
|
38203
|
+
n: external_exports.number().int().positive().max(50).optional().describe("How many recent sources to return (default 5)"),
|
|
38204
|
+
source_type: external_exports.enum(SOURCE_TYPES).optional().describe("Optional source type filter")
|
|
38205
|
+
},
|
|
38206
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: false }
|
|
38184
38207
|
},
|
|
38185
38208
|
async ({ n, source_type }) => {
|
|
38186
38209
|
try {
|
|
@@ -38208,11 +38231,15 @@ ${content}`);
|
|
|
38208
38231
|
}
|
|
38209
38232
|
}
|
|
38210
38233
|
);
|
|
38211
|
-
server2.
|
|
38234
|
+
server2.registerTool(
|
|
38212
38235
|
"kit_memory_save",
|
|
38213
|
-
"Save content to wiki/raw for inclusion after the next /wiki compile.",
|
|
38214
38236
|
{
|
|
38215
|
-
|
|
38237
|
+
title: "Save to Memory",
|
|
38238
|
+
description: "Save content to wiki/raw for inclusion after the next /wiki compile.",
|
|
38239
|
+
inputSchema: {
|
|
38240
|
+
content: external_exports.string().min(1).describe("Content to save to memory")
|
|
38241
|
+
},
|
|
38242
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false }
|
|
38216
38243
|
},
|
|
38217
38244
|
async ({ content }) => {
|
|
38218
38245
|
try {
|
|
@@ -38237,12 +38264,16 @@ ${content}`);
|
|
|
38237
38264
|
}
|
|
38238
38265
|
}
|
|
38239
38266
|
);
|
|
38240
|
-
server2.
|
|
38267
|
+
server2.registerTool(
|
|
38241
38268
|
"kit_memory_digest_init",
|
|
38242
|
-
"Initialize or toggle local conversation digesting. Downloads/cache-loads the pinned local model only when explicitly invoked.",
|
|
38243
38269
|
{
|
|
38244
|
-
|
|
38245
|
-
|
|
38270
|
+
title: "Initialize Conversation Digest",
|
|
38271
|
+
description: "Initialize or toggle local conversation digesting. Downloads/cache-loads the pinned local model only when explicitly invoked.",
|
|
38272
|
+
inputSchema: {
|
|
38273
|
+
model_id: external_exports.string().optional().describe("Digest model id"),
|
|
38274
|
+
enabled: external_exports.boolean().optional().describe("Enable or disable conversation digesting")
|
|
38275
|
+
},
|
|
38276
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true }
|
|
38246
38277
|
},
|
|
38247
38278
|
async ({ model_id, enabled }) => {
|
|
38248
38279
|
try {
|
|
@@ -11,8 +11,9 @@ function makeMockServer() {
|
|
|
11
11
|
const tools = new Map();
|
|
12
12
|
const descriptions = new Map();
|
|
13
13
|
const server = {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
registerTool(name, config, handler) {
|
|
15
|
+
if (config.description)
|
|
16
|
+
descriptions.set(name, config.description);
|
|
16
17
|
tools.set(name, handler);
|
|
17
18
|
},
|
|
18
19
|
};
|