@themkn/clockify-mcp 0.1.0

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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +105 -0
  3. package/SECURITY.md +20 -0
  4. package/config.example.json +4 -0
  5. package/dist/clockify/client.d.ts +53 -0
  6. package/dist/clockify/client.js +181 -0
  7. package/dist/clockify/client.js.map +1 -0
  8. package/dist/clockify/errors.d.ts +7 -0
  9. package/dist/clockify/errors.js +15 -0
  10. package/dist/clockify/errors.js.map +1 -0
  11. package/dist/clockify/types.d.ts +111 -0
  12. package/dist/clockify/types.js +2 -0
  13. package/dist/clockify/types.js.map +1 -0
  14. package/dist/config.d.ts +9 -0
  15. package/dist/config.js +49 -0
  16. package/dist/config.js.map +1 -0
  17. package/dist/index.d.ts +2 -0
  18. package/dist/index.js +24 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/server.d.ts +24 -0
  21. package/dist/server.js +63 -0
  22. package/dist/server.js.map +1 -0
  23. package/dist/tools/clients.d.ts +2 -0
  24. package/dist/tools/clients.js +60 -0
  25. package/dist/tools/clients.js.map +1 -0
  26. package/dist/tools/coerce.d.ts +11 -0
  27. package/dist/tools/coerce.js +43 -0
  28. package/dist/tools/coerce.js.map +1 -0
  29. package/dist/tools/meta.d.ts +2 -0
  30. package/dist/tools/meta.js +21 -0
  31. package/dist/tools/meta.js.map +1 -0
  32. package/dist/tools/projects.d.ts +2 -0
  33. package/dist/tools/projects.js +101 -0
  34. package/dist/tools/projects.js.map +1 -0
  35. package/dist/tools/shape.d.ts +92 -0
  36. package/dist/tools/shape.js +50 -0
  37. package/dist/tools/shape.js.map +1 -0
  38. package/dist/tools/tags.d.ts +2 -0
  39. package/dist/tools/tags.js +54 -0
  40. package/dist/tools/tags.js.map +1 -0
  41. package/dist/tools/tasks.d.ts +2 -0
  42. package/dist/tools/tasks.js +78 -0
  43. package/dist/tools/tasks.js.map +1 -0
  44. package/dist/tools/timeEntries.d.ts +2 -0
  45. package/dist/tools/timeEntries.js +161 -0
  46. package/dist/tools/timeEntries.js.map +1 -0
  47. package/package.json +39 -0
@@ -0,0 +1,24 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { type ZodTypeAny } from "zod";
3
+ import { ClockifyClient } from "./clockify/client.js";
4
+ import type { Config } from "./config.js";
5
+ import type { ClockifyUser } from "./clockify/types.js";
6
+ export interface ToolDefinition<Input> {
7
+ name: string;
8
+ description: string;
9
+ schema: ZodTypeAny;
10
+ handler: (input: Input, ctx: ToolContext) => Promise<unknown>;
11
+ }
12
+ export interface ToolContext {
13
+ client: ClockifyClient;
14
+ config: Config;
15
+ user: ClockifyUser;
16
+ }
17
+ export interface ServerBootstrap {
18
+ config: Config;
19
+ user: ClockifyUser;
20
+ client: ClockifyClient;
21
+ tools: ToolDefinition<unknown>[];
22
+ }
23
+ export declare function buildServer(bootstrap: ServerBootstrap): Server;
24
+ export declare function runServer(bootstrap: ServerBootstrap): Promise<void>;
package/dist/server.js ADDED
@@ -0,0 +1,63 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
4
+ import { z } from "zod";
5
+ import { ClockifyError } from "./clockify/errors.js";
6
+ export function buildServer(bootstrap) {
7
+ const { config, user, client, tools } = bootstrap;
8
+ const byName = new Map(tools.map((t) => [t.name, t]));
9
+ const ctx = { client, config, user };
10
+ const mcp = new Server({ name: "clockify-mcp", version: "0.1.0" }, { capabilities: { tools: {} } });
11
+ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
12
+ tools: tools.map((t) => ({
13
+ name: t.name,
14
+ description: t.description,
15
+ inputSchema: toInputSchema(t.schema),
16
+ })),
17
+ }));
18
+ mcp.setRequestHandler(CallToolRequestSchema, async (req) => {
19
+ const tool = byName.get(req.params.name);
20
+ if (!tool) {
21
+ return {
22
+ isError: true,
23
+ content: [{ type: "text", text: `Unknown tool: ${req.params.name}` }],
24
+ };
25
+ }
26
+ const parsed = tool.schema.safeParse(req.params.arguments ?? {});
27
+ if (!parsed.success) {
28
+ const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
29
+ return {
30
+ isError: true,
31
+ content: [{ type: "text", text: `Invalid input: ${msg}` }],
32
+ };
33
+ }
34
+ try {
35
+ const result = await tool.handler(parsed.data, ctx);
36
+ return {
37
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
38
+ };
39
+ }
40
+ catch (err) {
41
+ const text = err instanceof ClockifyError
42
+ ? err.toUserMessage()
43
+ : `Unexpected error: ${err.message}`;
44
+ return { isError: true, content: [{ type: "text", text }] };
45
+ }
46
+ });
47
+ return mcp;
48
+ }
49
+ export async function runServer(bootstrap) {
50
+ const server = buildServer(bootstrap);
51
+ const transport = new StdioServerTransport();
52
+ await server.connect(transport);
53
+ }
54
+ /**
55
+ * Project a zod schema to the JSON-Schema shape the MCP SDK expects for
56
+ * `Tool.inputSchema`. Delegates to zod 4's built-in `z.toJSONSchema`, then
57
+ * casts to the MCP SDK's narrower type (MCP requires `type: "object"` at the
58
+ * top level; our tool schemas always start with `z.object(...)`).
59
+ */
60
+ function toInputSchema(schema) {
61
+ return z.toJSONSchema(schema, { target: "draft-7" });
62
+ }
63
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { ToolDefinition } from "../server.js";
2
+ export declare const clientTools: ToolDefinition<unknown>[];
@@ -0,0 +1,60 @@
1
+ import { z } from "zod";
2
+ import { shapeClient } from "./shape.js";
3
+ import { zBoolean, zPositiveInt } from "./coerce.js";
4
+ const idString = z.string().min(1).refine((s) => !s.includes("/"), "must not contain '/'");
5
+ const ListInput = z
6
+ .object({
7
+ name: z.string().min(1).optional(),
8
+ archived: zBoolean().optional(),
9
+ page: zPositiveInt().optional(),
10
+ pageSize: zPositiveInt(200).optional(),
11
+ })
12
+ .strict();
13
+ const CreateInput = z.object({ name: z.string().min(1), note: z.string().optional() }).strict();
14
+ const UpdateInput = z
15
+ .object({
16
+ id: idString,
17
+ name: z.string().min(1).optional(),
18
+ note: z.string().optional(),
19
+ archived: zBoolean().optional(),
20
+ })
21
+ .strict();
22
+ const DeleteInput = z.object({ id: idString }).strict();
23
+ const c = (ctx) => ctx.client;
24
+ export const clientTools = [
25
+ {
26
+ name: "list_clients",
27
+ description: "List Clockify clients in the workspace.",
28
+ schema: ListInput,
29
+ handler: async (input, ctx) => {
30
+ const raw = await c(ctx).listClients(ctx.config.workspaceId, input);
31
+ return raw.map(shapeClient);
32
+ },
33
+ },
34
+ {
35
+ name: "create_client",
36
+ description: "Create a Clockify client.",
37
+ schema: CreateInput,
38
+ handler: async (input, ctx) => shapeClient(await c(ctx).createClient(ctx.config.workspaceId, input)),
39
+ },
40
+ {
41
+ name: "update_client",
42
+ description: "Patch a Clockify client. Any field omitted is left unchanged.",
43
+ schema: UpdateInput,
44
+ handler: async (input, ctx) => {
45
+ const { id, ...rest } = input;
46
+ return shapeClient(await c(ctx).updateClient(ctx.config.workspaceId, id, rest));
47
+ },
48
+ },
49
+ {
50
+ name: "delete_client",
51
+ description: "Delete a Clockify client.",
52
+ schema: DeleteInput,
53
+ handler: async (input, ctx) => {
54
+ const { id } = input;
55
+ await c(ctx).deleteClient(ctx.config.workspaceId, id);
56
+ return { deleted: true, id };
57
+ },
58
+ },
59
+ ];
60
+ //# sourceMappingURL=clients.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clients.js","sourceRoot":"","sources":["../../src/tools/clients.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Accepts a boolean, or the strings "true"/"false" (case-insensitive).
4
+ * Rejects everything else. Used because some MCP clients stringify tool
5
+ * arguments before sending them.
6
+ */
7
+ export declare function zBoolean(): z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodBoolean>;
8
+ /** Use this when you don't need chained number constraints. */
9
+ export declare function zNumber(): z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNumber>;
10
+ /** Use this for pagination-style numbers: positive int, optional max. */
11
+ export declare function zPositiveInt(max?: number): z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodNumber>;
@@ -0,0 +1,43 @@
1
+ import { z } from "zod";
2
+ const coerceBoolean = (v) => {
3
+ if (typeof v === "boolean")
4
+ return v;
5
+ if (typeof v === "string") {
6
+ const s = v.trim().toLowerCase();
7
+ if (s === "true")
8
+ return true;
9
+ if (s === "false")
10
+ return false;
11
+ }
12
+ return v; // leave for zod to reject
13
+ };
14
+ const coerceNumber = (v) => {
15
+ if (typeof v === "number")
16
+ return v;
17
+ if (typeof v === "string" && v.trim() !== "") {
18
+ const n = Number(v);
19
+ if (Number.isFinite(n))
20
+ return n;
21
+ }
22
+ return v; // leave for zod to reject
23
+ };
24
+ /**
25
+ * Accepts a boolean, or the strings "true"/"false" (case-insensitive).
26
+ * Rejects everything else. Used because some MCP clients stringify tool
27
+ * arguments before sending them.
28
+ */
29
+ export function zBoolean() {
30
+ return z.preprocess(coerceBoolean, z.boolean());
31
+ }
32
+ /** Use this when you don't need chained number constraints. */
33
+ export function zNumber() {
34
+ return z.preprocess(coerceNumber, z.number());
35
+ }
36
+ /** Use this for pagination-style numbers: positive int, optional max. */
37
+ export function zPositiveInt(max) {
38
+ const base = max === undefined
39
+ ? z.number().int().positive()
40
+ : z.number().int().positive().max(max);
41
+ return z.preprocess(coerceNumber, base);
42
+ }
43
+ //# sourceMappingURL=coerce.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"coerce.js","sourceRoot":"","sources":["../../src/tools/coerce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,aAAa,GAAG,CAAC,CAAU,EAAW,EAAE;IAC5C,IAAI,OAAO,CAAC,KAAK,SAAS;QAAE,OAAO,CAAC,CAAC;IACrC,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACjC,IAAI,CAAC,KAAK,MAAM;YAAE,OAAO,IAAI,CAAC;QAC9B,IAAI,CAAC,KAAK,OAAO;YAAE,OAAO,KAAK,CAAC;IAClC,CAAC;IACD,OAAO,CAAC,CAAC,CAAC,0BAA0B;AACtC,CAAC,CAAC;AAEF,MAAM,YAAY,GAAG,CAAC,CAAU,EAAW,EAAE;IAC3C,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC;IACpC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC7C,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,CAAC,CAAC,CAAC,0BAA0B;AACtC,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,QAAQ;IACtB,OAAO,CAAC,CAAC,UAAU,CAAC,aAAa,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AAClD,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,OAAO;IACrB,OAAO,CAAC,CAAC,UAAU,CAAC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;AAChD,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,MAAM,IAAI,GACR,GAAG,KAAK,SAAS;QACf,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;QAC7B,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC3C,OAAO,CAAC,CAAC,UAAU,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { ToolDefinition } from "../server.js";
2
+ export declare const metaTools: ToolDefinition<unknown>[];
@@ -0,0 +1,21 @@
1
+ import { z } from "zod";
2
+ const Empty = z.object({}).strict();
3
+ export const metaTools = [
4
+ {
5
+ name: "get_current_user",
6
+ description: "Return the Clockify user this server is acting as (resolved from the configured API key at startup).",
7
+ schema: Empty,
8
+ handler: async (_input, ctx) => ({
9
+ id: ctx.user.id,
10
+ email: ctx.user.email,
11
+ name: ctx.user.name,
12
+ }),
13
+ },
14
+ {
15
+ name: "get_workspace",
16
+ description: "Return the workspace id this server operates against.",
17
+ schema: Empty,
18
+ handler: async (_input, ctx) => ({ workspaceId: ctx.config.workspaceId }),
19
+ },
20
+ ];
21
+ //# sourceMappingURL=meta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta.js","sourceRoot":"","sources":["../../src/tools/meta.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;AAEpC,MAAM,CAAC,MAAM,SAAS,GAA8B;IAClD;QACE,IAAI,EAAE,kBAAkB;QACxB,WAAW,EACT,sGAAsG;QACxG,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;YAC/B,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC,EAAE;YACf,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK;YACrB,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI;SACpB,CAAC;KACH;IACD;QACE,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,uDAAuD;QACpE,MAAM,EAAE,KAAK;QACb,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;KAC1E;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { ToolDefinition } from "../server.js";
2
+ export declare const projectTools: ToolDefinition<unknown>[];
@@ -0,0 +1,101 @@
1
+ import { z } from "zod";
2
+ import { ClockifyError } from "../clockify/errors.js";
3
+ import { shapeProject } from "./shape.js";
4
+ import { zBoolean, zPositiveInt } from "./coerce.js";
5
+ const idString = z.string().min(1).refine((s) => !s.includes("/"), "must not contain '/'");
6
+ const ListInput = z
7
+ .object({
8
+ name: z.string().min(1).optional(),
9
+ clientId: idString.optional(),
10
+ archived: zBoolean().optional(),
11
+ page: zPositiveInt().optional(),
12
+ pageSize: zPositiveInt(200).optional(),
13
+ })
14
+ .strict();
15
+ const GetInput = z.object({ id: idString }).strict();
16
+ const CreateInput = z
17
+ .object({
18
+ name: z.string().min(1),
19
+ clientId: idString.optional(),
20
+ color: z.string().min(1).optional(),
21
+ billable: zBoolean().optional(),
22
+ note: z.string().optional(),
23
+ })
24
+ .strict();
25
+ const UpdateInput = z
26
+ .object({
27
+ id: idString,
28
+ name: z.string().min(1).optional(),
29
+ clientId: idString.optional(),
30
+ color: z.string().min(1).optional(),
31
+ billable: zBoolean().optional(),
32
+ note: z.string().optional(),
33
+ })
34
+ .strict();
35
+ const DeleteInput = z.object({ id: idString }).strict();
36
+ const c = (ctx) => ctx.client;
37
+ export const projectTools = [
38
+ {
39
+ name: "list_projects",
40
+ description: "List projects in the workspace. Filter by name substring, clientId, or archived state.",
41
+ schema: ListInput,
42
+ handler: async (input, ctx) => {
43
+ const i = input;
44
+ const raw = await c(ctx).listProjects(ctx.config.workspaceId, {
45
+ name: i.name,
46
+ clientIds: i.clientId ? [i.clientId] : undefined,
47
+ archived: i.archived,
48
+ page: i.page,
49
+ pageSize: i.pageSize,
50
+ });
51
+ return raw.map(shapeProject);
52
+ },
53
+ },
54
+ {
55
+ name: "get_project",
56
+ description: "Fetch a project by id.",
57
+ schema: GetInput,
58
+ handler: async (input, ctx) => {
59
+ const { id } = input;
60
+ return shapeProject(await c(ctx).getProject(ctx.config.workspaceId, id));
61
+ },
62
+ },
63
+ {
64
+ name: "create_project",
65
+ description: "Create a project.",
66
+ schema: CreateInput,
67
+ handler: async (input, ctx) => {
68
+ const body = input;
69
+ return shapeProject(await c(ctx).createProject(ctx.config.workspaceId, body));
70
+ },
71
+ },
72
+ {
73
+ name: "update_project",
74
+ description: "Patch a project. Any field omitted is left unchanged.",
75
+ schema: UpdateInput,
76
+ handler: async (input, ctx) => {
77
+ const { id, ...rest } = input;
78
+ return shapeProject(await c(ctx).updateProject(ctx.config.workspaceId, id, rest));
79
+ },
80
+ },
81
+ {
82
+ name: "delete_project",
83
+ description: "Attempt to delete a project. If Clockify refuses because the project has time entries, the project is archived instead. The response reports which action ran: { action: 'deleted' } or { action: 'archived' }.",
84
+ schema: DeleteInput,
85
+ handler: async (input, ctx) => {
86
+ const { id } = input;
87
+ try {
88
+ await c(ctx).deleteProject(ctx.config.workspaceId, id);
89
+ return { action: "deleted", id };
90
+ }
91
+ catch (err) {
92
+ if (err instanceof ClockifyError && (err.status === 400 || err.status === 403 || err.status === 409)) {
93
+ await c(ctx).archiveProject(ctx.config.workspaceId, id);
94
+ return { action: "archived", id };
95
+ }
96
+ throw err;
97
+ }
98
+ },
99
+ },
100
+ ];
101
+ //# sourceMappingURL=projects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/tools/projects.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,92 @@
1
+ interface RawTimeEntry {
2
+ id: string;
3
+ description?: string;
4
+ timeInterval?: {
5
+ start?: string;
6
+ end?: string | null;
7
+ duration?: string | null;
8
+ };
9
+ projectId?: string | null;
10
+ project?: {
11
+ id?: string;
12
+ name?: string;
13
+ } | null;
14
+ taskId?: string | null;
15
+ tagIds?: string[] | null;
16
+ billable?: boolean;
17
+ }
18
+ export interface TimeEntrySummary {
19
+ id: string;
20
+ description: string;
21
+ start: string | null;
22
+ end: string | null;
23
+ durationSeconds: number | null;
24
+ projectId: string | null;
25
+ projectName: string | null;
26
+ taskId: string | null;
27
+ tagIds: string[];
28
+ billable: boolean;
29
+ }
30
+ export declare function shapeTimeEntry(e: RawTimeEntry): TimeEntrySummary;
31
+ interface RawProject {
32
+ id: string;
33
+ name: string;
34
+ clientId?: string | null;
35
+ clientName?: string | null;
36
+ archived?: boolean;
37
+ billable?: boolean;
38
+ color?: string | null;
39
+ note?: string | null;
40
+ }
41
+ export interface ProjectSummary {
42
+ id: string;
43
+ name: string;
44
+ clientId: string | null;
45
+ clientName: string | null;
46
+ archived: boolean;
47
+ billable: boolean;
48
+ color: string | null;
49
+ }
50
+ export declare function shapeProject(p: RawProject): ProjectSummary;
51
+ interface RawTask {
52
+ id: string;
53
+ name: string;
54
+ projectId: string;
55
+ status?: string;
56
+ assigneeIds?: string[];
57
+ estimate?: string | null;
58
+ }
59
+ export interface TaskSummary {
60
+ id: string;
61
+ name: string;
62
+ projectId: string;
63
+ status: string | null;
64
+ assigneeIds: string[];
65
+ estimate: string | null;
66
+ }
67
+ export declare function shapeTask(t: RawTask): TaskSummary;
68
+ interface RawTag {
69
+ id: string;
70
+ name: string;
71
+ archived?: boolean;
72
+ }
73
+ export interface TagSummary {
74
+ id: string;
75
+ name: string;
76
+ archived: boolean;
77
+ }
78
+ export declare function shapeTag(t: RawTag): TagSummary;
79
+ interface RawClient {
80
+ id: string;
81
+ name: string;
82
+ archived?: boolean;
83
+ note?: string | null;
84
+ }
85
+ export interface ClientSummary {
86
+ id: string;
87
+ name: string;
88
+ archived: boolean;
89
+ note: string | null;
90
+ }
91
+ export declare function shapeClient(c: RawClient): ClientSummary;
92
+ export {};
@@ -0,0 +1,50 @@
1
+ export function shapeTimeEntry(e) {
2
+ const start = e.timeInterval?.start ?? null;
3
+ const end = e.timeInterval?.end ?? null;
4
+ return {
5
+ id: e.id,
6
+ description: e.description ?? "",
7
+ start,
8
+ end,
9
+ durationSeconds: computeDurationSeconds(start, end),
10
+ projectId: e.projectId ?? e.project?.id ?? null,
11
+ projectName: e.project?.name ?? null,
12
+ taskId: e.taskId ?? null,
13
+ tagIds: e.tagIds ?? [],
14
+ billable: e.billable ?? false,
15
+ };
16
+ }
17
+ function computeDurationSeconds(start, end) {
18
+ if (!start || !end)
19
+ return null;
20
+ const ms = Date.parse(end) - Date.parse(start);
21
+ return Number.isFinite(ms) ? Math.round(ms / 1000) : null;
22
+ }
23
+ export function shapeProject(p) {
24
+ return {
25
+ id: p.id,
26
+ name: p.name,
27
+ clientId: p.clientId ?? null,
28
+ clientName: p.clientName ?? null,
29
+ archived: p.archived ?? false,
30
+ billable: p.billable ?? false,
31
+ color: p.color ?? null,
32
+ };
33
+ }
34
+ export function shapeTask(t) {
35
+ return {
36
+ id: t.id,
37
+ name: t.name,
38
+ projectId: t.projectId,
39
+ status: t.status ?? null,
40
+ assigneeIds: t.assigneeIds ?? [],
41
+ estimate: t.estimate ?? null,
42
+ };
43
+ }
44
+ export function shapeTag(t) {
45
+ return { id: t.id, name: t.name, archived: t.archived ?? false };
46
+ }
47
+ export function shapeClient(c) {
48
+ return { id: c.id, name: c.name, archived: c.archived ?? false, note: c.note ?? null };
49
+ }
50
+ //# sourceMappingURL=shape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shape.js","sourceRoot":"","sources":["../../src/tools/shape.ts"],"names":[],"mappings":"AAwBA,MAAM,UAAU,cAAc,CAAC,CAAe;IAC5C,MAAM,KAAK,GAAG,CAAC,CAAC,YAAY,EAAE,KAAK,IAAI,IAAI,CAAC;IAC5C,MAAM,GAAG,GAAG,CAAC,CAAC,YAAY,EAAE,GAAG,IAAI,IAAI,CAAC;IACxC,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,EAAE;QAChC,KAAK;QACL,GAAG;QACH,eAAe,EAAE,sBAAsB,CAAC,KAAK,EAAE,GAAG,CAAC;QACnD,SAAS,EAAE,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,IAAI,IAAI;QAC/C,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,IAAI,IAAI,IAAI;QACpC,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,IAAI;QACxB,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE;QACtB,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,KAAK;KAC9B,CAAC;AACJ,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAoB,EAAE,GAAkB;IACtE,IAAI,CAAC,KAAK,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IAChC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC/C,OAAO,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC5D,CAAC;AAuBD,MAAM,UAAU,YAAY,CAAC,CAAa;IACxC,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAI;QAC5B,UAAU,EAAE,CAAC,CAAC,UAAU,IAAI,IAAI;QAChC,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,KAAK;QAC7B,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,KAAK;QAC7B,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI;KACvB,CAAC;AACJ,CAAC;AAoBD,MAAM,UAAU,SAAS,CAAC,CAAU;IAClC,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,MAAM,EAAE,CAAC,CAAC,MAAM,IAAI,IAAI;QACxB,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,EAAE;QAChC,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,IAAI;KAC7B,CAAC;AACJ,CAAC;AAcD,MAAM,UAAU,QAAQ,CAAC,CAAS;IAChC,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,KAAK,EAAE,CAAC;AACnE,CAAC;AAgBD,MAAM,UAAU,WAAW,CAAC,CAAY;IACtC,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;AACzF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { ToolDefinition } from "../server.js";
2
+ export declare const tagTools: ToolDefinition<unknown>[];
@@ -0,0 +1,54 @@
1
+ import { z } from "zod";
2
+ import { shapeTag } from "./shape.js";
3
+ import { zBoolean, zPositiveInt } from "./coerce.js";
4
+ const idString = z.string().min(1).refine((s) => !s.includes("/"), "must not contain '/'");
5
+ const ListInput = z
6
+ .object({
7
+ name: z.string().min(1).optional(),
8
+ archived: zBoolean().optional(),
9
+ page: zPositiveInt().optional(),
10
+ pageSize: zPositiveInt(200).optional(),
11
+ })
12
+ .strict();
13
+ const CreateInput = z.object({ name: z.string().min(1) }).strict();
14
+ const UpdateInput = z.object({ id: idString, name: z.string().min(1).optional(), archived: zBoolean().optional() }).strict();
15
+ const DeleteInput = z.object({ id: idString }).strict();
16
+ const c = (ctx) => ctx.client;
17
+ export const tagTools = [
18
+ {
19
+ name: "list_tags",
20
+ description: "List tags in the workspace. Filter by name or archived state.",
21
+ schema: ListInput,
22
+ handler: async (input, ctx) => {
23
+ const i = input;
24
+ const raw = await c(ctx).listTags(ctx.config.workspaceId, i);
25
+ return raw.map(shapeTag);
26
+ },
27
+ },
28
+ {
29
+ name: "create_tag",
30
+ description: "Create a tag.",
31
+ schema: CreateInput,
32
+ handler: async (input, ctx) => shapeTag(await c(ctx).createTag(ctx.config.workspaceId, input)),
33
+ },
34
+ {
35
+ name: "update_tag",
36
+ description: "Rename or archive a tag.",
37
+ schema: UpdateInput,
38
+ handler: async (input, ctx) => {
39
+ const { id, ...rest } = input;
40
+ return shapeTag(await c(ctx).updateTag(ctx.config.workspaceId, id, rest));
41
+ },
42
+ },
43
+ {
44
+ name: "delete_tag",
45
+ description: "Delete a tag.",
46
+ schema: DeleteInput,
47
+ handler: async (input, ctx) => {
48
+ const { id } = input;
49
+ await c(ctx).deleteTag(ctx.config.workspaceId, id);
50
+ return { deleted: true, id };
51
+ },
52
+ },
53
+ ];
54
+ //# sourceMappingURL=tags.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tags.js","sourceRoot":"","sources":["../../src/tools/tags.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { ToolDefinition } from "../server.js";
2
+ export declare const taskTools: ToolDefinition<unknown>[];