@todoist/comms-mcp 0.0.0-stage → 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.
- package/LICENSE +21 -0
- package/README.md +208 -2
- package/dist/comms-tool.d.ts +14 -0
- package/dist/comms-tool.js +1 -0
- package/dist/index.d.ts +1324 -0
- package/dist/index.js +55 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.js +24 -0
- package/dist/mcp-helpers.d.ts +17 -0
- package/dist/mcp-helpers.js +40 -0
- package/dist/mcp-server.d.ts +10 -0
- package/dist/mcp-server.js +78 -0
- package/dist/tool-registry.d.ts +3 -0
- package/dist/tool-registry.js +49 -0
- package/dist/tools/build-link.d.ts +63 -0
- package/dist/tools/build-link.js +93 -0
- package/dist/tools/channel-output.d.ts +19 -0
- package/dist/tools/channel-output.js +47 -0
- package/dist/tools/create-channel.d.ts +55 -0
- package/dist/tools/create-channel.js +44 -0
- package/dist/tools/create-conversation.d.ts +49 -0
- package/dist/tools/create-conversation.js +75 -0
- package/dist/tools/create-thread.d.ts +67 -0
- package/dist/tools/create-thread.js +126 -0
- package/dist/tools/delete-object.d.ts +44 -0
- package/dist/tools/delete-object.js +84 -0
- package/dist/tools/fetch-inbox.d.ts +91 -0
- package/dist/tools/fetch-inbox.js +227 -0
- package/dist/tools/get-groups.d.ts +62 -0
- package/dist/tools/get-groups.js +116 -0
- package/dist/tools/get-mentions.d.ts +97 -0
- package/dist/tools/get-mentions.js +126 -0
- package/dist/tools/get-users.d.ts +58 -0
- package/dist/tools/get-users.js +107 -0
- package/dist/tools/get-workspaces.d.ts +61 -0
- package/dist/tools/get-workspaces.js +120 -0
- package/dist/tools/list-channels.d.ts +47 -0
- package/dist/tools/list-channels.js +89 -0
- package/dist/tools/list-conversations.d.ts +66 -0
- package/dist/tools/list-conversations.js +212 -0
- package/dist/tools/load-conversation.d.ts +92 -0
- package/dist/tools/load-conversation.js +128 -0
- package/dist/tools/load-thread.d.ts +127 -0
- package/dist/tools/load-thread.js +175 -0
- package/dist/tools/mark-done.d.ts +111 -0
- package/dist/tools/mark-done.js +275 -0
- package/dist/tools/mark-read.d.ts +73 -0
- package/dist/tools/mark-read.js +214 -0
- package/dist/tools/react.d.ts +59 -0
- package/dist/tools/react.js +97 -0
- package/dist/tools/reply.d.ts +69 -0
- package/dist/tools/reply.js +122 -0
- package/dist/tools/search-content.d.ts +103 -0
- package/dist/tools/search-content.js +138 -0
- package/dist/tools/update-channel.d.ts +53 -0
- package/dist/tools/update-channel.js +45 -0
- package/dist/tools/update-object.d.ts +52 -0
- package/dist/tools/update-object.js +161 -0
- package/dist/tools/update-user-info.d.ts +55 -0
- package/dist/tools/update-user-info.js +270 -0
- package/dist/tools/user-info.d.ts +32 -0
- package/dist/tools/user-info.js +16 -0
- package/dist/tools/user-output.d.ts +9 -0
- package/dist/tools/user-output.js +28 -0
- package/dist/usage-tracking.d.ts +23 -0
- package/dist/usage-tracking.js +41 -0
- package/dist/utils/attachments.d.ts +24 -0
- package/dist/utils/attachments.js +57 -0
- package/dist/utils/concurrency.d.ts +20 -0
- package/dist/utils/concurrency.js +24 -0
- package/dist/utils/constants.d.ts +5 -0
- package/dist/utils/constants.js +5 -0
- package/dist/utils/degrade.d.ts +81 -0
- package/dist/utils/degrade.js +149 -0
- package/dist/utils/output-schemas.d.ts +1283 -0
- package/dist/utils/output-schemas.js +657 -0
- package/dist/utils/read-position.d.ts +21 -0
- package/dist/utils/read-position.js +37 -0
- package/dist/utils/search-results.d.ts +36 -0
- package/dist/utils/search-results.js +82 -0
- package/dist/utils/target-types.d.ts +114 -0
- package/dist/utils/target-types.js +58 -0
- package/dist/utils/test-helpers.d.ts +95 -0
- package/dist/utils/test-helpers.js +231 -0
- package/dist/utils/tool-names.d.ts +25 -0
- package/dist/utils/tool-names.js +25 -0
- package/dist/utils/url-helpers.d.ts +3 -0
- package/dist/utils/url-helpers.js +10 -0
- package/dist/utils/user-status.d.ts +8 -0
- package/dist/utils/user-status.js +33 -0
- package/dist/utils/validate-comms-token.d.ts +13 -0
- package/dist/utils/validate-comms-token.js +22 -0
- package/package.json +86 -5
|
@@ -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
|
+
}
|