@mcp-z/mcp-gmail 1.1.3 → 2.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 (89) hide show
  1. package/dist/cjs/index.js.map +1 -1
  2. package/dist/cjs/lib/google-auth.d.cts +9 -0
  3. package/dist/cjs/lib/google-auth.d.ts +9 -0
  4. package/dist/cjs/lib/google-auth.js +16 -0
  5. package/dist/cjs/lib/google-auth.js.map +1 -0
  6. package/dist/cjs/mcp/prompts/draft-email.d.cts +2 -3
  7. package/dist/cjs/mcp/prompts/draft-email.d.ts +2 -3
  8. package/dist/cjs/mcp/prompts/draft-email.js.map +1 -1
  9. package/dist/cjs/mcp/prompts/query-syntax.d.cts +2 -3
  10. package/dist/cjs/mcp/prompts/query-syntax.d.ts +2 -3
  11. package/dist/cjs/mcp/prompts/query-syntax.js.map +1 -1
  12. package/dist/cjs/mcp/resources/email.d.cts +6 -5
  13. package/dist/cjs/mcp/resources/email.d.ts +6 -5
  14. package/dist/cjs/mcp/resources/email.js +4 -3
  15. package/dist/cjs/mcp/resources/email.js.map +1 -1
  16. package/dist/cjs/mcp/tools/categories-list.js +4 -3
  17. package/dist/cjs/mcp/tools/categories-list.js.map +1 -1
  18. package/dist/cjs/mcp/tools/label-add.js +5 -4
  19. package/dist/cjs/mcp/tools/label-add.js.map +1 -1
  20. package/dist/cjs/mcp/tools/label-delete.js +8 -7
  21. package/dist/cjs/mcp/tools/label-delete.js.map +1 -1
  22. package/dist/cjs/mcp/tools/labels-list.d.cts +3 -3
  23. package/dist/cjs/mcp/tools/labels-list.d.ts +3 -3
  24. package/dist/cjs/mcp/tools/labels-list.js +4 -3
  25. package/dist/cjs/mcp/tools/labels-list.js.map +1 -1
  26. package/dist/cjs/mcp/tools/message-get.js +5 -5
  27. package/dist/cjs/mcp/tools/message-get.js.map +1 -1
  28. package/dist/cjs/mcp/tools/message-mark-read.js +5 -4
  29. package/dist/cjs/mcp/tools/message-mark-read.js.map +1 -1
  30. package/dist/cjs/mcp/tools/message-move-to-trash.js +8 -7
  31. package/dist/cjs/mcp/tools/message-move-to-trash.js.map +1 -1
  32. package/dist/cjs/mcp/tools/message-respond.js +6 -5
  33. package/dist/cjs/mcp/tools/message-respond.js.map +1 -1
  34. package/dist/cjs/mcp/tools/message-search.js +4 -4
  35. package/dist/cjs/mcp/tools/message-search.js.map +1 -1
  36. package/dist/cjs/mcp/tools/message-send.js +5 -4
  37. package/dist/cjs/mcp/tools/message-send.js.map +1 -1
  38. package/dist/cjs/mcp/tools/messages-export-csv.js +3 -3
  39. package/dist/cjs/mcp/tools/messages-export-csv.js.map +1 -1
  40. package/dist/cjs/setup/http.d.cts +1 -1
  41. package/dist/cjs/setup/http.d.ts +1 -1
  42. package/dist/cjs/setup/http.js +1 -2
  43. package/dist/cjs/setup/http.js.map +1 -1
  44. package/dist/cjs/setup/stdio.d.cts +1 -1
  45. package/dist/cjs/setup/stdio.d.ts +1 -1
  46. package/dist/cjs/setup/stdio.js +1 -2
  47. package/dist/cjs/setup/stdio.js.map +1 -1
  48. package/dist/esm/index.js +1 -1
  49. package/dist/esm/index.js.map +1 -1
  50. package/dist/esm/lib/google-auth.d.ts +9 -0
  51. package/dist/esm/lib/google-auth.js +11 -0
  52. package/dist/esm/lib/google-auth.js.map +1 -0
  53. package/dist/esm/mcp/prompts/draft-email.d.ts +2 -3
  54. package/dist/esm/mcp/prompts/draft-email.js.map +1 -1
  55. package/dist/esm/mcp/prompts/query-syntax.d.ts +2 -3
  56. package/dist/esm/mcp/prompts/query-syntax.js.map +1 -1
  57. package/dist/esm/mcp/resources/email.d.ts +6 -5
  58. package/dist/esm/mcp/resources/email.js +3 -2
  59. package/dist/esm/mcp/resources/email.js.map +1 -1
  60. package/dist/esm/mcp/tools/categories-list.js +4 -3
  61. package/dist/esm/mcp/tools/categories-list.js.map +1 -1
  62. package/dist/esm/mcp/tools/label-add.js +5 -4
  63. package/dist/esm/mcp/tools/label-add.js.map +1 -1
  64. package/dist/esm/mcp/tools/label-delete.js +8 -7
  65. package/dist/esm/mcp/tools/label-delete.js.map +1 -1
  66. package/dist/esm/mcp/tools/labels-list.d.ts +3 -3
  67. package/dist/esm/mcp/tools/labels-list.js +4 -3
  68. package/dist/esm/mcp/tools/labels-list.js.map +1 -1
  69. package/dist/esm/mcp/tools/message-get.js +6 -6
  70. package/dist/esm/mcp/tools/message-get.js.map +1 -1
  71. package/dist/esm/mcp/tools/message-mark-read.js +5 -4
  72. package/dist/esm/mcp/tools/message-mark-read.js.map +1 -1
  73. package/dist/esm/mcp/tools/message-move-to-trash.js +8 -7
  74. package/dist/esm/mcp/tools/message-move-to-trash.js.map +1 -1
  75. package/dist/esm/mcp/tools/message-respond.js +6 -5
  76. package/dist/esm/mcp/tools/message-respond.js.map +1 -1
  77. package/dist/esm/mcp/tools/message-search.js +4 -3
  78. package/dist/esm/mcp/tools/message-search.js.map +1 -1
  79. package/dist/esm/mcp/tools/message-send.js +5 -4
  80. package/dist/esm/mcp/tools/message-send.js.map +1 -1
  81. package/dist/esm/mcp/tools/messages-export-csv.js +4 -4
  82. package/dist/esm/mcp/tools/messages-export-csv.js.map +1 -1
  83. package/dist/esm/setup/http.d.ts +1 -1
  84. package/dist/esm/setup/http.js +1 -2
  85. package/dist/esm/setup/http.js.map +1 -1
  86. package/dist/esm/setup/stdio.d.ts +1 -1
  87. package/dist/esm/setup/stdio.js +1 -2
  88. package/dist/esm/setup/stdio.js.map +1 -1
  89. package/package.json +8 -8
@@ -1,9 +1,10 @@
1
1
  import { schemas } from '@mcp-z/oauth-google';
2
2
  const { AuthRequiredBranchSchema } = schemas;
3
- import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
3
+ import { ProtocolError, ProtocolErrorCode } from '@mcp-z/server';
4
4
  import { google } from 'googleapis';
5
5
  import { z } from 'zod';
6
6
  import { CHUNK_SIZE, MAX_BATCH_SIZE } from '../../constants.js';
7
+ import { googleAuth } from '../../lib/google-auth.js';
7
8
  const inputSchema = z.object({
8
9
  ids: z.array(z.coerce.string().trim().min(1)).min(1).describe('Gmail message IDs to move to trash')
9
10
  });
@@ -35,11 +36,11 @@ async function handler({ ids }, extra) {
35
36
  count: ids.length
36
37
  });
37
38
  if (!ids || ids.length === 0) {
38
- throw new McpError(ErrorCode.InvalidParams, 'Missing ids');
39
+ throw new ProtocolError(ProtocolErrorCode.InvalidParams, 'Missing ids');
39
40
  }
40
41
  // Validate batch size to prevent memory exhaustion
41
42
  if (ids.length > MAX_BATCH_SIZE) {
42
- throw new McpError(ErrorCode.InvalidParams, `Batch size ${ids.length} exceeds maximum allowed size of ${MAX_BATCH_SIZE}`);
43
+ throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Batch size ${ids.length} exceeds maximum allowed size of ${MAX_BATCH_SIZE}`);
43
44
  }
44
45
  // Validate and sanitize IDs
45
46
  const validatedIds = [];
@@ -58,15 +59,15 @@ async function handler({ ids }, extra) {
58
59
  validatedIds.push(trimmedId);
59
60
  }
60
61
  if (invalidIds.length > 0) {
61
- throw new McpError(ErrorCode.InvalidParams, `Found ${invalidIds.length} invalid IDs: ${invalidIds.join(', ')}`);
62
+ throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Found ${invalidIds.length} invalid IDs: ${invalidIds.join(', ')}`);
62
63
  }
63
64
  if (validatedIds.length === 0) {
64
- throw new McpError(ErrorCode.InvalidParams, 'No valid IDs found after validation');
65
+ throw new ProtocolError(ProtocolErrorCode.InvalidParams, 'No valid IDs found after validation');
65
66
  }
66
67
  try {
67
68
  const gmail = google.gmail({
68
69
  version: 'v1',
69
- auth: extra.authContext.auth
70
+ auth: googleAuth(extra.authContext.auth)
70
71
  });
71
72
  // Process operations in chunks to prevent memory exhaustion
72
73
  const allResults = [];
@@ -153,7 +154,7 @@ async function handler({ ids }, extra) {
153
154
  logger.error('gmail-message-move-to-trash error', {
154
155
  error: message
155
156
  });
156
- throw new McpError(ErrorCode.InternalError, `Error moving messages to trash: ${message}`, {
157
+ throw new ProtocolError(ProtocolErrorCode.InternalError, `Error moving messages to trash: ${message}`, {
157
158
  stack: error instanceof Error ? error.stack : undefined
158
159
  });
159
160
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-gmail/src/mcp/tools/message-move-to-trash.ts"],"sourcesContent":["import type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport type { ToolModule } from '@mcp-z/server';\nimport { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\nimport { google } from 'googleapis';\nimport { z } from 'zod';\nimport { CHUNK_SIZE, MAX_BATCH_SIZE } from '../../constants.ts';\n\nconst inputSchema = z.object({\n ids: z.array(z.coerce.string().trim().min(1)).min(1).describe('Gmail message IDs to move to trash'),\n});\n\nconst successBranchSchema = z.object({\n type: z.literal('success'),\n totalRequested: z.number().describe('Total number of messages requested to trash'),\n successCount: z.number().describe('Number of messages successfully moved to trash'),\n failureCount: z.number().describe('Number of messages that failed to move'),\n results: z\n .array(\n z.object({\n id: z.string().describe('Message ID'),\n success: z.boolean().describe('Whether the operation succeeded'),\n error: z.string().optional().describe('Error message if operation failed'),\n })\n )\n .describe('Individual results for each message'),\n});\n\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Move Gmail messages to trash (recoverable).',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\nasync function handler({ ids }: Input, extra: EnrichedExtra) {\n const logger = extra.logger;\n logger.info('gmail-message-move-to-trash called', { count: ids.length });\n\n if (!ids || ids.length === 0) {\n throw new McpError(ErrorCode.InvalidParams, 'Missing ids');\n }\n\n // Validate batch size to prevent memory exhaustion\n if (ids.length > MAX_BATCH_SIZE) {\n throw new McpError(ErrorCode.InvalidParams, `Batch size ${ids.length} exceeds maximum allowed size of ${MAX_BATCH_SIZE}`);\n }\n\n // Validate and sanitize IDs\n const validatedIds: string[] = [];\n const invalidIds: string[] = [];\n\n for (const id of ids) {\n const trimmedId = id.trim();\n if (!trimmedId) {\n invalidIds.push(id);\n continue;\n }\n // Basic Gmail message ID validation - should not contain certain characters\n if (trimmedId.includes('/') || trimmedId.includes('\\\\') || trimmedId.includes('<') || trimmedId.includes('>')) {\n invalidIds.push(id);\n continue;\n }\n validatedIds.push(trimmedId);\n }\n\n if (invalidIds.length > 0) {\n throw new McpError(ErrorCode.InvalidParams, `Found ${invalidIds.length} invalid IDs: ${invalidIds.join(', ')}`);\n }\n\n if (validatedIds.length === 0) {\n throw new McpError(ErrorCode.InvalidParams, 'No valid IDs found after validation');\n }\n\n try {\n const gmail = google.gmail({ version: 'v1', auth: extra.authContext.auth });\n // Process operations in chunks to prevent memory exhaustion\n const allResults: Array<{ id: string; success: boolean; error?: string }> = [];\n\n for (let i = 0; i < validatedIds.length; i += CHUNK_SIZE) {\n const chunk = validatedIds.slice(i, i + CHUNK_SIZE);\n logger.info('Processing chunk', { chunkIndex: i / CHUNK_SIZE + 1, chunkSize: chunk.length, totalChunks: Math.ceil(validatedIds.length / CHUNK_SIZE) });\n\n const chunkResults = await Promise.allSettled(\n chunk.map(async (id) => {\n await gmail.users.messages.trash({\n userId: 'me',\n id: id,\n });\n return { id, success: true };\n })\n );\n\n // Process chunk results\n const processedChunkResults = chunkResults.map((result, chunkIndex) => {\n const id = chunk[chunkIndex];\n if (!id) {\n throw new Error(`Chunk index ${chunkIndex} is out of bounds for chunk of size ${chunk.length}`);\n }\n if (result.status === 'fulfilled') {\n return { id, success: true };\n }\n\n // Extract error message more robustly\n let errorMessage = 'Unknown error';\n if (result.reason) {\n if (typeof result.reason === 'string') {\n errorMessage = result.reason;\n } else if (result.reason instanceof Error) {\n errorMessage = result.reason.message;\n } else if (result.reason && typeof result.reason === 'object' && 'message' in result.reason) {\n errorMessage = String(result.reason.message);\n } else if (result.reason && typeof result.reason === 'object' && 'error' in result.reason) {\n errorMessage = String(result.reason.error);\n } else {\n errorMessage = String(result.reason);\n }\n }\n\n return { id, success: false, error: errorMessage };\n });\n\n allResults.push(...processedChunkResults);\n }\n\n const successCount = allResults.filter((r) => r.success).length;\n const failureCount = allResults.filter((r) => !r.success).length;\n\n logger.info('gmail-message-move-to-trash completed', {\n totalRequested: validatedIds.length,\n successCount,\n failureCount,\n chunksProcessed: Math.ceil(validatedIds.length / CHUNK_SIZE),\n });\n\n const result: Output = {\n type: 'success' as const,\n totalRequested: validatedIds.length,\n successCount,\n failureCount,\n results: allResults,\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail-message-move-to-trash error', { error: message });\n\n throw new McpError(ErrorCode.InternalError, `Error moving messages to trash: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'message-move-to-trash',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["schemas","AuthRequiredBranchSchema","ErrorCode","McpError","google","z","CHUNK_SIZE","MAX_BATCH_SIZE","inputSchema","object","ids","array","coerce","string","trim","min","describe","successBranchSchema","type","literal","totalRequested","number","successCount","failureCount","results","id","success","boolean","error","optional","outputSchema","discriminatedUnion","config","description","result","handler","extra","logger","info","count","length","InvalidParams","validatedIds","invalidIds","trimmedId","push","includes","join","gmail","version","auth","authContext","allResults","i","chunk","slice","chunkIndex","chunkSize","totalChunks","Math","ceil","chunkResults","Promise","allSettled","map","users","messages","trash","userId","processedChunkResults","Error","status","errorMessage","reason","message","String","filter","r","chunksProcessed","content","text","JSON","stringify","structuredContent","InternalError","stack","undefined","createTool","name"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-gmail/src/mcp/tools/message-move-to-trash.ts"],"sourcesContent":["import type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport type { ToolModule } from '@mcp-z/server';\nimport { ProtocolError, ProtocolErrorCode } from '@mcp-z/server';\nimport { google } from 'googleapis';\nimport { z } from 'zod';\nimport { CHUNK_SIZE, MAX_BATCH_SIZE } from '../../constants.ts';\nimport { googleAuth } from '../../lib/google-auth.ts';\n\nconst inputSchema = z.object({\n ids: z.array(z.coerce.string().trim().min(1)).min(1).describe('Gmail message IDs to move to trash'),\n});\n\nconst successBranchSchema = z.object({\n type: z.literal('success'),\n totalRequested: z.number().describe('Total number of messages requested to trash'),\n successCount: z.number().describe('Number of messages successfully moved to trash'),\n failureCount: z.number().describe('Number of messages that failed to move'),\n results: z\n .array(\n z.object({\n id: z.string().describe('Message ID'),\n success: z.boolean().describe('Whether the operation succeeded'),\n error: z.string().optional().describe('Error message if operation failed'),\n })\n )\n .describe('Individual results for each message'),\n});\n\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Move Gmail messages to trash (recoverable).',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\nasync function handler({ ids }: Input, extra: EnrichedExtra) {\n const logger = extra.logger;\n logger.info('gmail-message-move-to-trash called', { count: ids.length });\n\n if (!ids || ids.length === 0) {\n throw new ProtocolError(ProtocolErrorCode.InvalidParams, 'Missing ids');\n }\n\n // Validate batch size to prevent memory exhaustion\n if (ids.length > MAX_BATCH_SIZE) {\n throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Batch size ${ids.length} exceeds maximum allowed size of ${MAX_BATCH_SIZE}`);\n }\n\n // Validate and sanitize IDs\n const validatedIds: string[] = [];\n const invalidIds: string[] = [];\n\n for (const id of ids) {\n const trimmedId = id.trim();\n if (!trimmedId) {\n invalidIds.push(id);\n continue;\n }\n // Basic Gmail message ID validation - should not contain certain characters\n if (trimmedId.includes('/') || trimmedId.includes('\\\\') || trimmedId.includes('<') || trimmedId.includes('>')) {\n invalidIds.push(id);\n continue;\n }\n validatedIds.push(trimmedId);\n }\n\n if (invalidIds.length > 0) {\n throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Found ${invalidIds.length} invalid IDs: ${invalidIds.join(', ')}`);\n }\n\n if (validatedIds.length === 0) {\n throw new ProtocolError(ProtocolErrorCode.InvalidParams, 'No valid IDs found after validation');\n }\n\n try {\n const gmail = google.gmail({ version: 'v1', auth: googleAuth(extra.authContext.auth) });\n // Process operations in chunks to prevent memory exhaustion\n const allResults: Array<{ id: string; success: boolean; error?: string }> = [];\n\n for (let i = 0; i < validatedIds.length; i += CHUNK_SIZE) {\n const chunk = validatedIds.slice(i, i + CHUNK_SIZE);\n logger.info('Processing chunk', { chunkIndex: i / CHUNK_SIZE + 1, chunkSize: chunk.length, totalChunks: Math.ceil(validatedIds.length / CHUNK_SIZE) });\n\n const chunkResults = await Promise.allSettled(\n chunk.map(async (id) => {\n await gmail.users.messages.trash({\n userId: 'me',\n id: id,\n });\n return { id, success: true };\n })\n );\n\n // Process chunk results\n const processedChunkResults = chunkResults.map((result, chunkIndex) => {\n const id = chunk[chunkIndex];\n if (!id) {\n throw new Error(`Chunk index ${chunkIndex} is out of bounds for chunk of size ${chunk.length}`);\n }\n if (result.status === 'fulfilled') {\n return { id, success: true };\n }\n\n // Extract error message more robustly\n let errorMessage = 'Unknown error';\n if (result.reason) {\n if (typeof result.reason === 'string') {\n errorMessage = result.reason;\n } else if (result.reason instanceof Error) {\n errorMessage = result.reason.message;\n } else if (result.reason && typeof result.reason === 'object' && 'message' in result.reason) {\n errorMessage = String(result.reason.message);\n } else if (result.reason && typeof result.reason === 'object' && 'error' in result.reason) {\n errorMessage = String(result.reason.error);\n } else {\n errorMessage = String(result.reason);\n }\n }\n\n return { id, success: false, error: errorMessage };\n });\n\n allResults.push(...processedChunkResults);\n }\n\n const successCount = allResults.filter((r) => r.success).length;\n const failureCount = allResults.filter((r) => !r.success).length;\n\n logger.info('gmail-message-move-to-trash completed', {\n totalRequested: validatedIds.length,\n successCount,\n failureCount,\n chunksProcessed: Math.ceil(validatedIds.length / CHUNK_SIZE),\n });\n\n const result: Output = {\n type: 'success' as const,\n totalRequested: validatedIds.length,\n successCount,\n failureCount,\n results: allResults,\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail-message-move-to-trash error', { error: message });\n\n throw new ProtocolError(ProtocolErrorCode.InternalError, `Error moving messages to trash: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'message-move-to-trash',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["schemas","AuthRequiredBranchSchema","ProtocolError","ProtocolErrorCode","google","z","CHUNK_SIZE","MAX_BATCH_SIZE","googleAuth","inputSchema","object","ids","array","coerce","string","trim","min","describe","successBranchSchema","type","literal","totalRequested","number","successCount","failureCount","results","id","success","boolean","error","optional","outputSchema","discriminatedUnion","config","description","result","handler","extra","logger","info","count","length","InvalidParams","validatedIds","invalidIds","trimmedId","push","includes","join","gmail","version","auth","authContext","allResults","i","chunk","slice","chunkIndex","chunkSize","totalChunks","Math","ceil","chunkResults","Promise","allSettled","map","users","messages","trash","userId","processedChunkResults","Error","status","errorMessage","reason","message","String","filter","r","chunksProcessed","content","text","JSON","stringify","structuredContent","InternalError","stack","undefined","createTool","name"],"mappings":"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"}
@@ -1,11 +1,12 @@
1
1
  import { ComposeContentTypeSchema } from '@mcp-z/email';
2
2
  import { schemas } from '@mcp-z/oauth-google';
3
3
  const { AuthRequiredBranchSchema } = schemas;
4
- import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
4
+ import { ProtocolError, ProtocolErrorCode } from '@mcp-z/server';
5
5
  import { google } from 'googleapis';
6
6
  import { z } from 'zod';
7
7
  import { extractEmails } from '../../email/parsing/headers-utils.js';
8
8
  import { b64url } from '../../lib/base64-encoding.js';
9
+ import { googleAuth } from '../../lib/google-auth.js';
9
10
  const inputSchema = z.object({
10
11
  id: z.coerce.string().trim().min(1).describe('Gmail message ID to reply to'),
11
12
  body: z.coerce.string().trim().min(1).describe('Reply body content (plain text or HTML)'),
@@ -29,7 +30,7 @@ const config = {
29
30
  async function handler({ id, body, contentType }, extra) {
30
31
  const logger = extra.logger;
31
32
  if (!id || !body) {
32
- throw new McpError(ErrorCode.InvalidParams, 'Missing id or body');
33
+ throw new ProtocolError(ProtocolErrorCode.InvalidParams, 'Missing id or body');
33
34
  }
34
35
  logger.info('gmail.message.respond called', {
35
36
  id,
@@ -40,7 +41,7 @@ async function handler({ id, body, contentType }, extra) {
40
41
  var _fullData_payload;
41
42
  const gmail = google.gmail({
42
43
  version: 'v1',
43
- auth: extra.authContext.auth
44
+ auth: googleAuth(extra.authContext.auth)
44
45
  });
45
46
  let full;
46
47
  try {
@@ -65,7 +66,7 @@ async function handler({ id, body, contentType }, extra) {
65
66
  logger.error('gmail.message.respond fetch error', {
66
67
  error: message
67
68
  });
68
- throw new McpError(ErrorCode.InternalError, `Error fetching message metadata: ${message}`, {
69
+ throw new ProtocolError(ProtocolErrorCode.InternalError, `Error fetching message metadata: ${message}`, {
69
70
  stack: error instanceof Error ? error.stack : undefined
70
71
  });
71
72
  }
@@ -138,7 +139,7 @@ async function handler({ id, body, contentType }, extra) {
138
139
  logger.error('gmail.message.respond error', {
139
140
  error: message
140
141
  });
141
- throw new McpError(ErrorCode.InternalError, `Error responding to message: ${message}`, {
142
+ throw new ProtocolError(ProtocolErrorCode.InternalError, `Error responding to message: ${message}`, {
142
143
  stack: error instanceof Error ? error.stack : undefined
143
144
  });
144
145
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-gmail/src/mcp/tools/message-respond.ts"],"sourcesContent":["import { ComposeContentTypeSchema } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport type { ToolModule } from '@mcp-z/server';\nimport { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\nimport { google } from 'googleapis';\nimport { z } from 'zod';\nimport { extractEmails } from '../../email/parsing/headers-utils.ts';\nimport { b64url } from '../../lib/base64-encoding.ts';\n\nconst inputSchema = z.object({\n id: z.coerce.string().trim().min(1).describe('Gmail message ID to reply to'),\n body: z.coerce.string().trim().min(1).describe('Reply body content (plain text or HTML)'),\n contentType: ComposeContentTypeSchema,\n});\n\nconst successBranchSchema = z.object({\n type: z.literal('success'),\n id: z.string().describe('Original message ID that was replied to'),\n});\n\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Send a reply to a Gmail message',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\nasync function handler({ id, body, contentType }: Input, extra: EnrichedExtra) {\n const logger = extra.logger;\n\n if (!id || !body) {\n throw new McpError(ErrorCode.InvalidParams, 'Missing id or body');\n }\n\n logger.info('gmail.message.respond called', { id, contentType });\n\n try {\n const gmail = google.gmail({ version: 'v1', auth: extra.authContext.auth });\n\n let full: unknown;\n try {\n const response = await gmail.users.messages.get({\n userId: 'me',\n id: id,\n format: 'metadata',\n metadataHeaders: ['From', 'To', 'Reply-To', 'Subject', 'Message-ID', 'References', 'In-Reply-To', 'Date'],\n });\n full = response.data;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.message.respond fetch error', { error: message });\n\n throw new McpError(ErrorCode.InternalError, `Error fetching message metadata: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n\n // Type-safe header extraction\n const fullData = full as { payload?: { headers?: unknown[] }; threadId?: unknown };\n const headersArray = Array.isArray(fullData?.payload?.headers) ? fullData.payload.headers : [];\n const headers = Object.fromEntries(\n headersArray.map((h: unknown) => {\n const header = h as { name?: unknown; value?: unknown };\n return [String(header.name ?? ''), String(header.value ?? '')];\n })\n );\n const fromHdr = headers.From || headers.from;\n const replyToHdr = headers['Reply-To'] || headers['reply-to'];\n const toAddr = (replyToHdr ? extractEmails(replyToHdr)[0] : extractEmails(fromHdr)[0]) ?? '';\n const subject = (headers.Subject || headers.subject) ?? '';\n const messageIdHeader = headers['Message-ID'] || headers['Message-Id'] || headers['message-id'];\n const references = (headers.References || headers.references) ?? '';\n const replySubject = /^re:/i.test(subject) ? subject : `Re: ${subject}`;\n const inReplyTo = messageIdHeader?.startsWith('<') ? messageIdHeader : messageIdHeader ? `<${messageIdHeader}>` : undefined;\n const refs = [references, inReplyTo].filter(Boolean).join(' ').trim();\n const mimeType = contentType === 'html' ? 'text/html' : 'text/plain';\n const lines = [`To: ${toAddr}`, `Subject: ${replySubject}`, `In-Reply-To: ${inReplyTo ?? ''}`, `References: ${refs}`, 'MIME-Version: 1.0', `Content-Type: ${mimeType}; charset=UTF-8`, '', body].join('\\r\\n');\n const raw = b64url(lines);\n\n // Prepare request body with conditional threadId for exactOptionalPropertyTypes\n const threadId = fullData?.threadId ? String(fullData.threadId) : undefined;\n await gmail.users.messages.send({\n userId: 'me',\n requestBody: {\n raw: raw,\n ...(threadId && { threadId }),\n },\n });\n\n logger.info('gmail.message.respond sent reply', { id });\n\n const result: Output = {\n type: 'success' as const,\n id,\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.message.respond error', { error: message });\n\n throw new McpError(ErrorCode.InternalError, `Error responding to message: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'message-respond',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["ComposeContentTypeSchema","schemas","AuthRequiredBranchSchema","ErrorCode","McpError","google","z","extractEmails","b64url","inputSchema","object","id","coerce","string","trim","min","describe","body","contentType","successBranchSchema","type","literal","outputSchema","discriminatedUnion","config","description","result","handler","extra","logger","InvalidParams","info","replyToHdr","headers","fullData","gmail","version","auth","authContext","full","response","users","messages","get","userId","format","metadataHeaders","data","error","message","Error","String","InternalError","stack","undefined","headersArray","Array","isArray","payload","Object","fromEntries","map","h","header","name","value","fromHdr","From","from","toAddr","subject","Subject","messageIdHeader","references","References","replySubject","test","inReplyTo","startsWith","refs","filter","Boolean","join","mimeType","lines","raw","threadId","send","requestBody","content","text","JSON","stringify","structuredContent","createTool"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-gmail/src/mcp/tools/message-respond.ts"],"sourcesContent":["import { ComposeContentTypeSchema } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport type { ToolModule } from '@mcp-z/server';\nimport { ProtocolError, ProtocolErrorCode } from '@mcp-z/server';\nimport { google } from 'googleapis';\nimport { z } from 'zod';\nimport { extractEmails } from '../../email/parsing/headers-utils.ts';\nimport { b64url } from '../../lib/base64-encoding.ts';\nimport { googleAuth } from '../../lib/google-auth.ts';\n\nconst inputSchema = z.object({\n id: z.coerce.string().trim().min(1).describe('Gmail message ID to reply to'),\n body: z.coerce.string().trim().min(1).describe('Reply body content (plain text or HTML)'),\n contentType: ComposeContentTypeSchema,\n});\n\nconst successBranchSchema = z.object({\n type: z.literal('success'),\n id: z.string().describe('Original message ID that was replied to'),\n});\n\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Send a reply to a Gmail message',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\nasync function handler({ id, body, contentType }: Input, extra: EnrichedExtra) {\n const logger = extra.logger;\n\n if (!id || !body) {\n throw new ProtocolError(ProtocolErrorCode.InvalidParams, 'Missing id or body');\n }\n\n logger.info('gmail.message.respond called', { id, contentType });\n\n try {\n const gmail = google.gmail({ version: 'v1', auth: googleAuth(extra.authContext.auth) });\n\n let full: unknown;\n try {\n const response = await gmail.users.messages.get({\n userId: 'me',\n id: id,\n format: 'metadata',\n metadataHeaders: ['From', 'To', 'Reply-To', 'Subject', 'Message-ID', 'References', 'In-Reply-To', 'Date'],\n });\n full = response.data;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.message.respond fetch error', { error: message });\n\n throw new ProtocolError(ProtocolErrorCode.InternalError, `Error fetching message metadata: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n\n // Type-safe header extraction\n const fullData = full as { payload?: { headers?: unknown[] }; threadId?: unknown };\n const headersArray = Array.isArray(fullData?.payload?.headers) ? fullData.payload.headers : [];\n const headers = Object.fromEntries(\n headersArray.map((h: unknown) => {\n const header = h as { name?: unknown; value?: unknown };\n return [String(header.name ?? ''), String(header.value ?? '')];\n })\n );\n const fromHdr = headers.From || headers.from;\n const replyToHdr = headers['Reply-To'] || headers['reply-to'];\n const toAddr = (replyToHdr ? extractEmails(replyToHdr)[0] : extractEmails(fromHdr)[0]) ?? '';\n const subject = (headers.Subject || headers.subject) ?? '';\n const messageIdHeader = headers['Message-ID'] || headers['Message-Id'] || headers['message-id'];\n const references = (headers.References || headers.references) ?? '';\n const replySubject = /^re:/i.test(subject) ? subject : `Re: ${subject}`;\n const inReplyTo = messageIdHeader?.startsWith('<') ? messageIdHeader : messageIdHeader ? `<${messageIdHeader}>` : undefined;\n const refs = [references, inReplyTo].filter(Boolean).join(' ').trim();\n const mimeType = contentType === 'html' ? 'text/html' : 'text/plain';\n const lines = [`To: ${toAddr}`, `Subject: ${replySubject}`, `In-Reply-To: ${inReplyTo ?? ''}`, `References: ${refs}`, 'MIME-Version: 1.0', `Content-Type: ${mimeType}; charset=UTF-8`, '', body].join('\\r\\n');\n const raw = b64url(lines);\n\n // Prepare request body with conditional threadId for exactOptionalPropertyTypes\n const threadId = fullData?.threadId ? String(fullData.threadId) : undefined;\n await gmail.users.messages.send({\n userId: 'me',\n requestBody: {\n raw: raw,\n ...(threadId && { threadId }),\n },\n });\n\n logger.info('gmail.message.respond sent reply', { id });\n\n const result: Output = {\n type: 'success' as const,\n id,\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.message.respond error', { error: message });\n\n throw new ProtocolError(ProtocolErrorCode.InternalError, `Error responding to message: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'message-respond',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["ComposeContentTypeSchema","schemas","AuthRequiredBranchSchema","ProtocolError","ProtocolErrorCode","google","z","extractEmails","b64url","googleAuth","inputSchema","object","id","coerce","string","trim","min","describe","body","contentType","successBranchSchema","type","literal","outputSchema","discriminatedUnion","config","description","result","handler","extra","logger","InvalidParams","info","replyToHdr","headers","fullData","gmail","version","auth","authContext","full","response","users","messages","get","userId","format","metadataHeaders","data","error","message","Error","String","InternalError","stack","undefined","headersArray","Array","isArray","payload","Object","fromEntries","map","h","header","name","value","fromHdr","From","from","toAddr","subject","Subject","messageIdHeader","references","References","replySubject","test","inReplyTo","startsWith","refs","filter","Boolean","join","mimeType","lines","raw","threadId","send","requestBody","content","text","JSON","stringify","structuredContent","createTool"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
1
+ import { ProtocolError, ProtocolErrorCode } from '@mcp-z/server';
2
2
  /** Gmail message search using middleware-based auth pattern */ import { EMAIL_COMMON_PATTERNS, EMAIL_FIELD_DESCRIPTIONS, EMAIL_FIELDS, EmailContentTypeSchema, EmailDetailSchema, ExcludeThreadHistorySchema } from '@mcp-z/email';
3
3
  import { schemas } from '@mcp-z/oauth-google';
4
4
  const { AuthRequiredBranchSchema } = schemas;
@@ -8,6 +8,7 @@ import { z } from 'zod';
8
8
  import { DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE } from '../../constants.js';
9
9
  import { extractBodyFromPayload } from '../../email/parsing/html-processing.js';
10
10
  import { executeQuery as executeGmailQuery } from '../../email/querying/execute-query.js';
11
+ import { googleAuth } from '../../lib/google-auth.js';
11
12
  import { GmailQueryParameterSchema, parseGmailQueryParameter } from '../../schemas/gmail-query-schema.js';
12
13
  const inputSchema = z.object({
13
14
  query: GmailQueryParameterSchema.optional().describe('Structured query object or JSON string for filtering messages. Use query-syntax prompt for reference and rawGmailQuery for Gmail syntax.'),
@@ -70,7 +71,7 @@ async function handler({ query, pageSize = DEFAULT_PAGE_SIZE, pageToken, fields,
70
71
  });
71
72
  const gmail = google.gmail({
72
73
  version: 'v1',
73
- auth: extra.authContext.auth
74
+ auth: googleAuth(extra.authContext.auth)
74
75
  });
75
76
  const started = Date.now();
76
77
  const exec = await executeGmailQuery(parsedQuery, {
@@ -167,7 +168,7 @@ async function handler({ query, pageSize = DEFAULT_PAGE_SIZE, pageToken, fields,
167
168
  logger.error('gmail.message.search error', {
168
169
  error: message
169
170
  });
170
- throw new McpError(ErrorCode.InternalError, `Error searching messages: ${message}`, {
171
+ throw new ProtocolError(ProtocolErrorCode.InternalError, `Error searching messages: ${message}`, {
171
172
  stack: error instanceof Error ? error.stack : undefined
172
173
  });
173
174
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-gmail/src/mcp/tools/message-search.ts"],"sourcesContent":["import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\n/** Gmail message search using middleware-based auth pattern */\n\nimport { EMAIL_COMMON_PATTERNS, EMAIL_FIELD_DESCRIPTIONS, EMAIL_FIELDS, EmailContentTypeSchema, type EmailDetail, EmailDetailSchema, ExcludeThreadHistorySchema } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { createFieldsSchema, createPaginationSchema, createShapeSchema, filterFields, parseFields, type ToolModule, toColumnarFormat } from '@mcp-z/server';\nimport { type gmail_v1, google } from 'googleapis';\nimport { z } from 'zod';\nimport { DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE } from '../../constants.ts';\nimport { extractBodyFromPayload } from '../../email/parsing/html-processing.ts';\nimport { executeQuery as executeGmailQuery } from '../../email/querying/execute-query.ts';\nimport { GmailQueryParameterSchema, parseGmailQueryParameter } from '../../schemas/gmail-query-schema.ts';\n\nconst inputSchema = z.object({\n query: GmailQueryParameterSchema.optional().describe('Structured query object or JSON string for filtering messages. Use query-syntax prompt for reference and rawGmailQuery for Gmail syntax.'),\n fields: createFieldsSchema({\n availableFields: EMAIL_FIELDS,\n fieldDescriptions: EMAIL_FIELD_DESCRIPTIONS,\n commonPatterns: EMAIL_COMMON_PATTERNS,\n resourceName: 'email message',\n }),\n ...createPaginationSchema({ defaultPageSize: DEFAULT_PAGE_SIZE, maxPageSize: MAX_PAGE_SIZE, provider: 'gmail' }).shape,\n shape: createShapeSchema(),\n contentType: EmailContentTypeSchema,\n excludeThreadHistory: ExcludeThreadHistorySchema,\n});\n\n// Success branch schemas for different shapes\nconst successObjectsBranchSchema = z.object({\n type: z.literal('success'),\n shape: z.literal('objects'),\n items: z.array(EmailDetailSchema).describe('Matching email messages'),\n nextPageToken: z.string().optional().describe('Token for fetching next page of results'),\n});\n\nconst successArraysBranchSchema = z.object({\n type: z.literal('success'),\n shape: z.literal('arrays'),\n columns: z.array(z.string()).describe('Column names in canonical order'),\n rows: z.array(z.array(z.unknown())).describe('Row data matching column order'),\n nextPageToken: z.string().optional().describe('Token for fetching next page of results'),\n});\n\n// Output schema with auth_required support\n// Using z.union instead of discriminatedUnion since we have two success branches with different shapes\nconst outputSchema = z.union([successObjectsBranchSchema, successArraysBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Search Gmail messages using structured query objects with flexible field selection.',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\nasync function handler({ query, pageSize = DEFAULT_PAGE_SIZE, pageToken, fields, shape = 'arrays', contentType = 'text', excludeThreadHistory = false }: Input, extra: EnrichedExtra) {\n const logger = extra.logger;\n\n try {\n const parsedQuery = parseGmailQueryParameter(query);\n const requestedFields = parseFields(fields, EMAIL_FIELDS);\n const includeBody = requestedFields === 'all' || requestedFields.has('body');\n\n logger.info('gmail.message.search called', {\n query: parsedQuery,\n pageSize,\n pageToken: pageToken ? '[provided]' : undefined,\n fields,\n includeBody,\n accountId: extra.authContext.accountId, // Available from middleware\n });\n\n const gmail = google.gmail({ version: 'v1', auth: extra.authContext.auth });\n\n const started = Date.now();\n\n const exec = await executeGmailQuery(\n parsedQuery,\n {\n client: gmail,\n logger,\n pageSize,\n ...(pageToken !== undefined && { pageToken }),\n includeBody,\n },\n (full: unknown) => {\n // Type-safe property access with guards\n const fullData = full as gmail_v1.Schema$Message;\n\n const headersArray = Array.isArray(fullData?.payload?.headers) ? fullData.payload.headers : [];\n const headers = Object.fromEntries(\n headersArray.map((h: unknown) => {\n const header = h as gmail_v1.Schema$MessagePartHeader;\n return [String(header.name ?? ''), String(header.value ?? '')];\n })\n );\n\n const mapped: Partial<EmailDetail> = {\n id: String(fullData?.id ?? ''),\n threadId: fullData?.threadId ? String(fullData.threadId) : undefined,\n from: headers?.From,\n to: headers?.To,\n subject: headers?.Subject,\n date: headers?.Date,\n snippet: fullData?.snippet ? String(fullData.snippet) : undefined,\n };\n\n if (includeBody) {\n const payload = fullData?.payload;\n // Cast to Schema$MessagePart for extractBodyFromPayload\n const body = payload ? extractBodyFromPayload(payload as gmail_v1.Schema$MessagePart, { contentType, excludeThreadHistory }) : '';\n if (body) {\n mapped.body = body;\n mapped.bodyContentType = contentType;\n }\n }\n return mapped;\n }\n );\n\n const items = exec.items;\n const metadata = exec.metadata;\n const durationMs = Date.now() - started;\n\n // Type-safe field filtering\n const filteredItems = items.map((item) => filterFields(item, requestedFields));\n\n logger.info('gmail.message.search results', { query, pageSize, resultCount: filteredItems.length, fields: fields || 'all' });\n logger.info('gmail.message.search metrics', { durationMs, metadata });\n\n // Type-safe metadata access\n const metadataObj = metadata as { nextPageToken?: string } | undefined;\n\n // Build result based on shape\n const result: Output =\n shape === 'arrays'\n ? {\n type: 'success' as const,\n shape: 'arrays' as const,\n ...toColumnarFormat(filteredItems, requestedFields, EMAIL_FIELDS),\n ...(metadataObj?.nextPageToken && { nextPageToken: metadataObj.nextPageToken }),\n }\n : {\n type: 'success' as const,\n shape: 'objects' as const,\n items: filteredItems,\n ...(metadataObj?.nextPageToken && { nextPageToken: metadataObj.nextPageToken }),\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.message.search error', { error: message });\n\n throw new McpError(ErrorCode.InternalError, `Error searching messages: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'message-search',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["ErrorCode","McpError","EMAIL_COMMON_PATTERNS","EMAIL_FIELD_DESCRIPTIONS","EMAIL_FIELDS","EmailContentTypeSchema","EmailDetailSchema","ExcludeThreadHistorySchema","schemas","AuthRequiredBranchSchema","createFieldsSchema","createPaginationSchema","createShapeSchema","filterFields","parseFields","toColumnarFormat","google","z","DEFAULT_PAGE_SIZE","MAX_PAGE_SIZE","extractBodyFromPayload","executeQuery","executeGmailQuery","GmailQueryParameterSchema","parseGmailQueryParameter","inputSchema","object","query","optional","describe","fields","availableFields","fieldDescriptions","commonPatterns","resourceName","defaultPageSize","maxPageSize","provider","shape","contentType","excludeThreadHistory","successObjectsBranchSchema","type","literal","items","array","nextPageToken","string","successArraysBranchSchema","columns","rows","unknown","outputSchema","union","config","description","result","handler","pageSize","pageToken","extra","logger","parsedQuery","requestedFields","includeBody","has","info","undefined","accountId","authContext","gmail","version","auth","started","Date","now","exec","client","full","fullData","headersArray","Array","isArray","payload","headers","Object","fromEntries","map","h","header","String","name","value","mapped","id","threadId","from","From","to","To","subject","Subject","date","snippet","body","bodyContentType","metadata","durationMs","filteredItems","item","resultCount","length","metadataObj","content","text","JSON","stringify","structuredContent","error","message","Error","InternalError","stack","createTool"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-gmail/src/mcp/tools/message-search.ts"],"sourcesContent":["import { ProtocolError, ProtocolErrorCode } from '@mcp-z/server';\n/** Gmail message search using middleware-based auth pattern */\n\nimport { EMAIL_COMMON_PATTERNS, EMAIL_FIELD_DESCRIPTIONS, EMAIL_FIELDS, EmailContentTypeSchema, type EmailDetail, EmailDetailSchema, ExcludeThreadHistorySchema } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { createFieldsSchema, createPaginationSchema, createShapeSchema, filterFields, parseFields, type ToolModule, toColumnarFormat } from '@mcp-z/server';\nimport { type gmail_v1, google } from 'googleapis';\nimport { z } from 'zod';\nimport { DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE } from '../../constants.ts';\nimport { extractBodyFromPayload } from '../../email/parsing/html-processing.ts';\nimport { executeQuery as executeGmailQuery } from '../../email/querying/execute-query.ts';\nimport { googleAuth } from '../../lib/google-auth.ts';\nimport { GmailQueryParameterSchema, parseGmailQueryParameter } from '../../schemas/gmail-query-schema.ts';\n\nconst inputSchema = z.object({\n query: GmailQueryParameterSchema.optional().describe('Structured query object or JSON string for filtering messages. Use query-syntax prompt for reference and rawGmailQuery for Gmail syntax.'),\n fields: createFieldsSchema({\n availableFields: EMAIL_FIELDS,\n fieldDescriptions: EMAIL_FIELD_DESCRIPTIONS,\n commonPatterns: EMAIL_COMMON_PATTERNS,\n resourceName: 'email message',\n }),\n ...createPaginationSchema({ defaultPageSize: DEFAULT_PAGE_SIZE, maxPageSize: MAX_PAGE_SIZE, provider: 'gmail' }).shape,\n shape: createShapeSchema(),\n contentType: EmailContentTypeSchema,\n excludeThreadHistory: ExcludeThreadHistorySchema,\n});\n\n// Success branch schemas for different shapes\nconst successObjectsBranchSchema = z.object({\n type: z.literal('success'),\n shape: z.literal('objects'),\n items: z.array(EmailDetailSchema).describe('Matching email messages'),\n nextPageToken: z.string().optional().describe('Token for fetching next page of results'),\n});\n\nconst successArraysBranchSchema = z.object({\n type: z.literal('success'),\n shape: z.literal('arrays'),\n columns: z.array(z.string()).describe('Column names in canonical order'),\n rows: z.array(z.array(z.unknown())).describe('Row data matching column order'),\n nextPageToken: z.string().optional().describe('Token for fetching next page of results'),\n});\n\n// Output schema with auth_required support\n// Using z.union instead of discriminatedUnion since we have two success branches with different shapes\nconst outputSchema = z.union([successObjectsBranchSchema, successArraysBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Search Gmail messages using structured query objects with flexible field selection.',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\nasync function handler({ query, pageSize = DEFAULT_PAGE_SIZE, pageToken, fields, shape = 'arrays', contentType = 'text', excludeThreadHistory = false }: Input, extra: EnrichedExtra) {\n const logger = extra.logger;\n\n try {\n const parsedQuery = parseGmailQueryParameter(query);\n const requestedFields = parseFields(fields, EMAIL_FIELDS);\n const includeBody = requestedFields === 'all' || requestedFields.has('body');\n\n logger.info('gmail.message.search called', {\n query: parsedQuery,\n pageSize,\n pageToken: pageToken ? '[provided]' : undefined,\n fields,\n includeBody,\n accountId: extra.authContext.accountId, // Available from middleware\n });\n\n const gmail = google.gmail({ version: 'v1', auth: googleAuth(extra.authContext.auth) });\n\n const started = Date.now();\n\n const exec = await executeGmailQuery(\n parsedQuery,\n {\n client: gmail,\n logger,\n pageSize,\n ...(pageToken !== undefined && { pageToken }),\n includeBody,\n },\n (full: unknown) => {\n // Type-safe property access with guards\n const fullData = full as gmail_v1.Schema$Message;\n\n const headersArray = Array.isArray(fullData?.payload?.headers) ? fullData.payload.headers : [];\n const headers = Object.fromEntries(\n headersArray.map((h: unknown) => {\n const header = h as gmail_v1.Schema$MessagePartHeader;\n return [String(header.name ?? ''), String(header.value ?? '')];\n })\n );\n\n const mapped: Partial<EmailDetail> = {\n id: String(fullData?.id ?? ''),\n threadId: fullData?.threadId ? String(fullData.threadId) : undefined,\n from: headers?.From,\n to: headers?.To,\n subject: headers?.Subject,\n date: headers?.Date,\n snippet: fullData?.snippet ? String(fullData.snippet) : undefined,\n };\n\n if (includeBody) {\n const payload = fullData?.payload;\n // Cast to Schema$MessagePart for extractBodyFromPayload\n const body = payload ? extractBodyFromPayload(payload as gmail_v1.Schema$MessagePart, { contentType, excludeThreadHistory }) : '';\n if (body) {\n mapped.body = body;\n mapped.bodyContentType = contentType;\n }\n }\n return mapped;\n }\n );\n\n const items = exec.items;\n const metadata = exec.metadata;\n const durationMs = Date.now() - started;\n\n // Type-safe field filtering\n const filteredItems = items.map((item) => filterFields(item, requestedFields));\n\n logger.info('gmail.message.search results', { query, pageSize, resultCount: filteredItems.length, fields: fields || 'all' });\n logger.info('gmail.message.search metrics', { durationMs, metadata });\n\n // Type-safe metadata access\n const metadataObj = metadata as { nextPageToken?: string } | undefined;\n\n // Build result based on shape\n const result: Output =\n shape === 'arrays'\n ? {\n type: 'success' as const,\n shape: 'arrays' as const,\n ...toColumnarFormat(filteredItems, requestedFields, EMAIL_FIELDS),\n ...(metadataObj?.nextPageToken && { nextPageToken: metadataObj.nextPageToken }),\n }\n : {\n type: 'success' as const,\n shape: 'objects' as const,\n items: filteredItems,\n ...(metadataObj?.nextPageToken && { nextPageToken: metadataObj.nextPageToken }),\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.message.search error', { error: message });\n\n throw new ProtocolError(ProtocolErrorCode.InternalError, `Error searching messages: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'message-search',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["ProtocolError","ProtocolErrorCode","EMAIL_COMMON_PATTERNS","EMAIL_FIELD_DESCRIPTIONS","EMAIL_FIELDS","EmailContentTypeSchema","EmailDetailSchema","ExcludeThreadHistorySchema","schemas","AuthRequiredBranchSchema","createFieldsSchema","createPaginationSchema","createShapeSchema","filterFields","parseFields","toColumnarFormat","google","z","DEFAULT_PAGE_SIZE","MAX_PAGE_SIZE","extractBodyFromPayload","executeQuery","executeGmailQuery","googleAuth","GmailQueryParameterSchema","parseGmailQueryParameter","inputSchema","object","query","optional","describe","fields","availableFields","fieldDescriptions","commonPatterns","resourceName","defaultPageSize","maxPageSize","provider","shape","contentType","excludeThreadHistory","successObjectsBranchSchema","type","literal","items","array","nextPageToken","string","successArraysBranchSchema","columns","rows","unknown","outputSchema","union","config","description","result","handler","pageSize","pageToken","extra","logger","parsedQuery","requestedFields","includeBody","has","info","undefined","accountId","authContext","gmail","version","auth","started","Date","now","exec","client","full","fullData","headersArray","Array","isArray","payload","headers","Object","fromEntries","map","h","header","String","name","value","mapped","id","threadId","from","From","to","To","subject","Subject","date","snippet","body","bodyContentType","metadata","durationMs","filteredItems","item","resultCount","length","metadataObj","content","text","JSON","stringify","structuredContent","error","message","Error","InternalError","stack","createTool"],"mappings":"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"}
@@ -1,11 +1,12 @@
1
1
  import { ComposeContentTypeSchema, createEmailRecipientsSchema, createMessageResultSchema } from '@mcp-z/email';
2
2
  import { schemas } from '@mcp-z/oauth-google';
3
3
  const { AuthRequiredBranchSchema } = schemas;
4
- import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
4
+ import { ProtocolError, ProtocolErrorCode } from '@mcp-z/server';
5
5
  import { google } from 'googleapis';
6
6
  import { z } from 'zod';
7
7
  import { buildRfc822FromArgs } from '../../email/composition/rfc822-builder.js';
8
8
  import { b64url } from '../../lib/base64-encoding.js';
9
+ import { googleAuth } from '../../lib/google-auth.js';
9
10
  const inputSchema = z.object({
10
11
  to: createEmailRecipientsSchema('to', true),
11
12
  cc: createEmailRecipientsSchema('cc', false),
@@ -40,7 +41,7 @@ async function handler(params, extra) {
40
41
  contentType
41
42
  });
42
43
  if (!to) {
43
- throw new McpError(ErrorCode.InvalidParams, 'Missing required field: to');
44
+ throw new ProtocolError(ProtocolErrorCode.InvalidParams, 'Missing required field: to');
44
45
  }
45
46
  try {
46
47
  // Build RFC822 message - only include optional headers when defined to satisfy
@@ -57,7 +58,7 @@ async function handler(params, extra) {
57
58
  const encodedMessage = b64url(raw);
58
59
  const gmail = google.gmail({
59
60
  version: 'v1',
60
- auth: extra.authContext.auth
61
+ auth: googleAuth(extra.authContext.auth)
61
62
  });
62
63
  const sendRes = await gmail.users.messages.send({
63
64
  userId: 'me',
@@ -101,7 +102,7 @@ async function handler(params, extra) {
101
102
  logger.error('gmail.message.send error', {
102
103
  error: message
103
104
  });
104
- throw new McpError(ErrorCode.InternalError, `Error sending message: ${message}`, {
105
+ throw new ProtocolError(ProtocolErrorCode.InternalError, `Error sending message: ${message}`, {
105
106
  stack: error instanceof Error ? error.stack : undefined
106
107
  });
107
108
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-gmail/src/mcp/tools/message-send.ts"],"sourcesContent":["import { ComposeContentTypeSchema, createEmailRecipientsSchema, createMessageResultSchema } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport type { ToolModule } from '@mcp-z/server';\nimport { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\nimport { google } from 'googleapis';\nimport { z } from 'zod';\nimport { buildRfc822FromArgs } from '../../email/composition/rfc822-builder.ts';\nimport { b64url } from '../../lib/base64-encoding.ts';\n\nconst inputSchema = z.object({\n to: createEmailRecipientsSchema('to', true),\n cc: createEmailRecipientsSchema('cc', false),\n bcc: createEmailRecipientsSchema('bcc', false),\n subject: z.string().describe('Message subject').default(''),\n body: z.string().trim().min(1).describe('Email body content (plain text or HTML)'),\n contentType: ComposeContentTypeSchema,\n});\n\n// Success branch schema\nconst successBranchSchema = z.object({\n type: z.literal('success'),\n item: createMessageResultSchema('gmail'),\n});\n\n// Output schema with auth_required support\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Send an email message through Gmail',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\nasync function handler(params: Input, extra: EnrichedExtra) {\n const { to, cc, bcc, subject, body, contentType } = params;\n const logger = extra.logger;\n logger.info('gmail.message.send called', { to, subject, contentType });\n\n if (!to) {\n throw new McpError(ErrorCode.InvalidParams, 'Missing required field: to');\n }\n\n try {\n // Build RFC822 message - only include optional headers when defined to satisfy\n // exactOptionalPropertyTypes (avoid passing `undefined` into optional props)\n const msgArgs: { to: string; cc?: string; bcc?: string; subject?: string; body: string; contentType: 'text' | 'html' } = { to, body, contentType };\n if (cc !== undefined) msgArgs.cc = cc;\n if (bcc !== undefined) msgArgs.bcc = bcc;\n if (subject !== undefined) msgArgs.subject = subject;\n\n const raw = buildRfc822FromArgs(msgArgs);\n const encodedMessage = b64url(raw);\n\n const gmail = google.gmail({ version: 'v1', auth: extra.authContext.auth });\n\n const sendRes = await gmail.users.messages.send({\n userId: 'me',\n requestBody: { raw: encodedMessage },\n });\n const sendData = sendRes.data;\n const messageId = sendData.id || 'unknown';\n logger.info('Gmail: sent message successfully', { id: messageId });\n logger.info('gmail.message.send result (typed)', { to, subject, messageId });\n\n const totalRecipients = (Array.isArray(to) ? to.length : 1) + (cc ? (Array.isArray(cc) ? cc.length : 1) : 0) + (bcc ? (Array.isArray(bcc) ? bcc.length : 1) : 0);\n const result: Output = {\n type: 'success' as const,\n item: {\n id: messageId,\n sentAt: new Date().toISOString(),\n recipientCount: totalRecipients,\n webLink: `https://mail.google.com/mail/u/0/#sent/${messageId}`,\n },\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.message.send error', { error: message });\n\n throw new McpError(ErrorCode.InternalError, `Error sending message: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'message-send',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["ComposeContentTypeSchema","createEmailRecipientsSchema","createMessageResultSchema","schemas","AuthRequiredBranchSchema","ErrorCode","McpError","google","z","buildRfc822FromArgs","b64url","inputSchema","object","to","cc","bcc","subject","string","describe","default","body","trim","min","contentType","successBranchSchema","type","literal","item","outputSchema","discriminatedUnion","config","description","result","handler","params","extra","logger","info","InvalidParams","msgArgs","undefined","raw","encodedMessage","gmail","version","auth","authContext","sendRes","users","messages","send","userId","requestBody","sendData","data","messageId","id","totalRecipients","Array","isArray","length","sentAt","Date","toISOString","recipientCount","webLink","content","text","JSON","stringify","structuredContent","error","message","Error","String","InternalError","stack","createTool","name"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-gmail/src/mcp/tools/message-send.ts"],"sourcesContent":["import { ComposeContentTypeSchema, createEmailRecipientsSchema, createMessageResultSchema } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport type { ToolModule } from '@mcp-z/server';\nimport { ProtocolError, ProtocolErrorCode } from '@mcp-z/server';\nimport { google } from 'googleapis';\nimport { z } from 'zod';\nimport { buildRfc822FromArgs } from '../../email/composition/rfc822-builder.ts';\nimport { b64url } from '../../lib/base64-encoding.ts';\nimport { googleAuth } from '../../lib/google-auth.ts';\n\nconst inputSchema = z.object({\n to: createEmailRecipientsSchema('to', true),\n cc: createEmailRecipientsSchema('cc', false),\n bcc: createEmailRecipientsSchema('bcc', false),\n subject: z.string().describe('Message subject').default(''),\n body: z.string().trim().min(1).describe('Email body content (plain text or HTML)'),\n contentType: ComposeContentTypeSchema,\n});\n\n// Success branch schema\nconst successBranchSchema = z.object({\n type: z.literal('success'),\n item: createMessageResultSchema('gmail'),\n});\n\n// Output schema with auth_required support\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Send an email message through Gmail',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\nasync function handler(params: Input, extra: EnrichedExtra) {\n const { to, cc, bcc, subject, body, contentType } = params;\n const logger = extra.logger;\n logger.info('gmail.message.send called', { to, subject, contentType });\n\n if (!to) {\n throw new ProtocolError(ProtocolErrorCode.InvalidParams, 'Missing required field: to');\n }\n\n try {\n // Build RFC822 message - only include optional headers when defined to satisfy\n // exactOptionalPropertyTypes (avoid passing `undefined` into optional props)\n const msgArgs: { to: string; cc?: string; bcc?: string; subject?: string; body: string; contentType: 'text' | 'html' } = { to, body, contentType };\n if (cc !== undefined) msgArgs.cc = cc;\n if (bcc !== undefined) msgArgs.bcc = bcc;\n if (subject !== undefined) msgArgs.subject = subject;\n\n const raw = buildRfc822FromArgs(msgArgs);\n const encodedMessage = b64url(raw);\n\n const gmail = google.gmail({ version: 'v1', auth: googleAuth(extra.authContext.auth) });\n\n const sendRes = await gmail.users.messages.send({\n userId: 'me',\n requestBody: { raw: encodedMessage },\n });\n const sendData = sendRes.data;\n const messageId = sendData.id || 'unknown';\n logger.info('Gmail: sent message successfully', { id: messageId });\n logger.info('gmail.message.send result (typed)', { to, subject, messageId });\n\n const totalRecipients = (Array.isArray(to) ? to.length : 1) + (cc ? (Array.isArray(cc) ? cc.length : 1) : 0) + (bcc ? (Array.isArray(bcc) ? bcc.length : 1) : 0);\n const result: Output = {\n type: 'success' as const,\n item: {\n id: messageId,\n sentAt: new Date().toISOString(),\n recipientCount: totalRecipients,\n webLink: `https://mail.google.com/mail/u/0/#sent/${messageId}`,\n },\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.message.send error', { error: message });\n\n throw new ProtocolError(ProtocolErrorCode.InternalError, `Error sending message: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'message-send',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["ComposeContentTypeSchema","createEmailRecipientsSchema","createMessageResultSchema","schemas","AuthRequiredBranchSchema","ProtocolError","ProtocolErrorCode","google","z","buildRfc822FromArgs","b64url","googleAuth","inputSchema","object","to","cc","bcc","subject","string","describe","default","body","trim","min","contentType","successBranchSchema","type","literal","item","outputSchema","discriminatedUnion","config","description","result","handler","params","extra","logger","info","InvalidParams","msgArgs","undefined","raw","encodedMessage","gmail","version","auth","authContext","sendRes","users","messages","send","userId","requestBody","sendData","data","messageId","id","totalRecipients","Array","isArray","length","sentAt","Date","toISOString","recipientCount","webLink","content","text","JSON","stringify","structuredContent","error","message","Error","String","InternalError","stack","createTool","name"],"mappings":"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"}
@@ -1,8 +1,7 @@
1
1
  import { EmailContentTypeSchema, ExcludeThreadHistorySchema } from '@mcp-z/email';
2
2
  import { schemas } from '@mcp-z/oauth-google';
3
3
  const { AuthRequiredBranchSchema } = schemas;
4
- import { getFileUri, reserveFile } from '@mcp-z/server';
5
- import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
4
+ import { getFileUri, ProtocolError, ProtocolErrorCode, reserveFile } from '@mcp-z/server';
6
5
  import { stringify } from 'csv-stringify/sync';
7
6
  import { createWriteStream } from 'fs';
8
7
  import { unlink } from 'fs/promises';
@@ -11,6 +10,7 @@ import { z } from 'zod';
11
10
  import { DEFAULT_PAGE_SIZE } from '../../constants.js';
12
11
  import { extractBodyFromPayload } from '../../email/parsing/html-processing.js';
13
12
  import { executeQuery as executeGmailQuery } from '../../email/querying/execute-query.js';
13
+ import { googleAuth } from '../../lib/google-auth.js';
14
14
  import { GmailQueryParameterSchema, parseGmailQueryParameter } from '../../schemas/gmail-query-schema.js';
15
15
  const DEFAULT_MAX_ITEMS = 10000;
16
16
  const MAX_EXPORT_ITEMS = 50000;
@@ -71,7 +71,7 @@ const config = {
71
71
  });
72
72
  const gmail = google.gmail({
73
73
  version: 'v1',
74
- auth: extra.authContext.auth
74
+ auth: googleAuth(extra.authContext.auth)
75
75
  });
76
76
  // Create CSV headers (all email fields)
77
77
  const csvHeaders = [
@@ -248,7 +248,7 @@ const config = {
248
248
  logger.error('gmail.messages.export-csv error', {
249
249
  error: message
250
250
  });
251
- throw new McpError(ErrorCode.InternalError, `Error exporting messages to CSV: ${message}`, {
251
+ throw new ProtocolError(ProtocolErrorCode.InternalError, `Error exporting messages to CSV: ${message}`, {
252
252
  stack: error instanceof Error ? error.stack : undefined
253
253
  });
254
254
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-gmail/src/mcp/tools/messages-export-csv.ts"],"sourcesContent":["import { EmailContentTypeSchema, ExcludeThreadHistorySchema } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { getFileUri, reserveFile, type ToolModule } from '@mcp-z/server';\nimport { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\n\nimport { stringify } from 'csv-stringify/sync';\nimport { createWriteStream } from 'fs';\nimport { unlink } from 'fs/promises';\nimport { type gmail_v1, google } from 'googleapis';\nimport { z } from 'zod';\nimport { DEFAULT_PAGE_SIZE } from '../../constants.ts';\nimport { extractBodyFromPayload } from '../../email/parsing/html-processing.ts';\nimport { executeQuery as executeGmailQuery } from '../../email/querying/execute-query.ts';\nimport { GmailQueryParameterSchema, parseGmailQueryParameter } from '../../schemas/gmail-query-schema.ts';\nimport type { StorageExtra } from '../../types.ts';\n\nconst DEFAULT_MAX_ITEMS = 10000;\nconst MAX_EXPORT_ITEMS = 50000;\n\n/**\n * CSV row format based on EmailDetail\n * All fields are strings (empty string instead of undefined)\n * Includes additional CSV-specific fields: provider and labels\n */\ninterface CsvRow {\n id: string;\n threadId: string;\n from: string;\n to: string;\n cc: string;\n bcc: string;\n subject: string;\n date: string;\n snippet: string;\n body: string;\n provider: string;\n labels: string;\n}\n\nconst inputSchema = z.object({\n query: GmailQueryParameterSchema.optional().describe('Structured query object or JSON string for filtering messages. Use query-syntax prompt for reference and rawGmailQuery for Gmail syntax.'),\n maxItems: z.number().int().positive().max(MAX_EXPORT_ITEMS).default(DEFAULT_MAX_ITEMS).describe(`Maximum messages to export (default: ${DEFAULT_MAX_ITEMS}, max: ${MAX_EXPORT_ITEMS})`),\n filename: z.string().trim().min(1).default('gmail-messages.csv').describe('Output filename (default: gmail-messages.csv)'),\n contentType: EmailContentTypeSchema,\n excludeThreadHistory: ExcludeThreadHistorySchema,\n});\n\nconst successBranchSchema = z.object({\n type: z.literal('success'),\n uri: z.string().describe('File URI (file:// or http://)'),\n filename: z.string().describe('Stored filename'),\n rowCount: z.number().describe('Number of messages exported'),\n truncated: z.boolean().describe('Whether export was truncated at maxItems'),\n});\n\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Export Gmail messages to CSV with streaming pagination. Returns file URI. Use query-syntax prompt for query reference.',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\n/**\n * Handler for gmail-messages-export-csv tool\n *\n * CRITICAL: Streaming implementation per user requirements\n * - Generate UUID upfront\n * - Write CSV header immediately\n * - Append rows as batches arrive\n * - Delete partial file on error\n * - NO RETRIES (fail fast on error)\n */\nasync function handler({ query, maxItems, filename, contentType, excludeThreadHistory }: Input, extra: EnrichedExtra & StorageExtra) {\n const logger = extra.logger;\n const { storageContext } = extra;\n const { transport, resourceStoreUri, baseUrl } = storageContext;\n\n // Reserve file location for streaming write (creates directory, generates ID, formats filename)\n const reservation = await reserveFile(filename, {\n resourceStoreUri,\n });\n const { storedName, fullPath } = reservation;\n\n logger.info('gmail.messages.export-csv starting streaming export', { path: fullPath, maxItems });\n\n try {\n const parsedQuery = parseGmailQueryParameter(query);\n\n logger.info('gmail.messages.export-csv called', {\n query: parsedQuery,\n maxItems,\n filename,\n accountId: extra.authContext.accountId,\n });\n\n const gmail = google.gmail({ version: 'v1', auth: extra.authContext.auth });\n\n // Create CSV headers (all email fields)\n const csvHeaders = ['id', 'threadId', 'from', 'to', 'cc', 'bcc', 'subject', 'date', 'snippet', 'body', 'provider', 'labels'];\n\n // Create write stream and write headers immediately\n const writeStream = createWriteStream(fullPath, { encoding: 'utf-8' });\n const headerLine = stringify([csvHeaders], { header: false, quoted: true, quote: '\"', escape: '\"' });\n writeStream.write(headerLine);\n\n // Internal pagination loop - append to CSV with each batch\n // NO RETRIES: If any error occurs, fail the whole operation and clean up\n let totalRows = 0;\n let nextPageToken: string | undefined;\n const started = Date.now();\n\n while (totalRows < maxItems) {\n const remainingItems = maxItems - totalRows;\n const pageSize = Math.min(remainingItems, DEFAULT_PAGE_SIZE);\n\n const exec: {\n items: CsvRow[];\n metadata?: { nextPageToken?: string };\n } = await executeGmailQuery(\n parsedQuery,\n {\n client: gmail,\n logger,\n pageSize,\n ...(nextPageToken !== undefined && { pageToken: nextPageToken }),\n includeBody: true, // Always include body for CSV export\n },\n (full: unknown): CsvRow => {\n // Type-safe property access with guards\n const fullData = full as {\n id?: unknown;\n threadId?: unknown;\n snippet?: unknown;\n labelIds?: unknown[];\n payload?: { headers?: unknown[] };\n };\n\n const headersArray = Array.isArray(fullData?.payload?.headers) ? fullData.payload.headers : [];\n const headers = Object.fromEntries(\n headersArray.map((h: unknown) => {\n const header = h as { name?: unknown; value?: unknown };\n return [String(header.name ?? ''), String(header.value ?? '')];\n })\n );\n\n const payload = fullData?.payload;\n // Cast to Schema$MessagePart for extractBodyFromPayload\n const body = payload ? extractBodyFromPayload(payload as gmail_v1.Schema$MessagePart, { contentType, excludeThreadHistory }) : '';\n\n const labelIds = Array.isArray(fullData?.labelIds) ? fullData.labelIds.map((id) => String(id ?? '')) : [];\n\n return {\n id: String(fullData?.id ?? ''),\n threadId: fullData?.threadId ? String(fullData.threadId) : '',\n from: headers?.From || '',\n to: headers?.To || '',\n cc: headers?.Cc || '',\n bcc: headers?.Bcc || '',\n subject: headers?.Subject || '',\n date: headers?.Date || '',\n snippet: fullData?.snippet ? String(fullData.snippet) : '',\n body,\n provider: 'gmail',\n labels: labelIds.join(';'),\n };\n }\n );\n\n // Type-safe CSV row mapping\n const csvRows = exec.items.map((row) => {\n return [row.id, row.threadId, row.from, row.to, row.cc, row.bcc, row.subject, row.date, row.snippet, row.body, row.provider, row.labels];\n });\n\n // Append rows to CSV file immediately\n if (csvRows.length > 0) {\n const rowsContent = stringify(csvRows, { header: false, quoted: true, quote: '\"', escape: '\"' });\n writeStream.write(rowsContent);\n }\n\n totalRows += exec.items.length;\n nextPageToken = exec.metadata?.nextPageToken;\n\n logger.info('gmail.messages.export-csv batch written', {\n batchSize: exec.items.length,\n totalRows,\n hasMore: Boolean(nextPageToken),\n });\n\n // Exit if no more results or reached maxItems\n if (!nextPageToken || exec.items.length === 0) {\n break;\n }\n }\n\n // Close write stream\n await new Promise<void>((resolve, reject) => {\n writeStream.end(() => resolve());\n writeStream.on('error', reject);\n });\n\n const durationMs = Date.now() - started;\n const truncated = totalRows >= maxItems && Boolean(nextPageToken);\n\n logger.info('gmail.messages.export-csv completed', {\n rowCount: totalRows,\n truncated,\n durationMs,\n filename: storedName,\n });\n\n // Generate URI based on transport type (stdio: file://, HTTP: http://)\n const uri = getFileUri(storedName, transport, {\n resourceStoreUri,\n ...(baseUrl && { baseUrl }),\n endpoint: '/files',\n });\n\n const result: Output = {\n type: 'success' as const,\n uri,\n filename: storedName,\n rowCount: totalRows,\n truncated,\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n // CRITICAL: Clean up partial CSV file on error\n try {\n await unlink(fullPath);\n logger.debug('Cleaned up partial CSV file after error', { path: fullPath });\n } catch (_cleanupError) {\n logger.debug('Could not clean up CSV file (may not exist)', { path: fullPath });\n }\n\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.messages.export-csv error', { error: message });\n\n throw new McpError(ErrorCode.InternalError, `Error exporting messages to CSV: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'messages-export-csv',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["EmailContentTypeSchema","ExcludeThreadHistorySchema","schemas","AuthRequiredBranchSchema","getFileUri","reserveFile","ErrorCode","McpError","stringify","createWriteStream","unlink","google","z","DEFAULT_PAGE_SIZE","extractBodyFromPayload","executeQuery","executeGmailQuery","GmailQueryParameterSchema","parseGmailQueryParameter","DEFAULT_MAX_ITEMS","MAX_EXPORT_ITEMS","inputSchema","object","query","optional","describe","maxItems","number","int","positive","max","default","filename","string","trim","min","contentType","excludeThreadHistory","successBranchSchema","type","literal","uri","rowCount","truncated","boolean","outputSchema","discriminatedUnion","config","description","result","handler","extra","logger","storageContext","transport","resourceStoreUri","baseUrl","reservation","storedName","fullPath","info","path","parsedQuery","accountId","authContext","gmail","version","auth","csvHeaders","writeStream","encoding","headerLine","header","quoted","quote","escape","write","totalRows","nextPageToken","started","Date","now","exec","remainingItems","pageSize","Math","client","undefined","pageToken","includeBody","full","fullData","headersArray","Array","isArray","payload","headers","Object","fromEntries","map","h","String","name","value","body","labelIds","id","threadId","from","From","to","To","cc","Cc","bcc","Bcc","subject","Subject","date","snippet","provider","labels","join","csvRows","items","row","length","rowsContent","metadata","batchSize","hasMore","Boolean","Promise","resolve","reject","end","on","durationMs","endpoint","content","text","JSON","structuredContent","error","debug","_cleanupError","message","Error","InternalError","stack","createTool"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-gmail/src/mcp/tools/messages-export-csv.ts"],"sourcesContent":["import { EmailContentTypeSchema, ExcludeThreadHistorySchema } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { getFileUri, ProtocolError, ProtocolErrorCode, reserveFile, type ToolModule } from '@mcp-z/server';\n\nimport { stringify } from 'csv-stringify/sync';\nimport { createWriteStream } from 'fs';\nimport { unlink } from 'fs/promises';\nimport { type gmail_v1, google } from 'googleapis';\nimport { z } from 'zod';\nimport { DEFAULT_PAGE_SIZE } from '../../constants.ts';\nimport { extractBodyFromPayload } from '../../email/parsing/html-processing.ts';\nimport { executeQuery as executeGmailQuery } from '../../email/querying/execute-query.ts';\nimport { googleAuth } from '../../lib/google-auth.ts';\nimport { GmailQueryParameterSchema, parseGmailQueryParameter } from '../../schemas/gmail-query-schema.ts';\nimport type { StorageExtra } from '../../types.ts';\n\nconst DEFAULT_MAX_ITEMS = 10000;\nconst MAX_EXPORT_ITEMS = 50000;\n\n/**\n * CSV row format based on EmailDetail\n * All fields are strings (empty string instead of undefined)\n * Includes additional CSV-specific fields: provider and labels\n */\ninterface CsvRow {\n id: string;\n threadId: string;\n from: string;\n to: string;\n cc: string;\n bcc: string;\n subject: string;\n date: string;\n snippet: string;\n body: string;\n provider: string;\n labels: string;\n}\n\nconst inputSchema = z.object({\n query: GmailQueryParameterSchema.optional().describe('Structured query object or JSON string for filtering messages. Use query-syntax prompt for reference and rawGmailQuery for Gmail syntax.'),\n maxItems: z.number().int().positive().max(MAX_EXPORT_ITEMS).default(DEFAULT_MAX_ITEMS).describe(`Maximum messages to export (default: ${DEFAULT_MAX_ITEMS}, max: ${MAX_EXPORT_ITEMS})`),\n filename: z.string().trim().min(1).default('gmail-messages.csv').describe('Output filename (default: gmail-messages.csv)'),\n contentType: EmailContentTypeSchema,\n excludeThreadHistory: ExcludeThreadHistorySchema,\n});\n\nconst successBranchSchema = z.object({\n type: z.literal('success'),\n uri: z.string().describe('File URI (file:// or http://)'),\n filename: z.string().describe('Stored filename'),\n rowCount: z.number().describe('Number of messages exported'),\n truncated: z.boolean().describe('Whether export was truncated at maxItems'),\n});\n\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Export Gmail messages to CSV with streaming pagination. Returns file URI. Use query-syntax prompt for query reference.',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\n/**\n * Handler for gmail-messages-export-csv tool\n *\n * CRITICAL: Streaming implementation per user requirements\n * - Generate UUID upfront\n * - Write CSV header immediately\n * - Append rows as batches arrive\n * - Delete partial file on error\n * - NO RETRIES (fail fast on error)\n */\nasync function handler({ query, maxItems, filename, contentType, excludeThreadHistory }: Input, extra: EnrichedExtra & StorageExtra) {\n const logger = extra.logger;\n const { storageContext } = extra;\n const { transport, resourceStoreUri, baseUrl } = storageContext;\n\n // Reserve file location for streaming write (creates directory, generates ID, formats filename)\n const reservation = await reserveFile(filename, {\n resourceStoreUri,\n });\n const { storedName, fullPath } = reservation;\n\n logger.info('gmail.messages.export-csv starting streaming export', { path: fullPath, maxItems });\n\n try {\n const parsedQuery = parseGmailQueryParameter(query);\n\n logger.info('gmail.messages.export-csv called', {\n query: parsedQuery,\n maxItems,\n filename,\n accountId: extra.authContext.accountId,\n });\n\n const gmail = google.gmail({ version: 'v1', auth: googleAuth(extra.authContext.auth) });\n\n // Create CSV headers (all email fields)\n const csvHeaders = ['id', 'threadId', 'from', 'to', 'cc', 'bcc', 'subject', 'date', 'snippet', 'body', 'provider', 'labels'];\n\n // Create write stream and write headers immediately\n const writeStream = createWriteStream(fullPath, { encoding: 'utf-8' });\n const headerLine = stringify([csvHeaders], { header: false, quoted: true, quote: '\"', escape: '\"' });\n writeStream.write(headerLine);\n\n // Internal pagination loop - append to CSV with each batch\n // NO RETRIES: If any error occurs, fail the whole operation and clean up\n let totalRows = 0;\n let nextPageToken: string | undefined;\n const started = Date.now();\n\n while (totalRows < maxItems) {\n const remainingItems = maxItems - totalRows;\n const pageSize = Math.min(remainingItems, DEFAULT_PAGE_SIZE);\n\n const exec: {\n items: CsvRow[];\n metadata?: { nextPageToken?: string };\n } = await executeGmailQuery(\n parsedQuery,\n {\n client: gmail,\n logger,\n pageSize,\n ...(nextPageToken !== undefined && { pageToken: nextPageToken }),\n includeBody: true, // Always include body for CSV export\n },\n (full: unknown): CsvRow => {\n // Type-safe property access with guards\n const fullData = full as {\n id?: unknown;\n threadId?: unknown;\n snippet?: unknown;\n labelIds?: unknown[];\n payload?: { headers?: unknown[] };\n };\n\n const headersArray = Array.isArray(fullData?.payload?.headers) ? fullData.payload.headers : [];\n const headers = Object.fromEntries(\n headersArray.map((h: unknown) => {\n const header = h as { name?: unknown; value?: unknown };\n return [String(header.name ?? ''), String(header.value ?? '')];\n })\n );\n\n const payload = fullData?.payload;\n // Cast to Schema$MessagePart for extractBodyFromPayload\n const body = payload ? extractBodyFromPayload(payload as gmail_v1.Schema$MessagePart, { contentType, excludeThreadHistory }) : '';\n\n const labelIds = Array.isArray(fullData?.labelIds) ? fullData.labelIds.map((id) => String(id ?? '')) : [];\n\n return {\n id: String(fullData?.id ?? ''),\n threadId: fullData?.threadId ? String(fullData.threadId) : '',\n from: headers?.From || '',\n to: headers?.To || '',\n cc: headers?.Cc || '',\n bcc: headers?.Bcc || '',\n subject: headers?.Subject || '',\n date: headers?.Date || '',\n snippet: fullData?.snippet ? String(fullData.snippet) : '',\n body,\n provider: 'gmail',\n labels: labelIds.join(';'),\n };\n }\n );\n\n // Type-safe CSV row mapping\n const csvRows = exec.items.map((row) => {\n return [row.id, row.threadId, row.from, row.to, row.cc, row.bcc, row.subject, row.date, row.snippet, row.body, row.provider, row.labels];\n });\n\n // Append rows to CSV file immediately\n if (csvRows.length > 0) {\n const rowsContent = stringify(csvRows, { header: false, quoted: true, quote: '\"', escape: '\"' });\n writeStream.write(rowsContent);\n }\n\n totalRows += exec.items.length;\n nextPageToken = exec.metadata?.nextPageToken;\n\n logger.info('gmail.messages.export-csv batch written', {\n batchSize: exec.items.length,\n totalRows,\n hasMore: Boolean(nextPageToken),\n });\n\n // Exit if no more results or reached maxItems\n if (!nextPageToken || exec.items.length === 0) {\n break;\n }\n }\n\n // Close write stream\n await new Promise<void>((resolve, reject) => {\n writeStream.end(() => resolve());\n writeStream.on('error', reject);\n });\n\n const durationMs = Date.now() - started;\n const truncated = totalRows >= maxItems && Boolean(nextPageToken);\n\n logger.info('gmail.messages.export-csv completed', {\n rowCount: totalRows,\n truncated,\n durationMs,\n filename: storedName,\n });\n\n // Generate URI based on transport type (stdio: file://, HTTP: http://)\n const uri = getFileUri(storedName, transport, {\n resourceStoreUri,\n ...(baseUrl && { baseUrl }),\n endpoint: '/files',\n });\n\n const result: Output = {\n type: 'success' as const,\n uri,\n filename: storedName,\n rowCount: totalRows,\n truncated,\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n // CRITICAL: Clean up partial CSV file on error\n try {\n await unlink(fullPath);\n logger.debug('Cleaned up partial CSV file after error', { path: fullPath });\n } catch (_cleanupError) {\n logger.debug('Could not clean up CSV file (may not exist)', { path: fullPath });\n }\n\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.messages.export-csv error', { error: message });\n\n throw new ProtocolError(ProtocolErrorCode.InternalError, `Error exporting messages to CSV: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'messages-export-csv',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["EmailContentTypeSchema","ExcludeThreadHistorySchema","schemas","AuthRequiredBranchSchema","getFileUri","ProtocolError","ProtocolErrorCode","reserveFile","stringify","createWriteStream","unlink","google","z","DEFAULT_PAGE_SIZE","extractBodyFromPayload","executeQuery","executeGmailQuery","googleAuth","GmailQueryParameterSchema","parseGmailQueryParameter","DEFAULT_MAX_ITEMS","MAX_EXPORT_ITEMS","inputSchema","object","query","optional","describe","maxItems","number","int","positive","max","default","filename","string","trim","min","contentType","excludeThreadHistory","successBranchSchema","type","literal","uri","rowCount","truncated","boolean","outputSchema","discriminatedUnion","config","description","result","handler","extra","logger","storageContext","transport","resourceStoreUri","baseUrl","reservation","storedName","fullPath","info","path","parsedQuery","accountId","authContext","gmail","version","auth","csvHeaders","writeStream","encoding","headerLine","header","quoted","quote","escape","write","totalRows","nextPageToken","started","Date","now","exec","remainingItems","pageSize","Math","client","undefined","pageToken","includeBody","full","fullData","headersArray","Array","isArray","payload","headers","Object","fromEntries","map","h","String","name","value","body","labelIds","id","threadId","from","From","to","To","cc","Cc","bcc","Bcc","subject","Subject","date","snippet","provider","labels","join","csvRows","items","row","length","rowsContent","metadata","batchSize","hasMore","Boolean","Promise","resolve","reject","end","on","durationMs","endpoint","content","text","JSON","structuredContent","error","debug","_cleanupError","message","Error","InternalError","stack","createTool"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
1
+ import { McpServer } from '@mcp-z/server';
2
2
  import type { RuntimeOverrides, ServerConfig } from '../types.js';
3
3
  export declare function createHTTPServer(config: ServerConfig, overrides?: RuntimeOverrides): Promise<{
4
4
  httpServer: import("node:http").Server<typeof import("node:http").IncomingMessage, typeof import("node:http").ServerResponse>;
@@ -1,5 +1,4 @@
1
- import { composeMiddleware, connectHttp, createFileServingRouter, registerPrompts, registerResources, registerTools } from '@mcp-z/server';
2
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
1
+ import { composeMiddleware, connectHttp, createFileServingRouter, McpServer, registerPrompts, registerResources, registerTools } from '@mcp-z/server';
3
2
  import cors from 'cors';
4
3
  import express from 'express';
5
4
  import { createDefaultRuntime } from './runtime.js';
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-gmail/src/setup/http.ts"],"sourcesContent":["import { composeMiddleware, connectHttp, createFileServingRouter, registerPrompts, registerResources, registerTools } from '@mcp-z/server';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport cors from 'cors';\nimport express from 'express';\nimport type { RuntimeOverrides, ServerConfig } from '../types.ts';\nimport { createDefaultRuntime } from './runtime.ts';\n\nexport async function createHTTPServer(config: ServerConfig, overrides?: RuntimeOverrides) {\n const runtime = await createDefaultRuntime(config, overrides);\n const modules = runtime.createDomainModules();\n const layers = runtime.middlewareFactories.map((factory) => factory(runtime.deps));\n const composed = composeMiddleware(modules, layers);\n const logger = runtime.deps.logger;\n const port = config.transport.port;\n if (!port) throw new Error('Port is required for HTTP transport');\n\n const tools = [...composed.tools, ...runtime.deps.oauthAdapters.accountTools];\n const filteredTools =\n config.auth === 'dcr'\n ? tools.filter((tool) => tool.name !== 'messages-export-csv') // No file storage in DCR (public cloud responsibility)\n : tools;\n const prompts = [...composed.prompts, ...runtime.deps.oauthAdapters.accountPrompts];\n\n const mcpServer = new McpServer({ name: config.name, version: config.version });\n registerTools(mcpServer, filteredTools);\n registerResources(mcpServer, composed.resources);\n registerPrompts(mcpServer, prompts);\n\n const app = express();\n app.use(express.json({ limit: '10mb' }));\n\n // Must mount '/mcp' before any permissive app-level cors(), or that layer answers its\n // preflight first; pass baseUrl's origin/host below or a public deployment 403s itself.\n const publicUrl = config.baseUrl ? new URL(config.baseUrl) : undefined;\n logger.info(`Starting ${config.name} MCP server (http)`);\n const { close, httpServer } = await connectHttp(mcpServer, {\n logger,\n app,\n port,\n allowedOrigins: publicUrl ? [publicUrl.origin] : undefined,\n allowedHosts: publicUrl ? [publicUrl.host] : undefined,\n });\n\n // The loopback OAuth callback, the file-export download, and the DCR discovery/\n // registration endpoints are all meant to be reached from a browser on another\n // origin. Keep cors() for them, scoped to their own routes - never in front of '/mcp'.\n if (runtime.deps.oauthAdapters.loopbackRouter) {\n app.use('/', cors(), runtime.deps.oauthAdapters.loopbackRouter);\n logger.info('Mounted loopback OAuth callback router');\n }\n\n if (config.auth !== 'dcr') {\n const fileRouter = createFileServingRouter({ resourceStoreUri: config.resourceStoreUri }, { contentType: 'text/csv', contentDisposition: 'attachment' });\n app.use('/files', cors(), fileRouter);\n }\n\n if (runtime.deps.oauthAdapters.dcrRouter) {\n app.use('/', cors(), runtime.deps.oauthAdapters.dcrRouter);\n logger.info('Mounted DCR router with OAuth endpoints');\n }\n\n logger.info('http transport ready');\n\n return {\n httpServer,\n mcpServer,\n logger,\n close: async () => {\n await close();\n await runtime.close();\n },\n };\n}\n"],"names":["composeMiddleware","connectHttp","createFileServingRouter","registerPrompts","registerResources","registerTools","McpServer","cors","express","createDefaultRuntime","createHTTPServer","config","overrides","runtime","modules","createDomainModules","layers","middlewareFactories","map","factory","deps","composed","logger","port","transport","Error","tools","oauthAdapters","accountTools","filteredTools","auth","filter","tool","name","prompts","accountPrompts","mcpServer","version","resources","app","use","json","limit","publicUrl","baseUrl","URL","undefined","info","close","httpServer","allowedOrigins","origin","allowedHosts","host","loopbackRouter","fileRouter","resourceStoreUri","contentType","contentDisposition","dcrRouter"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-gmail/src/setup/http.ts"],"sourcesContent":["import { composeMiddleware, connectHttp, createFileServingRouter, McpServer, registerPrompts, registerResources, registerTools } from '@mcp-z/server';\nimport cors from 'cors';\nimport express from 'express';\nimport type { RuntimeOverrides, ServerConfig } from '../types.ts';\nimport { createDefaultRuntime } from './runtime.ts';\n\nexport async function createHTTPServer(config: ServerConfig, overrides?: RuntimeOverrides) {\n const runtime = await createDefaultRuntime(config, overrides);\n const modules = runtime.createDomainModules();\n const layers = runtime.middlewareFactories.map((factory) => factory(runtime.deps));\n const composed = composeMiddleware(modules, layers);\n const logger = runtime.deps.logger;\n const port = config.transport.port;\n if (!port) throw new Error('Port is required for HTTP transport');\n\n const tools = [...composed.tools, ...runtime.deps.oauthAdapters.accountTools];\n const filteredTools =\n config.auth === 'dcr'\n ? tools.filter((tool) => tool.name !== 'messages-export-csv') // No file storage in DCR (public cloud responsibility)\n : tools;\n const prompts = [...composed.prompts, ...runtime.deps.oauthAdapters.accountPrompts];\n\n const mcpServer = new McpServer({ name: config.name, version: config.version });\n registerTools(mcpServer, filteredTools);\n registerResources(mcpServer, composed.resources);\n registerPrompts(mcpServer, prompts);\n\n const app = express();\n app.use(express.json({ limit: '10mb' }));\n\n // Must mount '/mcp' before any permissive app-level cors(), or that layer answers its\n // preflight first; pass baseUrl's origin/host below or a public deployment 403s itself.\n const publicUrl = config.baseUrl ? new URL(config.baseUrl) : undefined;\n logger.info(`Starting ${config.name} MCP server (http)`);\n const { close, httpServer } = await connectHttp(mcpServer, {\n logger,\n app,\n port,\n allowedOrigins: publicUrl ? [publicUrl.origin] : undefined,\n allowedHosts: publicUrl ? [publicUrl.host] : undefined,\n });\n\n // The loopback OAuth callback, the file-export download, and the DCR discovery/\n // registration endpoints are all meant to be reached from a browser on another\n // origin. Keep cors() for them, scoped to their own routes - never in front of '/mcp'.\n if (runtime.deps.oauthAdapters.loopbackRouter) {\n app.use('/', cors(), runtime.deps.oauthAdapters.loopbackRouter);\n logger.info('Mounted loopback OAuth callback router');\n }\n\n if (config.auth !== 'dcr') {\n const fileRouter = createFileServingRouter({ resourceStoreUri: config.resourceStoreUri }, { contentType: 'text/csv', contentDisposition: 'attachment' });\n app.use('/files', cors(), fileRouter);\n }\n\n if (runtime.deps.oauthAdapters.dcrRouter) {\n app.use('/', cors(), runtime.deps.oauthAdapters.dcrRouter);\n logger.info('Mounted DCR router with OAuth endpoints');\n }\n\n logger.info('http transport ready');\n\n return {\n httpServer,\n mcpServer,\n logger,\n close: async () => {\n await close();\n await runtime.close();\n },\n };\n}\n"],"names":["composeMiddleware","connectHttp","createFileServingRouter","McpServer","registerPrompts","registerResources","registerTools","cors","express","createDefaultRuntime","createHTTPServer","config","overrides","runtime","modules","createDomainModules","layers","middlewareFactories","map","factory","deps","composed","logger","port","transport","Error","tools","oauthAdapters","accountTools","filteredTools","auth","filter","tool","name","prompts","accountPrompts","mcpServer","version","resources","app","use","json","limit","publicUrl","baseUrl","URL","undefined","info","close","httpServer","allowedOrigins","origin","allowedHosts","host","loopbackRouter","fileRouter","resourceStoreUri","contentType","contentDisposition","dcrRouter"],"mappings":"AAAA,SAASA,iBAAiB,EAAEC,WAAW,EAAEC,uBAAuB,EAAEC,SAAS,EAAEC,eAAe,EAAEC,iBAAiB,EAAEC,aAAa,QAAQ,gBAAgB;AACtJ,OAAOC,UAAU,OAAO;AACxB,OAAOC,aAAa,UAAU;AAE9B,SAASC,oBAAoB,QAAQ,eAAe;AAEpD,OAAO,eAAeC,iBAAiBC,MAAoB,EAAEC,SAA4B;IACvF,MAAMC,UAAU,MAAMJ,qBAAqBE,QAAQC;IACnD,MAAME,UAAUD,QAAQE,mBAAmB;IAC3C,MAAMC,SAASH,QAAQI,mBAAmB,CAACC,GAAG,CAAC,CAACC,UAAYA,QAAQN,QAAQO,IAAI;IAChF,MAAMC,WAAWrB,kBAAkBc,SAASE;IAC5C,MAAMM,SAAST,QAAQO,IAAI,CAACE,MAAM;IAClC,MAAMC,OAAOZ,OAAOa,SAAS,CAACD,IAAI;IAClC,IAAI,CAACA,MAAM,MAAM,IAAIE,MAAM;IAE3B,MAAMC,QAAQ;WAAIL,SAASK,KAAK;WAAKb,QAAQO,IAAI,CAACO,aAAa,CAACC,YAAY;KAAC;IAC7E,MAAMC,gBACJlB,OAAOmB,IAAI,KAAK,QACZJ,MAAMK,MAAM,CAAC,CAACC,OAASA,KAAKC,IAAI,KAAK,uBAAuB,uDAAuD;OACnHP;IACN,MAAMQ,UAAU;WAAIb,SAASa,OAAO;WAAKrB,QAAQO,IAAI,CAACO,aAAa,CAACQ,cAAc;KAAC;IAEnF,MAAMC,YAAY,IAAIjC,UAAU;QAAE8B,MAAMtB,OAAOsB,IAAI;QAAEI,SAAS1B,OAAO0B,OAAO;IAAC;IAC7E/B,cAAc8B,WAAWP;IACzBxB,kBAAkB+B,WAAWf,SAASiB,SAAS;IAC/ClC,gBAAgBgC,WAAWF;IAE3B,MAAMK,MAAM/B;IACZ+B,IAAIC,GAAG,CAAChC,QAAQiC,IAAI,CAAC;QAAEC,OAAO;IAAO;IAErC,sFAAsF;IACtF,wFAAwF;IACxF,MAAMC,YAAYhC,OAAOiC,OAAO,GAAG,IAAIC,IAAIlC,OAAOiC,OAAO,IAAIE;IAC7DxB,OAAOyB,IAAI,CAAC,CAAC,SAAS,EAAEpC,OAAOsB,IAAI,CAAC,kBAAkB,CAAC;IACvD,MAAM,EAAEe,KAAK,EAAEC,UAAU,EAAE,GAAG,MAAMhD,YAAYmC,WAAW;QACzDd;QACAiB;QACAhB;QACA2B,gBAAgBP,YAAY;YAACA,UAAUQ,MAAM;SAAC,GAAGL;QACjDM,cAAcT,YAAY;YAACA,UAAUU,IAAI;SAAC,GAAGP;IAC/C;IAEA,gFAAgF;IAChF,+EAA+E;IAC/E,uFAAuF;IACvF,IAAIjC,QAAQO,IAAI,CAACO,aAAa,CAAC2B,cAAc,EAAE;QAC7Cf,IAAIC,GAAG,CAAC,KAAKjC,QAAQM,QAAQO,IAAI,CAACO,aAAa,CAAC2B,cAAc;QAC9DhC,OAAOyB,IAAI,CAAC;IACd;IAEA,IAAIpC,OAAOmB,IAAI,KAAK,OAAO;QACzB,MAAMyB,aAAarD,wBAAwB;YAAEsD,kBAAkB7C,OAAO6C,gBAAgB;QAAC,GAAG;YAAEC,aAAa;YAAYC,oBAAoB;QAAa;QACtJnB,IAAIC,GAAG,CAAC,UAAUjC,QAAQgD;IAC5B;IAEA,IAAI1C,QAAQO,IAAI,CAACO,aAAa,CAACgC,SAAS,EAAE;QACxCpB,IAAIC,GAAG,CAAC,KAAKjC,QAAQM,QAAQO,IAAI,CAACO,aAAa,CAACgC,SAAS;QACzDrC,OAAOyB,IAAI,CAAC;IACd;IAEAzB,OAAOyB,IAAI,CAAC;IAEZ,OAAO;QACLE;QACAb;QACAd;QACA0B,OAAO;YACL,MAAMA;YACN,MAAMnC,QAAQmC,KAAK;QACrB;IACF;AACF"}