basecamp-mcp 1.0.1

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 (58) hide show
  1. package/README.md +155 -0
  2. package/dist/constants.d.ts +14 -0
  3. package/dist/constants.d.ts.map +1 -0
  4. package/dist/constants.js +14 -0
  5. package/dist/constants.js.map +1 -0
  6. package/dist/index.d.ts +20 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +71 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/schemas/common.d.ts +13 -0
  11. package/dist/schemas/common.d.ts.map +1 -0
  12. package/dist/schemas/common.js +19 -0
  13. package/dist/schemas/common.js.map +1 -0
  14. package/dist/tools/comments.d.ts +7 -0
  15. package/dist/tools/comments.d.ts.map +1 -0
  16. package/dist/tools/comments.js +179 -0
  17. package/dist/tools/comments.js.map +1 -0
  18. package/dist/tools/kanban.d.ts +6 -0
  19. package/dist/tools/kanban.d.ts.map +1 -0
  20. package/dist/tools/kanban.js +390 -0
  21. package/dist/tools/kanban.js.map +1 -0
  22. package/dist/tools/messages.d.ts +8 -0
  23. package/dist/tools/messages.d.ts.map +1 -0
  24. package/dist/tools/messages.js +300 -0
  25. package/dist/tools/messages.js.map +1 -0
  26. package/dist/tools/people.d.ts +6 -0
  27. package/dist/tools/people.d.ts.map +1 -0
  28. package/dist/tools/people.js +142 -0
  29. package/dist/tools/people.js.map +1 -0
  30. package/dist/tools/projects.d.ts +11 -0
  31. package/dist/tools/projects.d.ts.map +1 -0
  32. package/dist/tools/projects.js +116 -0
  33. package/dist/tools/projects.js.map +1 -0
  34. package/dist/tools/todos.d.ts +6 -0
  35. package/dist/tools/todos.d.ts.map +1 -0
  36. package/dist/tools/todos.js +223 -0
  37. package/dist/tools/todos.js.map +1 -0
  38. package/dist/types.d.ts +27 -0
  39. package/dist/types.d.ts.map +1 -0
  40. package/dist/types.js +5 -0
  41. package/dist/types.js.map +1 -0
  42. package/dist/utils/auth.d.ts +24 -0
  43. package/dist/utils/auth.d.ts.map +1 -0
  44. package/dist/utils/auth.js +62 -0
  45. package/dist/utils/auth.js.map +1 -0
  46. package/dist/utils/contentOperations.d.ts +55 -0
  47. package/dist/utils/contentOperations.d.ts.map +1 -0
  48. package/dist/utils/contentOperations.js +109 -0
  49. package/dist/utils/contentOperations.js.map +1 -0
  50. package/dist/utils/errorHandlers.d.ts +11 -0
  51. package/dist/utils/errorHandlers.d.ts.map +1 -0
  52. package/dist/utils/errorHandlers.js +87 -0
  53. package/dist/utils/errorHandlers.js.map +1 -0
  54. package/dist/utils/serializers.d.ts +27 -0
  55. package/dist/utils/serializers.d.ts.map +1 -0
  56. package/dist/utils/serializers.js +19 -0
  57. package/dist/utils/serializers.js.map +1 -0
  58. package/package.json +65 -0
@@ -0,0 +1,223 @@
1
+ /**
2
+ * TODO tools for Basecamp MCP server
3
+ */
4
+ import { asyncPagedToArray } from "basecamp-client";
5
+ import { z } from "zod";
6
+ import { BasecampIdSchema } from "../schemas/common.js";
7
+ import { initializeBasecampClient } from "../utils/auth.js";
8
+ import { htmlRules } from "../utils/contentOperations.js";
9
+ import { handleBasecampError } from "../utils/errorHandlers.js";
10
+ export function registerTodoTools(server) {
11
+ server.registerTool("basecamp_get_todoset", {
12
+ title: "Get Basecamp Todo Set",
13
+ description: "Get todo set container for a project. Returns todo lists and groups.",
14
+ inputSchema: {
15
+ bucket_id: BasecampIdSchema,
16
+ todoset_id: BasecampIdSchema,
17
+ },
18
+ annotations: {
19
+ readOnlyHint: true,
20
+ destructiveHint: false,
21
+ idempotentHint: true,
22
+ openWorldHint: true,
23
+ },
24
+ }, async (params) => {
25
+ try {
26
+ const client = await initializeBasecampClient();
27
+ const responseTodoSet = await client.todoSets.get({
28
+ params: { bucketId: params.bucket_id, todosetId: params.todoset_id },
29
+ });
30
+ if (responseTodoSet.status !== 200 || !responseTodoSet.body) {
31
+ throw new Error("Failed to fetch todo set");
32
+ }
33
+ const todoLists = await asyncPagedToArray({
34
+ fetchPage: client.todoLists.list,
35
+ request: {
36
+ params: {
37
+ bucketId: params.bucket_id,
38
+ todosetId: params.todoset_id,
39
+ },
40
+ query: {},
41
+ },
42
+ });
43
+ const todoSet = responseTodoSet.body;
44
+ return {
45
+ content: [
46
+ {
47
+ type: "text",
48
+ text: JSON.stringify({
49
+ id: todoSet.id,
50
+ name: todoSet.name,
51
+ url: todoSet.app_url,
52
+ completed: todoSet.completed,
53
+ todoLists: todoLists.map((list) => ({
54
+ id: list.id,
55
+ url: list.app_url,
56
+ title: list.title,
57
+ completed: list.completed,
58
+ position: list.position,
59
+ })),
60
+ }, null, 2),
61
+ },
62
+ ],
63
+ };
64
+ }
65
+ catch (error) {
66
+ return {
67
+ content: [{ type: "text", text: handleBasecampError(error) }],
68
+ };
69
+ }
70
+ });
71
+ server.registerTool("basecamp_list_todos", {
72
+ title: "List Basecamp Todos",
73
+ description: "List todos in a todo list. Filter by status: 'active' or 'archived'.",
74
+ inputSchema: {
75
+ bucket_id: BasecampIdSchema,
76
+ todolist_id: BasecampIdSchema,
77
+ status: z.enum(["active", "archived"]).default("active").optional(),
78
+ completed: z.enum(["true"]).optional(),
79
+ },
80
+ annotations: {
81
+ readOnlyHint: true,
82
+ destructiveHint: false,
83
+ idempotentHint: true,
84
+ openWorldHint: true,
85
+ },
86
+ }, async (params) => {
87
+ try {
88
+ const client = await initializeBasecampClient();
89
+ const todos = await asyncPagedToArray({
90
+ fetchPage: client.todos.list,
91
+ request: {
92
+ params: {
93
+ bucketId: params.bucket_id,
94
+ todolistId: params.todolist_id,
95
+ },
96
+ query: { status: params.status, completed: params.completed },
97
+ },
98
+ });
99
+ return {
100
+ content: [
101
+ {
102
+ type: "text",
103
+ text: JSON.stringify({
104
+ count: todos.length,
105
+ todos: todos.map((t) => ({
106
+ id: t.id,
107
+ content: t.content,
108
+ completed: t.completed,
109
+ })),
110
+ }, null, 2),
111
+ },
112
+ ],
113
+ };
114
+ }
115
+ catch (error) {
116
+ return {
117
+ content: [{ type: "text", text: handleBasecampError(error) }],
118
+ };
119
+ }
120
+ });
121
+ server.registerTool("basecamp_create_todo", {
122
+ title: "Create Basecamp Todo",
123
+ description: `Create a new todo item in a todo list. ${htmlRules}`,
124
+ inputSchema: {
125
+ bucket_id: BasecampIdSchema,
126
+ todolist_id: BasecampIdSchema,
127
+ content: z.string().min(1),
128
+ description: z.string().optional(),
129
+ },
130
+ annotations: {
131
+ readOnlyHint: false,
132
+ destructiveHint: false,
133
+ idempotentHint: false,
134
+ openWorldHint: true,
135
+ },
136
+ }, async (params) => {
137
+ try {
138
+ const client = await initializeBasecampClient();
139
+ const response = await client.todos.create({
140
+ params: {
141
+ bucketId: params.bucket_id,
142
+ todolistId: params.todolist_id,
143
+ },
144
+ body: { content: params.content, description: params.description },
145
+ });
146
+ if (response.status !== 201 || !response.body) {
147
+ throw new Error("Failed to create todo");
148
+ }
149
+ return {
150
+ content: [
151
+ {
152
+ type: "text",
153
+ text: `Todo created!\n\nID: ${response.body.id}\nContent: ${response.body.content}`,
154
+ },
155
+ ],
156
+ };
157
+ }
158
+ catch (error) {
159
+ return {
160
+ content: [{ type: "text", text: handleBasecampError(error) }],
161
+ };
162
+ }
163
+ });
164
+ server.registerTool("basecamp_complete_todo", {
165
+ title: "Complete Basecamp Todo",
166
+ description: "Mark a todo as completed.",
167
+ inputSchema: {
168
+ bucket_id: BasecampIdSchema,
169
+ todo_id: BasecampIdSchema,
170
+ },
171
+ annotations: {
172
+ readOnlyHint: false,
173
+ destructiveHint: false,
174
+ idempotentHint: true,
175
+ openWorldHint: true,
176
+ },
177
+ }, async (params) => {
178
+ try {
179
+ const client = await initializeBasecampClient();
180
+ await client.todos.complete({
181
+ params: { bucketId: params.bucket_id, todoId: params.todo_id },
182
+ });
183
+ return {
184
+ content: [{ type: "text", text: "Todo marked as completed!" }],
185
+ };
186
+ }
187
+ catch (error) {
188
+ return {
189
+ content: [{ type: "text", text: handleBasecampError(error) }],
190
+ };
191
+ }
192
+ });
193
+ server.registerTool("basecamp_uncomplete_todo", {
194
+ title: "Uncomplete Basecamp Todo",
195
+ description: "Mark a todo as incomplete (undo completion).",
196
+ inputSchema: {
197
+ bucket_id: BasecampIdSchema,
198
+ todo_id: BasecampIdSchema,
199
+ },
200
+ annotations: {
201
+ readOnlyHint: false,
202
+ destructiveHint: false,
203
+ idempotentHint: true,
204
+ openWorldHint: true,
205
+ },
206
+ }, async (params) => {
207
+ try {
208
+ const client = await initializeBasecampClient();
209
+ await client.todos.uncomplete({
210
+ params: { bucketId: params.bucket_id, todoId: params.todo_id },
211
+ });
212
+ return {
213
+ content: [{ type: "text", text: "Todo marked as incomplete!" }],
214
+ };
215
+ }
216
+ catch (error) {
217
+ return {
218
+ content: [{ type: "text", text: handleBasecampError(error) }],
219
+ };
220
+ }
221
+ });
222
+ }
223
+ //# sourceMappingURL=todos.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"todos.js","sourceRoot":"","sources":["../../src/tools/todos.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAC1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAEhE,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IACjD,MAAM,CAAC,YAAY,CACjB,sBAAsB,EACtB;QACE,KAAK,EAAE,uBAAuB;QAC9B,WAAW,EACT,sEAAsE;QACxE,WAAW,EAAE;YACX,SAAS,EAAE,gBAAgB;YAC3B,UAAU,EAAE,gBAAgB;SAC7B;QACD,WAAW,EAAE;YACX,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,IAAI;SACpB;KACF,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,wBAAwB,EAAE,CAAC;YAEhD,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAChD,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,UAAU,EAAE;aACrE,CAAC,CAAC;YAEH,IAAI,eAAe,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;gBAC5D,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;YAC9C,CAAC;YAED,MAAM,SAAS,GAAG,MAAM,iBAAiB,CAAC;gBACxC,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,IAAI;gBAChC,OAAO,EAAE;oBACP,MAAM,EAAE;wBACN,QAAQ,EAAE,MAAM,CAAC,SAAS;wBAC1B,SAAS,EAAE,MAAM,CAAC,UAAU;qBAC7B;oBACD,KAAK,EAAE,EAAE;iBACV;aACF,CAAC,CAAC;YAEH,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC;YACrC,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB;4BACE,EAAE,EAAE,OAAO,CAAC,EAAE;4BACd,IAAI,EAAE,OAAO,CAAC,IAAI;4BAClB,GAAG,EAAE,OAAO,CAAC,OAAO;4BACpB,SAAS,EAAE,OAAO,CAAC,SAAS;4BAC5B,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;gCAClC,EAAE,EAAE,IAAI,CAAC,EAAE;gCACX,GAAG,EAAE,IAAI,CAAC,OAAO;gCACjB,KAAK,EAAE,IAAI,CAAC,KAAK;gCACjB,SAAS,EAAE,IAAI,CAAC,SAAS;gCACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ;6BACxB,CAAC,CAAC;yBACJ,EACD,IAAI,EACJ,CAAC,CACF;qBACF;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;aAC9D,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,qBAAqB,EACrB;QACE,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EACT,sEAAsE;QACxE,WAAW,EAAE;YACX,SAAS,EAAE,gBAAgB;YAC3B,WAAW,EAAE,gBAAgB;YAC7B,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE;YACnE,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE;SACvC;QACD,WAAW,EAAE;YACX,YAAY,EAAE,IAAI;YAClB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,IAAI;SACpB;KACF,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,wBAAwB,EAAE,CAAC;YAChD,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC;gBACpC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI;gBAC5B,OAAO,EAAE;oBACP,MAAM,EAAE;wBACN,QAAQ,EAAE,MAAM,CAAC,SAAS;wBAC1B,UAAU,EAAE,MAAM,CAAC,WAAW;qBAC/B;oBACD,KAAK,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE;iBAC9D;aACF,CAAC,CAAC;YAEH,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB;4BACE,KAAK,EAAE,KAAK,CAAC,MAAM;4BACnB,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gCACvB,EAAE,EAAE,CAAC,CAAC,EAAE;gCACR,OAAO,EAAE,CAAC,CAAC,OAAO;gCAClB,SAAS,EAAE,CAAC,CAAC,SAAS;6BACvB,CAAC,CAAC;yBACJ,EACD,IAAI,EACJ,CAAC,CACF;qBACF;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;aAC9D,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,sBAAsB,EACtB;QACE,KAAK,EAAE,sBAAsB;QAC7B,WAAW,EAAE,0CAA0C,SAAS,EAAE;QAClE,WAAW,EAAE;YACX,SAAS,EAAE,gBAAgB;YAC3B,WAAW,EAAE,gBAAgB;YAC7B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SACnC;QACD,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,KAAK;YACrB,aAAa,EAAE,IAAI;SACpB;KACF,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,wBAAwB,EAAE,CAAC;YAChD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;gBACzC,MAAM,EAAE;oBACN,QAAQ,EAAE,MAAM,CAAC,SAAS;oBAC1B,UAAU,EAAE,MAAM,CAAC,WAAW;iBAC/B;gBACD,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE;aACnE,CAAC,CAAC;YAEH,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAC9C,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;YAC3C,CAAC;YAED,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,wBAAwB,QAAQ,CAAC,IAAI,CAAC,EAAE,cAAc,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE;qBACpF;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;aAC9D,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,wBAAwB,EACxB;QACE,KAAK,EAAE,wBAAwB;QAC/B,WAAW,EAAE,2BAA2B;QACxC,WAAW,EAAE;YACX,SAAS,EAAE,gBAAgB;YAC3B,OAAO,EAAE,gBAAgB;SAC1B;QACD,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,IAAI;SACpB;KACF,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,wBAAwB,EAAE,CAAC;YAChD,MAAM,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;gBAC1B,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE;aAC/D,CAAC,CAAC;YAEH,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,2BAA2B,EAAE,CAAC;aAC/D,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;aAC9D,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,0BAA0B,EAC1B;QACE,KAAK,EAAE,0BAA0B;QACjC,WAAW,EAAE,8CAA8C;QAC3D,WAAW,EAAE;YACX,SAAS,EAAE,gBAAgB;YAC3B,OAAO,EAAE,gBAAgB;SAC1B;QACD,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,KAAK;YACtB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,IAAI;SACpB;KACF,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,wBAAwB,EAAE,CAAC;YAChD,MAAM,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC;gBAC5B,MAAM,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE;aAC/D,CAAC,CAAC;YAEH,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,4BAA4B,EAAE,CAAC;aAChE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;aAC9D,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * TypeScript types and enums for the Basecamp MCP server
3
+ */
4
+ /** Parsed Basecamp URL structure */
5
+ export interface ParsedBasecampUrl {
6
+ accountId: string;
7
+ bucketId: string;
8
+ resourceType: string;
9
+ resourceId: string;
10
+ fullUrl: string;
11
+ }
12
+ /** Pagination metadata for list responses */
13
+ export interface PaginationMetadata {
14
+ total: number;
15
+ count: number;
16
+ offset: number;
17
+ has_more: boolean;
18
+ next_offset?: number;
19
+ }
20
+ /** Truncation metadata when response exceeds character limit */
21
+ export interface TruncationInfo {
22
+ truncated: boolean;
23
+ truncation_message?: string;
24
+ original_count?: number;
25
+ returned_count?: number;
26
+ }
27
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,oCAAoC;AACpC,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,6CAA6C;AAC7C,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,gEAAgE;AAChE,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,OAAO,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB"}
package/dist/types.js ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * TypeScript types and enums for the Basecamp MCP server
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Authentication utilities for Basecamp API
3
+ */
4
+ import { type Client } from "basecamp-client";
5
+ /**
6
+ * Initialize and return an authenticated Basecamp client.
7
+ *
8
+ * Uses environment variables:
9
+ * - BASECAMP_CLIENT_ID
10
+ * - BASECAMP_CLIENT_SECRET
11
+ * - BASECAMP_REFRESH_TOKEN
12
+ * - BASECAMP_USER_AGENT (optional)
13
+ * - BASECAMP_ACCOUNT_ID
14
+ *
15
+ * @param accountId - Basecamp account ID to use for the client
16
+ * @returns Authenticated Basecamp client instance
17
+ * @throws Error if required environment variables are missing or authentication fails
18
+ */
19
+ export declare function initializeBasecampClient(): Promise<Client>;
20
+ /**
21
+ * Clear the cached bearer token (useful for forcing token refresh)
22
+ */
23
+ export declare function clearTokenCache(): void;
24
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/utils/auth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAe,KAAK,MAAM,EAAkB,MAAM,iBAAiB,CAAC;AAK3E;;;;;;;;;;;;;GAaG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,MAAM,CAAC,CAwChE;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAEtC"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Authentication utilities for Basecamp API
3
+ */
4
+ import { buildClient, getBearerToken } from "basecamp-client";
5
+ /** Cached bearer token to avoid repeated OAuth requests */
6
+ let cachedBearerToken = null;
7
+ /**
8
+ * Initialize and return an authenticated Basecamp client.
9
+ *
10
+ * Uses environment variables:
11
+ * - BASECAMP_CLIENT_ID
12
+ * - BASECAMP_CLIENT_SECRET
13
+ * - BASECAMP_REFRESH_TOKEN
14
+ * - BASECAMP_USER_AGENT (optional)
15
+ * - BASECAMP_ACCOUNT_ID
16
+ *
17
+ * @param accountId - Basecamp account ID to use for the client
18
+ * @returns Authenticated Basecamp client instance
19
+ * @throws Error if required environment variables are missing or authentication fails
20
+ */
21
+ export async function initializeBasecampClient() {
22
+ // Validate required environment variables
23
+ const requiredEnvVars = [
24
+ "BASECAMP_CLIENT_ID",
25
+ "BASECAMP_CLIENT_SECRET",
26
+ "BASECAMP_REFRESH_TOKEN",
27
+ "BASECAMP_ACCOUNT_ID",
28
+ ];
29
+ const missing = requiredEnvVars.filter((varName) => !process.env[varName]);
30
+ if (missing.length > 0) {
31
+ throw new Error(`Missing required environment variables: ${missing.join(", ")}. ` +
32
+ `Please set these in your environment or .env file.`);
33
+ }
34
+ // Get bearer token (cache if possible to avoid repeated OAuth requests)
35
+ if (!cachedBearerToken) {
36
+ try {
37
+ cachedBearerToken = await getBearerToken({
38
+ clientId: process.env.BASECAMP_CLIENT_ID,
39
+ clientSecret: process.env.BASECAMP_CLIENT_SECRET,
40
+ refreshToken: process.env.BASECAMP_REFRESH_TOKEN,
41
+ userAgent: process.env.BASECAMP_USER_AGENT,
42
+ });
43
+ }
44
+ catch (error) {
45
+ throw new Error(`Failed to obtain Basecamp access token: ${error instanceof Error ? error.message : String(error)}. ` +
46
+ `Check your BASECAMP_CLIENT_ID, BASECAMP_CLIENT_SECRET, and BASECAMP_REFRESH_TOKEN are correct.`);
47
+ }
48
+ }
49
+ // Build and return client
50
+ return buildClient({
51
+ bearerToken: cachedBearerToken,
52
+ accountId: process.env.BASECAMP_ACCOUNT_ID,
53
+ userAgent: process.env.BASECAMP_USER_AGENT,
54
+ });
55
+ }
56
+ /**
57
+ * Clear the cached bearer token (useful for forcing token refresh)
58
+ */
59
+ export function clearTokenCache() {
60
+ cachedBearerToken = null;
61
+ }
62
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/utils/auth.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,WAAW,EAAe,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE3E,2DAA2D;AAC3D,IAAI,iBAAiB,GAAkB,IAAI,CAAC;AAE5C;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB;IAC5C,0CAA0C;IAC1C,MAAM,eAAe,GAAG;QACtB,oBAAoB;QACpB,wBAAwB;QACxB,wBAAwB;QACxB,qBAAqB;KACtB,CAAC;IAEF,MAAM,OAAO,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3E,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,2CAA2C,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;YAC/D,oDAAoD,CACvD,CAAC;IACJ,CAAC;IAED,wEAAwE;IACxE,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,IAAI,CAAC;YACH,iBAAiB,GAAG,MAAM,cAAc,CAAC;gBACvC,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAmB;gBACzC,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAuB;gBACjD,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAuB;gBACjD,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB;aAC3C,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CACb,2CAA2C,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI;gBACnG,gGAAgG,CACnG,CAAC;QACJ,CAAC;IACH,CAAC;IAED,0BAA0B;IAC1B,OAAO,WAAW,CAAC;QACjB,WAAW,EAAE,iBAAiB;QAC9B,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAoB;QAC3C,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB;KAC3C,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe;IAC7B,iBAAiB,GAAG,IAAI,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Shared utilities and schemas for content manipulation operations
3
+ * Used by messages, comments, and other content-based tools
4
+ */
5
+ import { z } from "zod";
6
+ export declare const htmlRules = "\n\nHTML rules for content:\n\n* Allowed tags: div, h1, br, strong, em, strike, a (with an href attribute), pre, ol, ul, li, blockquote, bc-attachment (with sgid attribute).\n* Try to be semantic despite the limitations of tags. Use double <br> as paragraphs\n* To mention people: <bc-attachment sgid=\"{ person.attachable_sgid }\"></bc-attachment>\n";
7
+ /**
8
+ * Shared Zod schema for content operation fields
9
+ * These fields can be composed into tool-specific schemas
10
+ */
11
+ export declare const ContentOperationFields: {
12
+ content: z.ZodOptional<z.ZodString>;
13
+ content_append: z.ZodOptional<z.ZodString>;
14
+ content_prepend: z.ZodOptional<z.ZodString>;
15
+ search_replace: z.ZodOptional<z.ZodArray<z.ZodObject<{
16
+ find: z.ZodString;
17
+ replace: z.ZodString;
18
+ }, "strip", z.ZodTypeAny, {
19
+ find: string;
20
+ replace: string;
21
+ }, {
22
+ find: string;
23
+ replace: string;
24
+ }>, "many">>;
25
+ };
26
+ /**
27
+ * Parameters for applying content operations
28
+ */
29
+ export interface ContentOperationParams {
30
+ content?: string;
31
+ content_append?: string;
32
+ content_prepend?: string;
33
+ search_replace?: Array<{
34
+ find: string;
35
+ replace: string;
36
+ }>;
37
+ }
38
+ /**
39
+ * Apply content operations to existing content
40
+ *
41
+ * @param currentContent - The current content to operate on
42
+ * @param operations - The operations to apply
43
+ * @returns The final content after applying all operations, or undefined if no operations
44
+ * @throws Error if validation fails (mutual exclusivity, no operations provided)
45
+ */
46
+ export declare function applyContentOperations(currentContent: string, operations: ContentOperationParams): string | undefined;
47
+ /**
48
+ * Validate that at least one content operation is provided
49
+ *
50
+ * @param operations - The operations to validate
51
+ * @param additionalFields - Additional field names that count as valid operations
52
+ * @throws Error if no operations are provided
53
+ */
54
+ export declare function validateContentOperations(operations: ContentOperationParams, additionalFields?: string[]): void;
55
+ //# sourceMappingURL=contentOperations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contentOperations.d.ts","sourceRoot":"","sources":["../../src/utils/contentOperations.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,SAAS,mWAOrB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;CAgClC,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC3D;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,sBAAsB,GACjC,MAAM,GAAG,SAAS,CAkDpB;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,sBAAsB,EAClC,gBAAgB,GAAE,MAAM,EAAO,GAC9B,IAAI,CAmBN"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Shared utilities and schemas for content manipulation operations
3
+ * Used by messages, comments, and other content-based tools
4
+ */
5
+ import { z } from "zod";
6
+ export const htmlRules = `
7
+
8
+ HTML rules for content:
9
+
10
+ * Allowed tags: div, h1, br, strong, em, strike, a (with an href attribute), pre, ol, ul, li, blockquote, bc-attachment (with sgid attribute).
11
+ * Try to be semantic despite the limitations of tags. Use double <br> as paragraphs
12
+ * To mention people: <bc-attachment sgid="{ person.attachable_sgid }"></bc-attachment>
13
+ `;
14
+ /**
15
+ * Shared Zod schema for content operation fields
16
+ * These fields can be composed into tool-specific schemas
17
+ */
18
+ export const ContentOperationFields = {
19
+ content: z
20
+ .string()
21
+ .optional()
22
+ .describe(`If provided, replaces entire HTML content. Cannot be used with content_append, content_prepend, or search_replace.`),
23
+ content_append: z
24
+ .string()
25
+ .optional()
26
+ .describe("Text to append to the end of current content. Cannot be used with content."),
27
+ content_prepend: z
28
+ .string()
29
+ .optional()
30
+ .describe("Text to prepend to the beginning of current content. Cannot be used with content."),
31
+ search_replace: z
32
+ .array(z.object({
33
+ find: z.string().describe("Text to search for"),
34
+ replace: z
35
+ .string()
36
+ .describe("Text to replace ALL the occurrences with"),
37
+ }))
38
+ .optional()
39
+ .describe("Array of search-replace operations to apply to current content. Cannot be used with content."),
40
+ };
41
+ /**
42
+ * Apply content operations to existing content
43
+ *
44
+ * @param currentContent - The current content to operate on
45
+ * @param operations - The operations to apply
46
+ * @returns The final content after applying all operations, or undefined if no operations
47
+ * @throws Error if validation fails (mutual exclusivity, no operations provided)
48
+ */
49
+ export function applyContentOperations(currentContent, operations) {
50
+ const hasPartialOps = operations.content_append ||
51
+ operations.content_prepend ||
52
+ operations.search_replace;
53
+ // Validate mutual exclusivity
54
+ if (operations.content && hasPartialOps) {
55
+ throw new Error("Cannot use 'content' with partial operations (content_append, content_prepend, search_replace). Use either full replacement or partial operations, not both.");
56
+ }
57
+ // If full content replacement, return it directly
58
+ if (operations.content !== undefined) {
59
+ return operations.content;
60
+ }
61
+ // If no operations at all, return undefined (no changes)
62
+ if (!hasPartialOps) {
63
+ return undefined;
64
+ }
65
+ // Apply partial operations
66
+ let finalContent = currentContent;
67
+ // Apply search-replace operations first
68
+ if (operations.search_replace) {
69
+ for (const operation of operations.search_replace) {
70
+ // Check if the search string exists in the content
71
+ if (!finalContent.includes(operation.find)) {
72
+ throw new Error(`Search string not found: "${operation.find}". The content does not contain this text.`);
73
+ }
74
+ finalContent = finalContent.replaceAll(operation.find, operation.replace);
75
+ }
76
+ }
77
+ // Apply prepend
78
+ if (operations.content_prepend) {
79
+ finalContent = operations.content_prepend + finalContent;
80
+ }
81
+ // Apply append
82
+ if (operations.content_append) {
83
+ finalContent = finalContent + operations.content_append;
84
+ }
85
+ return finalContent;
86
+ }
87
+ /**
88
+ * Validate that at least one content operation is provided
89
+ *
90
+ * @param operations - The operations to validate
91
+ * @param additionalFields - Additional field names that count as valid operations
92
+ * @throws Error if no operations are provided
93
+ */
94
+ export function validateContentOperations(operations, additionalFields = []) {
95
+ const hasContentOp = operations.content ||
96
+ operations.content_append ||
97
+ operations.content_prepend ||
98
+ operations.search_replace;
99
+ const hasAdditionalFields = additionalFields.some((field) => operations[field] !== undefined);
100
+ if (!hasContentOp && !hasAdditionalFields) {
101
+ const fieldsStr = [
102
+ "content",
103
+ "partial operations",
104
+ ...additionalFields,
105
+ ].join(", ");
106
+ throw new Error(`At least one field (${fieldsStr}) must be provided`);
107
+ }
108
+ }
109
+ //# sourceMappingURL=contentOperations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contentOperations.js","sourceRoot":"","sources":["../../src/utils/contentOperations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Error handling utilities for Basecamp API
3
+ */
4
+ /**
5
+ * Convert Basecamp API errors to helpful, actionable error messages for LLMs.
6
+ *
7
+ * @param error - Error object from API call
8
+ * @returns Human-readable error message with guidance
9
+ */
10
+ export declare function handleBasecampError(error: unknown): string;
11
+ //# sourceMappingURL=errorHandlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorHandlers.d.ts","sourceRoot":"","sources":["../../src/utils/errorHandlers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CA8E1D"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Error handling utilities for Basecamp API
3
+ */
4
+ /**
5
+ * Convert Basecamp API errors to helpful, actionable error messages for LLMs.
6
+ *
7
+ * @param error - Error object from API call
8
+ * @returns Human-readable error message with guidance
9
+ */
10
+ export function handleBasecampError(error) {
11
+ // Handle HTTP response errors
12
+ if (error && typeof error === "object" && "status" in error) {
13
+ const status = error.status;
14
+ switch (status) {
15
+ case 400:
16
+ return ("Error: Bad request. Check that all required parameters are provided and formatted correctly. " +
17
+ extractErrorDetails(error));
18
+ case 401:
19
+ return ("Error: Authentication failed. Your access token may have expired. " +
20
+ "Try restarting the server to refresh the token, or check your BASECAMP_REFRESH_TOKEN is valid.");
21
+ case 403:
22
+ return ("Error: Access denied. You don't have permission to access this resource. " +
23
+ "Check that you're using the correct account ID and that your Basecamp user has access to this project/resource.");
24
+ case 404:
25
+ return ("Error: Resource not found. The requested resource (message, todo, project, etc.) doesn't exist or has been deleted. " +
26
+ "Verify the ID is correct and the resource hasn't been moved to trash.");
27
+ case 422:
28
+ return ("Error: Validation failed. The request data didn't pass Basecamp's validation rules. " +
29
+ extractErrorDetails(error) +
30
+ " Check the data format and required fields.");
31
+ case 429:
32
+ return ("Error: Rate limit exceeded. Too many requests have been made to the Basecamp API. " +
33
+ "Please wait a moment before trying again.");
34
+ case 500:
35
+ case 502:
36
+ case 503:
37
+ case 504:
38
+ return ("Error: Basecamp server error. The Basecamp API is experiencing issues. " +
39
+ "Please try again in a moment.");
40
+ default:
41
+ return `Error: API request failed with status ${status}. ${extractErrorDetails(error)}`;
42
+ }
43
+ }
44
+ // Handle network/connection errors
45
+ if (error && typeof error === "object" && "code" in error) {
46
+ const code = error.code;
47
+ if (code === "ECONNABORTED" || code === "ETIMEDOUT") {
48
+ return ("Error: Request timed out. The Basecamp API took too long to respond. " +
49
+ "Please try again.");
50
+ }
51
+ if (code === "ECONNREFUSED" || code === "ENOTFOUND") {
52
+ return ("Error: Unable to connect to Basecamp API. " +
53
+ "Check your internet connection and try again.");
54
+ }
55
+ }
56
+ // Generic error fallback
57
+ return `Error: ${error instanceof Error ? error.message : String(error)}`;
58
+ }
59
+ /**
60
+ * Extract additional error details from API response if available.
61
+ *
62
+ * @param error - Error object
63
+ * @returns Error details string or empty string
64
+ */
65
+ function extractErrorDetails(error) {
66
+ if (!error || typeof error !== "object") {
67
+ return "";
68
+ }
69
+ // Try to extract error message from response body
70
+ if ("body" in error && error.body && typeof error.body === "object") {
71
+ const body = error.body;
72
+ if ("error" in body && typeof body.error === "string") {
73
+ return `Details: ${body.error}`;
74
+ }
75
+ if ("message" in body && typeof body.message === "string") {
76
+ return `Details: ${body.message}`;
77
+ }
78
+ if ("errors" in body && Array.isArray(body.errors)) {
79
+ const errorMessages = body.errors
80
+ .map((e) => (typeof e === "string" ? e : JSON.stringify(e)))
81
+ .join(", ");
82
+ return `Details: ${errorMessages}`;
83
+ }
84
+ }
85
+ return "";
86
+ }
87
+ //# sourceMappingURL=errorHandlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errorHandlers.js","sourceRoot":"","sources":["../../src/utils/errorHandlers.ts"],"names":[],"mappings":"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"}