@kaneo/mcp 0.1.5 → 0.1.6
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 +17 -3
- package/dist/auth/auth-service.d.ts +24 -0
- package/dist/auth/auth-service.js +18 -0
- package/dist/auth/device-flow.d.ts +21 -0
- package/dist/auth/token-store.d.ts +10 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +0 -0
- package/dist/install/index.d.ts +11 -0
- package/dist/install/index.js +1 -1
- package/dist/install/merge-config.d.ts +10 -0
- package/dist/install/resolve-entry.d.ts +5 -0
- package/dist/install/targets.d.ts +39 -0
- package/dist/install/targets.js +1 -1
- package/dist/install/wizard.d.ts +4 -0
- package/dist/kaneo/client.d.ts +14 -0
- package/dist/kaneo/client.js +3 -1
- package/dist/kaneo/task-helpers.d.ts +19 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +2 -1
- package/dist/tools/register.d.ts +5 -0
- package/dist/tools/register.js +55 -0
- package/dist/utils/mcp-result.d.ts +3 -0
- package/dist/utils/normalize-base-url.d.ts +4 -0
- package/package.json +12 -6
package/README.md
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# Kaneo MCP server
|
|
2
2
|
|
|
3
|
-
`@kaneo/mcp` is a local MCP server for Kaneo.
|
|
3
|
+
`@kaneo/mcp` is a local stdio MCP server for Kaneo.
|
|
4
4
|
|
|
5
5
|
It runs over stdio, signs in with Kaneo's device flow, and then calls the Kaneo API with a bearer token. The package lives in `packages/mcp` in this monorepo and exposes the `kaneo-mcp` CLI.
|
|
6
6
|
|
|
7
|
+
> **Tip:** Every Kaneo instance also ships a built-in HTTP MCP endpoint at `/api/mcp`. If your MCP client supports Streamable HTTP transport (e.g. Claude Code), you can connect directly without this package. See the [MCP docs](https://docs.kaneo.app/core/integrations/mcp) for details.
|
|
8
|
+
|
|
7
9
|
## Prerequisites
|
|
8
10
|
|
|
9
11
|
- Node.js 20+
|
|
@@ -23,6 +25,7 @@ DEVICE_AUTH_CLIENT_IDS=kaneo-cli,kaneo-mcp,your-client-id
|
|
|
23
25
|
|----------|-------------|
|
|
24
26
|
| `KANEO_API_URL` | Kaneo API origin (default `http://localhost:1337`). Do not include `/api`. |
|
|
25
27
|
| `KANEO_MCP_CLIENT_ID` | Device-flow client id (default `kaneo-mcp`). Must match `DEVICE_AUTH_CLIENT_IDS` on the server. |
|
|
28
|
+
| `KANEO_API_KEY` | **Optional.** A Kaneo API key (create one under Settings → Account → Developer). When set, the server authenticates with it as a Bearer token and skips the interactive device flow. Use this for headless/Docker setups. |
|
|
26
29
|
|
|
27
30
|
## Install
|
|
28
31
|
|
|
@@ -106,10 +109,21 @@ On the first tool call that needs Kaneo, the server:
|
|
|
106
109
|
4. Polls `POST /api/auth/device/token` until approved
|
|
107
110
|
5. Stores the access token at `~/.config/kaneo-mcp/credentials.json` with mode `0600`
|
|
108
111
|
|
|
112
|
+
### Non-interactive (API key)
|
|
113
|
+
|
|
114
|
+
For headless or sandboxed environments where opening a browser is impractical, set `KANEO_API_KEY` to a key created under Settings → Account → Developer. The server sends it as a Bearer token on every request and skips the device flow entirely, so no token is cached to disk.
|
|
115
|
+
|
|
109
116
|
## Tools
|
|
110
117
|
|
|
111
118
|
- Session: `whoami`, `list_workspaces`
|
|
112
119
|
- Projects: `list_projects`, `get_project`, `create_project`, `update_project`
|
|
113
120
|
- Tasks: `list_tasks`, `get_task`, `create_task`, `update_task`, `move_task`, `update_task_status`
|
|
114
|
-
- Comments: `list_task_comments`, `create_task_comment`
|
|
115
|
-
- Labels: `list_workspace_labels`, `create_label`, `attach_label_to_task`, `detach_label_from_task`
|
|
121
|
+
- Comments: `list_task_comments`, `create_task_comment`, `update_task_comment`, `delete_task_comment`
|
|
122
|
+
- Labels: `list_workspace_labels`, `create_label`, `attach_label_to_task`, `detach_label_from_task`, `delete_label`
|
|
123
|
+
- Task relations: `create_task_relation`, `get_task_relations`, `delete_task_relation`
|
|
124
|
+
|
|
125
|
+
## Releasing
|
|
126
|
+
|
|
127
|
+
Bump `version` in `packages/mcp/package.json` and merge to `main`. The [publish workflow](../../.github/workflows/publish-mcp.yml) runs the package tests, publishes the new version to npm, and creates a `mcp-v<version>` GitHub release. Nothing is published while the version stays the same, so tool changes reach npm only once the version is bumped.
|
|
128
|
+
|
|
129
|
+
Publishing a GitHub release manually also works: tag it `mcp-v<version>` with the tag version matching `packages/mcp/package.json` on the tagged commit.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export type AuthServiceOptions = {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
clientId: string;
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare class AuthService {
|
|
7
|
+
readonly baseUrl: string;
|
|
8
|
+
readonly clientId: string;
|
|
9
|
+
private readonly apiKey?;
|
|
10
|
+
private activeGetAccessTokenPromise?;
|
|
11
|
+
constructor(options: AuthServiceOptions);
|
|
12
|
+
/**
|
|
13
|
+
* True when a pre-created Kaneo API key is used instead of the interactive
|
|
14
|
+
* device flow. Callers use this to avoid clearing/retrying auth on a 401.
|
|
15
|
+
*/
|
|
16
|
+
get usingApiKey(): boolean;
|
|
17
|
+
clearToken(): Promise<void>;
|
|
18
|
+
private validateAccessToken;
|
|
19
|
+
private log;
|
|
20
|
+
/**
|
|
21
|
+
* Returns a valid access token, running the device authorization flow if needed.
|
|
22
|
+
*/
|
|
23
|
+
getAccessToken(): Promise<string>;
|
|
24
|
+
}
|
|
@@ -4,12 +4,24 @@ import { clearCredentials, loadCredentials, saveCredentials, } from "./token-sto
|
|
|
4
4
|
export class AuthService {
|
|
5
5
|
baseUrl;
|
|
6
6
|
clientId;
|
|
7
|
+
apiKey;
|
|
7
8
|
activeGetAccessTokenPromise;
|
|
8
9
|
constructor(options) {
|
|
9
10
|
this.baseUrl = options.baseUrl;
|
|
10
11
|
this.clientId = options.clientId;
|
|
12
|
+
this.apiKey = options.apiKey;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* True when a pre-created Kaneo API key is used instead of the interactive
|
|
16
|
+
* device flow. Callers use this to avoid clearing/retrying auth on a 401.
|
|
17
|
+
*/
|
|
18
|
+
get usingApiKey() {
|
|
19
|
+
return Boolean(this.apiKey);
|
|
11
20
|
}
|
|
12
21
|
async clearToken() {
|
|
22
|
+
// Nothing to clear for API-key auth; the key is static config.
|
|
23
|
+
if (this.apiKey)
|
|
24
|
+
return;
|
|
13
25
|
await clearCredentials();
|
|
14
26
|
}
|
|
15
27
|
async validateAccessToken(token) {
|
|
@@ -39,6 +51,12 @@ export class AuthService {
|
|
|
39
51
|
* Returns a valid access token, running the device authorization flow if needed.
|
|
40
52
|
*/
|
|
41
53
|
async getAccessToken() {
|
|
54
|
+
// Non-interactive auth: a pre-created Kaneo API key (KANEO_API_KEY) is sent
|
|
55
|
+
// as a Bearer token, which the REST API already accepts. This skips the
|
|
56
|
+
// device flow so the MCP server works in headless/Docker environments.
|
|
57
|
+
if (this.apiKey) {
|
|
58
|
+
return this.apiKey;
|
|
59
|
+
}
|
|
42
60
|
if (this.activeGetAccessTokenPromise) {
|
|
43
61
|
return await this.activeGetAccessTokenPromise;
|
|
44
62
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type DeviceCodeResponse = {
|
|
2
|
+
device_code: string;
|
|
3
|
+
user_code: string;
|
|
4
|
+
verification_uri: string;
|
|
5
|
+
verification_uri_complete?: string;
|
|
6
|
+
interval: number;
|
|
7
|
+
expires_in: number;
|
|
8
|
+
};
|
|
9
|
+
export type DeviceTokenErrorBody = {
|
|
10
|
+
error?: string;
|
|
11
|
+
error_description?: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function requestDeviceCode(baseUrl: string, clientId: string): Promise<DeviceCodeResponse>;
|
|
14
|
+
/**
|
|
15
|
+
* Polls `/api/auth/device/token` until success or terminal error.
|
|
16
|
+
* First attempt is immediate; subsequent attempts wait `interval` seconds (increased on `slow_down`).
|
|
17
|
+
*/
|
|
18
|
+
export declare function pollDeviceAccessToken(baseUrl: string, clientId: string, deviceCode: string, initialIntervalSec: number, options?: {
|
|
19
|
+
maxWaitMs?: number;
|
|
20
|
+
log?: (msg: string) => void;
|
|
21
|
+
}): Promise<string>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type StoredCredentials = {
|
|
2
|
+
version: 1;
|
|
3
|
+
baseUrl: string;
|
|
4
|
+
clientId: string;
|
|
5
|
+
accessToken: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function credentialsPath(): string;
|
|
8
|
+
export declare function loadCredentials(): Promise<StoredCredentials | null>;
|
|
9
|
+
export declare function saveCredentials(data: StoredCredentials): Promise<void>;
|
|
10
|
+
export declare function clearCredentials(): Promise<void>;
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runCli(): Promise<void>;
|
package/dist/cli.js
CHANGED
|
@@ -35,7 +35,7 @@ async function startMcpServer() {
|
|
|
35
35
|
await server.connect(transport);
|
|
36
36
|
}
|
|
37
37
|
function printMainHelp() {
|
|
38
|
-
console.log(`kaneo-mcp
|
|
38
|
+
console.log(`kaneo-mcp: Kaneo MCP server (stdio transport)
|
|
39
39
|
|
|
40
40
|
Usage:
|
|
41
41
|
npx @kaneo/mcp Interactive installer (terminal only; no global install)
|
package/dist/index.d.ts
ADDED
package/dist/index.js
CHANGED
|
File without changes
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type ParsedInstallArgs = {
|
|
2
|
+
target?: string;
|
|
3
|
+
output?: string;
|
|
4
|
+
name: string;
|
|
5
|
+
yes: boolean;
|
|
6
|
+
apiUrl?: string;
|
|
7
|
+
projectDir: string;
|
|
8
|
+
help: boolean;
|
|
9
|
+
};
|
|
10
|
+
export declare function parseInstallArgs(argv: string[]): ParsedInstallArgs;
|
|
11
|
+
export declare function runInstall(argv: string[]): Promise<void>;
|
package/dist/install/index.js
CHANGED
|
@@ -273,7 +273,7 @@ export async function runInstall(argv) {
|
|
|
273
273
|
console.log("\nRestart your MCP client (or reload the window) if needed.");
|
|
274
274
|
}
|
|
275
275
|
function printInstallHelp() {
|
|
276
|
-
console.log(`kaneo-mcp install
|
|
276
|
+
console.log(`kaneo-mcp install: register Kaneo in an MCP client config
|
|
277
277
|
|
|
278
278
|
Usage:
|
|
279
279
|
kaneo-mcp install [options]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type McpServerEntry = {
|
|
2
|
+
command: string;
|
|
3
|
+
args: string[];
|
|
4
|
+
env?: Record<string, string>;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Merges or replaces `mcpServers[serverName]` and returns formatted JSON.
|
|
8
|
+
* Preserves other top-level keys and other MCP server entries.
|
|
9
|
+
*/
|
|
10
|
+
export declare function mergeMcpServerEntry(existingJson: string | null, serverName: string, serverConfig: McpServerEntry): string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export type InstallTargetId = "cursor-user" | "cursor-project" | "claude-desktop" | "custom";
|
|
2
|
+
export type InstallTarget = {
|
|
3
|
+
id: InstallTargetId;
|
|
4
|
+
label: string;
|
|
5
|
+
description: string;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Validates a non-interactive custom MCP config path (same rules as the install wizard).
|
|
9
|
+
* Returns the trimmed absolute path on success.
|
|
10
|
+
*/
|
|
11
|
+
export declare function validateCustomConfigPathInput(raw: string): {
|
|
12
|
+
ok: true;
|
|
13
|
+
path: string;
|
|
14
|
+
} | {
|
|
15
|
+
ok: false;
|
|
16
|
+
message: string;
|
|
17
|
+
};
|
|
18
|
+
export declare const INSTALL_TARGETS: readonly [{
|
|
19
|
+
readonly id: "cursor-user";
|
|
20
|
+
readonly label: "Cursor (user-wide)";
|
|
21
|
+
readonly description: "~/.cursor/mcp.json, available in all projects";
|
|
22
|
+
}, {
|
|
23
|
+
readonly id: "cursor-project";
|
|
24
|
+
readonly label: "Cursor (this project only)";
|
|
25
|
+
readonly description: ".cursor/mcp.json in the current directory";
|
|
26
|
+
}, {
|
|
27
|
+
readonly id: "claude-desktop";
|
|
28
|
+
readonly label: "Claude Desktop";
|
|
29
|
+
readonly description: "claude_desktop_config.json for the Claude app";
|
|
30
|
+
}, {
|
|
31
|
+
readonly id: "custom";
|
|
32
|
+
readonly label: "Custom file path";
|
|
33
|
+
readonly description: "Any JSON file you choose (advanced)";
|
|
34
|
+
}];
|
|
35
|
+
export declare function getClaudeDesktopConfigPath(): string;
|
|
36
|
+
export declare function resolveTargetConfigPath(id: InstallTargetId, options: {
|
|
37
|
+
cwd: string;
|
|
38
|
+
customPath?: string;
|
|
39
|
+
}): string;
|
package/dist/install/targets.js
CHANGED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type InstallTargetId } from "./targets.js";
|
|
2
|
+
export declare function promptTargetSelect(): Promise<InstallTargetId[]>;
|
|
3
|
+
export declare function promptCustomConfigPath(): Promise<string>;
|
|
4
|
+
export declare function promptConfirmOverwrite(serverName: string, configPath: string): Promise<boolean>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AuthService } from "../auth/auth-service.js";
|
|
2
|
+
export type Json = null | boolean | number | string | Json[] | {
|
|
3
|
+
[key: string]: Json;
|
|
4
|
+
};
|
|
5
|
+
export declare class KaneoClient {
|
|
6
|
+
readonly baseUrl: string;
|
|
7
|
+
private readonly auth;
|
|
8
|
+
constructor(options: {
|
|
9
|
+
baseUrl: string;
|
|
10
|
+
auth: AuthService;
|
|
11
|
+
});
|
|
12
|
+
private authorizedFetch;
|
|
13
|
+
json<T = Json>(path: string, init?: RequestInit): Promise<T>;
|
|
14
|
+
}
|
package/dist/kaneo/client.js
CHANGED
|
@@ -18,7 +18,9 @@ export class KaneoClient {
|
|
|
18
18
|
? AbortSignal.any([init.signal, timeoutSignal])
|
|
19
19
|
: timeoutSignal;
|
|
20
20
|
const res = await fetch(url, { ...init, headers, signal });
|
|
21
|
-
|
|
21
|
+
// With a static API key there is nothing to refresh, so surface the 401
|
|
22
|
+
// instead of looping back into the interactive device flow.
|
|
23
|
+
if (res.status === 401 && !didRetry && !this.auth.usingApiKey) {
|
|
22
24
|
await this.auth.clearToken();
|
|
23
25
|
return this.authorizedFetch(path, init, true);
|
|
24
26
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
declare const PRIORITIES: readonly ["no-priority", "low", "medium", "high", "urgent"];
|
|
2
|
+
export type TaskPriority = (typeof PRIORITIES)[number];
|
|
3
|
+
export declare function isTaskPriority(v: string): v is TaskPriority;
|
|
4
|
+
export type TaskUpdatePatch = {
|
|
5
|
+
title?: string;
|
|
6
|
+
description?: string | null;
|
|
7
|
+
status?: string;
|
|
8
|
+
priority?: TaskPriority;
|
|
9
|
+
projectId?: string;
|
|
10
|
+
position?: number;
|
|
11
|
+
startDate?: string | null;
|
|
12
|
+
dueDate?: string | null;
|
|
13
|
+
userId?: string | null;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Builds the JSON body for `PUT /api/task/:id` from an existing task plus a patch.
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildFullTaskUpdateBody(existing: Record<string, unknown>, patch: TaskUpdatePatch): Record<string, string | number | undefined>;
|
|
19
|
+
export {};
|
package/dist/server.d.ts
ADDED
package/dist/server.js
CHANGED
|
@@ -9,7 +9,8 @@ const { version: packageVersion } = require("../package.json");
|
|
|
9
9
|
export function createMcpServer() {
|
|
10
10
|
const baseUrl = normalizeBaseUrl(process.env.KANEO_API_URL || "http://localhost:1337");
|
|
11
11
|
const clientId = process.env.KANEO_MCP_CLIENT_ID || "kaneo-mcp";
|
|
12
|
-
const
|
|
12
|
+
const apiKey = process.env.KANEO_API_KEY || undefined;
|
|
13
|
+
const auth = new AuthService({ baseUrl, clientId, apiKey });
|
|
13
14
|
const client = new KaneoClient({ baseUrl, auth });
|
|
14
15
|
const server = new McpServer({
|
|
15
16
|
name: "kaneo-mcp",
|
package/dist/tools/register.js
CHANGED
|
@@ -255,6 +255,22 @@ export function registerTools(server, ctx) {
|
|
|
255
255
|
method: "POST",
|
|
256
256
|
body: JSON.stringify({ content: args.content }),
|
|
257
257
|
})));
|
|
258
|
+
server.registerTool("update_task_comment", {
|
|
259
|
+
description: "Update one of your comments on a task.",
|
|
260
|
+
inputSchema: z.object({
|
|
261
|
+
commentId: nonEmptyString,
|
|
262
|
+
content: nonEmptyString,
|
|
263
|
+
}),
|
|
264
|
+
}, async (args) => run(() => client.json(`/api/comment/${encodeURIComponent(args.commentId)}`, {
|
|
265
|
+
method: "PUT",
|
|
266
|
+
body: JSON.stringify({ content: args.content }),
|
|
267
|
+
})));
|
|
268
|
+
server.registerTool("delete_task_comment", {
|
|
269
|
+
description: "Delete one of your comments from a task.",
|
|
270
|
+
inputSchema: z.object({ commentId: nonEmptyString }),
|
|
271
|
+
}, async (args) => run(() => client.json(`/api/comment/${encodeURIComponent(args.commentId)}`, {
|
|
272
|
+
method: "DELETE",
|
|
273
|
+
})));
|
|
258
274
|
server.registerTool("list_workspace_labels", {
|
|
259
275
|
description: "List labels defined in a workspace.",
|
|
260
276
|
inputSchema: z.object({ workspaceId: nonEmptyString }),
|
|
@@ -292,4 +308,43 @@ export function registerTools(server, ctx) {
|
|
|
292
308
|
}, async (args) => run(() => client.json(`/api/label/${encodeURIComponent(args.labelId)}/task`, {
|
|
293
309
|
method: "DELETE",
|
|
294
310
|
})));
|
|
311
|
+
server.registerTool("create_task_relation", {
|
|
312
|
+
description: "Create a relation between two tasks. relationType: 'subtask' (sourceTaskId is the parent, targetTaskId the child), 'blocks' (sourceTaskId blocks targetTaskId), or 'related' (bidirectional).",
|
|
313
|
+
inputSchema: z.object({
|
|
314
|
+
sourceTaskId: nonEmptyString,
|
|
315
|
+
targetTaskId: nonEmptyString,
|
|
316
|
+
relationType: z.enum(["subtask", "blocks", "related"]),
|
|
317
|
+
}),
|
|
318
|
+
}, async (args) => run(() => client.json("/api/task-relation", {
|
|
319
|
+
method: "POST",
|
|
320
|
+
body: JSON.stringify({
|
|
321
|
+
sourceTaskId: args.sourceTaskId,
|
|
322
|
+
targetTaskId: args.targetTaskId,
|
|
323
|
+
relationType: args.relationType,
|
|
324
|
+
}),
|
|
325
|
+
})));
|
|
326
|
+
server.registerTool("get_task_relations", {
|
|
327
|
+
description: "List all relations (subtask/blocks/related) involving a task.",
|
|
328
|
+
inputSchema: z.object({ taskId: nonEmptyString }),
|
|
329
|
+
}, async (args) => run(() => client.json(`/api/task-relation/${encodeURIComponent(args.taskId)}`, {
|
|
330
|
+
method: "GET",
|
|
331
|
+
})));
|
|
332
|
+
server.registerTool("delete_task_relation", {
|
|
333
|
+
description: "Delete a task relation by its relation ID.",
|
|
334
|
+
inputSchema: z.object({ id: nonEmptyString }),
|
|
335
|
+
}, async (args) => run(() => client.json(`/api/task-relation/${encodeURIComponent(args.id)}`, {
|
|
336
|
+
method: "DELETE",
|
|
337
|
+
})));
|
|
338
|
+
server.registerTool("delete_label", {
|
|
339
|
+
description: "Delete a label by ID. Only task-associated labels can be deleted; workspace-level labels (taskId null) are rejected by the API.",
|
|
340
|
+
inputSchema: z.object({ id: nonEmptyString }),
|
|
341
|
+
}, async (args) => run(async () => {
|
|
342
|
+
const label = (await client.json(`/api/label/${encodeURIComponent(args.id)}`, { method: "GET" }));
|
|
343
|
+
if (!label?.taskId) {
|
|
344
|
+
throw new Error("Label is not associated with a task and cannot be deleted (workspace-level labels are not deletable via this endpoint).");
|
|
345
|
+
}
|
|
346
|
+
return client.json(`/api/label/${encodeURIComponent(args.id)}`, {
|
|
347
|
+
method: "DELETE",
|
|
348
|
+
});
|
|
349
|
+
}));
|
|
295
350
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaneo/mcp",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Model Context Protocol (stdio) server for Kaneo
|
|
3
|
+
"version": "0.1.6",
|
|
4
|
+
"description": "Model Context Protocol (stdio) server for Kaneo: tasks, projects, labels, and device authorization",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/usekaneo/kaneo/",
|
|
7
7
|
"repository": {
|
|
@@ -13,6 +13,12 @@
|
|
|
13
13
|
"bin": {
|
|
14
14
|
"kaneo-mcp": "dist/index.js"
|
|
15
15
|
},
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"import": "./dist/server.js",
|
|
19
|
+
"types": "./dist/server.d.ts"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
16
22
|
"publishConfig": {
|
|
17
23
|
"access": "public"
|
|
18
24
|
},
|
|
@@ -37,17 +43,17 @@
|
|
|
37
43
|
"test:watch": "vitest --config vitest.config.ts"
|
|
38
44
|
},
|
|
39
45
|
"dependencies": {
|
|
40
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
46
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
41
47
|
"open": "^11.0.0",
|
|
42
48
|
"prompts": "^2.4.2",
|
|
43
|
-
"zod": "^4.3
|
|
49
|
+
"zod": "^4.4.3"
|
|
44
50
|
},
|
|
45
51
|
"devDependencies": {
|
|
46
52
|
"@kaneo/typescript-config": "workspace:*",
|
|
47
53
|
"@types/node": "^25.3.5",
|
|
48
54
|
"@types/prompts": "^2.4.9",
|
|
49
|
-
"tsx": "^4.
|
|
55
|
+
"tsx": "^4.23.1",
|
|
50
56
|
"typescript": "^5.9.3",
|
|
51
|
-
"vitest": "^4.1.
|
|
57
|
+
"vitest": "^4.1.10"
|
|
52
58
|
}
|
|
53
59
|
}
|