@mcp-z/mcp-gmail 1.1.4 → 1.2.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 (124) hide show
  1. package/dist/cjs/email/messages/fetch-message.d.cts +1 -1
  2. package/dist/cjs/email/messages/fetch-message.d.ts +1 -1
  3. package/dist/cjs/email/messages/fetch-message.js.map +1 -1
  4. package/dist/cjs/email/messages/messages.d.cts +1 -1
  5. package/dist/cjs/email/messages/messages.d.ts +1 -1
  6. package/dist/cjs/email/messages/messages.js.map +1 -1
  7. package/dist/cjs/email/parsing/html-processing.d.cts +1 -1
  8. package/dist/cjs/email/parsing/html-processing.d.ts +1 -1
  9. package/dist/cjs/email/parsing/html-processing.js.map +1 -1
  10. package/dist/cjs/email/querying/execute-query.d.cts +1 -1
  11. package/dist/cjs/email/querying/execute-query.d.ts +1 -1
  12. package/dist/cjs/email/querying/execute-query.js.map +1 -1
  13. package/dist/cjs/email/querying/pagination.d.cts +1 -1
  14. package/dist/cjs/email/querying/pagination.d.ts +1 -1
  15. package/dist/cjs/email/querying/pagination.js.map +1 -1
  16. package/dist/cjs/email/querying/search-execution.d.cts +1 -1
  17. package/dist/cjs/email/querying/search-execution.d.ts +1 -1
  18. package/dist/cjs/email/querying/search-execution.js.map +1 -1
  19. package/dist/cjs/index.js.map +1 -1
  20. package/dist/cjs/labels/gmail-labels.d.cts +1 -1
  21. package/dist/cjs/labels/gmail-labels.d.ts +1 -1
  22. package/dist/cjs/labels/gmail-labels.js.map +1 -1
  23. package/dist/cjs/lib/google-auth.d.cts +9 -0
  24. package/dist/cjs/lib/google-auth.d.ts +9 -0
  25. package/dist/cjs/lib/google-auth.js +16 -0
  26. package/dist/cjs/lib/google-auth.js.map +1 -0
  27. package/dist/cjs/mcp/prompts/draft-email.d.cts +2 -3
  28. package/dist/cjs/mcp/prompts/draft-email.d.ts +2 -3
  29. package/dist/cjs/mcp/prompts/draft-email.js.map +1 -1
  30. package/dist/cjs/mcp/prompts/query-syntax.d.cts +2 -3
  31. package/dist/cjs/mcp/prompts/query-syntax.d.ts +2 -3
  32. package/dist/cjs/mcp/prompts/query-syntax.js.map +1 -1
  33. package/dist/cjs/mcp/resources/email.d.cts +6 -5
  34. package/dist/cjs/mcp/resources/email.d.ts +6 -5
  35. package/dist/cjs/mcp/resources/email.js +6 -5
  36. package/dist/cjs/mcp/resources/email.js.map +1 -1
  37. package/dist/cjs/mcp/tools/categories-list.js +6 -5
  38. package/dist/cjs/mcp/tools/categories-list.js.map +1 -1
  39. package/dist/cjs/mcp/tools/label-add.js +7 -6
  40. package/dist/cjs/mcp/tools/label-add.js.map +1 -1
  41. package/dist/cjs/mcp/tools/label-delete.js +10 -9
  42. package/dist/cjs/mcp/tools/label-delete.js.map +1 -1
  43. package/dist/cjs/mcp/tools/labels-list.d.cts +3 -3
  44. package/dist/cjs/mcp/tools/labels-list.d.ts +3 -3
  45. package/dist/cjs/mcp/tools/labels-list.js +6 -5
  46. package/dist/cjs/mcp/tools/labels-list.js.map +1 -1
  47. package/dist/cjs/mcp/tools/message-get.js +7 -7
  48. package/dist/cjs/mcp/tools/message-get.js.map +1 -1
  49. package/dist/cjs/mcp/tools/message-mark-read.js +7 -6
  50. package/dist/cjs/mcp/tools/message-mark-read.js.map +1 -1
  51. package/dist/cjs/mcp/tools/message-move-to-trash.js +10 -9
  52. package/dist/cjs/mcp/tools/message-move-to-trash.js.map +1 -1
  53. package/dist/cjs/mcp/tools/message-respond.js +8 -7
  54. package/dist/cjs/mcp/tools/message-respond.js.map +1 -1
  55. package/dist/cjs/mcp/tools/message-search.js +6 -6
  56. package/dist/cjs/mcp/tools/message-search.js.map +1 -1
  57. package/dist/cjs/mcp/tools/message-send.js +7 -6
  58. package/dist/cjs/mcp/tools/message-send.js.map +1 -1
  59. package/dist/cjs/mcp/tools/messages-export-csv.js +5 -5
  60. package/dist/cjs/mcp/tools/messages-export-csv.js.map +1 -1
  61. package/dist/cjs/setup/http.d.cts +0 -2
  62. package/dist/cjs/setup/http.d.ts +0 -2
  63. package/dist/cjs/setup/http.js +18 -11
  64. package/dist/cjs/setup/http.js.map +1 -1
  65. package/dist/cjs/setup/stdio.d.cts +0 -2
  66. package/dist/cjs/setup/stdio.d.ts +0 -2
  67. package/dist/cjs/setup/stdio.js +18 -11
  68. package/dist/cjs/setup/stdio.js.map +1 -1
  69. package/dist/esm/email/messages/fetch-message.d.ts +1 -1
  70. package/dist/esm/email/messages/fetch-message.js.map +1 -1
  71. package/dist/esm/email/messages/messages.d.ts +1 -1
  72. package/dist/esm/email/messages/messages.js.map +1 -1
  73. package/dist/esm/email/parsing/html-processing.d.ts +1 -1
  74. package/dist/esm/email/parsing/html-processing.js.map +1 -1
  75. package/dist/esm/email/querying/execute-query.d.ts +1 -1
  76. package/dist/esm/email/querying/execute-query.js.map +1 -1
  77. package/dist/esm/email/querying/pagination.d.ts +1 -1
  78. package/dist/esm/email/querying/pagination.js.map +1 -1
  79. package/dist/esm/email/querying/search-execution.d.ts +1 -1
  80. package/dist/esm/email/querying/search-execution.js.map +1 -1
  81. package/dist/esm/index.js +1 -1
  82. package/dist/esm/index.js.map +1 -1
  83. package/dist/esm/labels/gmail-labels.d.ts +1 -1
  84. package/dist/esm/labels/gmail-labels.js.map +1 -1
  85. package/dist/esm/lib/google-auth.d.ts +9 -0
  86. package/dist/esm/lib/google-auth.js +11 -0
  87. package/dist/esm/lib/google-auth.js.map +1 -0
  88. package/dist/esm/mcp/prompts/draft-email.d.ts +2 -3
  89. package/dist/esm/mcp/prompts/draft-email.js.map +1 -1
  90. package/dist/esm/mcp/prompts/query-syntax.d.ts +2 -3
  91. package/dist/esm/mcp/prompts/query-syntax.js.map +1 -1
  92. package/dist/esm/mcp/resources/email.d.ts +6 -5
  93. package/dist/esm/mcp/resources/email.js +5 -4
  94. package/dist/esm/mcp/resources/email.js.map +1 -1
  95. package/dist/esm/mcp/tools/categories-list.js +6 -5
  96. package/dist/esm/mcp/tools/categories-list.js.map +1 -1
  97. package/dist/esm/mcp/tools/label-add.js +7 -6
  98. package/dist/esm/mcp/tools/label-add.js.map +1 -1
  99. package/dist/esm/mcp/tools/label-delete.js +10 -9
  100. package/dist/esm/mcp/tools/label-delete.js.map +1 -1
  101. package/dist/esm/mcp/tools/labels-list.d.ts +3 -3
  102. package/dist/esm/mcp/tools/labels-list.js +6 -5
  103. package/dist/esm/mcp/tools/labels-list.js.map +1 -1
  104. package/dist/esm/mcp/tools/message-get.js +8 -8
  105. package/dist/esm/mcp/tools/message-get.js.map +1 -1
  106. package/dist/esm/mcp/tools/message-mark-read.js +7 -6
  107. package/dist/esm/mcp/tools/message-mark-read.js.map +1 -1
  108. package/dist/esm/mcp/tools/message-move-to-trash.js +10 -9
  109. package/dist/esm/mcp/tools/message-move-to-trash.js.map +1 -1
  110. package/dist/esm/mcp/tools/message-respond.js +8 -7
  111. package/dist/esm/mcp/tools/message-respond.js.map +1 -1
  112. package/dist/esm/mcp/tools/message-search.js +6 -5
  113. package/dist/esm/mcp/tools/message-search.js.map +1 -1
  114. package/dist/esm/mcp/tools/message-send.js +7 -6
  115. package/dist/esm/mcp/tools/message-send.js.map +1 -1
  116. package/dist/esm/mcp/tools/messages-export-csv.js +6 -6
  117. package/dist/esm/mcp/tools/messages-export-csv.js.map +1 -1
  118. package/dist/esm/setup/http.d.ts +0 -2
  119. package/dist/esm/setup/http.js +18 -11
  120. package/dist/esm/setup/http.js.map +1 -1
  121. package/dist/esm/setup/stdio.d.ts +0 -2
  122. package/dist/esm/setup/stdio.js +18 -11
  123. package/dist/esm/setup/stdio.js.map +1 -1
  124. package/package.json +8 -9
@@ -1,13 +1,14 @@
1
- import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
1
+ import { gmail as gmailApi } from '@googleapis/gmail';
2
+ import { ProtocolError, ProtocolErrorCode } from '@mcp-z/server';
2
3
  /** 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
4
  import { schemas } from '@mcp-z/oauth-google';
4
5
  const { AuthRequiredBranchSchema } = schemas;
5
6
  import { createFieldsSchema, createPaginationSchema, createShapeSchema, filterFields, parseFields, toColumnarFormat } from '@mcp-z/server';
6
- import { google } from 'googleapis';
7
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.'),
@@ -68,9 +69,9 @@ async function handler({ query, pageSize = DEFAULT_PAGE_SIZE, pageToken, fields,
68
69
  includeBody,
69
70
  accountId: extra.authContext.accountId
70
71
  });
71
- const gmail = google.gmail({
72
+ const gmail = gmailApi({
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":"AAAA,SAASA,SAAS,EAAEC,QAAQ,QAAQ,qCAAqC;AACzE,6DAA6D,GAE7D,SAASC,qBAAqB,EAAEC,wBAAwB,EAAEC,YAAY,EAAEC,sBAAsB,EAAoBC,iBAAiB,EAAEC,0BAA0B,QAAQ,eAAe;AAEtL,SAASC,OAAO,QAAQ,sBAAsB;AAE9C,MAAM,EAAEC,wBAAwB,EAAE,GAAGD;AAErC,SAASE,kBAAkB,EAAEC,sBAAsB,EAAEC,iBAAiB,EAAEC,YAAY,EAAEC,WAAW,EAAmBC,gBAAgB,QAAQ,gBAAgB;AAC5J,SAAwBC,MAAM,QAAQ,aAAa;AACnD,SAASC,CAAC,QAAQ,MAAM;AACxB,SAASC,iBAAiB,EAAEC,aAAa,QAAQ,qBAAqB;AACtE,SAASC,sBAAsB,QAAQ,yCAAyC;AAChF,SAASC,gBAAgBC,iBAAiB,QAAQ,wCAAwC;AAC1F,SAASC,yBAAyB,EAAEC,wBAAwB,QAAQ,sCAAsC;AAE1G,MAAMC,cAAcR,EAAES,MAAM,CAAC;IAC3BC,OAAOJ,0BAA0BK,QAAQ,GAAGC,QAAQ,CAAC;IACrDC,QAAQpB,mBAAmB;QACzBqB,iBAAiB3B;QACjB4B,mBAAmB7B;QACnB8B,gBAAgB/B;QAChBgC,cAAc;IAChB;IACA,GAAGvB,uBAAuB;QAAEwB,iBAAiBjB;QAAmBkB,aAAajB;QAAekB,UAAU;IAAQ,GAAGC,KAAK;IACtHA,OAAO1B;IACP2B,aAAalC;IACbmC,sBAAsBjC;AACxB;AAEA,8CAA8C;AAC9C,MAAMkC,6BAA6BxB,EAAES,MAAM,CAAC;IAC1CgB,MAAMzB,EAAE0B,OAAO,CAAC;IAChBL,OAAOrB,EAAE0B,OAAO,CAAC;IACjBC,OAAO3B,EAAE4B,KAAK,CAACvC,mBAAmBuB,QAAQ,CAAC;IAC3CiB,eAAe7B,EAAE8B,MAAM,GAAGnB,QAAQ,GAAGC,QAAQ,CAAC;AAChD;AAEA,MAAMmB,4BAA4B/B,EAAES,MAAM,CAAC;IACzCgB,MAAMzB,EAAE0B,OAAO,CAAC;IAChBL,OAAOrB,EAAE0B,OAAO,CAAC;IACjBM,SAAShC,EAAE4B,KAAK,CAAC5B,EAAE8B,MAAM,IAAIlB,QAAQ,CAAC;IACtCqB,MAAMjC,EAAE4B,KAAK,CAAC5B,EAAE4B,KAAK,CAAC5B,EAAEkC,OAAO,KAAKtB,QAAQ,CAAC;IAC7CiB,eAAe7B,EAAE8B,MAAM,GAAGnB,QAAQ,GAAGC,QAAQ,CAAC;AAChD;AAEA,2CAA2C;AAC3C,uGAAuG;AACvG,MAAMuB,eAAenC,EAAEoC,KAAK,CAAC;IAACZ;IAA4BO;IAA2BvC;CAAyB;AAE9G,MAAM6C,SAAS;IACbC,aAAa;IACb9B,aAAaA;IACb2B,cAAcnC,EAAES,MAAM,CAAC;QACrB8B,QAAQJ;IACV;AACF;AAKA,eAAeK,QAAQ,EAAE9B,KAAK,EAAE+B,WAAWxC,iBAAiB,EAAEyC,SAAS,EAAE7B,MAAM,EAAEQ,QAAQ,QAAQ,EAAEC,cAAc,MAAM,EAAEC,uBAAuB,KAAK,EAAS,EAAEoB,KAAoB;IAClL,MAAMC,SAASD,MAAMC,MAAM;IAE3B,IAAI;QACF,MAAMC,cAActC,yBAAyBG;QAC7C,MAAMoC,kBAAkBjD,YAAYgB,QAAQ1B;QAC5C,MAAM4D,cAAcD,oBAAoB,SAASA,gBAAgBE,GAAG,CAAC;QAErEJ,OAAOK,IAAI,CAAC,+BAA+B;YACzCvC,OAAOmC;YACPJ;YACAC,WAAWA,YAAY,eAAeQ;YACtCrC;YACAkC;YACAI,WAAWR,MAAMS,WAAW,CAACD,SAAS;QACxC;QAEA,MAAME,QAAQtD,OAAOsD,KAAK,CAAC;YAAEC,SAAS;YAAMC,MAAMZ,MAAMS,WAAW,CAACG,IAAI;QAAC;QAEzE,MAAMC,UAAUC,KAAKC,GAAG;QAExB,MAAMC,OAAO,MAAMtD,kBACjBwC,aACA;YACEe,QAAQP;YACRT;YACAH;YACA,GAAIC,cAAcQ,aAAa;gBAAER;YAAU,CAAC;YAC5CK;QACF,GACA,CAACc;;gBAIoCC;YAHnC,wCAAwC;YACxC,MAAMA,WAAWD;YAEjB,MAAME,eAAeC,MAAMC,OAAO,CAACH,qBAAAA,gCAAAA,oBAAAA,SAAUI,OAAO,cAAjBJ,wCAAAA,kBAAmBK,OAAO,IAAIL,SAASI,OAAO,CAACC,OAAO,GAAG,EAAE;YAC9F,MAAMA,UAAUC,OAAOC,WAAW,CAChCN,aAAaO,GAAG,CAAC,CAACC;oBAEDC,cAA2BA;gBAD1C,MAAMA,SAASD;gBACf,OAAO;oBAACE,QAAOD,eAAAA,OAAOE,IAAI,cAAXF,0BAAAA,eAAe;oBAAKC,QAAOD,gBAAAA,OAAOG,KAAK,cAAZH,2BAAAA,gBAAgB;iBAAI;YAChE;YAGF,MAAMI,SAA+B;gBACnCC,IAAIJ,eAAOX,qBAAAA,+BAAAA,SAAUe,EAAE,uCAAI;gBAC3BC,UAAUhB,CAAAA,qBAAAA,+BAAAA,SAAUgB,QAAQ,IAAGL,OAAOX,SAASgB,QAAQ,IAAI5B;gBAC3D6B,IAAI,EAAEZ,oBAAAA,8BAAAA,QAASa,IAAI;gBACnBC,EAAE,EAAEd,oBAAAA,8BAAAA,QAASe,EAAE;gBACfC,OAAO,EAAEhB,oBAAAA,8BAAAA,QAASiB,OAAO;gBACzBC,IAAI,EAAElB,oBAAAA,8BAAAA,QAASV,IAAI;gBACnB6B,SAASxB,CAAAA,qBAAAA,+BAAAA,SAAUwB,OAAO,IAAGb,OAAOX,SAASwB,OAAO,IAAIpC;YAC1D;YAEA,IAAIH,aAAa;gBACf,MAAMmB,UAAUJ,qBAAAA,+BAAAA,SAAUI,OAAO;gBACjC,wDAAwD;gBACxD,MAAMqB,OAAOrB,UAAU/D,uBAAuB+D,SAAwC;oBAAE5C;oBAAaC;gBAAqB,KAAK;gBAC/H,IAAIgE,MAAM;oBACRX,OAAOW,IAAI,GAAGA;oBACdX,OAAOY,eAAe,GAAGlE;gBAC3B;YACF;YACA,OAAOsD;QACT;QAGF,MAAMjD,QAAQgC,KAAKhC,KAAK;QACxB,MAAM8D,WAAW9B,KAAK8B,QAAQ;QAC9B,MAAMC,aAAajC,KAAKC,GAAG,KAAKF;QAEhC,4BAA4B;QAC5B,MAAMmC,gBAAgBhE,MAAM2C,GAAG,CAAC,CAACsB,OAAShG,aAAagG,MAAM9C;QAE7DF,OAAOK,IAAI,CAAC,gCAAgC;YAAEvC;YAAO+B;YAAUoD,aAAaF,cAAcG,MAAM;YAAEjF,QAAQA,UAAU;QAAM;QAC1H+B,OAAOK,IAAI,CAAC,gCAAgC;YAAEyC;YAAYD;QAAS;QAEnE,4BAA4B;QAC5B,MAAMM,cAAcN;QAEpB,8BAA8B;QAC9B,MAAMlD,SACJlB,UAAU,WACN;YACEI,MAAM;YACNJ,OAAO;YACP,GAAGvB,iBAAiB6F,eAAe7C,iBAAiB3D,aAAa;YACjE,GAAI4G,CAAAA,wBAAAA,kCAAAA,YAAalE,aAAa,KAAI;gBAAEA,eAAekE,YAAYlE,aAAa;YAAC,CAAC;QAChF,IACA;YACEJ,MAAM;YACNJ,OAAO;YACPM,OAAOgE;YACP,GAAII,CAAAA,wBAAAA,kCAAAA,YAAalE,aAAa,KAAI;gBAAEA,eAAekE,YAAYlE,aAAa;YAAC,CAAC;QAChF;QAEN,OAAO;YACLmE,SAAS;gBACP;oBACEvE,MAAM;oBACNwE,MAAMC,KAAKC,SAAS,CAAC5D;gBACvB;aACD;YACD6D,mBAAmB;gBAAE7D;YAAO;QAC9B;IACF,EAAE,OAAO8D,OAAO;QACd,MAAMC,UAAUD,iBAAiBE,QAAQF,MAAMC,OAAO,GAAG7B,OAAO4B;QAChEzD,OAAOyD,KAAK,CAAC,8BAA8B;YAAEA,OAAOC;QAAQ;QAE5D,MAAM,IAAItH,SAASD,UAAUyH,aAAa,EAAE,CAAC,0BAA0B,EAAEF,SAAS,EAAE;YAClFG,OAAOJ,iBAAiBE,QAAQF,MAAMI,KAAK,GAAGvD;QAChD;IACF;AACF;AAEA,eAAe,SAASwD;IACtB,OAAO;QACLhC,MAAM;QACNrC;QACAG;IACF;AACF"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-gmail/src/mcp/tools/message-search.ts"],"sourcesContent":["import { type gmail_v1, gmail as gmailApi } from '@googleapis/gmail';\nimport { 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 { 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 = gmailApi({ 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":["gmail","gmailApi","ProtocolError","ProtocolErrorCode","EMAIL_COMMON_PATTERNS","EMAIL_FIELD_DESCRIPTIONS","EMAIL_FIELDS","EmailContentTypeSchema","EmailDetailSchema","ExcludeThreadHistorySchema","schemas","AuthRequiredBranchSchema","createFieldsSchema","createPaginationSchema","createShapeSchema","filterFields","parseFields","toColumnarFormat","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","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":"AAAA,SAAwBA,SAASC,QAAQ,QAAQ,oBAAoB;AACrE,SAASC,aAAa,EAAEC,iBAAiB,QAAQ,gBAAgB;AACjE,6DAA6D,GAE7D,SAASC,qBAAqB,EAAEC,wBAAwB,EAAEC,YAAY,EAAEC,sBAAsB,EAAoBC,iBAAiB,EAAEC,0BAA0B,QAAQ,eAAe;AAEtL,SAASC,OAAO,QAAQ,sBAAsB;AAE9C,MAAM,EAAEC,wBAAwB,EAAE,GAAGD;AAErC,SAASE,kBAAkB,EAAEC,sBAAsB,EAAEC,iBAAiB,EAAEC,YAAY,EAAEC,WAAW,EAAmBC,gBAAgB,QAAQ,gBAAgB;AAC5J,SAASC,CAAC,QAAQ,MAAM;AACxB,SAASC,iBAAiB,EAAEC,aAAa,QAAQ,qBAAqB;AACtE,SAASC,sBAAsB,QAAQ,yCAAyC;AAChF,SAASC,gBAAgBC,iBAAiB,QAAQ,wCAAwC;AAC1F,SAASC,UAAU,QAAQ,2BAA2B;AACtD,SAASC,yBAAyB,EAAEC,wBAAwB,QAAQ,sCAAsC;AAE1G,MAAMC,cAAcT,EAAEU,MAAM,CAAC;IAC3BC,OAAOJ,0BAA0BK,QAAQ,GAAGC,QAAQ,CAAC;IACrDC,QAAQpB,mBAAmB;QACzBqB,iBAAiB3B;QACjB4B,mBAAmB7B;QACnB8B,gBAAgB/B;QAChBgC,cAAc;IAChB;IACA,GAAGvB,uBAAuB;QAAEwB,iBAAiBlB;QAAmBmB,aAAalB;QAAemB,UAAU;IAAQ,GAAGC,KAAK;IACtHA,OAAO1B;IACP2B,aAAalC;IACbmC,sBAAsBjC;AACxB;AAEA,8CAA8C;AAC9C,MAAMkC,6BAA6BzB,EAAEU,MAAM,CAAC;IAC1CgB,MAAM1B,EAAE2B,OAAO,CAAC;IAChBL,OAAOtB,EAAE2B,OAAO,CAAC;IACjBC,OAAO5B,EAAE6B,KAAK,CAACvC,mBAAmBuB,QAAQ,CAAC;IAC3CiB,eAAe9B,EAAE+B,MAAM,GAAGnB,QAAQ,GAAGC,QAAQ,CAAC;AAChD;AAEA,MAAMmB,4BAA4BhC,EAAEU,MAAM,CAAC;IACzCgB,MAAM1B,EAAE2B,OAAO,CAAC;IAChBL,OAAOtB,EAAE2B,OAAO,CAAC;IACjBM,SAASjC,EAAE6B,KAAK,CAAC7B,EAAE+B,MAAM,IAAIlB,QAAQ,CAAC;IACtCqB,MAAMlC,EAAE6B,KAAK,CAAC7B,EAAE6B,KAAK,CAAC7B,EAAEmC,OAAO,KAAKtB,QAAQ,CAAC;IAC7CiB,eAAe9B,EAAE+B,MAAM,GAAGnB,QAAQ,GAAGC,QAAQ,CAAC;AAChD;AAEA,2CAA2C;AAC3C,uGAAuG;AACvG,MAAMuB,eAAepC,EAAEqC,KAAK,CAAC;IAACZ;IAA4BO;IAA2BvC;CAAyB;AAE9G,MAAM6C,SAAS;IACbC,aAAa;IACb9B,aAAaA;IACb2B,cAAcpC,EAAEU,MAAM,CAAC;QACrB8B,QAAQJ;IACV;AACF;AAKA,eAAeK,QAAQ,EAAE9B,KAAK,EAAE+B,WAAWzC,iBAAiB,EAAE0C,SAAS,EAAE7B,MAAM,EAAEQ,QAAQ,QAAQ,EAAEC,cAAc,MAAM,EAAEC,uBAAuB,KAAK,EAAS,EAAEoB,KAAoB;IAClL,MAAMC,SAASD,MAAMC,MAAM;IAE3B,IAAI;QACF,MAAMC,cAActC,yBAAyBG;QAC7C,MAAMoC,kBAAkBjD,YAAYgB,QAAQ1B;QAC5C,MAAM4D,cAAcD,oBAAoB,SAASA,gBAAgBE,GAAG,CAAC;QAErEJ,OAAOK,IAAI,CAAC,+BAA+B;YACzCvC,OAAOmC;YACPJ;YACAC,WAAWA,YAAY,eAAeQ;YACtCrC;YACAkC;YACAI,WAAWR,MAAMS,WAAW,CAACD,SAAS;QACxC;QAEA,MAAMtE,QAAQC,SAAS;YAAEuE,SAAS;YAAMC,MAAMjD,WAAWsC,MAAMS,WAAW,CAACE,IAAI;QAAE;QAEjF,MAAMC,UAAUC,KAAKC,GAAG;QAExB,MAAMC,OAAO,MAAMtD,kBACjByC,aACA;YACEc,QAAQ9E;YACR+D;YACAH;YACA,GAAIC,cAAcQ,aAAa;gBAAER;YAAU,CAAC;YAC5CK;QACF,GACA,CAACa;;gBAIoCC;YAHnC,wCAAwC;YACxC,MAAMA,WAAWD;YAEjB,MAAME,eAAeC,MAAMC,OAAO,CAACH,qBAAAA,gCAAAA,oBAAAA,SAAUI,OAAO,cAAjBJ,wCAAAA,kBAAmBK,OAAO,IAAIL,SAASI,OAAO,CAACC,OAAO,GAAG,EAAE;YAC9F,MAAMA,UAAUC,OAAOC,WAAW,CAChCN,aAAaO,GAAG,CAAC,CAACC;oBAEDC,cAA2BA;gBAD1C,MAAMA,SAASD;gBACf,OAAO;oBAACE,QAAOD,eAAAA,OAAOE,IAAI,cAAXF,0BAAAA,eAAe;oBAAKC,QAAOD,gBAAAA,OAAOG,KAAK,cAAZH,2BAAAA,gBAAgB;iBAAI;YAChE;YAGF,MAAMI,SAA+B;gBACnCC,IAAIJ,eAAOX,qBAAAA,+BAAAA,SAAUe,EAAE,uCAAI;gBAC3BC,UAAUhB,CAAAA,qBAAAA,+BAAAA,SAAUgB,QAAQ,IAAGL,OAAOX,SAASgB,QAAQ,IAAI3B;gBAC3D4B,IAAI,EAAEZ,oBAAAA,8BAAAA,QAASa,IAAI;gBACnBC,EAAE,EAAEd,oBAAAA,8BAAAA,QAASe,EAAE;gBACfC,OAAO,EAAEhB,oBAAAA,8BAAAA,QAASiB,OAAO;gBACzBC,IAAI,EAAElB,oBAAAA,8BAAAA,QAASV,IAAI;gBACnB6B,SAASxB,CAAAA,qBAAAA,+BAAAA,SAAUwB,OAAO,IAAGb,OAAOX,SAASwB,OAAO,IAAInC;YAC1D;YAEA,IAAIH,aAAa;gBACf,MAAMkB,UAAUJ,qBAAAA,+BAAAA,SAAUI,OAAO;gBACjC,wDAAwD;gBACxD,MAAMqB,OAAOrB,UAAU/D,uBAAuB+D,SAAwC;oBAAE3C;oBAAaC;gBAAqB,KAAK;gBAC/H,IAAI+D,MAAM;oBACRX,OAAOW,IAAI,GAAGA;oBACdX,OAAOY,eAAe,GAAGjE;gBAC3B;YACF;YACA,OAAOqD;QACT;QAGF,MAAMhD,QAAQ+B,KAAK/B,KAAK;QACxB,MAAM6D,WAAW9B,KAAK8B,QAAQ;QAC9B,MAAMC,aAAajC,KAAKC,GAAG,KAAKF;QAEhC,4BAA4B;QAC5B,MAAMmC,gBAAgB/D,MAAM0C,GAAG,CAAC,CAACsB,OAAS/F,aAAa+F,MAAM7C;QAE7DF,OAAOK,IAAI,CAAC,gCAAgC;YAAEvC;YAAO+B;YAAUmD,aAAaF,cAAcG,MAAM;YAAEhF,QAAQA,UAAU;QAAM;QAC1H+B,OAAOK,IAAI,CAAC,gCAAgC;YAAEwC;YAAYD;QAAS;QAEnE,4BAA4B;QAC5B,MAAMM,cAAcN;QAEpB,8BAA8B;QAC9B,MAAMjD,SACJlB,UAAU,WACN;YACEI,MAAM;YACNJ,OAAO;YACP,GAAGvB,iBAAiB4F,eAAe5C,iBAAiB3D,aAAa;YACjE,GAAI2G,CAAAA,wBAAAA,kCAAAA,YAAajE,aAAa,KAAI;gBAAEA,eAAeiE,YAAYjE,aAAa;YAAC,CAAC;QAChF,IACA;YACEJ,MAAM;YACNJ,OAAO;YACPM,OAAO+D;YACP,GAAII,CAAAA,wBAAAA,kCAAAA,YAAajE,aAAa,KAAI;gBAAEA,eAAeiE,YAAYjE,aAAa;YAAC,CAAC;QAChF;QAEN,OAAO;YACLkE,SAAS;gBACP;oBACEtE,MAAM;oBACNuE,MAAMC,KAAKC,SAAS,CAAC3D;gBACvB;aACD;YACD4D,mBAAmB;gBAAE5D;YAAO;QAC9B;IACF,EAAE,OAAO6D,OAAO;QACd,MAAMC,UAAUD,iBAAiBE,QAAQF,MAAMC,OAAO,GAAG7B,OAAO4B;QAChExD,OAAOwD,KAAK,CAAC,8BAA8B;YAAEA,OAAOC;QAAQ;QAE5D,MAAM,IAAItH,cAAcC,kBAAkBuH,aAAa,EAAE,CAAC,0BAA0B,EAAEF,SAAS,EAAE;YAC/FG,OAAOJ,iBAAiBE,QAAQF,MAAMI,KAAK,GAAGtD;QAChD;IACF;AACF;AAEA,eAAe,SAASuD;IACtB,OAAO;QACLhC,MAAM;QACNpC;QACAG;IACF;AACF"}
@@ -1,11 +1,12 @@
1
+ import { gmail as gmailApi } from '@googleapis/gmail';
1
2
  import { ComposeContentTypeSchema, createEmailRecipientsSchema, createMessageResultSchema } from '@mcp-z/email';
2
3
  import { schemas } from '@mcp-z/oauth-google';
3
4
  const { AuthRequiredBranchSchema } = schemas;
4
- import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
5
- import { google } from 'googleapis';
5
+ import { ProtocolError, ProtocolErrorCode } from '@mcp-z/server';
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
@@ -55,9 +56,9 @@ async function handler(params, extra) {
55
56
  if (subject !== undefined) msgArgs.subject = subject;
56
57
  const raw = buildRfc822FromArgs(msgArgs);
57
58
  const encodedMessage = b64url(raw);
58
- const gmail = google.gmail({
59
+ const gmail = gmailApi({
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 { gmail as gmailApi } from '@googleapis/gmail';\nimport { 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 { 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 = gmailApi({ 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":["gmail","gmailApi","ComposeContentTypeSchema","createEmailRecipientsSchema","createMessageResultSchema","schemas","AuthRequiredBranchSchema","ProtocolError","ProtocolErrorCode","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","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,16 +1,16 @@
1
+ import { gmail as gmailApi } from '@googleapis/gmail';
1
2
  import { EmailContentTypeSchema, ExcludeThreadHistorySchema } from '@mcp-z/email';
2
3
  import { schemas } from '@mcp-z/oauth-google';
3
4
  const { AuthRequiredBranchSchema } = schemas;
4
- import { getFileUri, reserveFile } from '@mcp-z/server';
5
- import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
5
+ import { getFileUri, ProtocolError, ProtocolErrorCode, reserveFile } from '@mcp-z/server';
6
6
  import { stringify } from 'csv-stringify/sync';
7
7
  import { createWriteStream } from 'fs';
8
8
  import { unlink } from 'fs/promises';
9
- import { google } from 'googleapis';
10
9
  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;
@@ -69,9 +69,9 @@ const config = {
69
69
  filename,
70
70
  accountId: extra.authContext.accountId
71
71
  });
72
- const gmail = google.gmail({
72
+ const gmail = gmailApi({
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 { type gmail_v1, gmail as gmailApi } from '@googleapis/gmail';\nimport { 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 { 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 = gmailApi({ 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":["gmail","gmailApi","EmailContentTypeSchema","ExcludeThreadHistorySchema","schemas","AuthRequiredBranchSchema","getFileUri","ProtocolError","ProtocolErrorCode","reserveFile","stringify","createWriteStream","unlink","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","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,8 +1,6 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
1
  import type { RuntimeOverrides, ServerConfig } from '../types.js';
3
2
  export declare function createHTTPServer(config: ServerConfig, overrides?: RuntimeOverrides): Promise<{
4
3
  httpServer: import("node:http").Server<typeof import("node:http").IncomingMessage, typeof import("node:http").ServerResponse>;
5
- mcpServer: McpServer;
6
4
  logger: import("@mcp-z/server").Logger;
7
5
  close: () => Promise<void>;
8
6
  }>;
@@ -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, defaultCacheHints, 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';
@@ -21,13 +20,22 @@ export async function createHTTPServer(config, overrides) {
21
20
  ...composed.prompts,
22
21
  ...runtime.deps.oauthAdapters.accountPrompts
23
22
  ];
24
- const mcpServer = new McpServer({
25
- name: config.name,
26
- version: config.version
27
- });
28
- registerTools(mcpServer, filteredTools);
29
- registerResources(mcpServer, composed.resources);
30
- registerPrompts(mcpServer, prompts);
23
+ // Built per request (HTTP) and per connection (stdio), not shared. The SDK caches the
24
+ // negotiated protocol revision on the McpServer instance - its own docs say a negotiated
25
+ // session never re-routes a method onto the other era - so one shared instance pins itself
26
+ // to whichever revision reaches it first and answers the other with -32601.
27
+ const buildServer = ()=>{
28
+ const mcpServer = new McpServer({
29
+ name: config.name,
30
+ version: config.version
31
+ }, {
32
+ cacheHints: defaultCacheHints
33
+ });
34
+ registerTools(mcpServer, filteredTools);
35
+ registerResources(mcpServer, composed.resources);
36
+ registerPrompts(mcpServer, prompts);
37
+ return mcpServer;
38
+ };
31
39
  const app = express();
32
40
  app.use(express.json({
33
41
  limit: '10mb'
@@ -36,7 +44,7 @@ export async function createHTTPServer(config, overrides) {
36
44
  // preflight first; pass baseUrl's origin/host below or a public deployment 403s itself.
37
45
  const publicUrl = config.baseUrl ? new URL(config.baseUrl) : undefined;
38
46
  logger.info(`Starting ${config.name} MCP server (http)`);
39
- const { close, httpServer } = await connectHttp(mcpServer, {
47
+ const { close, httpServer } = await connectHttp(buildServer, {
40
48
  logger,
41
49
  app,
42
50
  port,
@@ -70,7 +78,6 @@ export async function createHTTPServer(config, overrides) {
70
78
  logger.info('http transport ready');
71
79
  return {
72
80
  httpServer,
73
- mcpServer,
74
81
  logger,
75
82
  close: async ()=>{
76
83
  await close();
@@ -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, defaultCacheHints, 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 // Built per request (HTTP) and per connection (stdio), not shared. The SDK caches the\n // negotiated protocol revision on the McpServer instance - its own docs say a negotiated\n // session never re-routes a method onto the other era - so one shared instance pins itself\n // to whichever revision reaches it first and answers the other with -32601.\n const buildServer = () => {\n const mcpServer = new McpServer({ name: config.name, version: config.version }, { cacheHints: defaultCacheHints });\n registerTools(mcpServer, filteredTools);\n registerResources(mcpServer, composed.resources);\n registerPrompts(mcpServer, prompts);\n return mcpServer;\n };\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(buildServer, {\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 logger,\n close: async () => {\n await close();\n await runtime.close();\n },\n };\n}\n"],"names":["composeMiddleware","connectHttp","createFileServingRouter","defaultCacheHints","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","buildServer","mcpServer","version","cacheHints","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,7 +1,5 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
1
  import type { RuntimeOverrides, ServerConfig } from '../types.js';
3
2
  export declare function createStdioServer(config: ServerConfig, overrides?: RuntimeOverrides): Promise<{
4
- mcpServer: McpServer;
5
3
  logger: import("@mcp-z/server").Logger;
6
4
  close: () => Promise<void>;
7
5
  }>;
@@ -1,5 +1,4 @@
1
- import { composeMiddleware, connectStdio, registerPrompts, registerResources, registerTools } from '@mcp-z/server';
2
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
1
+ import { composeMiddleware, connectStdio, defaultCacheHints, McpServer, registerPrompts, registerResources, registerTools } from '@mcp-z/server';
3
2
  import { createDefaultRuntime } from './runtime.js';
4
3
  export async function createStdioServer(config, overrides) {
5
4
  const runtime = await createDefaultRuntime(config, overrides);
@@ -17,20 +16,28 @@ export async function createStdioServer(config, overrides) {
17
16
  ...composed.prompts,
18
17
  ...runtime.deps.oauthAdapters.accountPrompts
19
18
  ];
20
- const mcpServer = new McpServer({
21
- name: config.name,
22
- version: config.version
23
- });
24
- registerTools(mcpServer, filteredTools);
25
- registerResources(mcpServer, composed.resources);
26
- registerPrompts(mcpServer, prompts);
19
+ // Built per request (HTTP) and per connection (stdio), not shared. The SDK caches the
20
+ // negotiated protocol revision on the McpServer instance - its own docs say a negotiated
21
+ // session never re-routes a method onto the other era - so one shared instance pins itself
22
+ // to whichever revision reaches it first and answers the other with -32601.
23
+ const buildServer = ()=>{
24
+ const mcpServer = new McpServer({
25
+ name: config.name,
26
+ version: config.version
27
+ }, {
28
+ cacheHints: defaultCacheHints
29
+ });
30
+ registerTools(mcpServer, filteredTools);
31
+ registerResources(mcpServer, composed.resources);
32
+ registerPrompts(mcpServer, prompts);
33
+ return mcpServer;
34
+ };
27
35
  logger.info(`Starting ${config.name} MCP server (stdio)`);
28
- const { close } = await connectStdio(mcpServer, {
36
+ const { close } = await connectStdio(buildServer, {
29
37
  logger
30
38
  });
31
39
  logger.info('stdio transport ready');
32
40
  return {
33
- mcpServer,
34
41
  logger,
35
42
  close: async ()=>{
36
43
  await close();
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-gmail/src/setup/stdio.ts"],"sourcesContent":["import { composeMiddleware, connectStdio, registerPrompts, registerResources, registerTools } from '@mcp-z/server';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { RuntimeOverrides, ServerConfig } from '../types.ts';\nimport { createDefaultRuntime } from './runtime.ts';\n\nexport async function createStdioServer(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\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 logger.info(`Starting ${config.name} MCP server (stdio)`);\n const { close } = await connectStdio(mcpServer, { logger });\n logger.info('stdio transport ready');\n\n return {\n mcpServer,\n logger,\n close: async () => {\n await close();\n await runtime.close();\n },\n };\n}\n"],"names":["composeMiddleware","connectStdio","registerPrompts","registerResources","registerTools","McpServer","createDefaultRuntime","createStdioServer","config","overrides","runtime","modules","createDomainModules","layers","middlewareFactories","map","factory","deps","composed","logger","tools","oauthAdapters","accountTools","filteredTools","auth","filter","tool","name","prompts","accountPrompts","mcpServer","version","resources","info","close"],"mappings":"AAAA,SAASA,iBAAiB,EAAEC,YAAY,EAAEC,eAAe,EAAEC,iBAAiB,EAAEC,aAAa,QAAQ,gBAAgB;AACnH,SAASC,SAAS,QAAQ,0CAA0C;AAEpE,SAASC,oBAAoB,QAAQ,eAAe;AAEpD,OAAO,eAAeC,kBAAkBC,MAAoB,EAAEC,SAA4B;IACxF,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,WAAWlB,kBAAkBW,SAASE;IAC5C,MAAMM,SAAST,QAAQO,IAAI,CAACE,MAAM;IAElC,MAAMC,QAAQ;WAAIF,SAASE,KAAK;WAAKV,QAAQO,IAAI,CAACI,aAAa,CAACC,YAAY;KAAC;IAC7E,MAAMC,gBACJf,OAAOgB,IAAI,KAAK,QACZJ,MAAMK,MAAM,CAAC,CAACC,OAASA,KAAKC,IAAI,KAAK,uBAAuB,uDAAuD;OACnHP;IACN,MAAMQ,UAAU;WAAIV,SAASU,OAAO;WAAKlB,QAAQO,IAAI,CAACI,aAAa,CAACQ,cAAc;KAAC;IAEnF,MAAMC,YAAY,IAAIzB,UAAU;QAAEsB,MAAMnB,OAAOmB,IAAI;QAAEI,SAASvB,OAAOuB,OAAO;IAAC;IAC7E3B,cAAc0B,WAAWP;IACzBpB,kBAAkB2B,WAAWZ,SAASc,SAAS;IAC/C9B,gBAAgB4B,WAAWF;IAE3BT,OAAOc,IAAI,CAAC,CAAC,SAAS,EAAEzB,OAAOmB,IAAI,CAAC,mBAAmB,CAAC;IACxD,MAAM,EAAEO,KAAK,EAAE,GAAG,MAAMjC,aAAa6B,WAAW;QAAEX;IAAO;IACzDA,OAAOc,IAAI,CAAC;IAEZ,OAAO;QACLH;QACAX;QACAe,OAAO;YACL,MAAMA;YACN,MAAMxB,QAAQwB,KAAK;QACrB;IACF;AACF"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-gmail/src/setup/stdio.ts"],"sourcesContent":["import { composeMiddleware, connectStdio, defaultCacheHints, McpServer, registerPrompts, registerResources, registerTools } from '@mcp-z/server';\nimport type { RuntimeOverrides, ServerConfig } from '../types.ts';\nimport { createDefaultRuntime } from './runtime.ts';\n\nexport async function createStdioServer(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\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 // Built per request (HTTP) and per connection (stdio), not shared. The SDK caches the\n // negotiated protocol revision on the McpServer instance - its own docs say a negotiated\n // session never re-routes a method onto the other era - so one shared instance pins itself\n // to whichever revision reaches it first and answers the other with -32601.\n const buildServer = () => {\n const mcpServer = new McpServer({ name: config.name, version: config.version }, { cacheHints: defaultCacheHints });\n registerTools(mcpServer, filteredTools);\n registerResources(mcpServer, composed.resources);\n registerPrompts(mcpServer, prompts);\n return mcpServer;\n };\n\n logger.info(`Starting ${config.name} MCP server (stdio)`);\n const { close } = await connectStdio(buildServer, { logger });\n logger.info('stdio transport ready');\n\n return {\n logger,\n close: async () => {\n await close();\n await runtime.close();\n },\n };\n}\n"],"names":["composeMiddleware","connectStdio","defaultCacheHints","McpServer","registerPrompts","registerResources","registerTools","createDefaultRuntime","createStdioServer","config","overrides","runtime","modules","createDomainModules","layers","middlewareFactories","map","factory","deps","composed","logger","tools","oauthAdapters","accountTools","filteredTools","auth","filter","tool","name","prompts","accountPrompts","buildServer","mcpServer","version","cacheHints","resources","info","close"],"mappings":"AAAA,SAASA,iBAAiB,EAAEC,YAAY,EAAEC,iBAAiB,EAAEC,SAAS,EAAEC,eAAe,EAAEC,iBAAiB,EAAEC,aAAa,QAAQ,gBAAgB;AAEjJ,SAASC,oBAAoB,QAAQ,eAAe;AAEpD,OAAO,eAAeC,kBAAkBC,MAAoB,EAAEC,SAA4B;IACxF,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,WAAWnB,kBAAkBY,SAASE;IAC5C,MAAMM,SAAST,QAAQO,IAAI,CAACE,MAAM;IAElC,MAAMC,QAAQ;WAAIF,SAASE,KAAK;WAAKV,QAAQO,IAAI,CAACI,aAAa,CAACC,YAAY;KAAC;IAC7E,MAAMC,gBACJf,OAAOgB,IAAI,KAAK,QACZJ,MAAMK,MAAM,CAAC,CAACC,OAASA,KAAKC,IAAI,KAAK,uBAAuB,uDAAuD;OACnHP;IACN,MAAMQ,UAAU;WAAIV,SAASU,OAAO;WAAKlB,QAAQO,IAAI,CAACI,aAAa,CAACQ,cAAc;KAAC;IAEnF,sFAAsF;IACtF,yFAAyF;IACzF,2FAA2F;IAC3F,4EAA4E;IAC5E,MAAMC,cAAc;QAClB,MAAMC,YAAY,IAAI7B,UAAU;YAAEyB,MAAMnB,OAAOmB,IAAI;YAAEK,SAASxB,OAAOwB,OAAO;QAAC,GAAG;YAAEC,YAAYhC;QAAkB;QAChHI,cAAc0B,WAAWR;QACzBnB,kBAAkB2B,WAAWb,SAASgB,SAAS;QAC/C/B,gBAAgB4B,WAAWH;QAC3B,OAAOG;IACT;IAEAZ,OAAOgB,IAAI,CAAC,CAAC,SAAS,EAAE3B,OAAOmB,IAAI,CAAC,mBAAmB,CAAC;IACxD,MAAM,EAAES,KAAK,EAAE,GAAG,MAAMpC,aAAa8B,aAAa;QAAEX;IAAO;IAC3DA,OAAOgB,IAAI,CAAC;IAEZ,OAAO;QACLhB;QACAiB,OAAO;YACL,MAAMA;YACN,MAAM1B,QAAQ0B,KAAK;QACrB;IACF;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-z/mcp-gmail",
3
- "version": "1.1.4",
3
+ "version": "1.2.0",
4
4
  "description": "MCP server for Gmail integration with OAuth authentication, message search, batch operations, and Google Sheets export",
5
5
  "keywords": [
6
6
  "gmail",
@@ -67,29 +67,28 @@
67
67
  "version": "tsds version"
68
68
  },
69
69
  "dependencies": {
70
+ "@googleapis/gmail": "^18.0.0",
70
71
  "@mcp-z/email": "^1.0.0",
71
- "@mcp-z/oauth": "^1.0.5",
72
- "@mcp-z/oauth-google": "^1.1.3",
73
- "@mcp-z/server": "^1.2.0",
74
- "@modelcontextprotocol/sdk": "^1.0.0",
72
+ "@mcp-z/oauth": "^2.0.0",
73
+ "@mcp-z/oauth-google": "^2.0.1",
74
+ "@mcp-z/server": "^2.2.0",
75
75
  "cors": "^2.0.0",
76
76
  "csv-stringify": "^6.0.0",
77
77
  "express": "^5.0.0",
78
- "googleapis": "174.0.1",
79
78
  "keyv-file": "5.3.3",
80
79
  "keyv-registry": "^2.0.0",
81
80
  "module-root-sync": "^2.0.0",
82
81
  "node-html-parser": "^9.0.1",
83
82
  "pino": "^10.0.0",
84
- "zod": "^4.0.0"
83
+ "zod": "^4.2.0"
85
84
  },
86
85
  "devDependencies": {
87
- "@mcp-z/client": "^1.0.11",
86
+ "@mcp-z/client": "^2.0.0",
87
+ "@modelcontextprotocol/sdk": "^1.0.0",
88
88
  "@types/cors": "^2.8.19",
89
89
  "@types/express": "^5.0.6",
90
90
  "@types/mocha": "^10.0.10",
91
91
  "@types/node": "^26.2.0",
92
- "dotenv": "^17.2.3",
93
92
  "fs-remove-compat": "^1.0.4",
94
93
  "get-port": "5.1.1",
95
94
  "keyv": "^5.0.0",