@kaneo/mcp 0.1.10 → 0.1.12
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 +5 -2
- package/dist/kaneo/client.d.ts +1 -0
- package/dist/kaneo/client.js +3 -0
- package/dist/tools/register.d.ts +14 -4
- package/dist/tools/register.js +102 -49
- package/package.json +22 -18
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ It runs over stdio, signs in with Kaneo's device flow, and then calls the Kaneo
|
|
|
8
8
|
|
|
9
9
|
## Prerequisites
|
|
10
10
|
|
|
11
|
-
- Node.js
|
|
11
|
+
- Node.js 24+
|
|
12
12
|
- A running Kaneo API (for example `http://localhost:1337`) and web app (for device approval UI).
|
|
13
13
|
|
|
14
14
|
Kaneo allows `kaneo-cli` and `kaneo-mcp` by default, so you usually do not need extra server configuration.
|
|
@@ -118,7 +118,7 @@ For headless or sandboxed environments where opening a browser is impractical, s
|
|
|
118
118
|
- Session: `whoami`, `list_workspaces`, `list_workspace_members`, `list_notifications`
|
|
119
119
|
- Search: `search`
|
|
120
120
|
- Projects: `list_projects`, `get_project`, `create_project`, `update_project`, `list_project_columns`
|
|
121
|
-
- Tasks: `list_tasks`, `get_task`, `create_task`, `update_task`, `delete_task`, `move_task`, `update_task_status`, `update_task_assignee`, `update_task_due_date`, `list_task_activity`
|
|
121
|
+
- Tasks: `list_tasks`, `get_task`, `get_task_by_ticket_id`, `create_task`, `update_task`, `delete_task`, `move_task`, `update_task_status`, `update_task_assignee`, `update_task_due_date`, `list_task_activity`
|
|
122
122
|
- Time entries: `list_task_time_entries`, `get_time_entry`, `create_time_entry`, `update_time_entry`
|
|
123
123
|
- Comments: `list_task_comments`, `create_task_comment`, `update_task_comment`, `delete_task_comment`
|
|
124
124
|
- Labels: `list_workspace_labels`, `create_label`, `attach_label_to_task`, `detach_label_from_task`, `delete_label`
|
|
@@ -126,6 +126,9 @@ For headless or sandboxed environments where opening a browser is impractical, s
|
|
|
126
126
|
|
|
127
127
|
Call `list_project_columns` before setting a status: the column slugs it
|
|
128
128
|
returns are the values `create_task` and `update_task_status` accept.
|
|
129
|
+
Call `get_task_by_ticket_id` with a key such as `KAN-12` to retrieve one task
|
|
130
|
+
without listing a project. If the same key identifies multiple accessible tasks,
|
|
131
|
+
pass `workspaceId` or `projectId` to select one.
|
|
129
132
|
`list_workspace_members` resolves the user IDs the assignee tools expect.
|
|
130
133
|
Time entries have no delete endpoint on the API, so there is no
|
|
131
134
|
`delete_time_entry` tool.
|
package/dist/kaneo/client.d.ts
CHANGED
package/dist/kaneo/client.js
CHANGED
|
@@ -5,6 +5,9 @@ export class KaneoClient {
|
|
|
5
5
|
this.baseUrl = options.baseUrl;
|
|
6
6
|
this.auth = options.auth;
|
|
7
7
|
}
|
|
8
|
+
get usingApiKey() {
|
|
9
|
+
return this.auth.usingApiKey;
|
|
10
|
+
}
|
|
8
11
|
async authorizedFetch(path, init, didRetry = false) {
|
|
9
12
|
const token = await this.auth.getAccessToken();
|
|
10
13
|
const headers = new Headers(init?.headers);
|
package/dist/tools/register.d.ts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import
|
|
3
|
-
export
|
|
4
|
-
|
|
1
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
export type ToolClient = {
|
|
4
|
+
readonly usingApiKey?: boolean;
|
|
5
|
+
json<T = unknown>(path: string, init?: RequestInit): Promise<T>;
|
|
6
|
+
};
|
|
7
|
+
export type ToolRegistrar = {
|
|
8
|
+
registerTool(name: string, config: {
|
|
9
|
+
description: string;
|
|
10
|
+
inputSchema: z.ZodObject;
|
|
11
|
+
}, callback: (args: unknown) => Promise<CallToolResult>): unknown;
|
|
12
|
+
};
|
|
13
|
+
export declare function registerTools(server: ToolRegistrar, ctx: {
|
|
14
|
+
client: ToolClient;
|
|
5
15
|
}): void;
|
package/dist/tools/register.js
CHANGED
|
@@ -26,15 +26,21 @@ function run(fn) {
|
|
|
26
26
|
}
|
|
27
27
|
export function registerTools(server, ctx) {
|
|
28
28
|
const { client } = ctx;
|
|
29
|
-
server.registerTool(
|
|
30
|
-
|
|
29
|
+
const registerTool = (name, config, callback) => server.registerTool(name, config, async (args) => {
|
|
30
|
+
const parsed = config.inputSchema.safeParse(args);
|
|
31
|
+
if (!parsed.success)
|
|
32
|
+
return errorResult(z.prettifyError(parsed.error));
|
|
33
|
+
return callback(parsed.data);
|
|
34
|
+
});
|
|
35
|
+
registerTool("whoami", {
|
|
36
|
+
description: "Return the current Kaneo user for the configured authentication method.",
|
|
31
37
|
inputSchema: z.object({}),
|
|
32
|
-
}, async () => run(() => client.json("/api/auth/get-session", { method: "GET" })));
|
|
33
|
-
|
|
38
|
+
}, async () => run(() => client.json(client.usingApiKey ? "/api/user/me" : "/api/auth/get-session", { method: "GET" })));
|
|
39
|
+
registerTool("list_workspaces", {
|
|
34
40
|
description: "List workspaces (Better Auth organizations) the signed-in user can access.",
|
|
35
41
|
inputSchema: z.object({}),
|
|
36
42
|
}, async () => run(() => client.json("/api/auth/organization/list", { method: "GET" })));
|
|
37
|
-
|
|
43
|
+
registerTool("list_projects", {
|
|
38
44
|
description: "List projects in a workspace.",
|
|
39
45
|
inputSchema: z.object({
|
|
40
46
|
workspaceId: nonEmptyString.describe("Workspace ID"),
|
|
@@ -51,11 +57,11 @@ export function registerTools(server, ctx) {
|
|
|
51
57
|
}
|
|
52
58
|
return run(() => client.json(`/api/project?${qs.toString()}`, { method: "GET" }));
|
|
53
59
|
});
|
|
54
|
-
|
|
60
|
+
registerTool("get_project", {
|
|
55
61
|
description: "Get a single project by ID.",
|
|
56
62
|
inputSchema: z.object({ id: nonEmptyString }),
|
|
57
63
|
}, async (args) => run(() => client.json(`/api/project/${encodeURIComponent(args.id)}`)));
|
|
58
|
-
|
|
64
|
+
registerTool("create_project", {
|
|
59
65
|
description: "Create a project in a workspace.",
|
|
60
66
|
inputSchema: z.object({
|
|
61
67
|
name: nonEmptyString,
|
|
@@ -72,7 +78,7 @@ export function registerTools(server, ctx) {
|
|
|
72
78
|
slug: args.slug,
|
|
73
79
|
}),
|
|
74
80
|
})));
|
|
75
|
-
|
|
81
|
+
registerTool("update_project", {
|
|
76
82
|
description: "Update project metadata (PATCH-style: only provided fields are changed).",
|
|
77
83
|
inputSchema: z.object({
|
|
78
84
|
id: nonEmptyString,
|
|
@@ -123,8 +129,9 @@ export function registerTools(server, ctx) {
|
|
|
123
129
|
status: optionalNonEmptyString,
|
|
124
130
|
priority: prioritySchema.optional(),
|
|
125
131
|
assigneeId: optionalNonEmptyString,
|
|
126
|
-
page: z.number().int().
|
|
127
|
-
|
|
132
|
+
page: z.number().int().min(1).max(1_000_000).optional(),
|
|
133
|
+
relatedPage: z.number().int().min(1).max(1_000_000).optional(),
|
|
134
|
+
limit: z.number().int().min(1).max(100).optional(),
|
|
128
135
|
sortBy: z
|
|
129
136
|
.enum(["createdAt", "priority", "dueDate", "position", "title", "number"])
|
|
130
137
|
.optional(),
|
|
@@ -132,8 +139,8 @@ export function registerTools(server, ctx) {
|
|
|
132
139
|
dueBefore: optionalIsoDateTimeSchema,
|
|
133
140
|
dueAfter: optionalIsoDateTimeSchema,
|
|
134
141
|
});
|
|
135
|
-
|
|
136
|
-
description: "List tasks for a project (
|
|
142
|
+
registerTool("list_tasks", {
|
|
143
|
+
description: "List a bounded page of tasks for a project (50 by default, maximum 100). Use pagination.totalPages and page to retrieve the rest; filters and sorting apply before pagination. For every task page, also follow relatedPage through pagination.relatedTotalPages for complete labels, links and column metadata.",
|
|
137
144
|
inputSchema: listTasksSchema,
|
|
138
145
|
}, async (args) => {
|
|
139
146
|
const { projectId, ...rest } = args;
|
|
@@ -148,13 +155,29 @@ export function registerTools(server, ctx) {
|
|
|
148
155
|
const path = `/api/task/tasks/${encodeURIComponent(projectId)}${q ? `?${q}` : ""}`;
|
|
149
156
|
return run(() => client.json(path, { method: "GET" }));
|
|
150
157
|
});
|
|
151
|
-
|
|
158
|
+
registerTool("get_task", {
|
|
152
159
|
description: "Get a task by ID.",
|
|
153
160
|
inputSchema: z.object({ taskId: nonEmptyString }),
|
|
154
161
|
}, async (args) => run(() => client.json(`/api/task/${encodeURIComponent(args.taskId)}`, {
|
|
155
162
|
method: "GET",
|
|
156
163
|
})));
|
|
157
|
-
|
|
164
|
+
registerTool("get_task_by_ticket_id", {
|
|
165
|
+
description: "Get one task by its ticket ID (project key and number, e.g. KAN-12). If multiple accessible tasks share the ID, provide workspaceId or projectId.",
|
|
166
|
+
inputSchema: z.object({
|
|
167
|
+
ticketId: nonEmptyString,
|
|
168
|
+
workspaceId: optionalNonEmptyString,
|
|
169
|
+
projectId: optionalNonEmptyString,
|
|
170
|
+
}),
|
|
171
|
+
}, async ({ ticketId, workspaceId, projectId }) => {
|
|
172
|
+
const query = new URLSearchParams();
|
|
173
|
+
if (workspaceId)
|
|
174
|
+
query.set("workspaceId", workspaceId);
|
|
175
|
+
if (projectId)
|
|
176
|
+
query.set("projectId", projectId);
|
|
177
|
+
const suffix = query.toString();
|
|
178
|
+
return run(() => client.json(`/api/task/by-ticket-id/${encodeURIComponent(ticketId)}${suffix ? `?${suffix}` : ""}`, { method: "GET" }));
|
|
179
|
+
});
|
|
180
|
+
registerTool("create_task", {
|
|
158
181
|
description: "Create a task in a project.",
|
|
159
182
|
inputSchema: z.object({
|
|
160
183
|
projectId: nonEmptyString,
|
|
@@ -187,6 +210,22 @@ export function registerTools(server, ctx) {
|
|
|
187
210
|
body: JSON.stringify(body),
|
|
188
211
|
}));
|
|
189
212
|
});
|
|
213
|
+
registerTool("duplicate_task", {
|
|
214
|
+
description: "Duplicate a task in the same project, copying its fields and labels. Pass title to rename the copy.",
|
|
215
|
+
inputSchema: z.object({
|
|
216
|
+
taskId: nonEmptyString,
|
|
217
|
+
title: optionalNonEmptyString,
|
|
218
|
+
}),
|
|
219
|
+
}, async (args) => {
|
|
220
|
+
const body = {};
|
|
221
|
+
if (args.title !== undefined) {
|
|
222
|
+
body.title = args.title;
|
|
223
|
+
}
|
|
224
|
+
return run(() => client.json(`/api/task/duplicate/${encodeURIComponent(args.taskId)}`, {
|
|
225
|
+
method: "POST",
|
|
226
|
+
body: JSON.stringify(body),
|
|
227
|
+
}));
|
|
228
|
+
});
|
|
190
229
|
const updateTaskSchema = z.object({
|
|
191
230
|
taskId: nonEmptyString,
|
|
192
231
|
title: optionalNonEmptyString,
|
|
@@ -199,7 +238,7 @@ export function registerTools(server, ctx) {
|
|
|
199
238
|
dueDate: nullableOptionalIsoDateTimeSchema,
|
|
200
239
|
userId: nullableOptionalNonEmptyString,
|
|
201
240
|
});
|
|
202
|
-
|
|
241
|
+
registerTool("update_task", {
|
|
203
242
|
description: "Update a task (fetches current task, merges fields, then full update).",
|
|
204
243
|
inputSchema: updateTaskSchema,
|
|
205
244
|
}, async (args) => {
|
|
@@ -213,7 +252,7 @@ export function registerTools(server, ctx) {
|
|
|
213
252
|
});
|
|
214
253
|
});
|
|
215
254
|
});
|
|
216
|
-
|
|
255
|
+
registerTool("move_task", {
|
|
217
256
|
description: "Move a task to another project (and optional column status).",
|
|
218
257
|
inputSchema: z.object({
|
|
219
258
|
taskId: nonEmptyString,
|
|
@@ -229,7 +268,7 @@ export function registerTools(server, ctx) {
|
|
|
229
268
|
: {}),
|
|
230
269
|
}),
|
|
231
270
|
})));
|
|
232
|
-
|
|
271
|
+
registerTool("update_task_status", {
|
|
233
272
|
description: "Update only the status (column) of a task.",
|
|
234
273
|
inputSchema: z.object({
|
|
235
274
|
taskId: nonEmptyString,
|
|
@@ -239,13 +278,13 @@ export function registerTools(server, ctx) {
|
|
|
239
278
|
method: "PUT",
|
|
240
279
|
body: JSON.stringify({ status: args.status }),
|
|
241
280
|
})));
|
|
242
|
-
|
|
281
|
+
registerTool("list_task_comments", {
|
|
243
282
|
description: "List comments on a task.",
|
|
244
283
|
inputSchema: z.object({ taskId: nonEmptyString }),
|
|
245
284
|
}, async (args) => run(() => client.json(`/api/comment/${encodeURIComponent(args.taskId)}`, {
|
|
246
285
|
method: "GET",
|
|
247
286
|
})));
|
|
248
|
-
|
|
287
|
+
registerTool("create_task_comment", {
|
|
249
288
|
description: "Add a comment to a task.",
|
|
250
289
|
inputSchema: z.object({
|
|
251
290
|
taskId: nonEmptyString,
|
|
@@ -255,7 +294,7 @@ export function registerTools(server, ctx) {
|
|
|
255
294
|
method: "POST",
|
|
256
295
|
body: JSON.stringify({ content: args.content }),
|
|
257
296
|
})));
|
|
258
|
-
|
|
297
|
+
registerTool("update_task_comment", {
|
|
259
298
|
description: "Update one of your comments on a task.",
|
|
260
299
|
inputSchema: z.object({
|
|
261
300
|
commentId: nonEmptyString,
|
|
@@ -265,17 +304,17 @@ export function registerTools(server, ctx) {
|
|
|
265
304
|
method: "PUT",
|
|
266
305
|
body: JSON.stringify({ content: args.content }),
|
|
267
306
|
})));
|
|
268
|
-
|
|
307
|
+
registerTool("delete_task_comment", {
|
|
269
308
|
description: "Delete one of your comments from a task.",
|
|
270
309
|
inputSchema: z.object({ commentId: nonEmptyString }),
|
|
271
310
|
}, async (args) => run(() => client.json(`/api/comment/${encodeURIComponent(args.commentId)}`, {
|
|
272
311
|
method: "DELETE",
|
|
273
312
|
})));
|
|
274
|
-
|
|
313
|
+
registerTool("list_workspace_labels", {
|
|
275
314
|
description: "List labels defined in a workspace.",
|
|
276
315
|
inputSchema: z.object({ workspaceId: nonEmptyString }),
|
|
277
316
|
}, async (args) => run(() => client.json(`/api/label/workspace/${encodeURIComponent(args.workspaceId)}`, { method: "GET" })));
|
|
278
|
-
|
|
317
|
+
registerTool("create_label", {
|
|
279
318
|
description: "Create a label in a workspace (optionally attach to a task).",
|
|
280
319
|
inputSchema: z.object({
|
|
281
320
|
name: nonEmptyString,
|
|
@@ -292,7 +331,7 @@ export function registerTools(server, ctx) {
|
|
|
292
331
|
...(args.taskId !== undefined ? { taskId: args.taskId } : {}),
|
|
293
332
|
}),
|
|
294
333
|
})));
|
|
295
|
-
|
|
334
|
+
registerTool("attach_label_to_task", {
|
|
296
335
|
description: "Attach an existing label to a task.",
|
|
297
336
|
inputSchema: z.object({
|
|
298
337
|
labelId: nonEmptyString,
|
|
@@ -302,13 +341,13 @@ export function registerTools(server, ctx) {
|
|
|
302
341
|
method: "PUT",
|
|
303
342
|
body: JSON.stringify({ taskId: args.taskId }),
|
|
304
343
|
})));
|
|
305
|
-
|
|
344
|
+
registerTool("detach_label_from_task", {
|
|
306
345
|
description: "Detach a label from its current task.",
|
|
307
346
|
inputSchema: z.object({ labelId: nonEmptyString }),
|
|
308
347
|
}, async (args) => run(() => client.json(`/api/label/${encodeURIComponent(args.labelId)}/task`, {
|
|
309
348
|
method: "DELETE",
|
|
310
349
|
})));
|
|
311
|
-
|
|
350
|
+
registerTool("create_task_relation", {
|
|
312
351
|
description: "Create a relation between two tasks. relationType: 'subtask' (sourceTaskId is the parent, targetTaskId the child), 'blocks' (sourceTaskId blocks targetTaskId), or 'related' (bidirectional).",
|
|
313
352
|
inputSchema: z.object({
|
|
314
353
|
sourceTaskId: nonEmptyString,
|
|
@@ -323,35 +362,49 @@ export function registerTools(server, ctx) {
|
|
|
323
362
|
relationType: args.relationType,
|
|
324
363
|
}),
|
|
325
364
|
})));
|
|
326
|
-
|
|
365
|
+
registerTool("get_task_relations", {
|
|
327
366
|
description: "List all relations (subtask/blocks/related) involving a task.",
|
|
328
367
|
inputSchema: z.object({ taskId: nonEmptyString }),
|
|
329
368
|
}, async (args) => run(() => client.json(`/api/task-relation/${encodeURIComponent(args.taskId)}`, {
|
|
330
369
|
method: "GET",
|
|
331
370
|
})));
|
|
332
|
-
|
|
371
|
+
registerTool("delete_task_relation", {
|
|
333
372
|
description: "Delete a task relation by its relation ID.",
|
|
334
373
|
inputSchema: z.object({ id: nonEmptyString }),
|
|
335
374
|
}, async (args) => run(() => client.json(`/api/task-relation/${encodeURIComponent(args.id)}`, {
|
|
336
375
|
method: "DELETE",
|
|
337
376
|
})));
|
|
338
|
-
|
|
339
|
-
description: "Delete a label by ID.
|
|
377
|
+
registerTool("delete_label", {
|
|
378
|
+
description: "Delete a task or workspace label by ID. Workspace-label cascades resume automatically; repeat the tool if pendingDeletion remains true.",
|
|
340
379
|
inputSchema: z.object({ id: nonEmptyString }),
|
|
341
380
|
}, async (args) => run(async () => {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
381
|
+
let result;
|
|
382
|
+
const signal = AbortSignal.timeout(10_000);
|
|
383
|
+
// Bound work per tool call. The API persists the continuation boundary.
|
|
384
|
+
for (let page = 0; page < 100; page++) {
|
|
385
|
+
if (page > 0 && signal.aborted)
|
|
386
|
+
break;
|
|
387
|
+
try {
|
|
388
|
+
result = await client.json(`/api/label/${encodeURIComponent(args.id)}`, { method: "DELETE", signal });
|
|
389
|
+
}
|
|
390
|
+
catch (error) {
|
|
391
|
+
if (signal.aborted && result)
|
|
392
|
+
break;
|
|
393
|
+
throw error;
|
|
394
|
+
}
|
|
395
|
+
if (!result ||
|
|
396
|
+
typeof result !== "object" ||
|
|
397
|
+
!("pendingDeletion" in result) ||
|
|
398
|
+
!result.pendingDeletion)
|
|
399
|
+
break;
|
|
345
400
|
}
|
|
346
|
-
return
|
|
347
|
-
method: "DELETE",
|
|
348
|
-
});
|
|
401
|
+
return result;
|
|
349
402
|
}));
|
|
350
|
-
|
|
403
|
+
registerTool("list_workspace_members", {
|
|
351
404
|
description: "List the members of a workspace. Use this to resolve the user ID an assignee tool expects.",
|
|
352
405
|
inputSchema: z.object({ workspaceId: nonEmptyString }),
|
|
353
406
|
}, async (args) => run(() => client.json(`/api/workspace/${encodeURIComponent(args.workspaceId)}/members`)));
|
|
354
|
-
|
|
407
|
+
registerTool("search", {
|
|
355
408
|
description: "Search across tasks, projects, workspaces, comments, and activities.",
|
|
356
409
|
inputSchema: z.object({
|
|
357
410
|
q: nonEmptyString.describe("Search query"),
|
|
@@ -388,17 +441,17 @@ export function registerTools(server, ctx) {
|
|
|
388
441
|
qs.set("limit", String(args.limit));
|
|
389
442
|
return run(() => client.json(`/api/search?${qs.toString()}`));
|
|
390
443
|
});
|
|
391
|
-
|
|
444
|
+
registerTool("list_project_columns", {
|
|
392
445
|
description: "List a project's columns. Their slugs are the values update_task_status and create_task accept as a status.",
|
|
393
446
|
inputSchema: z.object({ projectId: nonEmptyString }),
|
|
394
447
|
}, async (args) => run(() => client.json(`/api/column/${encodeURIComponent(args.projectId)}`)));
|
|
395
|
-
|
|
448
|
+
registerTool("delete_task", {
|
|
396
449
|
description: "Delete a task by ID.",
|
|
397
450
|
inputSchema: z.object({ taskId: nonEmptyString }),
|
|
398
451
|
}, async (args) => run(() => client.json(`/api/task/${encodeURIComponent(args.taskId)}`, {
|
|
399
452
|
method: "DELETE",
|
|
400
453
|
})));
|
|
401
|
-
|
|
454
|
+
registerTool("update_task_assignee", {
|
|
402
455
|
description: "Assign a task to a workspace member, or pass a null userId to unassign it.",
|
|
403
456
|
inputSchema: z.object({
|
|
404
457
|
taskId: nonEmptyString,
|
|
@@ -410,7 +463,7 @@ export function registerTools(server, ctx) {
|
|
|
410
463
|
method: "PUT",
|
|
411
464
|
body: JSON.stringify({ userId: args.userId }),
|
|
412
465
|
})));
|
|
413
|
-
|
|
466
|
+
registerTool("update_task_due_date", {
|
|
414
467
|
description: "Set a task's due date. Omit dueDate to clear it.",
|
|
415
468
|
inputSchema: z.object({
|
|
416
469
|
taskId: nonEmptyString,
|
|
@@ -420,15 +473,15 @@ export function registerTools(server, ctx) {
|
|
|
420
473
|
method: "PUT",
|
|
421
474
|
body: JSON.stringify(args.dueDate === undefined ? {} : { dueDate: args.dueDate }),
|
|
422
475
|
})));
|
|
423
|
-
|
|
476
|
+
registerTool("list_task_time_entries", {
|
|
424
477
|
description: "List the time entries logged against a task.",
|
|
425
478
|
inputSchema: z.object({ taskId: nonEmptyString }),
|
|
426
479
|
}, async (args) => run(() => client.json(`/api/time-entry/task/${encodeURIComponent(args.taskId)}`)));
|
|
427
|
-
|
|
480
|
+
registerTool("get_time_entry", {
|
|
428
481
|
description: "Get a single time entry by ID.",
|
|
429
482
|
inputSchema: z.object({ id: nonEmptyString }),
|
|
430
483
|
}, async (args) => run(() => client.json(`/api/time-entry/${encodeURIComponent(args.id)}`)));
|
|
431
|
-
|
|
484
|
+
registerTool("create_time_entry", {
|
|
432
485
|
description: "Log time against a task. Omit endTime to leave the entry running.",
|
|
433
486
|
inputSchema: z.object({
|
|
434
487
|
taskId: nonEmptyString,
|
|
@@ -445,8 +498,8 @@ export function registerTools(server, ctx) {
|
|
|
445
498
|
...(args.description ? { description: args.description } : {}),
|
|
446
499
|
}),
|
|
447
500
|
})));
|
|
448
|
-
|
|
449
|
-
description: "Update a time entry. startTime is required;
|
|
501
|
+
registerTool("update_time_entry", {
|
|
502
|
+
description: "Update a time entry. startTime is required; omitting endTime keeps the stored one. startTime cannot be later than the end time.",
|
|
450
503
|
inputSchema: z.object({
|
|
451
504
|
id: nonEmptyString,
|
|
452
505
|
startTime: isoDateTimeSchema,
|
|
@@ -461,11 +514,11 @@ export function registerTools(server, ctx) {
|
|
|
461
514
|
...(args.description ? { description: args.description } : {}),
|
|
462
515
|
}),
|
|
463
516
|
})));
|
|
464
|
-
|
|
517
|
+
registerTool("list_task_activity", {
|
|
465
518
|
description: "List a task's activity history.",
|
|
466
519
|
inputSchema: z.object({ taskId: nonEmptyString }),
|
|
467
520
|
}, async (args) => run(() => client.json(`/api/activity/${encodeURIComponent(args.taskId)}`)));
|
|
468
|
-
|
|
521
|
+
registerTool("list_notifications", {
|
|
469
522
|
description: "List the signed-in user's notifications.",
|
|
470
523
|
inputSchema: z.object({}),
|
|
471
524
|
}, async () => run(() => client.json("/api/notification")));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaneo/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"mcpName": "io.github.usekaneo/kaneo",
|
|
5
5
|
"description": "Official MCP (Model Context Protocol) server for Kaneo, the open source project management platform: manage tasks, projects, and labels from Claude, Cursor, and other MCP clients",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,6 +19,10 @@
|
|
|
19
19
|
".": {
|
|
20
20
|
"import": "./dist/server.js",
|
|
21
21
|
"types": "./dist/server.d.ts"
|
|
22
|
+
},
|
|
23
|
+
"./tools": {
|
|
24
|
+
"types": "./dist/tools/register.d.ts",
|
|
25
|
+
"import": "./dist/tools/register.js"
|
|
22
26
|
}
|
|
23
27
|
},
|
|
24
28
|
"publishConfig": {
|
|
@@ -30,39 +34,39 @@
|
|
|
30
34
|
"LICENSE"
|
|
31
35
|
],
|
|
32
36
|
"keywords": [
|
|
37
|
+
"ai-agents",
|
|
38
|
+
"claude",
|
|
39
|
+
"kanban",
|
|
40
|
+
"kaneo",
|
|
41
|
+
"kaneo-mcp",
|
|
33
42
|
"mcp",
|
|
34
43
|
"mcp-server",
|
|
35
44
|
"model-context-protocol",
|
|
36
|
-
"kaneo",
|
|
37
|
-
"kaneo-mcp",
|
|
38
45
|
"project-management",
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"ai-agents",
|
|
42
|
-
"claude",
|
|
43
|
-
"stdio"
|
|
46
|
+
"stdio",
|
|
47
|
+
"tasks"
|
|
44
48
|
],
|
|
45
49
|
"scripts": {
|
|
46
|
-
"build": "
|
|
50
|
+
"build": "vp run compile",
|
|
47
51
|
"prepublishOnly": "pnpm run build",
|
|
48
52
|
"dev": "tsx watch src/index.ts",
|
|
49
|
-
"lint": "
|
|
53
|
+
"lint": "vp check .",
|
|
50
54
|
"start": "node dist/index.js",
|
|
51
|
-
"test": "
|
|
52
|
-
"test:watch": "
|
|
55
|
+
"test": "vp run test:run",
|
|
56
|
+
"test:watch": "vp test --config vitest.config.ts"
|
|
53
57
|
},
|
|
54
58
|
"dependencies": {
|
|
55
|
-
"@modelcontextprotocol/sdk": "^1.30.
|
|
56
|
-
"open": "^11.0.
|
|
59
|
+
"@modelcontextprotocol/sdk": "^1.30.1",
|
|
60
|
+
"open": "^11.0.4",
|
|
57
61
|
"prompts": "^2.4.2",
|
|
58
|
-
"zod": "^4.
|
|
62
|
+
"zod": "^4.6.5"
|
|
59
63
|
},
|
|
60
64
|
"devDependencies": {
|
|
61
65
|
"@kaneo/typescript-config": "workspace:*",
|
|
62
|
-
"@types/node": "^26.
|
|
66
|
+
"@types/node": "^26.6.2",
|
|
63
67
|
"@types/prompts": "^2.4.9",
|
|
64
|
-
"tsx": "^4.23.
|
|
68
|
+
"tsx": "^4.23.15",
|
|
65
69
|
"typescript": "^7.0.2",
|
|
66
|
-
"
|
|
70
|
+
"vite-plus": "catalog:"
|
|
67
71
|
}
|
|
68
72
|
}
|