mcp-twake-mail 0.1.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 (114) hide show
  1. package/LICENSE +663 -0
  2. package/README.md +332 -0
  3. package/build/auth/index.d.ts +3 -0
  4. package/build/auth/index.js +4 -0
  5. package/build/auth/index.js.map +1 -0
  6. package/build/auth/oidc-flow.d.ts +47 -0
  7. package/build/auth/oidc-flow.js +146 -0
  8. package/build/auth/oidc-flow.js.map +1 -0
  9. package/build/auth/token-refresh.d.ts +56 -0
  10. package/build/auth/token-refresh.js +132 -0
  11. package/build/auth/token-refresh.js.map +1 -0
  12. package/build/auth/token-store.d.ts +33 -0
  13. package/build/auth/token-store.js +63 -0
  14. package/build/auth/token-store.js.map +1 -0
  15. package/build/cli/commands/auth.d.ts +5 -0
  16. package/build/cli/commands/auth.js +49 -0
  17. package/build/cli/commands/auth.js.map +1 -0
  18. package/build/cli/commands/check.d.ts +4 -0
  19. package/build/cli/commands/check.js +125 -0
  20. package/build/cli/commands/check.js.map +1 -0
  21. package/build/cli/commands/setup.d.ts +4 -0
  22. package/build/cli/commands/setup.js +172 -0
  23. package/build/cli/commands/setup.js.map +1 -0
  24. package/build/cli/index.d.ts +15 -0
  25. package/build/cli/index.js +56 -0
  26. package/build/cli/index.js.map +1 -0
  27. package/build/cli/prompts/setup-wizard.d.ts +38 -0
  28. package/build/cli/prompts/setup-wizard.js +121 -0
  29. package/build/cli/prompts/setup-wizard.js.map +1 -0
  30. package/build/config/__tests__/logger.test.d.ts +1 -0
  31. package/build/config/__tests__/logger.test.js +28 -0
  32. package/build/config/__tests__/logger.test.js.map +1 -0
  33. package/build/config/__tests__/schema.test.d.ts +1 -0
  34. package/build/config/__tests__/schema.test.js +101 -0
  35. package/build/config/__tests__/schema.test.js.map +1 -0
  36. package/build/config/logger.d.ts +3 -0
  37. package/build/config/logger.js +9 -0
  38. package/build/config/logger.js.map +1 -0
  39. package/build/config/schema.d.ts +28 -0
  40. package/build/config/schema.js +81 -0
  41. package/build/config/schema.js.map +1 -0
  42. package/build/errors.d.ts +34 -0
  43. package/build/errors.js +154 -0
  44. package/build/errors.js.map +1 -0
  45. package/build/errors.test.d.ts +1 -0
  46. package/build/errors.test.js +234 -0
  47. package/build/errors.test.js.map +1 -0
  48. package/build/index.d.ts +2 -0
  49. package/build/index.js +12 -0
  50. package/build/index.js.map +1 -0
  51. package/build/jmap/client.d.ts +96 -0
  52. package/build/jmap/client.js +267 -0
  53. package/build/jmap/client.js.map +1 -0
  54. package/build/mcp/server.d.ts +24 -0
  55. package/build/mcp/server.js +68 -0
  56. package/build/mcp/server.js.map +1 -0
  57. package/build/mcp/tools/attachment.d.ts +30 -0
  58. package/build/mcp/tools/attachment.js +246 -0
  59. package/build/mcp/tools/attachment.js.map +1 -0
  60. package/build/mcp/tools/attachment.test.d.ts +1 -0
  61. package/build/mcp/tools/attachment.test.js +457 -0
  62. package/build/mcp/tools/attachment.test.js.map +1 -0
  63. package/build/mcp/tools/email-operations.d.ts +10 -0
  64. package/build/mcp/tools/email-operations.js +828 -0
  65. package/build/mcp/tools/email-operations.js.map +1 -0
  66. package/build/mcp/tools/email-operations.test.d.ts +1 -0
  67. package/build/mcp/tools/email-operations.test.js +453 -0
  68. package/build/mcp/tools/email-operations.test.js.map +1 -0
  69. package/build/mcp/tools/email-sending.d.ts +10 -0
  70. package/build/mcp/tools/email-sending.js +682 -0
  71. package/build/mcp/tools/email-sending.js.map +1 -0
  72. package/build/mcp/tools/email.d.ts +10 -0
  73. package/build/mcp/tools/email.js +365 -0
  74. package/build/mcp/tools/email.js.map +1 -0
  75. package/build/mcp/tools/email.test.d.ts +1 -0
  76. package/build/mcp/tools/email.test.js +332 -0
  77. package/build/mcp/tools/email.test.js.map +1 -0
  78. package/build/mcp/tools/index.d.ts +14 -0
  79. package/build/mcp/tools/index.js +29 -0
  80. package/build/mcp/tools/index.js.map +1 -0
  81. package/build/mcp/tools/mailbox.d.ts +10 -0
  82. package/build/mcp/tools/mailbox.js +195 -0
  83. package/build/mcp/tools/mailbox.js.map +1 -0
  84. package/build/mcp/tools/mailbox.test.d.ts +1 -0
  85. package/build/mcp/tools/mailbox.test.js +231 -0
  86. package/build/mcp/tools/mailbox.test.js.map +1 -0
  87. package/build/mcp/tools/thread.d.ts +10 -0
  88. package/build/mcp/tools/thread.js +282 -0
  89. package/build/mcp/tools/thread.js.map +1 -0
  90. package/build/mcp/tools/thread.test.d.ts +1 -0
  91. package/build/mcp/tools/thread.test.js +384 -0
  92. package/build/mcp/tools/thread.test.js.map +1 -0
  93. package/build/transformers/__tests__/email.test.d.ts +1 -0
  94. package/build/transformers/__tests__/email.test.js +438 -0
  95. package/build/transformers/__tests__/email.test.js.map +1 -0
  96. package/build/transformers/__tests__/mailbox.test.d.ts +1 -0
  97. package/build/transformers/__tests__/mailbox.test.js +222 -0
  98. package/build/transformers/__tests__/mailbox.test.js.map +1 -0
  99. package/build/transformers/email.d.ts +76 -0
  100. package/build/transformers/email.js +138 -0
  101. package/build/transformers/email.js.map +1 -0
  102. package/build/transformers/index.d.ts +5 -0
  103. package/build/transformers/index.js +6 -0
  104. package/build/transformers/index.js.map +1 -0
  105. package/build/transformers/mailbox.d.ts +43 -0
  106. package/build/transformers/mailbox.js +70 -0
  107. package/build/transformers/mailbox.js.map +1 -0
  108. package/build/types/dto.d.ts +91 -0
  109. package/build/types/dto.js +9 -0
  110. package/build/types/dto.js.map +1 -0
  111. package/build/types/jmap.d.ts +110 -0
  112. package/build/types/jmap.js +5 -0
  113. package/build/types/jmap.js.map +1 -0
  114. package/package.json +71 -0
@@ -0,0 +1,231 @@
1
+ /**
2
+ * Tests for mailbox MCP tools - get_mailbox, list_mailboxes.
3
+ */
4
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
5
+ import { registerMailboxTools } from './mailbox.js';
6
+ describe('registerMailboxTools', () => {
7
+ let mockServer;
8
+ let mockJmapClient;
9
+ let mockLogger;
10
+ let registeredTools;
11
+ beforeEach(() => {
12
+ registeredTools = new Map();
13
+ // Mock MCP server - uses .tool() method
14
+ mockServer = {
15
+ tool: vi.fn((name, _desc, _schema, _annotations, handler) => {
16
+ registeredTools.set(name, handler);
17
+ }),
18
+ };
19
+ // Mock JMAP client
20
+ mockJmapClient = {
21
+ getSession: vi.fn(() => ({ accountId: 'account-1', apiUrl: 'https://jmap.example.com/api' })),
22
+ request: vi.fn(),
23
+ parseMethodResponse: vi.fn(),
24
+ };
25
+ // Mock logger (silent)
26
+ mockLogger = {
27
+ debug: vi.fn(),
28
+ info: vi.fn(),
29
+ warn: vi.fn(),
30
+ error: vi.fn(),
31
+ };
32
+ // Register all tools
33
+ registerMailboxTools(mockServer, mockJmapClient, mockLogger);
34
+ });
35
+ describe('get_mailbox', () => {
36
+ it('returns transformed mailbox on success', async () => {
37
+ const mockMailbox = {
38
+ id: 'mailbox-1',
39
+ name: 'Inbox',
40
+ role: 'inbox',
41
+ totalEmails: 100,
42
+ unreadEmails: 10,
43
+ sortOrder: 1,
44
+ parentId: null,
45
+ };
46
+ vi.mocked(mockJmapClient.request).mockResolvedValue({
47
+ methodResponses: [
48
+ ['Mailbox/get', { accountId: 'account-1', list: [mockMailbox], notFound: [] }, 'get-mailbox'],
49
+ ],
50
+ });
51
+ vi.mocked(mockJmapClient.parseMethodResponse).mockReturnValue({
52
+ success: true,
53
+ data: { accountId: 'account-1', list: [mockMailbox], notFound: [] },
54
+ });
55
+ const handler = registeredTools.get('get_mailbox');
56
+ const result = await handler({ mailboxId: 'mailbox-1' });
57
+ expect(result.isError).toBeUndefined();
58
+ const parsed = JSON.parse(result.content[0].text);
59
+ expect(parsed.id).toBe('mailbox-1');
60
+ expect(parsed.name).toBe('Inbox');
61
+ expect(parsed.role).toBe('inbox');
62
+ expect(parsed.totalEmails).toBe(100);
63
+ expect(parsed.unreadEmails).toBe(10);
64
+ });
65
+ it('returns error when mailbox not found in notFound array', async () => {
66
+ vi.mocked(mockJmapClient.request).mockResolvedValue({
67
+ methodResponses: [
68
+ ['Mailbox/get', { accountId: 'account-1', list: [], notFound: ['mailbox-nonexistent'] }, 'get-mailbox'],
69
+ ],
70
+ });
71
+ vi.mocked(mockJmapClient.parseMethodResponse).mockReturnValue({
72
+ success: true,
73
+ data: { accountId: 'account-1', list: [], notFound: ['mailbox-nonexistent'] },
74
+ });
75
+ const handler = registeredTools.get('get_mailbox');
76
+ const result = await handler({ mailboxId: 'mailbox-nonexistent' });
77
+ expect(result.isError).toBe(true);
78
+ expect(result.content[0].text).toContain('Mailbox not found');
79
+ });
80
+ it('returns error when mailbox list is empty', async () => {
81
+ vi.mocked(mockJmapClient.request).mockResolvedValue({
82
+ methodResponses: [
83
+ ['Mailbox/get', { accountId: 'account-1', list: [], notFound: [] }, 'get-mailbox'],
84
+ ],
85
+ });
86
+ vi.mocked(mockJmapClient.parseMethodResponse).mockReturnValue({
87
+ success: true,
88
+ data: { accountId: 'account-1', list: [], notFound: [] },
89
+ });
90
+ const handler = registeredTools.get('get_mailbox');
91
+ const result = await handler({ mailboxId: 'mailbox-missing' });
92
+ expect(result.isError).toBe(true);
93
+ expect(result.content[0].text).toContain('Mailbox not found');
94
+ });
95
+ it('returns error on JMAP error', async () => {
96
+ vi.mocked(mockJmapClient.request).mockResolvedValue({
97
+ methodResponses: [
98
+ ['error', { type: 'serverError', description: 'Internal server error' }, 'get-mailbox'],
99
+ ],
100
+ });
101
+ vi.mocked(mockJmapClient.parseMethodResponse).mockReturnValue({
102
+ success: false,
103
+ error: { type: 'serverError', description: 'Internal server error' },
104
+ });
105
+ const handler = registeredTools.get('get_mailbox');
106
+ const result = await handler({ mailboxId: 'mailbox-1' });
107
+ expect(result.isError).toBe(true);
108
+ expect(result.content[0].text).toContain('Error retrieving mailbox');
109
+ expect(result.content[0].text).toContain('Internal server error');
110
+ });
111
+ it('handles exception gracefully', async () => {
112
+ vi.mocked(mockJmapClient.request).mockRejectedValue(new Error('Network error'));
113
+ const handler = registeredTools.get('get_mailbox');
114
+ const result = await handler({ mailboxId: 'mailbox-1' });
115
+ expect(result.isError).toBe(true);
116
+ expect(result.content[0].text).toContain('Error retrieving mailbox');
117
+ expect(result.content[0].text).toContain('Network error');
118
+ });
119
+ });
120
+ describe('list_mailboxes', () => {
121
+ it('returns all mailboxes when no filter', async () => {
122
+ const mockMailboxes = [
123
+ { id: 'inbox', name: 'Inbox', role: 'inbox', totalEmails: 100, unreadEmails: 10, sortOrder: 1, parentId: null },
124
+ { id: 'sent', name: 'Sent', role: 'sent', totalEmails: 50, unreadEmails: 0, sortOrder: 2, parentId: null },
125
+ { id: 'custom', name: 'Custom Folder', role: null, totalEmails: 20, unreadEmails: 5, sortOrder: 100, parentId: null },
126
+ ];
127
+ vi.mocked(mockJmapClient.request).mockResolvedValue({
128
+ methodResponses: [
129
+ ['Mailbox/get', { accountId: 'account-1', list: mockMailboxes }, 'list-mailboxes'],
130
+ ],
131
+ });
132
+ vi.mocked(mockJmapClient.parseMethodResponse).mockReturnValue({
133
+ success: true,
134
+ data: { accountId: 'account-1', list: mockMailboxes },
135
+ });
136
+ const handler = registeredTools.get('list_mailboxes');
137
+ const result = await handler({});
138
+ expect(result.isError).toBeUndefined();
139
+ const parsed = JSON.parse(result.content[0].text);
140
+ expect(parsed).toHaveLength(3);
141
+ });
142
+ it('filters mailboxes by role', async () => {
143
+ const mockMailboxes = [
144
+ { id: 'inbox', name: 'Inbox', role: 'inbox', totalEmails: 100, unreadEmails: 10, sortOrder: 1, parentId: null },
145
+ { id: 'sent', name: 'Sent', role: 'sent', totalEmails: 50, unreadEmails: 0, sortOrder: 2, parentId: null },
146
+ { id: 'drafts', name: 'Drafts', role: 'drafts', totalEmails: 5, unreadEmails: 0, sortOrder: 3, parentId: null },
147
+ ];
148
+ vi.mocked(mockJmapClient.request).mockResolvedValue({
149
+ methodResponses: [
150
+ ['Mailbox/get', { accountId: 'account-1', list: mockMailboxes }, 'list-mailboxes'],
151
+ ],
152
+ });
153
+ vi.mocked(mockJmapClient.parseMethodResponse).mockReturnValue({
154
+ success: true,
155
+ data: { accountId: 'account-1', list: mockMailboxes },
156
+ });
157
+ const handler = registeredTools.get('list_mailboxes');
158
+ const result = await handler({ role: 'inbox' });
159
+ expect(result.isError).toBeUndefined();
160
+ const parsed = JSON.parse(result.content[0].text);
161
+ expect(parsed).toHaveLength(1);
162
+ expect(parsed[0].role).toBe('inbox');
163
+ });
164
+ it('returns empty array when no mailboxes match filter', async () => {
165
+ const mockMailboxes = [
166
+ { id: 'inbox', name: 'Inbox', role: 'inbox', totalEmails: 100, unreadEmails: 10, sortOrder: 1, parentId: null },
167
+ ];
168
+ vi.mocked(mockJmapClient.request).mockResolvedValue({
169
+ methodResponses: [
170
+ ['Mailbox/get', { accountId: 'account-1', list: mockMailboxes }, 'list-mailboxes'],
171
+ ],
172
+ });
173
+ vi.mocked(mockJmapClient.parseMethodResponse).mockReturnValue({
174
+ success: true,
175
+ data: { accountId: 'account-1', list: mockMailboxes },
176
+ });
177
+ const handler = registeredTools.get('list_mailboxes');
178
+ const result = await handler({ role: 'archive' });
179
+ expect(result.isError).toBeUndefined();
180
+ const parsed = JSON.parse(result.content[0].text);
181
+ expect(parsed).toHaveLength(0);
182
+ });
183
+ it('returns empty array when list is undefined', async () => {
184
+ vi.mocked(mockJmapClient.request).mockResolvedValue({
185
+ methodResponses: [
186
+ ['Mailbox/get', { accountId: 'account-1' }, 'list-mailboxes'],
187
+ ],
188
+ });
189
+ vi.mocked(mockJmapClient.parseMethodResponse).mockReturnValue({
190
+ success: true,
191
+ data: { accountId: 'account-1' },
192
+ });
193
+ const handler = registeredTools.get('list_mailboxes');
194
+ const result = await handler({});
195
+ expect(result.isError).toBeUndefined();
196
+ const parsed = JSON.parse(result.content[0].text);
197
+ expect(parsed).toEqual([]);
198
+ });
199
+ it('returns error on JMAP error', async () => {
200
+ vi.mocked(mockJmapClient.request).mockResolvedValue({
201
+ methodResponses: [
202
+ ['error', { type: 'serverError', description: 'Internal error' }, 'list-mailboxes'],
203
+ ],
204
+ });
205
+ vi.mocked(mockJmapClient.parseMethodResponse).mockReturnValue({
206
+ success: false,
207
+ error: { type: 'serverError', description: 'Internal error' },
208
+ });
209
+ const handler = registeredTools.get('list_mailboxes');
210
+ const result = await handler({});
211
+ expect(result.isError).toBe(true);
212
+ expect(result.content[0].text).toContain('Error listing mailboxes');
213
+ });
214
+ it('handles exception gracefully', async () => {
215
+ vi.mocked(mockJmapClient.request).mockRejectedValue(new Error('Connection timeout'));
216
+ const handler = registeredTools.get('list_mailboxes');
217
+ const result = await handler({});
218
+ expect(result.isError).toBe(true);
219
+ expect(result.content[0].text).toContain('Error listing mailboxes');
220
+ expect(result.content[0].text).toContain('Connection timeout');
221
+ });
222
+ });
223
+ describe('tool registration', () => {
224
+ it('registers both mailbox tools', () => {
225
+ expect(registeredTools.has('get_mailbox')).toBe(true);
226
+ expect(registeredTools.has('list_mailboxes')).toBe(true);
227
+ expect(registeredTools.size).toBe(2);
228
+ });
229
+ });
230
+ });
231
+ //# sourceMappingURL=mailbox.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mailbox.test.js","sourceRoot":"","sources":["../../../src/mcp/tools/mailbox.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { JMAPClient } from '../../jmap/client.js';
3
+ import type { Logger } from '../../config/logger.js';
4
+ /**
5
+ * Register thread MCP tools with the server.
6
+ * @param server MCP server instance
7
+ * @param jmapClient JMAP client for API calls
8
+ * @param logger Pino logger
9
+ */
10
+ export declare function registerThreadTools(server: McpServer, jmapClient: JMAPClient, logger: Logger): void;
@@ -0,0 +1,282 @@
1
+ /**
2
+ * Thread MCP tools - get_thread, get_thread_emails.
3
+ * These tools enable AI assistants to navigate email conversations.
4
+ */
5
+ import { z } from 'zod';
6
+ import { transformEmail } from '../../transformers/email.js';
7
+ /**
8
+ * Common annotations for read-only thread tools.
9
+ */
10
+ const THREAD_READ_ANNOTATIONS = {
11
+ readOnlyHint: true,
12
+ destructiveHint: false,
13
+ idempotentHint: true,
14
+ openWorldHint: true,
15
+ };
16
+ /**
17
+ * Properties to fetch for full email content in thread context.
18
+ */
19
+ const FULL_EMAIL_PROPERTIES = [
20
+ 'id',
21
+ 'blobId',
22
+ 'threadId',
23
+ 'mailboxIds',
24
+ 'keywords',
25
+ 'from',
26
+ 'to',
27
+ 'cc',
28
+ 'bcc',
29
+ 'replyTo',
30
+ 'subject',
31
+ 'receivedAt',
32
+ 'sentAt',
33
+ 'preview',
34
+ 'hasAttachment',
35
+ 'size',
36
+ 'bodyValues',
37
+ 'textBody',
38
+ 'htmlBody',
39
+ 'attachments',
40
+ ];
41
+ /**
42
+ * Register thread MCP tools with the server.
43
+ * @param server MCP server instance
44
+ * @param jmapClient JMAP client for API calls
45
+ * @param logger Pino logger
46
+ */
47
+ export function registerThreadTools(server, jmapClient, logger) {
48
+ // get_thread - retrieve thread by ID (THREAD-01)
49
+ server.registerTool('get_thread', {
50
+ title: 'Get Thread',
51
+ description: 'Retrieve a thread by ID, returning the thread ID and list of email IDs in oldest-first order.',
52
+ inputSchema: {
53
+ threadId: z.string().describe('The unique identifier of the thread to retrieve'),
54
+ },
55
+ annotations: THREAD_READ_ANNOTATIONS,
56
+ }, async ({ threadId }) => {
57
+ logger.debug({ threadId }, 'get_thread called');
58
+ try {
59
+ const session = jmapClient.getSession();
60
+ const response = await jmapClient.request([
61
+ [
62
+ 'Thread/get',
63
+ {
64
+ accountId: session.accountId,
65
+ ids: [threadId],
66
+ },
67
+ 'getThread',
68
+ ],
69
+ ]);
70
+ const result = jmapClient.parseMethodResponse(response.methodResponses[0]);
71
+ if (!result.success) {
72
+ logger.error({ error: result.error, threadId }, 'JMAP error in get_thread');
73
+ return {
74
+ isError: true,
75
+ content: [
76
+ {
77
+ type: 'text',
78
+ text: `Failed to retrieve thread: ${result.error?.description || result.error?.type || 'Unknown error'}`,
79
+ },
80
+ ],
81
+ };
82
+ }
83
+ const threads = result.data?.list;
84
+ const notFound = result.data?.notFound;
85
+ // Check if thread was not found
86
+ if (notFound && notFound.includes(threadId)) {
87
+ return {
88
+ isError: true,
89
+ content: [
90
+ {
91
+ type: 'text',
92
+ text: `Thread not found: ${threadId}`,
93
+ },
94
+ ],
95
+ };
96
+ }
97
+ if (!threads || threads.length === 0) {
98
+ return {
99
+ isError: true,
100
+ content: [
101
+ {
102
+ type: 'text',
103
+ text: `Thread not found: ${threadId}`,
104
+ },
105
+ ],
106
+ };
107
+ }
108
+ const thread = threads[0];
109
+ logger.debug({ threadId, emailCount: thread.emailIds.length }, 'get_thread success');
110
+ return {
111
+ content: [
112
+ {
113
+ type: 'text',
114
+ text: JSON.stringify({
115
+ id: thread.id,
116
+ emailIds: thread.emailIds,
117
+ }, null, 2),
118
+ },
119
+ ],
120
+ };
121
+ }
122
+ catch (error) {
123
+ logger.error({ error, threadId }, 'Exception in get_thread');
124
+ return {
125
+ isError: true,
126
+ content: [
127
+ {
128
+ type: 'text',
129
+ text: `Error retrieving thread: ${error instanceof Error ? error.message : String(error)}`,
130
+ },
131
+ ],
132
+ };
133
+ }
134
+ });
135
+ // get_thread_emails - retrieve all emails in a thread (THREAD-02)
136
+ server.registerTool('get_thread_emails', {
137
+ title: 'Get Thread Emails',
138
+ description: 'Retrieve all emails in a thread with full content, returned in oldest-first order.',
139
+ inputSchema: {
140
+ threadId: z.string().describe('The unique identifier of the thread'),
141
+ },
142
+ annotations: THREAD_READ_ANNOTATIONS,
143
+ }, async ({ threadId }) => {
144
+ logger.debug({ threadId }, 'get_thread_emails called');
145
+ try {
146
+ const session = jmapClient.getSession();
147
+ // Step 1: Get thread to retrieve emailIds
148
+ const threadResponse = await jmapClient.request([
149
+ [
150
+ 'Thread/get',
151
+ {
152
+ accountId: session.accountId,
153
+ ids: [threadId],
154
+ },
155
+ 'getThread',
156
+ ],
157
+ ]);
158
+ const threadResult = jmapClient.parseMethodResponse(threadResponse.methodResponses[0]);
159
+ if (!threadResult.success) {
160
+ logger.error({ error: threadResult.error, threadId }, 'JMAP error in get_thread_emails (Thread/get)');
161
+ return {
162
+ isError: true,
163
+ content: [
164
+ {
165
+ type: 'text',
166
+ text: `Failed to retrieve thread: ${threadResult.error?.description || threadResult.error?.type || 'Unknown error'}`,
167
+ },
168
+ ],
169
+ };
170
+ }
171
+ const threads = threadResult.data?.list;
172
+ const notFound = threadResult.data?.notFound;
173
+ // Check if thread was not found
174
+ if (notFound && notFound.includes(threadId)) {
175
+ return {
176
+ isError: true,
177
+ content: [
178
+ {
179
+ type: 'text',
180
+ text: `Thread not found: ${threadId}`,
181
+ },
182
+ ],
183
+ };
184
+ }
185
+ if (!threads || threads.length === 0) {
186
+ return {
187
+ isError: true,
188
+ content: [
189
+ {
190
+ type: 'text',
191
+ text: `Thread not found: ${threadId}`,
192
+ },
193
+ ],
194
+ };
195
+ }
196
+ const thread = threads[0];
197
+ const emailIds = thread.emailIds;
198
+ // Handle empty thread (no emails)
199
+ if (!emailIds || emailIds.length === 0) {
200
+ logger.debug({ threadId }, 'get_thread_emails success (empty thread)');
201
+ return {
202
+ content: [
203
+ {
204
+ type: 'text',
205
+ text: JSON.stringify({
206
+ threadId,
207
+ emails: [],
208
+ }, null, 2),
209
+ },
210
+ ],
211
+ };
212
+ }
213
+ // Step 2: Get all emails in the thread
214
+ const emailResponse = await jmapClient.request([
215
+ [
216
+ 'Email/get',
217
+ {
218
+ accountId: session.accountId,
219
+ ids: emailIds,
220
+ properties: FULL_EMAIL_PROPERTIES,
221
+ fetchTextBodyValues: true,
222
+ fetchHTMLBodyValues: true,
223
+ bodyProperties: ['partId', 'blobId', 'type', 'name', 'size'],
224
+ },
225
+ 'getEmails',
226
+ ],
227
+ ]);
228
+ const emailResult = jmapClient.parseMethodResponse(emailResponse.methodResponses[0]);
229
+ if (!emailResult.success) {
230
+ logger.error({ error: emailResult.error, threadId }, 'JMAP error in get_thread_emails (Email/get)');
231
+ return {
232
+ isError: true,
233
+ content: [
234
+ {
235
+ type: 'text',
236
+ text: `Failed to retrieve thread emails: ${emailResult.error?.description || emailResult.error?.type || 'Unknown error'}`,
237
+ },
238
+ ],
239
+ };
240
+ }
241
+ const emails = emailResult.data?.list || [];
242
+ // Transform emails and maintain order (emailIds from Thread/get is oldest-first per RFC 8621)
243
+ // Create a map for quick lookup by ID
244
+ const emailMap = new Map();
245
+ for (const email of emails) {
246
+ const emailObj = email;
247
+ emailMap.set(emailObj.id, email);
248
+ }
249
+ // Preserve the order from emailIds (oldest-first)
250
+ const orderedEmails = emailIds
251
+ .map((id) => emailMap.get(id))
252
+ .filter((email) => email !== undefined)
253
+ .map((email) => transformEmail(email));
254
+ logger.debug({ threadId, emailCount: orderedEmails.length }, 'get_thread_emails success');
255
+ return {
256
+ content: [
257
+ {
258
+ type: 'text',
259
+ text: JSON.stringify({
260
+ threadId,
261
+ emails: orderedEmails,
262
+ }, null, 2),
263
+ },
264
+ ],
265
+ };
266
+ }
267
+ catch (error) {
268
+ logger.error({ error, threadId }, 'Exception in get_thread_emails');
269
+ return {
270
+ isError: true,
271
+ content: [
272
+ {
273
+ type: 'text',
274
+ text: `Error retrieving thread emails: ${error instanceof Error ? error.message : String(error)}`,
275
+ },
276
+ ],
277
+ };
278
+ }
279
+ });
280
+ logger.debug('Thread tools registered: get_thread, get_thread_emails');
281
+ }
282
+ //# sourceMappingURL=thread.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread.js","sourceRoot":"","sources":["../../../src/mcp/tools/thread.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};