basecamp-mcp 1.1.2 → 1.2.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 (75) hide show
  1. package/dist/index.d.ts +7 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +16 -7
  4. package/dist/index.js.map +1 -1
  5. package/dist/tools/activity.d.ts +6 -4
  6. package/dist/tools/activity.d.ts.map +1 -1
  7. package/dist/tools/activity.js +13 -285
  8. package/dist/tools/activity.js.map +1 -1
  9. package/dist/tools/auth.d.ts.map +1 -1
  10. package/dist/tools/auth.js +5 -11
  11. package/dist/tools/auth.js.map +1 -1
  12. package/dist/tools/campfires.d.ts +13 -0
  13. package/dist/tools/campfires.d.ts.map +1 -0
  14. package/dist/tools/campfires.js +221 -0
  15. package/dist/tools/campfires.js.map +1 -0
  16. package/dist/tools/checkins.d.ts.map +1 -1
  17. package/dist/tools/checkins.js +10 -74
  18. package/dist/tools/checkins.js.map +1 -1
  19. package/dist/tools/comments.d.ts.map +1 -1
  20. package/dist/tools/comments.js +9 -44
  21. package/dist/tools/comments.js.map +1 -1
  22. package/dist/tools/files.d.ts +21 -0
  23. package/dist/tools/files.d.ts.map +1 -0
  24. package/dist/tools/files.js +659 -0
  25. package/dist/tools/files.js.map +1 -0
  26. package/dist/tools/kanban.d.ts.map +1 -1
  27. package/dist/tools/kanban.js +78 -137
  28. package/dist/tools/kanban.js.map +1 -1
  29. package/dist/tools/messages.d.ts.map +1 -1
  30. package/dist/tools/messages.js +31 -71
  31. package/dist/tools/messages.js.map +1 -1
  32. package/dist/tools/people.d.ts.map +1 -1
  33. package/dist/tools/people.js +5 -19
  34. package/dist/tools/people.js.map +1 -1
  35. package/dist/tools/projects.d.ts.map +1 -1
  36. package/dist/tools/projects.js +4 -16
  37. package/dist/tools/projects.js.map +1 -1
  38. package/dist/tools/todos.d.ts.map +1 -1
  39. package/dist/tools/todos.js +60 -84
  40. package/dist/tools/todos.js.map +1 -1
  41. package/dist/utils/auth.d.ts +7 -2
  42. package/dist/utils/auth.d.ts.map +1 -1
  43. package/dist/utils/auth.js +19 -11
  44. package/dist/utils/auth.js.map +1 -1
  45. package/dist/utils/contentOperations.d.ts +2 -2
  46. package/dist/utils/credentials.d.ts.map +1 -1
  47. package/dist/utils/credentials.js.map +1 -1
  48. package/dist/utils/errorHandlers.d.ts.map +1 -1
  49. package/dist/utils/errorHandlers.js +53 -29
  50. package/dist/utils/errorHandlers.js.map +1 -1
  51. package/dist/utils/oauth.d.ts +1 -0
  52. package/dist/utils/oauth.d.ts.map +1 -1
  53. package/dist/utils/oauth.js +18 -0
  54. package/dist/utils/oauth.js.map +1 -1
  55. package/dist/utils/pagination.d.ts +43 -0
  56. package/dist/utils/pagination.d.ts.map +1 -0
  57. package/dist/utils/pagination.js +72 -0
  58. package/dist/utils/pagination.js.map +1 -0
  59. package/dist/utils/parseSince.d.ts +11 -0
  60. package/dist/utils/parseSince.d.ts.map +1 -0
  61. package/dist/utils/parseSince.js +48 -0
  62. package/dist/utils/parseSince.js.map +1 -0
  63. package/dist/utils/serializers.d.ts +17 -2
  64. package/dist/utils/serializers.d.ts.map +1 -1
  65. package/dist/utils/serializers.js +16 -0
  66. package/dist/utils/serializers.js.map +1 -1
  67. package/package.json +5 -3
  68. package/dist/tools/documents.d.ts +0 -11
  69. package/dist/tools/documents.d.ts.map +0 -1
  70. package/dist/tools/documents.js +0 -453
  71. package/dist/tools/documents.js.map +0 -1
  72. package/dist/tools/uploads.d.ts +0 -9
  73. package/dist/tools/uploads.d.ts.map +0 -1
  74. package/dist/tools/uploads.js +0 -319
  75. package/dist/tools/uploads.js.map +0 -1
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Lazy pagination over Basecamp list endpoints.
3
+ *
4
+ * The SDK's high-level `.list()` methods eagerly fetch every page before
5
+ * returning, and the exported `paginateAll`/`fetchAllPages` helpers are unusable
6
+ * with `client.GET` responses (the body is already consumed to build `data`, so
7
+ * their internal `.clone()` throws). This module provides a generator that pages
8
+ * on demand by following `Link: rel="next"` headers, so callers can stop early
9
+ * (e.g. once results predate a cutoff). Shared by the recordings feed
10
+ * (`activity.ts`) and campfire lines (`campfires.ts`).
11
+ */
12
+ import type { initializeBasecampClient } from "./auth.js";
13
+ /** Safety cap on pages fetched, mirroring the SDK's DEFAULT_MAX_PAGES. */
14
+ export declare const MAX_PAGES = 10000;
15
+ export type BasecampClientInstance = Awaited<ReturnType<typeof initializeBasecampClient>>;
16
+ export type LowLevelGet = (path: string, init: {
17
+ params: {
18
+ query?: Record<string, unknown>;
19
+ path?: Record<string, unknown>;
20
+ };
21
+ }) => Promise<{
22
+ data?: unknown;
23
+ error?: unknown;
24
+ response: Response;
25
+ }>;
26
+ /**
27
+ * Recursively coerce Basecamp person IDs that arrive as strings into numbers,
28
+ * mirroring the normalization the SDK's high-level `.list()` methods apply.
29
+ * The low-level `client.GET` path used for lazy pagination skips it, so we
30
+ * replicate it here to keep creator IDs consistent for filtering/output.
31
+ */
32
+ export declare function normalizePersonIds(obj: unknown): void;
33
+ /**
34
+ * Lazily page through a list endpoint via the low-level client, yielding items
35
+ * one at a time so callers can stop early.
36
+ *
37
+ * Reuses the SDK client so auth, User-Agent, and retry behavior are preserved.
38
+ */
39
+ export declare function paginate<T>(client: BasecampClientInstance, path: string, params: {
40
+ query?: Record<string, unknown>;
41
+ path?: Record<string, unknown>;
42
+ }): AsyncGenerator<T>;
43
+ //# sourceMappingURL=pagination.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../src/utils/pagination.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAE1D,0EAA0E;AAC1E,eAAO,MAAM,SAAS,QAAS,CAAC;AAEhC,MAAM,MAAM,sBAAsB,GAAG,OAAO,CAC1C,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAC5C,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,CACxB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE;IACJ,MAAM,EAAE;QACN,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAChC,CAAC;CACH,KACE,OAAO,CAAC;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC,CAAC;AAEtE;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAwBrD;AAED;;;;;GAKG;AACH,wBAAuB,QAAQ,CAAC,CAAC,EAC/B,MAAM,EAAE,sBAAsB,EAC9B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE;IACN,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,GACA,cAAc,CAAC,CAAC,CAAC,CAsBnB"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Lazy pagination over Basecamp list endpoints.
3
+ *
4
+ * The SDK's high-level `.list()` methods eagerly fetch every page before
5
+ * returning, and the exported `paginateAll`/`fetchAllPages` helpers are unusable
6
+ * with `client.GET` responses (the body is already consumed to build `data`, so
7
+ * their internal `.clone()` throws). This module provides a generator that pages
8
+ * on demand by following `Link: rel="next"` headers, so callers can stop early
9
+ * (e.g. once results predate a cutoff). Shared by the recordings feed
10
+ * (`activity.ts`) and campfire lines (`campfires.ts`).
11
+ */
12
+ import { parseNextLink } from "@37signals/basecamp";
13
+ /** Safety cap on pages fetched, mirroring the SDK's DEFAULT_MAX_PAGES. */
14
+ export const MAX_PAGES = 10_000;
15
+ /**
16
+ * Recursively coerce Basecamp person IDs that arrive as strings into numbers,
17
+ * mirroring the normalization the SDK's high-level `.list()` methods apply.
18
+ * The low-level `client.GET` path used for lazy pagination skips it, so we
19
+ * replicate it here to keep creator IDs consistent for filtering/output.
20
+ */
21
+ export function normalizePersonIds(obj) {
22
+ if (!obj || typeof obj !== "object")
23
+ return;
24
+ if (Array.isArray(obj)) {
25
+ for (const item of obj)
26
+ normalizePersonIds(item);
27
+ return;
28
+ }
29
+ const rec = obj;
30
+ if ("personable_type" in rec && typeof rec.id === "string") {
31
+ const idStr = rec.id;
32
+ if (/^-?\d+$/.test(idStr) && Number.isSafeInteger(Number(idStr))) {
33
+ rec.id = Number(idStr);
34
+ }
35
+ else {
36
+ // Non-numeric sentinel (e.g. "basecamp") or unsafe integer — preserve
37
+ // the original as a label and zero the numeric id.
38
+ rec.system_label = idStr;
39
+ rec.id = 0;
40
+ }
41
+ }
42
+ for (const val of Object.values(rec)) {
43
+ if (typeof val === "object" && val !== null)
44
+ normalizePersonIds(val);
45
+ }
46
+ }
47
+ /**
48
+ * Lazily page through a list endpoint via the low-level client, yielding items
49
+ * one at a time so callers can stop early.
50
+ *
51
+ * Reuses the SDK client so auth, User-Agent, and retry behavior are preserved.
52
+ */
53
+ export async function* paginate(client, path, params) {
54
+ const get = client.GET;
55
+ const baseQuery = params.query ?? {};
56
+ for (let page = 1; page <= MAX_PAGES; page++) {
57
+ const { data, error, response } = await get(path, {
58
+ params: { ...params, query: { ...baseQuery, page } },
59
+ });
60
+ if (error || !response.ok) {
61
+ throw new Error(`Failed to fetch ${path} (page ${page})`);
62
+ }
63
+ const items = (data ?? []);
64
+ normalizePersonIds(items);
65
+ for (const item of items) {
66
+ yield item;
67
+ }
68
+ if (!parseNextLink(response.headers.get("Link")))
69
+ break;
70
+ }
71
+ }
72
+ //# sourceMappingURL=pagination.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../src/utils/pagination.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD,0EAA0E;AAC1E,MAAM,CAAC,MAAM,SAAS,GAAG,MAAM,CAAC;AAgBhC;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAY;IAC7C,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO;IAE5C,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,KAAK,MAAM,IAAI,IAAI,GAAG;YAAE,kBAAkB,CAAC,IAAI,CAAC,CAAC;QACjD,OAAO;IACT,CAAC;IAED,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,IAAI,iBAAiB,IAAI,GAAG,IAAI,OAAO,GAAG,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;QAC3D,MAAM,KAAK,GAAG,GAAG,CAAC,EAAE,CAAC;QACrB,IAAI,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YACjE,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,sEAAsE;YACtE,mDAAmD;YACnD,GAAG,CAAC,YAAY,GAAG,KAAK,CAAC;YACzB,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;QACb,CAAC;IACH,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACrC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;YAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC;IACvE,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,SAAS,CAAC,CAAC,QAAQ,CAC7B,MAA8B,EAC9B,IAAY,EACZ,MAGC;IAED,MAAM,GAAG,GAAG,MAAM,CAAC,GAA6B,CAAC;IACjD,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;IAErC,KAAK,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC;QAC7C,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE;YAChD,MAAM,EAAE,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,EAAE,GAAG,SAAS,EAAE,IAAI,EAAE,EAAE;SACrD,CAAC,CAAC;QAEH,IAAI,KAAK,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,UAAU,IAAI,GAAG,CAAC,CAAC;QAC5D,CAAC;QAED,MAAM,KAAK,GAAG,CAAC,IAAI,IAAI,EAAE,CAAQ,CAAC;QAClC,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAE1B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,CAAC;QACb,CAAC;QAED,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;YAAE,MAAM;IAC1D,CAAC;AACH,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Parse a "since" value into a Date object, used by the activity feed and
3
+ * campfire browsing tools to filter results to a recent time window.
4
+ *
5
+ * Supports:
6
+ * - Relative durations: "24h", "7d", "2w"
7
+ * - Keywords: "today", "yesterday"
8
+ * - ISO 8601 dates: "2024-01-15", "2024-01-15T10:00:00Z"
9
+ */
10
+ export declare function parseSince(value: string): Date;
11
+ //# sourceMappingURL=parseSince.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseSince.d.ts","sourceRoot":"","sources":["../../src/utils/parseSince.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAkD9C"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Parse a "since" value into a Date object, used by the activity feed and
3
+ * campfire browsing tools to filter results to a recent time window.
4
+ *
5
+ * Supports:
6
+ * - Relative durations: "24h", "7d", "2w"
7
+ * - Keywords: "today", "yesterday"
8
+ * - ISO 8601 dates: "2024-01-15", "2024-01-15T10:00:00Z"
9
+ */
10
+ export function parseSince(value) {
11
+ const now = new Date();
12
+ const trimmed = value.trim();
13
+ const lower = trimmed.toLowerCase();
14
+ // Relative durations: Nh, Nd, Nw
15
+ const hourMatch = lower.match(/^(\d+)h$/);
16
+ if (hourMatch) {
17
+ return new Date(now.getTime() - Number.parseInt(hourMatch[1], 10) * 3600000);
18
+ }
19
+ const dayMatch = lower.match(/^(\d+)d$/);
20
+ if (dayMatch) {
21
+ return new Date(now.getTime() - Number.parseInt(dayMatch[1], 10) * 86400000);
22
+ }
23
+ const weekMatch = lower.match(/^(\d+)w$/);
24
+ if (weekMatch) {
25
+ return new Date(now.getTime() - Number.parseInt(weekMatch[1], 10) * 7 * 86400000);
26
+ }
27
+ // Keywords
28
+ if (lower === "today") {
29
+ const d = new Date(now);
30
+ d.setHours(0, 0, 0, 0);
31
+ return d;
32
+ }
33
+ if (lower === "yesterday") {
34
+ const d = new Date(now);
35
+ d.setDate(d.getDate() - 1);
36
+ d.setHours(0, 0, 0, 0);
37
+ return d;
38
+ }
39
+ // ISO 8601 / date string
40
+ const parsed = new Date(trimmed);
41
+ if (Number.isNaN(parsed.getTime())) {
42
+ throw new Error(`Invalid since value: "${value}". ` +
43
+ 'Use ISO 8601 (e.g., "2024-01-15"), relative duration (e.g., "24h", "7d", "2w"), ' +
44
+ 'or keyword ("today", "yesterday").');
45
+ }
46
+ return parsed;
47
+ }
48
+ //# sourceMappingURL=parseSince.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseSince.js","sourceRoot":"","sources":["../../src/utils/parseSince.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAEpC,iCAAiC;IACjC,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC1C,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,IAAI,IAAI,CACb,GAAG,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,OAAO,CAC5D,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACzC,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,IAAI,IAAI,CACb,GAAG,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,QAAQ,CAC5D,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAC1C,IAAI,SAAS,EAAE,CAAC;QACd,OAAO,IAAI,IAAI,CACb,GAAG,CAAC,OAAO,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,QAAQ,CACjE,CAAC;IACJ,CAAC;IAED,WAAW;IACX,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;QACtB,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACvB,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,KAAK,KAAK,WAAW,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;QAC3B,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACvB,OAAO,CAAC,CAAC;IACX,CAAC;IAED,yBAAyB;IACzB,MAAM,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CACb,yBAAyB,KAAK,KAAK;YACjC,kFAAkF;YAClF,oCAAoC,CACvC,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -7,7 +7,7 @@
7
7
  interface BasecampPerson {
8
8
  id: number;
9
9
  name: string;
10
- attachable_sgid: string;
10
+ attachable_sgid?: string;
11
11
  }
12
12
  /**
13
13
  * Serialized person object for MCP responses
@@ -15,7 +15,7 @@ interface BasecampPerson {
15
15
  export interface SerializedPerson {
16
16
  id: number;
17
17
  name: string;
18
- attachable_sgid: string;
18
+ attachable_sgid?: string;
19
19
  }
20
20
  /**
21
21
  * Serialize a Basecamp person object to a consistent format
@@ -23,5 +23,20 @@ export interface SerializedPerson {
23
23
  * @returns Serialized person with id and name
24
24
  */
25
25
  export declare function serializePerson(person: BasecampPerson | null | undefined): SerializedPerson | null;
26
+ /**
27
+ * Creator object as exposed by the activity feed and campfire browsing tools:
28
+ * id + name + email. In contrast to {@link serializePerson}, this surfaces the
29
+ * email address (useful for attributing activity) rather than the
30
+ * `attachable_sgid` (which is only needed for attachment authoring).
31
+ */
32
+ export declare function serializeCreator(person: {
33
+ id: number;
34
+ name: string;
35
+ email_address?: string;
36
+ } | null | undefined): {
37
+ id: number;
38
+ name: string;
39
+ email?: string;
40
+ } | null;
26
41
  export {};
27
42
  //# sourceMappingURL=serializers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"serializers.d.ts","sourceRoot":"","sources":["../../src/utils/serializers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,UAAU,cAAc;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,GACxC,gBAAgB,GAAG,IAAI,CAUzB"}
1
+ {"version":3,"file":"serializers.d.ts","sourceRoot":"","sources":["../../src/utils/serializers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;GAEG;AACH,UAAU,cAAc;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,GACxC,gBAAgB,GAAG,IAAI,CAUzB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EACF;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GACpD,IAAI,GACJ,SAAS,GACZ;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAUrD"}
@@ -16,4 +16,20 @@ export function serializePerson(person) {
16
16
  attachable_sgid: person.attachable_sgid,
17
17
  };
18
18
  }
19
+ /**
20
+ * Creator object as exposed by the activity feed and campfire browsing tools:
21
+ * id + name + email. In contrast to {@link serializePerson}, this surfaces the
22
+ * email address (useful for attributing activity) rather than the
23
+ * `attachable_sgid` (which is only needed for attachment authoring).
24
+ */
25
+ export function serializeCreator(person) {
26
+ if (!person) {
27
+ return null;
28
+ }
29
+ return {
30
+ id: person.id,
31
+ name: person.name,
32
+ email: person.email_address,
33
+ };
34
+ }
19
35
  //# sourceMappingURL=serializers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"serializers.js","sourceRoot":"","sources":["../../src/utils/serializers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAoBH;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAyC;IAEzC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,eAAe,EAAE,MAAM,CAAC,eAAe;KACxC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"serializers.js","sourceRoot":"","sources":["../../src/utils/serializers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAoBH;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAyC;IAEzC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,eAAe,EAAE,MAAM,CAAC,eAAe;KACxC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAGa;IAEb,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,EAAE;QACb,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,KAAK,EAAE,MAAM,CAAC,aAAa;KAC5B,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "basecamp-mcp",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "description": "Model Context Protocol (MCP) server for Basecamp integration. Enables LLMs to interact with Basecamp projects, messages, todos, comments, people, and kanban boards.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -22,7 +22,8 @@
22
22
  "check": "biome check --write .",
23
23
  "check:ci": "biome check .",
24
24
  "prepublishOnly": "npm run clean && npm run build",
25
- "test": "echo 'All good'"
25
+ "test": "vitest run",
26
+ "test:watch": "vitest watch"
26
27
  },
27
28
  "engines": {
28
29
  "node": ">=18"
@@ -48,8 +49,8 @@
48
49
  },
49
50
  "homepage": "https://github.com/stefanoverna/basecamp-mcp#readme",
50
51
  "dependencies": {
52
+ "@37signals/basecamp": "^0.7.3",
51
53
  "@modelcontextprotocol/sdk": "^1.6.1",
52
- "basecamp-client": "^1.0.10",
53
54
  "zod": "^3.23.8"
54
55
  },
55
56
  "devDependencies": {
@@ -60,6 +61,7 @@
60
61
  "np": "^10.2.0",
61
62
  "tsx": "^4.19.2",
62
63
  "typescript": "^5.7.2",
64
+ "vitest": "^4.1.8",
63
65
  "xml2js": "^0.6.2"
64
66
  }
65
67
  }
@@ -1,11 +0,0 @@
1
- /**
2
- * Document, Vault & File download tools for Basecamp MCP server
3
- *
4
- * Vaults are folders in Basecamp's "Docs & Files" section.
5
- * Documents are rich-text documents stored inside vaults.
6
- * Uploads are files stored in vaults.
7
- * Blobs are inline attachments embedded in rich text via <bc-attachment> tags.
8
- */
9
- import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10
- export declare function registerDocumentTools(server: McpServer): void;
11
- //# sourceMappingURL=documents.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"documents.d.ts","sourceRoot":"","sources":["../../src/tools/documents.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAczE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6gB7D"}