@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,25 @@
1
+ export const ToolNames = {
2
+ USER_INFO: 'user-info',
3
+ UPDATE_USER_INFO: 'update-user-info',
4
+ FETCH_INBOX: 'fetch-inbox',
5
+ LOAD_THREAD: 'load-thread',
6
+ LOAD_CONVERSATION: 'load-conversation',
7
+ SEARCH_CONTENT: 'search-content',
8
+ GET_MENTIONS: 'get-mentions',
9
+ CREATE_CHANNEL: 'create-channel',
10
+ UPDATE_CHANNEL: 'update-channel',
11
+ CREATE_THREAD: 'create-thread',
12
+ CREATE_CONVERSATION: 'create-conversation',
13
+ UPDATE_OBJECT: 'update-object',
14
+ DELETE_OBJECT: 'delete-object',
15
+ REPLY: 'reply',
16
+ REACT: 'react',
17
+ MARK_DONE: 'mark-done',
18
+ MARK_READ: 'mark-read',
19
+ BUILD_LINK: 'build-link',
20
+ GET_WORKSPACES: 'get-workspaces',
21
+ GET_USERS: 'get-users',
22
+ GET_GROUPS: 'get-groups',
23
+ LIST_CHANNELS: 'list-channels',
24
+ LIST_CONVERSATIONS: 'list-conversations',
25
+ };
@@ -0,0 +1,3 @@
1
+ export declare function getWorkspaceUrl(workspaceId: number): string;
2
+ export declare function getChannelUrl(workspaceId: number, channelId: string): string;
3
+ export declare function getConversationUrl(workspaceId: number, conversationId: string): string;
@@ -0,0 +1,10 @@
1
+ import { getFullCommsURL } from '@doist/comms-sdk';
2
+ export function getWorkspaceUrl(workspaceId) {
3
+ return getFullCommsURL({ workspaceId });
4
+ }
5
+ export function getChannelUrl(workspaceId, channelId) {
6
+ return getFullCommsURL({ workspaceId, channelId });
7
+ }
8
+ export function getConversationUrl(workspaceId, conversationId) {
9
+ return getFullCommsURL({ workspaceId, conversationId });
10
+ }
@@ -0,0 +1,8 @@
1
+ import type { UserStatus } from '@doist/comms-sdk';
2
+ import type { UserInfoOutput } from './output-schemas.js';
3
+ type StatusOutput = NonNullable<UserInfoOutput['status']>;
4
+ declare function normaliseActiveUntil(activeUntil: string): string;
5
+ declare function toStatusOutput(status: UserStatus): StatusOutput;
6
+ /** The status lines of a user-info text, in the same `**Label:** value` form as the rest. */
7
+ declare function describeStatus(status: StatusOutput | undefined): string[];
8
+ export { describeStatus, normaliseActiveUntil, toStatusOutput };
@@ -0,0 +1,33 @@
1
+ // Comms sends RFC 3339, but an end that fails to parse is still worth showing, so it is reported as
2
+ // sent. A set never gets this far with one: it fails the comparison with the end it asked for.
3
+ function normaliseActiveUntil(activeUntil) {
4
+ const parsed = new Date(activeUntil);
5
+ return Number.isNaN(parsed.getTime()) ? activeUntil : parsed.toISOString();
6
+ }
7
+ function toStatusOutput(status) {
8
+ const activeUntil = status.activeUntil ? normaliseActiveUntil(status.activeUntil) : undefined;
9
+ return {
10
+ message: status.message,
11
+ ...(status.emoji ? { emoji: status.emoji } : {}),
12
+ ...(activeUntil ? { activeUntil } : {}),
13
+ pauseNotifications: Boolean(status.effects?.pauseNotifications),
14
+ pauseActivity: Boolean(status.effects?.pauseActivity),
15
+ };
16
+ }
17
+ /** The status lines of a user-info text, in the same `**Label:** value` form as the rest. */
18
+ function describeStatus(status) {
19
+ if (!status) {
20
+ return ['**Status:** none'];
21
+ }
22
+ const lines = [`**Status:** ${status.emoji ? `${status.emoji} ` : ''}${status.message}`];
23
+ lines.push(`**Status Until:** ${status.activeUntil ?? 'no end'}`);
24
+ const effects = [
25
+ status.pauseNotifications ? 'Comms notifications paused' : undefined,
26
+ status.pauseActivity ? 'Karma and streaks paused' : undefined,
27
+ ].filter((effect) => effect !== undefined);
28
+ if (effects.length > 0) {
29
+ lines.push(`**Status Effects:** ${effects.join(', ')}`);
30
+ }
31
+ return lines;
32
+ }
33
+ export { describeStatus, normaliseActiveUntil, toStatusOutput };
@@ -0,0 +1,13 @@
1
+ import { type TokenValidationResult } from '@todoist/mcp-core/host';
2
+ /**
3
+ * Validates a Comms API token with a status-only call to the session-user endpoint.
4
+ *
5
+ * Resolves `'valid'`, `'invalid'` (401) or `'forbidden'` (403), so a host can answer a
6
+ * scope-deficient token with an RFC 6750 `insufficient_scope` challenge rather than a blanket
7
+ * 401. The request carries the usage-tracking headers, as the tool `auth:validate-token`.
8
+ *
9
+ * @throws {TokenValidationError} (from `@todoist/mcp-core/host`) for any other status, such as a
10
+ * 5xx or a 404 from a misconfigured base URL, carrying it as `httpStatusCode`. Network and
11
+ * timeout errors propagate unchanged.
12
+ */
13
+ export declare function validateCommsToken(token: string, baseUrl?: string): Promise<TokenValidationResult>;
@@ -0,0 +1,22 @@
1
+ import { validateBearerToken } from '@todoist/mcp-core/host';
2
+ import { buildUsageTrackingHeaders } from '../usage-tracking.js';
3
+ /** Production Comms API base URL, used when no explicit base is given. */
4
+ const DEFAULT_BASE_URL = 'https://comms.todoist.com';
5
+ /**
6
+ * Validates a Comms API token with a status-only call to the session-user endpoint.
7
+ *
8
+ * Resolves `'valid'`, `'invalid'` (401) or `'forbidden'` (403), so a host can answer a
9
+ * scope-deficient token with an RFC 6750 `insufficient_scope` challenge rather than a blanket
10
+ * 401. The request carries the usage-tracking headers, as the tool `auth:validate-token`.
11
+ *
12
+ * @throws {TokenValidationError} (from `@todoist/mcp-core/host`) for any other status, such as a
13
+ * 5xx or a 404 from a misconfigured base URL, carrying it as `httpStatusCode`. Network and
14
+ * timeout errors propagate unchanged.
15
+ */
16
+ export function validateCommsToken(token, baseUrl = DEFAULT_BASE_URL) {
17
+ return validateBearerToken({
18
+ url: `${baseUrl}/api/v1/users/get_session_user`,
19
+ token,
20
+ headers: buildUsageTrackingHeaders('auth:validate-token'),
21
+ });
22
+ }
package/package.json CHANGED
@@ -1,10 +1,87 @@
1
1
  {
2
- "name": "@todoist/comms-mcp",
3
- "version": "0.0.1",
4
- "description": "OIDC trusted publishing setup package for @todoist/comms-mcp",
5
- "keywords": [
6
- "oidc",
7
- "trusted-publishing",
8
- "setup"
9
- ]
2
+ "name": "@todoist/comms-mcp",
3
+ "version": "11.0.0",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "mcpName": "com.doist/comms-mcp",
8
+ "bin": {
9
+ "comms-mcp": "dist/main.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "package.json",
14
+ "LICENSE",
15
+ "README.md"
16
+ ],
17
+ "license": "MIT",
18
+ "description": "MCP server and importable AI tools for the Doist Comms API",
19
+ "author": "Doist",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/todoist/comms-mcp.git"
23
+ },
24
+ "keywords": [
25
+ "comms",
26
+ "doist",
27
+ "ai",
28
+ "mcp",
29
+ "collaboration",
30
+ "model-context-protocol"
31
+ ],
32
+ "publishConfig": {
33
+ "access": "public",
34
+ "provenance": true
35
+ },
36
+ "engines": {
37
+ "node": ">=24",
38
+ "npm": ">=11"
39
+ },
40
+ "scripts": {
41
+ "test": "vitest run",
42
+ "test:watch": "vitest",
43
+ "test:coverage": "vitest run --coverage",
44
+ "build": "rimraf dist && npx tsc --project tsconfig.json",
45
+ "postbuild": "chmod +x dist/main.js",
46
+ "start": "npm run build && npx @modelcontextprotocol/inspector node dist/main.js",
47
+ "dev": "concurrently \"npx tsc --watch\" \"npx @modelcontextprotocol/inspector npx nodemon --quiet --watch dist --ext js --exec node dist/main.js\"",
48
+ "type-check": "npx tsc --noEmit && npx tsc --noEmit -p .agents/scripts",
49
+ "format:check": "oxlint src scripts .agents/scripts *.config.js *.config.ts && oxfmt --check",
50
+ "format:fix": "oxlint src scripts .agents/scripts *.config.js *.config.ts --fix && oxfmt",
51
+ "prepublishOnly": "npm run build && npm test",
52
+ "prepare": "lefthook install --reset-hooks-path",
53
+ "verify": "node .agents/scripts/verify.ts",
54
+ "tool": "tsx scripts/run-tool.ts",
55
+ "tool:list": "tsx scripts/run-tool.ts --list",
56
+ "review:worktree": "node .agents/scripts/review-worktree.ts"
57
+ },
58
+ "dependencies": {
59
+ "@doist/comms-sdk": "3.12.0",
60
+ "@todoist/mcp-core": "1.0.0",
61
+ "dotenv": "17.4.2",
62
+ "p-limit": "6.2.0",
63
+ "zod": "4.6.7"
64
+ },
65
+ "peerDependencies": {
66
+ "@modelcontextprotocol/server": "^2.2.0"
67
+ },
68
+ "devDependencies": {
69
+ "@modelcontextprotocol/client": "2.3.0",
70
+ "@semantic-release/changelog": "6.0.3",
71
+ "@semantic-release/git": "10.0.1",
72
+ "@types/node": "22.19.17",
73
+ "@vitest/coverage-v8": "4.1.12",
74
+ "concurrently": "10.0.6",
75
+ "conventional-changelog-conventionalcommits": "9.3.1",
76
+ "gpt-tokenizer": "3.4.0",
77
+ "lefthook": "2.2.2",
78
+ "nodemon": "3.1.14",
79
+ "oxfmt": "0.72.0",
80
+ "oxlint": "1.63.0",
81
+ "rimraf": "6.1.3",
82
+ "semantic-release": "25.0.3",
83
+ "tsx": "4.22.4",
84
+ "typescript": "6.0.3",
85
+ "vitest": "4.1.12"
86
+ }
10
87
  }