@todoist/comms-mcp 0.0.1 → 11.0.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 (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +198 -34
  3. package/dist/comms-tool.d.ts +14 -0
  4. package/dist/comms-tool.js +1 -0
  5. package/dist/index.d.ts +1324 -0
  6. package/dist/index.js +55 -0
  7. package/dist/main.d.ts +2 -0
  8. package/dist/main.js +24 -0
  9. package/dist/mcp-helpers.d.ts +17 -0
  10. package/dist/mcp-helpers.js +40 -0
  11. package/dist/mcp-server.d.ts +10 -0
  12. package/dist/mcp-server.js +78 -0
  13. package/dist/tool-registry.d.ts +3 -0
  14. package/dist/tool-registry.js +49 -0
  15. package/dist/tools/build-link.d.ts +63 -0
  16. package/dist/tools/build-link.js +93 -0
  17. package/dist/tools/channel-output.d.ts +19 -0
  18. package/dist/tools/channel-output.js +47 -0
  19. package/dist/tools/create-channel.d.ts +55 -0
  20. package/dist/tools/create-channel.js +44 -0
  21. package/dist/tools/create-conversation.d.ts +49 -0
  22. package/dist/tools/create-conversation.js +75 -0
  23. package/dist/tools/create-thread.d.ts +67 -0
  24. package/dist/tools/create-thread.js +126 -0
  25. package/dist/tools/delete-object.d.ts +44 -0
  26. package/dist/tools/delete-object.js +84 -0
  27. package/dist/tools/fetch-inbox.d.ts +91 -0
  28. package/dist/tools/fetch-inbox.js +227 -0
  29. package/dist/tools/get-groups.d.ts +62 -0
  30. package/dist/tools/get-groups.js +116 -0
  31. package/dist/tools/get-mentions.d.ts +97 -0
  32. package/dist/tools/get-mentions.js +126 -0
  33. package/dist/tools/get-users.d.ts +58 -0
  34. package/dist/tools/get-users.js +107 -0
  35. package/dist/tools/get-workspaces.d.ts +61 -0
  36. package/dist/tools/get-workspaces.js +120 -0
  37. package/dist/tools/list-channels.d.ts +47 -0
  38. package/dist/tools/list-channels.js +89 -0
  39. package/dist/tools/list-conversations.d.ts +66 -0
  40. package/dist/tools/list-conversations.js +212 -0
  41. package/dist/tools/load-conversation.d.ts +92 -0
  42. package/dist/tools/load-conversation.js +128 -0
  43. package/dist/tools/load-thread.d.ts +127 -0
  44. package/dist/tools/load-thread.js +175 -0
  45. package/dist/tools/mark-done.d.ts +111 -0
  46. package/dist/tools/mark-done.js +275 -0
  47. package/dist/tools/mark-read.d.ts +73 -0
  48. package/dist/tools/mark-read.js +214 -0
  49. package/dist/tools/react.d.ts +59 -0
  50. package/dist/tools/react.js +97 -0
  51. package/dist/tools/reply.d.ts +69 -0
  52. package/dist/tools/reply.js +122 -0
  53. package/dist/tools/search-content.d.ts +103 -0
  54. package/dist/tools/search-content.js +138 -0
  55. package/dist/tools/update-channel.d.ts +53 -0
  56. package/dist/tools/update-channel.js +45 -0
  57. package/dist/tools/update-object.d.ts +52 -0
  58. package/dist/tools/update-object.js +161 -0
  59. package/dist/tools/update-user-info.d.ts +55 -0
  60. package/dist/tools/update-user-info.js +270 -0
  61. package/dist/tools/user-info.d.ts +32 -0
  62. package/dist/tools/user-info.js +16 -0
  63. package/dist/tools/user-output.d.ts +9 -0
  64. package/dist/tools/user-output.js +28 -0
  65. package/dist/usage-tracking.d.ts +23 -0
  66. package/dist/usage-tracking.js +41 -0
  67. package/dist/utils/attachments.d.ts +24 -0
  68. package/dist/utils/attachments.js +57 -0
  69. package/dist/utils/concurrency.d.ts +20 -0
  70. package/dist/utils/concurrency.js +24 -0
  71. package/dist/utils/constants.d.ts +5 -0
  72. package/dist/utils/constants.js +5 -0
  73. package/dist/utils/degrade.d.ts +81 -0
  74. package/dist/utils/degrade.js +149 -0
  75. package/dist/utils/output-schemas.d.ts +1283 -0
  76. package/dist/utils/output-schemas.js +657 -0
  77. package/dist/utils/read-position.d.ts +21 -0
  78. package/dist/utils/read-position.js +37 -0
  79. package/dist/utils/search-results.d.ts +36 -0
  80. package/dist/utils/search-results.js +82 -0
  81. package/dist/utils/target-types.d.ts +114 -0
  82. package/dist/utils/target-types.js +58 -0
  83. package/dist/utils/test-helpers.d.ts +95 -0
  84. package/dist/utils/test-helpers.js +231 -0
  85. package/dist/utils/tool-names.d.ts +25 -0
  86. package/dist/utils/tool-names.js +25 -0
  87. package/dist/utils/url-helpers.d.ts +3 -0
  88. package/dist/utils/url-helpers.js +10 -0
  89. package/dist/utils/user-status.d.ts +8 -0
  90. package/dist/utils/user-status.js +33 -0
  91. package/dist/utils/validate-comms-token.d.ts +13 -0
  92. package/dist/utils/validate-comms-token.js +22 -0
  93. package/package.json +85 -8
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Several tools deliberately degrade past a lookup they can live without — a name
3
+ * they only needed for a label, a channel they can identify by ID. Swallowing the
4
+ * rejection silently leaves a user who has left the workspace looking exactly like
5
+ * an expired token, so record what was dropped and why.
6
+ */
7
+ /** Failed identifiers reported per batch before the rest are counted only. */
8
+ export const SAMPLE_LIMIT = 5;
9
+ const runAll = (items, worker) => Promise.all(items.map(worker));
10
+ /**
11
+ * Reduces an error to the fields worth logging. The error object can carry a
12
+ * whole API response, and with it names and email addresses that have no place
13
+ * in a log line.
14
+ */
15
+ function describeError(error) {
16
+ return error instanceof Error
17
+ ? { name: error.name, message: error.message }
18
+ : { message: String(error) };
19
+ }
20
+ /**
21
+ * Resolves every id, degrading past individual failures to `null` and reporting
22
+ * them as one log line per batch.
23
+ *
24
+ * A batch is as large as the caller's input, so one expired token must not
25
+ * become one log event per id.
26
+ *
27
+ * @param toolName - The tool doing the lookups, for the log prefix.
28
+ * @param message - What could not be resolved, e.g. 'failed to resolve channel creator'.
29
+ * @param ids - The identifiers to resolve.
30
+ * @param resolve - Performs one lookup.
31
+ * @param options.runner - How to run the batch. Defaults to `Promise.all`; pass
32
+ * `limitedAll` at fan-out sites that need a concurrency ceiling.
33
+ * @returns Each result in input order, with `null` where the lookup failed.
34
+ */
35
+ export async function degradeAllWithLog(toolName, message, ids, resolve, options = {}) {
36
+ const failures = [];
37
+ const run = options.runner ?? runAll;
38
+ const results = await run(ids, async (id) => {
39
+ try {
40
+ return await resolve(id);
41
+ }
42
+ catch (error) {
43
+ failures.push({ id, error });
44
+ return null;
45
+ }
46
+ });
47
+ const firstFailure = failures[0];
48
+ if (firstFailure) {
49
+ console.error(`${toolName}: ${message}`, {
50
+ failed: failures.length,
51
+ of: ids.length,
52
+ sample: failures.slice(0, SAMPLE_LIMIT).map((failure) => failure.id),
53
+ error: describeError(firstFailure.error),
54
+ });
55
+ }
56
+ return results;
57
+ }
58
+ /**
59
+ * Resolves workspace users in one batched lookup, degrading the way
60
+ * {@link degradeAllWithLog} does: a user the workspace has no record of, or a
61
+ * failed request, is left out of the result and reported in one log line.
62
+ *
63
+ * @param client - The Comms API client.
64
+ * @param toolName - The tool doing the lookups, for the log prefix.
65
+ * @param message - What could not be resolved, e.g. 'failed to resolve thread participant'.
66
+ * @param workspaceId - The workspace the users belong to.
67
+ * @param userIds - The users to resolve.
68
+ * @returns The resolved users keyed by id.
69
+ */
70
+ export async function resolveUsersWithLog(client, toolName, message, workspaceId, userIds) {
71
+ const ids = [...new Set(userIds)];
72
+ const users = new Map();
73
+ if (ids.length === 0) {
74
+ return users;
75
+ }
76
+ let error;
77
+ try {
78
+ const byId = await client.workspaceUsers.getUsersByIds({ workspaceId, userIds: ids });
79
+ for (const id of ids) {
80
+ const user = byId[id];
81
+ if (user) {
82
+ users.set(id, user);
83
+ }
84
+ }
85
+ }
86
+ catch (caught) {
87
+ error = caught;
88
+ }
89
+ const missing = ids.filter((id) => !users.has(id));
90
+ if (missing.length > 0) {
91
+ console.error(`${toolName}: ${message}`, {
92
+ failed: missing.length,
93
+ of: ids.length,
94
+ sample: missing.slice(0, SAMPLE_LIMIT),
95
+ error: error === undefined ? { message: 'not found' } : describeError(error),
96
+ });
97
+ }
98
+ return users;
99
+ }
100
+ /**
101
+ * Builds a `.catch` handler that logs the failure and resolves to `fallback`.
102
+ * For one-off lookups; use {@link degradeAllWithLog} for a batch, so a batch of
103
+ * failures reports once rather than per id.
104
+ *
105
+ * @param toolName - The tool doing the lookup, for the log prefix.
106
+ * @param message - What could not be resolved.
107
+ * @param context - Identifiers worth having in the log, e.g. `{ workspaceId }`.
108
+ * @param fallback - The value to resolve to instead.
109
+ */
110
+ export function degradeWithLog(toolName, message, context, fallback) {
111
+ return (error) => {
112
+ console.error(`${toolName}: ${message}`, { ...context, error: describeError(error) });
113
+ return fallback;
114
+ };
115
+ }
116
+ /**
117
+ * Reports the items a batch tool could not act on, as one log line per call.
118
+ *
119
+ * Tools like mark-done and mark-read fold per-item errors into the tool result
120
+ * instead of throwing, so without this the server answers 200 and logs nothing
121
+ * while a caller's items stayed untouched — a whole batch can fail on an expired
122
+ * token or a dropped connection with no trace on this side. Stays quiet when
123
+ * there is nothing to report.
124
+ *
125
+ * Sample entries are logged as given, so pass only the fields worth having in
126
+ * a log line.
127
+ *
128
+ * @param toolName - The tool that ran the batch, for the log prefix.
129
+ * @param failed - Items the tool could not complete.
130
+ * @param options.warnings - Items that completed but with a secondary op failing.
131
+ * @param options.context - Extra attributes for the log line, e.g. `{ itemType }`.
132
+ */
133
+ export function logOperationFailures(toolName, failed, options = {}) {
134
+ const { warnings = [], context = {} } = options;
135
+ if (failed.length === 0 && warnings.length === 0) {
136
+ return;
137
+ }
138
+ // The first error goes in the message itself. Datadog's full-text search
139
+ // reaches the message but not the values nested inside `failedSample`, so a
140
+ // search for the reason (`GOAWAY`, `401`) finds nothing without this.
141
+ const firstError = (failed[0] ?? warnings[0])?.error;
142
+ console.error(`${toolName}: operations failed: ${firstError}`, {
143
+ ...context,
144
+ failed: failed.length,
145
+ warnings: warnings.length,
146
+ failedSample: failed.slice(0, SAMPLE_LIMIT),
147
+ warningSample: warnings.slice(0, SAMPLE_LIMIT),
148
+ });
149
+ }