@mcp-z/mcp-outlook 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/mcp/tools/messages-export-csv.js +4 -4
- package/dist/cjs/mcp/tools/messages-export-csv.js.map +1 -1
- package/dist/cjs/setup/config.d.cts +3 -2
- package/dist/cjs/setup/config.d.ts +3 -2
- package/dist/cjs/setup/config.js +19 -8
- package/dist/cjs/setup/config.js.map +1 -1
- package/dist/cjs/setup/http.js +1 -1
- package/dist/cjs/setup/http.js.map +1 -1
- package/dist/cjs/setup/runtime.js +6 -6
- package/dist/cjs/setup/runtime.js.map +1 -1
- package/dist/cjs/types.d.cts +2 -2
- package/dist/cjs/types.d.ts +2 -2
- package/dist/esm/mcp/tools/messages-export-csv.js +3 -3
- package/dist/esm/mcp/tools/messages-export-csv.js.map +1 -1
- package/dist/esm/setup/config.d.ts +3 -2
- package/dist/esm/setup/config.js +25 -12
- package/dist/esm/setup/config.js.map +1 -1
- package/dist/esm/setup/http.js +1 -1
- package/dist/esm/setup/http.js.map +1 -1
- package/dist/esm/setup/runtime.js +5 -5
- package/dist/esm/setup/runtime.js.map +1 -1
- package/dist/esm/types.d.ts +2 -2
- package/dist/esm/types.js.map +1 -1
- package/package.json +18 -19
|
@@ -250,14 +250,14 @@ var config = {
|
|
|
250
250
|
* - NO RETRIES (fail fast on error)
|
|
251
251
|
*/ function handler(_0, _1) {
|
|
252
252
|
return _async_to_generator(function(param, extra) {
|
|
253
|
-
var query, maxItems, filename, contentType, excludeThreadHistory, logger, storageContext, transport,
|
|
253
|
+
var query, maxItems, filename, contentType, excludeThreadHistory, logger, storageContext, transport, resourceStoreUri, baseUrl, reservation, storedName, fullPath, graph, csvHeaders, writeStream, headerLine, totalRows, nextPageToken, started, _exec_metadata, remainingItems, pageSize, exec, csvRows, rowsContent, durationMs, truncated, uri, result, error, _cleanupError, message;
|
|
254
254
|
return _ts_generator(this, function(_state) {
|
|
255
255
|
switch(_state.label){
|
|
256
256
|
case 0:
|
|
257
257
|
query = param.query, maxItems = param.maxItems, filename = param.filename, contentType = param.contentType, excludeThreadHistory = param.excludeThreadHistory;
|
|
258
258
|
logger = extra.logger;
|
|
259
259
|
storageContext = extra.storageContext;
|
|
260
|
-
transport = storageContext.transport,
|
|
260
|
+
transport = storageContext.transport, resourceStoreUri = storageContext.resourceStoreUri, baseUrl = storageContext.baseUrl;
|
|
261
261
|
logger.info('outlook.messages.export-csv called', {
|
|
262
262
|
query: query,
|
|
263
263
|
maxItems: maxItems,
|
|
@@ -267,7 +267,7 @@ var config = {
|
|
|
267
267
|
return [
|
|
268
268
|
4,
|
|
269
269
|
(0, _server.reserveFile)(filename, {
|
|
270
|
-
|
|
270
|
+
resourceStoreUri: resourceStoreUri
|
|
271
271
|
})
|
|
272
272
|
];
|
|
273
273
|
case 1:
|
|
@@ -455,7 +455,7 @@ var config = {
|
|
|
455
455
|
});
|
|
456
456
|
// Generate URI based on transport type (stdio: file://, HTTP: http://)
|
|
457
457
|
uri = (0, _server.getFileUri)(storedName, transport, _object_spread_props(_object_spread({
|
|
458
|
-
|
|
458
|
+
resourceStoreUri: resourceStoreUri
|
|
459
459
|
}, baseUrl && {
|
|
460
460
|
baseUrl: baseUrl
|
|
461
461
|
}), {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/src/mcp/tools/messages-export-csv.ts"],"sourcesContent":["/** Outlook message CSV export tool - streams results to file without loading all data into context */\n\nimport { EmailContentTypeSchema, ExcludeThreadHistorySchema, extractCurrentMessageFromHtml, extractCurrentMessageFromHtmlToText } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-microsoft';\nimport { schemas } from '@mcp-z/oauth-microsoft';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { getFileUri, reserveFile, type ToolModule } from '@mcp-z/server';\nimport { Client } from '@microsoft/microsoft-graph-client';\nimport type * as MicrosoftGraph from '@microsoft/microsoft-graph-types';\nimport { type CallToolResult, ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\nimport { stringify } from 'csv-stringify/sync';\nimport { createWriteStream } from 'fs';\nimport { unlink } from 'fs/promises';\nimport { z } from 'zod';\nimport { executeQuery as executeOutlookQuery } from '../../email/querying/execute-query.ts';\nimport { OutlookQuerySchema } from '../../schemas/outlook-query-schema.ts';\nimport type { StorageExtra } from '../../types.ts';\n\nconst DEFAULT_PAGE_SIZE = 50;\nconst DEFAULT_MAX_ITEMS = 10000;\nconst MAX_EXPORT_ITEMS = 50000;\n\nconst ExportResultSchema = z.object({\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 inputSchema = z.object({\n query: OutlookQuerySchema.optional().describe('Structured query object for filtering messages. Use query-syntax prompt for reference.'),\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('outlook-messages.csv').describe('Output filename (default: outlook-messages.csv)'),\n contentType: EmailContentTypeSchema,\n excludeThreadHistory: ExcludeThreadHistorySchema,\n});\n\n// Success branch schema\nconst successBranchSchema = ExportResultSchema.extend({\n type: z.literal('success'),\n});\n\n// Output schema with auth_required support\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Export Outlook 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 outlook-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): Promise<CallToolResult> {\n const logger = extra.logger;\n const { storageContext } = extra;\n const { transport, storageDir, baseUrl } = storageContext;\n\n logger.info('outlook.messages.export-csv called', {\n query,\n maxItems,\n filename,\n accountId: extra.authContext.accountId,\n });\n\n // Reserve file location for streaming write (creates directory, generates ID, formats filename)\n const reservation = await reserveFile(filename, {\n storageDir,\n });\n const { storedName, fullPath } = reservation;\n\n logger.info('outlook.messages.export-csv starting streaming export', { path: fullPath, maxItems });\n\n try {\n const graph = Client.initWithMiddleware({ authProvider: 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: Array<{\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 metadata?: { nextPageToken?: string };\n } = await executeOutlookQuery(\n graph,\n query,\n {\n logger,\n pageSize,\n ...(nextPageToken !== undefined && { pageToken: nextPageToken }),\n includeBody: true, // Always include body for CSV export\n limit: pageSize,\n },\n (m: unknown) => {\n const message = m as MicrosoftGraph.Message;\n const to = Array.isArray(message?.toRecipients)\n ? message.toRecipients\n .map((r: MicrosoftGraph.Recipient) => r?.emailAddress?.address ?? (r as { address?: string })?.address)\n .filter(Boolean)\n .join(', ')\n : '';\n const cc = Array.isArray(message?.ccRecipients)\n ? message.ccRecipients\n .map((r: MicrosoftGraph.Recipient) => r?.emailAddress?.address ?? (r as { address?: string })?.address)\n .filter(Boolean)\n .join(', ')\n : '';\n const bcc = Array.isArray(message?.bccRecipients)\n ? message.bccRecipients\n .map((r: MicrosoftGraph.Recipient) => r?.emailAddress?.address ?? (r as { address?: string })?.address)\n .filter(Boolean)\n .join(', ')\n : '';\n const fromAddr = message?.from?.emailAddress?.address ?? (message?.from as { address?: string })?.address ?? '';\n const categories = Array.isArray(message?.categories) ? message.categories.join(';') : '';\n\n // Process body based on contentType and excludeThreadHistory options\n let body = message?.body?.content ?? '';\n const isHtml = message?.body?.contentType?.toLowerCase() === 'html';\n\n if (isHtml && excludeThreadHistory) {\n body = extractCurrentMessageFromHtml(body);\n }\n\n if (isHtml && contentType === 'text') {\n body = excludeThreadHistory ? extractCurrentMessageFromHtmlToText(body) : extractCurrentMessageFromHtmlToText(message?.body?.content ?? '');\n }\n\n return {\n id: String(message?.id ?? ''),\n threadId: message?.conversationId ? String(message.conversationId) : '',\n from: fromAddr,\n to,\n cc,\n bcc,\n subject: message?.subject ?? '',\n date: message?.receivedDateTime ?? '',\n snippet: message?.bodyPreview ?? '',\n body,\n provider: 'outlook' as const,\n labels: categories,\n };\n }\n );\n\n const csvRows = exec.items.map((item) => {\n return [item.id, item.threadId, item.from, item.to, item.cc, item.bcc, item.subject, item.date, item.snippet, item.body, item.provider, item.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('outlook.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('outlook.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 storageDir,\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('outlook.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":["createTool","AuthRequiredBranchSchema","schemas","DEFAULT_PAGE_SIZE","DEFAULT_MAX_ITEMS","MAX_EXPORT_ITEMS","ExportResultSchema","z","object","uri","string","describe","filename","rowCount","number","truncated","boolean","inputSchema","query","OutlookQuerySchema","optional","maxItems","int","positive","max","default","trim","min","contentType","EmailContentTypeSchema","excludeThreadHistory","ExcludeThreadHistorySchema","successBranchSchema","extend","type","literal","outputSchema","discriminatedUnion","config","description","result","handler","extra","logger","storageContext","transport","storageDir","baseUrl","reservation","storedName","fullPath","graph","csvHeaders","writeStream","headerLine","totalRows","nextPageToken","started","exec","remainingItems","pageSize","csvRows","rowsContent","durationMs","error","_cleanupError","message","info","accountId","authContext","reserveFile","path","Client","initWithMiddleware","authProvider","auth","createWriteStream","encoding","stringify","header","quoted","quote","escape","write","Date","now","Math","executeOutlookQuery","undefined","pageToken","includeBody","limit","m","to","Array","isArray","toRecipients","map","r","emailAddress","address","filter","Boolean","join","cc","ccRecipients","bcc","bccRecipients","fromAddr","from","categories","body","content","isHtml","toLowerCase","extractCurrentMessageFromHtml","extractCurrentMessageFromHtmlToText","id","String","threadId","conversationId","subject","date","receivedDateTime","snippet","bodyPreview","provider","labels","items","item","length","metadata","batchSize","hasMore","Promise","resolve","reject","end","on","getFileUri","endpoint","text","JSON","structuredContent","unlink","debug","Error","McpError","ErrorCode","InternalError","stack","name"],"mappings":"AAAA,oGAAoG;;;;+BA8QpG;;;eAAwBA;;;qBA5Q+G;8BAE/G;sBAIiC;oCAClC;qBAEkC;oBAC/B;kBACQ;wBACX;mBACL;8BACkC;oCACjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAXnC,IAAM,AAAEC,2BAA6BC,uBAAO,CAApCD;AAcR,IAAME,oBAAoB;AAC1B,IAAMC,oBAAoB;AAC1B,IAAMC,mBAAmB;AAEzB,IAAMC,qBAAqBC,MAAC,CAACC,MAAM,CAAC;IAClCC,KAAKF,MAAC,CAACG,MAAM,GAAGC,QAAQ,CAAC;IACzBC,UAAUL,MAAC,CAACG,MAAM,GAAGC,QAAQ,CAAC;IAC9BE,UAAUN,MAAC,CAACO,MAAM,GAAGH,QAAQ,CAAC;IAC9BI,WAAWR,MAAC,CAACS,OAAO,GAAGL,QAAQ,CAAC;AAClC;AAEA,IAAMM,cAAcV,MAAC,CAACC,MAAM,CAAC;IAC3BU,OAAOC,wCAAkB,CAACC,QAAQ,GAAGT,QAAQ,CAAC;IAC9CU,UAAUd,MAAC,CAACO,MAAM,GAAGQ,GAAG,GAAGC,QAAQ,GAAGC,GAAG,CAACnB,kBAAkBoB,OAAO,CAACrB,mBAAmBO,QAAQ,CAAC,AAAC,wCAAkEN,OAA3BD,mBAAkB,WAA0B,OAAjBC,kBAAiB;IACpLO,UAAUL,MAAC,CAACG,MAAM,GAAGgB,IAAI,GAAGC,GAAG,CAAC,GAAGF,OAAO,CAAC,wBAAwBd,QAAQ,CAAC;IAC5EiB,aAAaC,6BAAsB;IACnCC,sBAAsBC,iCAA0B;AAClD;AAEA,wBAAwB;AACxB,IAAMC,sBAAsB1B,mBAAmB2B,MAAM,CAAC;IACpDC,MAAM3B,MAAC,CAAC4B,OAAO,CAAC;AAClB;AAEA,2CAA2C;AAC3C,IAAMC,eAAe7B,MAAC,CAAC8B,kBAAkB,CAAC,QAAQ;IAACL;IAAqB/B;CAAyB;AAEjG,IAAMqC,SAAS;IACbC,aAAa;IACbtB,aAAaA;IACbmB,cAAc7B,MAAC,CAACC,MAAM,CAAC;QACrBgC,QAAQJ;IACV;AACF;AAKA;;;;;;;;;CASC,GACD,SAAeK;wCAAQ,KAAuE,EAAEC,KAAmC;YAA1GxB,OAAOG,UAAUT,UAAUgB,aAAaE,sBACzDa,QACEC,gBACAC,WAAWC,YAAYC,SAUzBC,aAGEC,YAAYC,UAKZC,OAGAC,YAGAC,aACAC,YAKFC,WACAC,eACEC,SA+FYC,gBA5FVC,gBACAC,UAEAF,MA8EAG,SAMEC,aAyBJC,YACAhD,WAUAN,KAMA+B,QAiBCwB,OAKEC,eAIHC;;;;oBAjMehD,QAAF,MAAEA,OAAOG,WAAT,MAASA,UAAUT,WAAnB,MAAmBA,UAAUgB,cAA7B,MAA6BA,aAAaE,uBAA1C,MAA0CA;oBACzDa,SAASD,MAAMC,MAAM;oBACnBC,iBAAmBF,MAAnBE;oBACAC,YAAmCD,eAAnCC,WAAWC,aAAwBF,eAAxBE,YAAYC,UAAYH,eAAZG;oBAE/BJ,OAAOwB,IAAI,CAAC,sCAAsC;wBAChDjD,OAAAA;wBACAG,UAAAA;wBACAT,UAAAA;wBACAwD,WAAW1B,MAAM2B,WAAW,CAACD,SAAS;oBACxC;oBAGoB;;wBAAME,IAAAA,mBAAW,EAAC1D,UAAU;4BAC9CkC,YAAAA;wBACF;;;oBAFME,cAAc;oBAGZC,aAAyBD,YAAzBC,YAAYC,WAAaF,YAAbE;oBAEpBP,OAAOwB,IAAI,CAAC,yDAAyD;wBAAEI,MAAMrB;wBAAU7B,UAAAA;oBAAS;;;;;;;;;oBAGxF8B,QAAQqB,4BAAM,CAACC,kBAAkB,CAAC;wBAAEC,cAAchC,MAAM2B,WAAW,CAACM,IAAI;oBAAC;oBAE/E,wCAAwC;oBAClCvB;wBAAc;wBAAM;wBAAY;wBAAQ;wBAAM;wBAAM;wBAAO;wBAAW;wBAAQ;wBAAW;wBAAQ;wBAAY;;oBAEnH,oDAAoD;oBAC9CC,cAAcuB,IAAAA,qBAAiB,EAAC1B,UAAU;wBAAE2B,UAAU;oBAAQ;oBAC9DvB,aAAawB,IAAAA,eAAS;wBAAE1B;uBAAa;wBAAE2B,QAAQ;wBAAOC,QAAQ;wBAAMC,OAAO;wBAAKC,QAAQ;oBAAI;oBAClG7B,YAAY8B,KAAK,CAAC7B;oBAElB,2DAA2D;oBAC3D,yEAAyE;oBACrEC,YAAY;oBAEVE,UAAU2B,KAAKC,GAAG;;;yBAEjB9B,CAAAA,YAAYlC,QAAO;;;;oBAClBsC,iBAAiBtC,WAAWkC;oBAC5BK,WAAW0B,KAAK3D,GAAG,CAACgC,gBAAgBxD;oBAkBtC;;wBAAMoF,IAAAA,4BAAmB,EAC3BpC,OACAjC,OACA;4BACEyB,QAAAA;4BACAiB,UAAAA;2BACIJ,kBAAkBgC,aAAa;4BAAEC,WAAWjC;wBAAc;4BAC9DkC,aAAa;4BACbC,OAAO/B;4BAET,SAACgC;gCAoBkB1B;gCAAAA,4BAAAA,eAAyCA,gBAI/CA,eACIA,2BAAAA;4BAxBf,IAAMA,UAAU0B;4BAChB,IAAMC,KAAKC,MAAMC,OAAO,CAAC7B,oBAAAA,8BAAAA,QAAS8B,YAAY,IAC1C9B,QAAQ8B,YAAY,CACjBC,GAAG,CAAC,SAACC;;oCAAgCA;+CAAAA,cAAAA,yBAAAA,kBAAAA,EAAGC,YAAY,cAAfD,sCAAAA,gBAAiBE,OAAO,uCAAKF,cAAAA,wBAAD,AAACA,EAA4BE,OAAO;+BACrGC,MAAM,CAACC,SACPC,IAAI,CAAC,QACR;4BACJ,IAAMC,KAAKV,MAAMC,OAAO,CAAC7B,oBAAAA,8BAAAA,QAASuC,YAAY,IAC1CvC,QAAQuC,YAAY,CACjBR,GAAG,CAAC,SAACC;;oCAAgCA;+CAAAA,cAAAA,yBAAAA,kBAAAA,EAAGC,YAAY,cAAfD,sCAAAA,gBAAiBE,OAAO,uCAAKF,cAAAA,wBAAD,AAACA,EAA4BE,OAAO;+BACrGC,MAAM,CAACC,SACPC,IAAI,CAAC,QACR;4BACJ,IAAMG,MAAMZ,MAAMC,OAAO,CAAC7B,oBAAAA,8BAAAA,QAASyC,aAAa,IAC5CzC,QAAQyC,aAAa,CAClBV,GAAG,CAAC,SAACC;;oCAAgCA;+CAAAA,cAAAA,yBAAAA,kBAAAA,EAAGC,YAAY,cAAfD,sCAAAA,gBAAiBE,OAAO,uCAAKF,cAAAA,wBAAD,AAACA,EAA4BE,OAAO;+BACrGC,MAAM,CAACC,SACPC,IAAI,CAAC,QACR;4BACJ,IAAMK,YAAW1C,gBAAAA,oBAAAA,+BAAAA,gBAAAA,QAAS2C,IAAI,cAAb3C,qCAAAA,6BAAAA,cAAeiC,YAAY,cAA3BjC,iDAAAA,2BAA6BkC,OAAO,yCAAKlC,oBAAAA,+BAAAA,iBAAAA,QAAS2C,IAAI,cAAb3C,qCAAD,AAACA,eAAwCkC,OAAO,cAAxFlC,kBAAAA,OAA4F;4BAC7G,IAAM4C,aAAahB,MAAMC,OAAO,CAAC7B,oBAAAA,8BAAAA,QAAS4C,UAAU,IAAI5C,QAAQ4C,UAAU,CAACP,IAAI,CAAC,OAAO;4BAEvF,qEAAqE;4BACrE,IAAIQ,gBAAO7C,oBAAAA,+BAAAA,gBAAAA,QAAS6C,IAAI,cAAb7C,oCAAAA,cAAe8C,OAAO,yCAAI;4BACrC,IAAMC,SAAS/C,CAAAA,oBAAAA,+BAAAA,iBAAAA,QAAS6C,IAAI,cAAb7C,sCAAAA,4BAAAA,eAAetC,WAAW,cAA1BsC,gDAAAA,0BAA4BgD,WAAW,QAAO;4BAE7D,IAAID,UAAUnF,sBAAsB;gCAClCiF,OAAOI,IAAAA,oCAA6B,EAACJ;4BACvC;4BAEA,IAAIE,UAAUrF,gBAAgB,QAAQ;;oCAC0EsC;gCAA9G6C,OAAOjF,uBAAuBsF,IAAAA,0CAAmC,EAACL,QAAQK,IAAAA,0CAAmC,WAAClD,oBAAAA,+BAAAA,iBAAAA,QAAS6C,IAAI,cAAb7C,qCAAAA,eAAe8C,OAAO,yCAAI;4BAC1I;4BAEA,OAAO;gCACLK,IAAIC,gBAAOpD,oBAAAA,8BAAAA,QAASmD,EAAE,yCAAI;gCAC1BE,UAAUrD,CAAAA,oBAAAA,8BAAAA,QAASsD,cAAc,IAAGF,OAAOpD,QAAQsD,cAAc,IAAI;gCACrEX,MAAMD;gCACNf,IAAAA;gCACAW,IAAAA;gCACAE,KAAAA;gCACAe,OAAO,WAAEvD,oBAAAA,8BAAAA,QAASuD,OAAO,yCAAI;gCAC7BC,IAAI,WAAExD,oBAAAA,8BAAAA,QAASyD,gBAAgB,yCAAI;gCACnCC,OAAO,WAAE1D,oBAAAA,8BAAAA,QAAS2D,WAAW,yCAAI;gCACjCd,MAAAA;gCACAe,UAAU;gCACVC,QAAQjB;4BACV;wBACF;;;oBA3EIpD,OAgBF;oBA8DEG,UAAUH,KAAKsE,KAAK,CAAC/B,GAAG,CAAC,SAACgC;wBAC9B,OAAO;4BAACA,KAAKZ,EAAE;4BAAEY,KAAKV,QAAQ;4BAAEU,KAAKpB,IAAI;4BAAEoB,KAAKpC,EAAE;4BAAEoC,KAAKzB,EAAE;4BAAEyB,KAAKvB,GAAG;4BAAEuB,KAAKR,OAAO;4BAAEQ,KAAKP,IAAI;4BAAEO,KAAKL,OAAO;4BAAEK,KAAKlB,IAAI;4BAAEkB,KAAKH,QAAQ;4BAAEG,KAAKF,MAAM;yBAAC;oBACtJ;oBAEA,sCAAsC;oBACtC,IAAIlE,QAAQqE,MAAM,GAAG,GAAG;wBAChBpE,cAAcgB,IAAAA,eAAS,EAACjB,SAAS;4BAAEkB,QAAQ;4BAAOC,QAAQ;4BAAMC,OAAO;4BAAKC,QAAQ;wBAAI;wBAC9F7B,YAAY8B,KAAK,CAACrB;oBACpB;oBAEAP,aAAaG,KAAKsE,KAAK,CAACE,MAAM;oBAC9B1E,iBAAgBE,iBAAAA,KAAKyE,QAAQ,cAAbzE,qCAAAA,eAAeF,aAAa;oBAE5Cb,OAAOwB,IAAI,CAAC,6CAA6C;wBACvDiE,WAAW1E,KAAKsE,KAAK,CAACE,MAAM;wBAC5B3E,WAAAA;wBACA8E,SAAS/B,QAAQ9C;oBACnB;oBAEA,8CAA8C;oBAC9C,IAAI,CAACA,iBAAiBE,KAAKsE,KAAK,CAACE,MAAM,KAAK,GAAG;wBAC7C;;;;oBACF;;;;;;oBAGF,qBAAqB;oBACrB;;wBAAM,IAAII,QAAc,SAACC,SAASC;4BAChCnF,YAAYoF,GAAG,CAAC;uCAAMF;;4BACtBlF,YAAYqF,EAAE,CAAC,SAASF;wBAC1B;;;oBAHA;oBAKMzE,aAAaqB,KAAKC,GAAG,KAAK5B;oBAC1B1C,YAAYwC,aAAalC,YAAYiF,QAAQ9C;oBAEnDb,OAAOwB,IAAI,CAAC,yCAAyC;wBACnDtD,UAAU0C;wBACVxC,WAAAA;wBACAgD,YAAAA;wBACAnD,UAAUqC;oBACZ;oBAEA,uEAAuE;oBACjExC,MAAMkI,IAAAA,kBAAU,EAAC1F,YAAYJ,WAAW;wBAC5CC,YAAAA;uBACIC,WAAW;wBAAEA,SAAAA;oBAAQ;wBACzB6F,UAAU;;oBAGNpG,SAAiB;wBACrBN,MAAM;wBACNzB,KAAAA;wBACAG,UAAUqC;wBACVpC,UAAU0C;wBACVxC,WAAAA;oBACF;oBAEA;;wBAAO;4BACLiG,OAAO;gCACL;oCACE9E,MAAM;oCACN2G,MAAMC,KAAKhE,SAAS,CAACtC;gCACvB;;4BAEFuG,mBAAmB;gCAAEvG,QAAAA;4BAAO;wBAC9B;;;oBACOwB;;;;;;;;;oBAGL;;wBAAMgF,IAAAA,gBAAM,EAAC9F;;;oBAAb;oBACAP,OAAOsG,KAAK,CAAC,2CAA2C;wBAAE1E,MAAMrB;oBAAS;;;;;;oBAClEe;oBACPtB,OAAOsG,KAAK,CAAC,+CAA+C;wBAAE1E,MAAMrB;oBAAS;;;;;;oBAGzEgB,UAAUF,AAAK,YAALA,OAAiBkF,SAAQlF,MAAME,OAAO,GAAGoD,OAAOtD;oBAChErB,OAAOqB,KAAK,CAAC,qCAAqC;wBAAEA,OAAOE;oBAAQ;oBAEnE,MAAM,IAAIiF,eAAQ,CAACC,gBAAS,CAACC,aAAa,EAAE,AAAC,oCAA2C,OAARnF,UAAW;wBACzFoF,OAAOtF,AAAK,YAALA,OAAiBkF,SAAQlF,MAAMsF,KAAK,GAAG9D;oBAChD;;;;;;;IAEJ;;AAEe,SAASxF;IACtB,OAAO;QACLuJ,MAAM;QACNjH,QAAAA;QACAG,SAAAA;IACF;AACF"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/src/mcp/tools/messages-export-csv.ts"],"sourcesContent":["/** Outlook message CSV export tool - streams results to file without loading all data into context */\n\nimport { EmailContentTypeSchema, ExcludeThreadHistorySchema, extractCurrentMessageFromHtml, extractCurrentMessageFromHtmlToText } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-microsoft';\nimport { schemas } from '@mcp-z/oauth-microsoft';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { getFileUri, reserveFile, type ToolModule } from '@mcp-z/server';\nimport { Client } from '@microsoft/microsoft-graph-client';\nimport type * as MicrosoftGraph from '@microsoft/microsoft-graph-types';\nimport { type CallToolResult, ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\nimport { stringify } from 'csv-stringify/sync';\nimport { createWriteStream } from 'fs';\nimport { unlink } from 'fs/promises';\nimport { z } from 'zod';\nimport { executeQuery as executeOutlookQuery } from '../../email/querying/execute-query.ts';\nimport { OutlookQuerySchema } from '../../schemas/outlook-query-schema.ts';\nimport type { StorageExtra } from '../../types.ts';\n\nconst DEFAULT_PAGE_SIZE = 50;\nconst DEFAULT_MAX_ITEMS = 10000;\nconst MAX_EXPORT_ITEMS = 50000;\n\nconst ExportResultSchema = z.object({\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 inputSchema = z.object({\n query: OutlookQuerySchema.optional().describe('Structured query object for filtering messages. Use query-syntax prompt for reference.'),\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('outlook-messages.csv').describe('Output filename (default: outlook-messages.csv)'),\n contentType: EmailContentTypeSchema,\n excludeThreadHistory: ExcludeThreadHistorySchema,\n});\n\n// Success branch schema\nconst successBranchSchema = ExportResultSchema.extend({\n type: z.literal('success'),\n});\n\n// Output schema with auth_required support\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Export Outlook 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 outlook-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): Promise<CallToolResult> {\n const logger = extra.logger;\n const { storageContext } = extra;\n const { transport, resourceStoreUri, baseUrl } = storageContext;\n\n logger.info('outlook.messages.export-csv called', {\n query,\n maxItems,\n filename,\n accountId: extra.authContext.accountId,\n });\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('outlook.messages.export-csv starting streaming export', { path: fullPath, maxItems });\n\n try {\n const graph = Client.initWithMiddleware({ authProvider: 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: Array<{\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 metadata?: { nextPageToken?: string };\n } = await executeOutlookQuery(\n graph,\n query,\n {\n logger,\n pageSize,\n ...(nextPageToken !== undefined && { pageToken: nextPageToken }),\n includeBody: true, // Always include body for CSV export\n limit: pageSize,\n },\n (m: unknown) => {\n const message = m as MicrosoftGraph.Message;\n const to = Array.isArray(message?.toRecipients)\n ? message.toRecipients\n .map((r: MicrosoftGraph.Recipient) => r?.emailAddress?.address ?? (r as { address?: string })?.address)\n .filter(Boolean)\n .join(', ')\n : '';\n const cc = Array.isArray(message?.ccRecipients)\n ? message.ccRecipients\n .map((r: MicrosoftGraph.Recipient) => r?.emailAddress?.address ?? (r as { address?: string })?.address)\n .filter(Boolean)\n .join(', ')\n : '';\n const bcc = Array.isArray(message?.bccRecipients)\n ? message.bccRecipients\n .map((r: MicrosoftGraph.Recipient) => r?.emailAddress?.address ?? (r as { address?: string })?.address)\n .filter(Boolean)\n .join(', ')\n : '';\n const fromAddr = message?.from?.emailAddress?.address ?? (message?.from as { address?: string })?.address ?? '';\n const categories = Array.isArray(message?.categories) ? message.categories.join(';') : '';\n\n // Process body based on contentType and excludeThreadHistory options\n let body = message?.body?.content ?? '';\n const isHtml = message?.body?.contentType?.toLowerCase() === 'html';\n\n if (isHtml && excludeThreadHistory) {\n body = extractCurrentMessageFromHtml(body);\n }\n\n if (isHtml && contentType === 'text') {\n body = excludeThreadHistory ? extractCurrentMessageFromHtmlToText(body) : extractCurrentMessageFromHtmlToText(message?.body?.content ?? '');\n }\n\n return {\n id: String(message?.id ?? ''),\n threadId: message?.conversationId ? String(message.conversationId) : '',\n from: fromAddr,\n to,\n cc,\n bcc,\n subject: message?.subject ?? '',\n date: message?.receivedDateTime ?? '',\n snippet: message?.bodyPreview ?? '',\n body,\n provider: 'outlook' as const,\n labels: categories,\n };\n }\n );\n\n const csvRows = exec.items.map((item) => {\n return [item.id, item.threadId, item.from, item.to, item.cc, item.bcc, item.subject, item.date, item.snippet, item.body, item.provider, item.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('outlook.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('outlook.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('outlook.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":["createTool","AuthRequiredBranchSchema","schemas","DEFAULT_PAGE_SIZE","DEFAULT_MAX_ITEMS","MAX_EXPORT_ITEMS","ExportResultSchema","z","object","uri","string","describe","filename","rowCount","number","truncated","boolean","inputSchema","query","OutlookQuerySchema","optional","maxItems","int","positive","max","default","trim","min","contentType","EmailContentTypeSchema","excludeThreadHistory","ExcludeThreadHistorySchema","successBranchSchema","extend","type","literal","outputSchema","discriminatedUnion","config","description","result","handler","extra","logger","storageContext","transport","resourceStoreUri","baseUrl","reservation","storedName","fullPath","graph","csvHeaders","writeStream","headerLine","totalRows","nextPageToken","started","exec","remainingItems","pageSize","csvRows","rowsContent","durationMs","error","_cleanupError","message","info","accountId","authContext","reserveFile","path","Client","initWithMiddleware","authProvider","auth","createWriteStream","encoding","stringify","header","quoted","quote","escape","write","Date","now","Math","executeOutlookQuery","undefined","pageToken","includeBody","limit","m","to","Array","isArray","toRecipients","map","r","emailAddress","address","filter","Boolean","join","cc","ccRecipients","bcc","bccRecipients","fromAddr","from","categories","body","content","isHtml","toLowerCase","extractCurrentMessageFromHtml","extractCurrentMessageFromHtmlToText","id","String","threadId","conversationId","subject","date","receivedDateTime","snippet","bodyPreview","provider","labels","items","item","length","metadata","batchSize","hasMore","Promise","resolve","reject","end","on","getFileUri","endpoint","text","JSON","structuredContent","unlink","debug","Error","McpError","ErrorCode","InternalError","stack","name"],"mappings":"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"}
|
|
@@ -22,7 +22,7 @@ export declare function handleVersionHelp(args: string[]): {
|
|
|
22
22
|
* - --port=<port> Enable HTTP transport on specified port
|
|
23
23
|
* - --stdio Enable stdio transport (default if no port)
|
|
24
24
|
* - --log-level=<level> Logging level (default: info)
|
|
25
|
-
* - --
|
|
25
|
+
* - --resource-store-uri=<uri> Resource store URI for CSV file storage (default: file://~/.mcp-z/mcp-outlook/files)
|
|
26
26
|
* - --base-url=<url> Base URL for HTTP file serving (default: http://localhost for HTTP transports)
|
|
27
27
|
*
|
|
28
28
|
* Environment Variables:
|
|
@@ -34,9 +34,10 @@ export declare function handleVersionHelp(args: string[]): {
|
|
|
34
34
|
* - DCR_MODE DCR mode (optional, same format as --dcr-mode)
|
|
35
35
|
* - DCR_VERIFY_URL External verification URL (optional, same as --dcr-verify-url)
|
|
36
36
|
* - DCR_STORE_URI DCR storage URI (optional, same as --dcr-store-uri)
|
|
37
|
+
* - TOKEN_STORE_URI Token storage URI (optional)
|
|
37
38
|
* - PORT Default HTTP port (optional)
|
|
38
39
|
* - LOG_LEVEL Default logging level (optional)
|
|
39
|
-
* -
|
|
40
|
+
* - RESOURCE_STORE_URI Resource store URI (optional, file://)
|
|
40
41
|
* - BASE_URL Base URL for HTTP file serving (optional)
|
|
41
42
|
*
|
|
42
43
|
* OAuth Scopes (from constants.ts):
|
|
@@ -22,7 +22,7 @@ export declare function handleVersionHelp(args: string[]): {
|
|
|
22
22
|
* - --port=<port> Enable HTTP transport on specified port
|
|
23
23
|
* - --stdio Enable stdio transport (default if no port)
|
|
24
24
|
* - --log-level=<level> Logging level (default: info)
|
|
25
|
-
* - --
|
|
25
|
+
* - --resource-store-uri=<uri> Resource store URI for CSV file storage (default: file://~/.mcp-z/mcp-outlook/files)
|
|
26
26
|
* - --base-url=<url> Base URL for HTTP file serving (default: http://localhost for HTTP transports)
|
|
27
27
|
*
|
|
28
28
|
* Environment Variables:
|
|
@@ -34,9 +34,10 @@ export declare function handleVersionHelp(args: string[]): {
|
|
|
34
34
|
* - DCR_MODE DCR mode (optional, same format as --dcr-mode)
|
|
35
35
|
* - DCR_VERIFY_URL External verification URL (optional, same as --dcr-verify-url)
|
|
36
36
|
* - DCR_STORE_URI DCR storage URI (optional, same as --dcr-store-uri)
|
|
37
|
+
* - TOKEN_STORE_URI Token storage URI (optional)
|
|
37
38
|
* - PORT Default HTTP port (optional)
|
|
38
39
|
* - LOG_LEVEL Default logging level (optional)
|
|
39
|
-
* -
|
|
40
|
+
* - RESOURCE_STORE_URI Resource store URI (optional, file://)
|
|
40
41
|
* - BASE_URL Base URL for HTTP file serving (optional)
|
|
41
42
|
*
|
|
42
43
|
* OAuth Scopes (from constants.ts):
|
package/dist/cjs/setup/config.js
CHANGED
|
@@ -131,7 +131,7 @@ function _type_of(obj) {
|
|
|
131
131
|
return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
|
|
132
132
|
}
|
|
133
133
|
var pkg = JSON.parse(_fs.readFileSync(_path.join((0, _modulerootsync.default)(_url.fileURLToPath(require("url").pathToFileURL(__filename).toString())), 'package.json'), 'utf-8'));
|
|
134
|
-
var HELP_TEXT = "\nUsage: mcp-outlook [options]\n\nMCP server for Outlook/Microsoft email management with OAuth authentication.\n\nOptions:\n --version Show version number\n --help Show this help message\n --auth=<mode> Authentication mode (default: loopback-oauth)\n Modes: loopback-oauth, device-code, dcr\n --headless Disable browser auto-open, return auth URL instead\n --redirect-uri=<uri> OAuth redirect URI (default: ephemeral loopback)\n --tenant-id=<id> Microsoft tenant ID (overrides MS_TENANT_ID env var)\n --dcr-mode=<mode> DCR mode (self-hosted or external, default: self-hosted)\n --dcr-verify-url=<url> External verification endpoint (required for external mode)\n --dcr-store-uri=<uri> DCR client storage URI (required for self-hosted mode)\n --port=<port> Enable HTTP transport on specified port\n --stdio Enable stdio transport (default if no port)\n --log-level=<level> Logging level (default: info)\n --
|
|
134
|
+
var HELP_TEXT = "\nUsage: mcp-outlook [options]\n\nMCP server for Outlook/Microsoft email management with OAuth authentication.\n\nOptions:\n --version Show version number\n --help Show this help message\n --auth=<mode> Authentication mode (default: loopback-oauth)\n Modes: loopback-oauth, device-code, dcr\n --headless Disable browser auto-open, return auth URL instead\n --redirect-uri=<uri> OAuth redirect URI (default: ephemeral loopback)\n --tenant-id=<id> Microsoft tenant ID (overrides MS_TENANT_ID env var)\n --dcr-mode=<mode> DCR mode (self-hosted or external, default: self-hosted)\n --dcr-verify-url=<url> External verification endpoint (required for external mode)\n --dcr-store-uri=<uri> DCR client storage URI (required for self-hosted mode)\n --port=<port> Enable HTTP transport on specified port\n --stdio Enable stdio transport (default if no port)\n --log-level=<level> Logging level (default: info)\n --resource-store-uri=<uri> Resource store URI for CSV file storage (default: file://~/.mcp-z/mcp-outlook/files)\n --base-url=<url> Base URL for HTTP file serving (default: http://localhost for HTTP transports)\n\nEnvironment Variables:\n MS_CLIENT_ID OAuth client ID (REQUIRED)\n MS_TENANT_ID Microsoft tenant ID (REQUIRED)\n MS_CLIENT_SECRET OAuth client secret (optional)\n AUTH_MODE Default authentication mode (optional)\n HEADLESS Disable browser auto-open (optional)\n DCR_MODE DCR mode (optional, same format as --dcr-mode)\n DCR_VERIFY_URL External verification URL (optional, same as --dcr-verify-url)\n DCR_STORE_URI DCR storage URI (optional, same as --dcr-store-uri)\n TOKEN_STORE_URI Token storage URI (optional)\n PORT Default HTTP port (optional)\n LOG_LEVEL Default logging level (optional)\n RESOURCE_STORE_URI Resource store URI (optional, file://)\n BASE_URL Base URL for HTTP file serving (optional)\n\nOAuth Scopes:\n openid profile offline_access https://graph.microsoft.com/User.Read https://graph.microsoft.com/Mail.ReadWrite https://graph.microsoft.com/Mail.Send https://graph.microsoft.com/MailboxSettings.ReadWrite\n\nExamples:\n mcp-outlook # Use default settings\n mcp-outlook --auth=device-code # Use device code auth\n mcp-outlook --port=3000 # HTTP transport on port 3000\n mcp-outlook --tenant-id=xxx # Set tenant ID\n mcp-outlook --resource-store-uri=file:///tmp/emails # Custom resource store URI\n MS_CLIENT_ID=xxx mcp-outlook # Set client ID via env var\n".trim();
|
|
135
135
|
function handleVersionHelp(args) {
|
|
136
136
|
var values = (0, _util.parseArgs)({
|
|
137
137
|
args: args,
|
|
@@ -163,7 +163,7 @@ function parseConfig(args, env) {
|
|
|
163
163
|
var oauthConfig = (0, _oauthmicrosoft.parseConfig)(args, env);
|
|
164
164
|
// Parse DCR configuration if DCR mode is enabled
|
|
165
165
|
var dcrConfig = oauthConfig.auth === 'dcr' ? (0, _oauthmicrosoft.parseDcrConfig)(args, env, _constantsts.MS_SCOPE) : undefined;
|
|
166
|
-
// Parse application-level config (LOG_LEVEL,
|
|
166
|
+
// Parse application-level config (LOG_LEVEL, RESOURCE_STORE_URI, BASE_URL)
|
|
167
167
|
var values = (0, _util.parseArgs)({
|
|
168
168
|
args: args,
|
|
169
169
|
options: {
|
|
@@ -173,7 +173,7 @@ function parseConfig(args, env) {
|
|
|
173
173
|
'base-url': {
|
|
174
174
|
type: 'string'
|
|
175
175
|
},
|
|
176
|
-
'
|
|
176
|
+
'resource-store-uri': {
|
|
177
177
|
type: 'string'
|
|
178
178
|
}
|
|
179
179
|
},
|
|
@@ -200,10 +200,10 @@ function parseConfig(args, env) {
|
|
|
200
200
|
var envLogLevel = env.LOG_LEVEL;
|
|
201
201
|
var logLevel = (_ref1 = cliLogLevel !== null && cliLogLevel !== void 0 ? cliLogLevel : envLogLevel) !== null && _ref1 !== void 0 ? _ref1 : 'info';
|
|
202
202
|
// Parse file storage configuration
|
|
203
|
-
var
|
|
204
|
-
var
|
|
205
|
-
var
|
|
206
|
-
|
|
203
|
+
var cliResourceStoreUri = typeof values['resource-store-uri'] === 'string' ? values['resource-store-uri'] : undefined;
|
|
204
|
+
var envResourceStoreUri = env.RESOURCE_STORE_URI;
|
|
205
|
+
var defaultResourceStorePath = _path.join(baseDir, name, 'files');
|
|
206
|
+
var resourceStoreUri = normalizeResourceStoreUri((_ref2 = cliResourceStoreUri !== null && cliResourceStoreUri !== void 0 ? cliResourceStoreUri : envResourceStoreUri) !== null && _ref2 !== void 0 ? _ref2 : defaultResourceStorePath);
|
|
207
207
|
var cliBaseUrl = typeof values['base-url'] === 'string' ? values['base-url'] : undefined;
|
|
208
208
|
var envBaseUrl = env.BASE_URL;
|
|
209
209
|
var baseUrl = cliBaseUrl !== null && cliBaseUrl !== void 0 ? cliBaseUrl : envBaseUrl;
|
|
@@ -215,7 +215,7 @@ function parseConfig(args, env) {
|
|
|
215
215
|
name: name,
|
|
216
216
|
version: pkg.version,
|
|
217
217
|
repositoryUrl: repositoryUrl,
|
|
218
|
-
|
|
218
|
+
resourceStoreUri: resourceStoreUri
|
|
219
219
|
});
|
|
220
220
|
if (baseUrl !== undefined) result.baseUrl = baseUrl;
|
|
221
221
|
if (dcrConfig !== undefined) result.dcrConfig = dcrConfig;
|
|
@@ -224,4 +224,15 @@ function parseConfig(args, env) {
|
|
|
224
224
|
function createConfig() {
|
|
225
225
|
return parseConfig(process.argv, process.env);
|
|
226
226
|
}
|
|
227
|
+
function normalizeResourceStoreUri(resourceStoreUri) {
|
|
228
|
+
var filePrefix = 'file://';
|
|
229
|
+
if (resourceStoreUri.startsWith(filePrefix)) {
|
|
230
|
+
var rawPath = resourceStoreUri.slice(filePrefix.length);
|
|
231
|
+
var expandedPath = rawPath.startsWith('~') ? rawPath.replace(/^~/, (0, _os.homedir)()) : rawPath;
|
|
232
|
+
return "".concat(filePrefix).concat(_path.resolve(expandedPath));
|
|
233
|
+
}
|
|
234
|
+
if (resourceStoreUri.includes('://')) return resourceStoreUri;
|
|
235
|
+
var expandedPath1 = resourceStoreUri.startsWith('~') ? resourceStoreUri.replace(/^~/, (0, _os.homedir)()) : resourceStoreUri;
|
|
236
|
+
return "".concat(filePrefix).concat(_path.resolve(expandedPath1));
|
|
237
|
+
}
|
|
227
238
|
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/src/setup/config.ts"],"sourcesContent":["import { parseDcrConfig, parseConfig as parseOAuthConfig } from '@mcp-z/oauth-microsoft';\nimport { findConfigPath, parseConfig as parseTransportConfig } from '@mcp-z/server';\nimport * as fs from 'fs';\nimport moduleRoot from 'module-root-sync';\nimport { homedir } from 'os';\nimport * as path from 'path';\nimport * as url from 'url';\nimport { parseArgs } from 'util';\nimport { MS_SCOPE } from '../constants.ts';\nimport type { ServerConfig } from '../types.ts';\n\nconst pkg = JSON.parse(fs.readFileSync(path.join(moduleRoot(url.fileURLToPath(import.meta.url)), 'package.json'), 'utf-8'));\n\nconst HELP_TEXT = `\nUsage: mcp-outlook [options]\n\nMCP server for Outlook/Microsoft email management with OAuth authentication.\n\nOptions:\n --version Show version number\n --help Show this help message\n --auth=<mode> Authentication mode (default: loopback-oauth)\n Modes: loopback-oauth, device-code, dcr\n --headless Disable browser auto-open, return auth URL instead\n --redirect-uri=<uri> OAuth redirect URI (default: ephemeral loopback)\n --tenant-id=<id> Microsoft tenant ID (overrides MS_TENANT_ID env var)\n --dcr-mode=<mode> DCR mode (self-hosted or external, default: self-hosted)\n --dcr-verify-url=<url> External verification endpoint (required for external mode)\n --dcr-store-uri=<uri> DCR client storage URI (required for self-hosted mode)\n --port=<port> Enable HTTP transport on specified port\n --stdio Enable stdio transport (default if no port)\n --log-level=<level> Logging level (default: info)\n --storage-dir=<path> Directory for CSV file storage (default: .mcp-z/files)\n --base-url=<url> Base URL for HTTP file serving (default: http://localhost for HTTP transports)\n\nEnvironment Variables:\n MS_CLIENT_ID OAuth client ID (REQUIRED)\n MS_TENANT_ID Microsoft tenant ID (REQUIRED)\n MS_CLIENT_SECRET OAuth client secret (optional)\n AUTH_MODE Default authentication mode (optional)\n HEADLESS Disable browser auto-open (optional)\n DCR_MODE DCR mode (optional, same format as --dcr-mode)\n DCR_VERIFY_URL External verification URL (optional, same as --dcr-verify-url)\n DCR_STORE_URI DCR storage URI (optional, same as --dcr-store-uri)\n PORT Default HTTP port (optional)\n LOG_LEVEL Default logging level (optional)\n STORAGE_DIR Directory for CSV file storage (optional)\n BASE_URL Base URL for HTTP file serving (optional)\n\nOAuth Scopes:\n openid profile offline_access https://graph.microsoft.com/User.Read https://graph.microsoft.com/Mail.ReadWrite https://graph.microsoft.com/Mail.Send https://graph.microsoft.com/MailboxSettings.ReadWrite\n\nExamples:\n mcp-outlook # Use default settings\n mcp-outlook --auth=device-code # Use device code auth\n mcp-outlook --port=3000 # HTTP transport on port 3000\n mcp-outlook --tenant-id=xxx # Set tenant ID\n mcp-outlook --storage-dir=./emails # Custom storage directory\n MS_CLIENT_ID=xxx mcp-outlook # Set client ID via env var\n`.trim();\n\n/**\n * Handle --version and --help flags before config parsing.\n * These should work without requiring any configuration.\n */\nexport function handleVersionHelp(args: string[]): { handled: boolean; output?: string } {\n const { values } = parseArgs({\n args,\n options: {\n version: { type: 'boolean' },\n help: { type: 'boolean' },\n },\n strict: false,\n });\n\n if (values.version) return { handled: true, output: pkg.version };\n if (values.help) return { handled: true, output: HELP_TEXT };\n return { handled: false };\n}\n\n/**\n * Parse Outlook server configuration from CLI arguments and environment.\n *\n * CLI Arguments (all optional):\n * - --auth=<mode> Authentication mode (default: loopback-oauth)\n * Modes: loopback-oauth, device-code, dcr\n * - --headless Disable browser auto-open, return auth URL instead\n * - --redirect-uri=<uri> OAuth redirect URI (default: ephemeral loopback)\n * - --tenant-id=<id> Microsoft tenant ID (overrides MS_TENANT_ID env var)\n * - --dcr-mode=<mode> DCR mode (self-hosted or external, default: self-hosted)\n * - --dcr-verify-url=<url> External verification endpoint (required for external mode)\n * - --dcr-store-uri=<uri> DCR client storage URI (required for self-hosted mode)\n * - --port=<port> Enable HTTP transport on specified port\n * - --stdio Enable stdio transport (default if no port)\n * - --log-level=<level> Logging level (default: info)\n * - --storage-dir=<path> Directory for CSV file storage (default: .mcp-z/files)\n * - --base-url=<url> Base URL for HTTP file serving (default: http://localhost for HTTP transports)\n *\n * Environment Variables:\n * - MS_CLIENT_ID OAuth client ID (REQUIRED)\n * - MS_TENANT_ID Microsoft tenant ID (REQUIRED)\n * - MS_CLIENT_SECRET OAuth client secret (optional)\n * - AUTH_MODE Default authentication mode (optional)\n * - HEADLESS Disable browser auto-open (optional)\n * - DCR_MODE DCR mode (optional, same format as --dcr-mode)\n * - DCR_VERIFY_URL External verification URL (optional, same as --dcr-verify-url)\n * - DCR_STORE_URI DCR storage URI (optional, same as --dcr-store-uri)\n * - PORT Default HTTP port (optional)\n * - LOG_LEVEL Default logging level (optional)\n * - STORAGE_DIR Directory for CSV file storage (optional)\n * - BASE_URL Base URL for HTTP file serving (optional)\n *\n * OAuth Scopes (from constants.ts):\n * openid profile offline_access https://graph.microsoft.com/User.Read https://graph.microsoft.com/Mail.ReadWrite https://graph.microsoft.com/Mail.Send https://graph.microsoft.com/MailboxSettings.ReadWrite\n */\nexport function parseConfig(args: string[], env: Record<string, string | undefined>): ServerConfig {\n const transportConfig = parseTransportConfig(args, env);\n const oauthConfig = parseOAuthConfig(args, env);\n\n // Parse DCR configuration if DCR mode is enabled\n const dcrConfig = oauthConfig.auth === 'dcr' ? parseDcrConfig(args, env, MS_SCOPE) : undefined;\n\n // Parse application-level config (LOG_LEVEL, STORAGE_DIR, BASE_URL)\n const { values } = parseArgs({\n args,\n options: {\n 'log-level': { type: 'string' },\n 'base-url': { type: 'string' },\n 'storage-dir': { type: 'string' },\n },\n strict: false, // Allow other arguments\n allowPositionals: true,\n });\n\n const name = pkg.name.replace(/^@[^/]+\\//, '');\n // Parse repository URL from package.json, stripping git+ prefix and .git suffix\n const rawRepoUrl = typeof pkg.repository === 'object' ? pkg.repository.url : pkg.repository;\n const repositoryUrl = rawRepoUrl?.replace(/^git\\+/, '').replace(/\\.git$/, '') ?? `https://github.com/mcp-z/${name}`;\n let rootDir = homedir();\n try {\n const configPath = findConfigPath({ config: '.mcp.json', cwd: process.cwd(), stopDir: homedir() });\n rootDir = path.dirname(configPath);\n } catch {\n rootDir = homedir();\n }\n const baseDir = path.join(rootDir, '.mcp-z');\n const cliLogLevel = typeof values['log-level'] === 'string' ? values['log-level'] : undefined;\n const envLogLevel = env.LOG_LEVEL;\n const logLevel = cliLogLevel ?? envLogLevel ?? 'info';\n\n // Parse file storage configuration\n const cliStorageDir = typeof values['storage-dir'] === 'string' ? values['storage-dir'] : undefined;\n const envStorageDir = env.STORAGE_DIR;\n let storageDir = cliStorageDir ?? envStorageDir ?? path.join(baseDir, name, 'files');\n if (storageDir.startsWith('~')) storageDir = storageDir.replace(/^~/, homedir());\n\n const cliBaseUrl = typeof values['base-url'] === 'string' ? values['base-url'] : undefined;\n const envBaseUrl = env.BASE_URL;\n const baseUrl = cliBaseUrl ?? envBaseUrl;\n\n // Combine configs\n const result: ServerConfig = {\n ...oauthConfig, // Includes clientId, auth, headless, redirectUri\n transport: transportConfig.transport,\n logLevel,\n baseDir,\n name,\n version: pkg.version,\n repositoryUrl,\n storageDir: path.resolve(storageDir),\n };\n if (baseUrl !== undefined) result.baseUrl = baseUrl;\n if (dcrConfig !== undefined) result.dcrConfig = dcrConfig;\n return result;\n}\n\n/**\n * Build production configuration from process globals.\n * Entry point for production server.\n */\nexport function createConfig(): ServerConfig {\n return parseConfig(process.argv, process.env);\n}\n"],"names":["createConfig","handleVersionHelp","parseConfig","pkg","JSON","parse","fs","readFileSync","path","join","moduleRoot","url","fileURLToPath","HELP_TEXT","trim","args","values","parseArgs","options","version","type","help","strict","handled","output","env","cliLogLevel","cliStorageDir","transportConfig","parseTransportConfig","oauthConfig","parseOAuthConfig","dcrConfig","auth","parseDcrConfig","MS_SCOPE","undefined","allowPositionals","name","replace","rawRepoUrl","repository","repositoryUrl","rootDir","homedir","configPath","findConfigPath","config","cwd","process","stopDir","dirname","baseDir","envLogLevel","LOG_LEVEL","logLevel","envStorageDir","STORAGE_DIR","storageDir","startsWith","cliBaseUrl","envBaseUrl","BASE_URL","baseUrl","result","transport","resolve","argv"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/src/setup/config.ts"],"sourcesContent":["import { parseDcrConfig, parseConfig as parseOAuthConfig } from '@mcp-z/oauth-microsoft';\nimport { findConfigPath, parseConfig as parseTransportConfig } from '@mcp-z/server';\nimport * as fs from 'fs';\nimport moduleRoot from 'module-root-sync';\nimport { homedir } from 'os';\nimport * as path from 'path';\nimport * as url from 'url';\nimport { parseArgs } from 'util';\nimport { MS_SCOPE } from '../constants.ts';\nimport type { ServerConfig } from '../types.ts';\n\nconst pkg = JSON.parse(fs.readFileSync(path.join(moduleRoot(url.fileURLToPath(import.meta.url)), 'package.json'), 'utf-8'));\n\nconst HELP_TEXT = `\nUsage: mcp-outlook [options]\n\nMCP server for Outlook/Microsoft email management with OAuth authentication.\n\nOptions:\n --version Show version number\n --help Show this help message\n --auth=<mode> Authentication mode (default: loopback-oauth)\n Modes: loopback-oauth, device-code, dcr\n --headless Disable browser auto-open, return auth URL instead\n --redirect-uri=<uri> OAuth redirect URI (default: ephemeral loopback)\n --tenant-id=<id> Microsoft tenant ID (overrides MS_TENANT_ID env var)\n --dcr-mode=<mode> DCR mode (self-hosted or external, default: self-hosted)\n --dcr-verify-url=<url> External verification endpoint (required for external mode)\n --dcr-store-uri=<uri> DCR client storage URI (required for self-hosted mode)\n --port=<port> Enable HTTP transport on specified port\n --stdio Enable stdio transport (default if no port)\n --log-level=<level> Logging level (default: info)\n --resource-store-uri=<uri> Resource store URI for CSV file storage (default: file://~/.mcp-z/mcp-outlook/files)\n --base-url=<url> Base URL for HTTP file serving (default: http://localhost for HTTP transports)\n\nEnvironment Variables:\n MS_CLIENT_ID OAuth client ID (REQUIRED)\n MS_TENANT_ID Microsoft tenant ID (REQUIRED)\n MS_CLIENT_SECRET OAuth client secret (optional)\n AUTH_MODE Default authentication mode (optional)\n HEADLESS Disable browser auto-open (optional)\n DCR_MODE DCR mode (optional, same format as --dcr-mode)\n DCR_VERIFY_URL External verification URL (optional, same as --dcr-verify-url)\n DCR_STORE_URI DCR storage URI (optional, same as --dcr-store-uri)\n TOKEN_STORE_URI Token storage URI (optional)\n PORT Default HTTP port (optional)\n LOG_LEVEL Default logging level (optional)\n RESOURCE_STORE_URI Resource store URI (optional, file://)\n BASE_URL Base URL for HTTP file serving (optional)\n\nOAuth Scopes:\n openid profile offline_access https://graph.microsoft.com/User.Read https://graph.microsoft.com/Mail.ReadWrite https://graph.microsoft.com/Mail.Send https://graph.microsoft.com/MailboxSettings.ReadWrite\n\nExamples:\n mcp-outlook # Use default settings\n mcp-outlook --auth=device-code # Use device code auth\n mcp-outlook --port=3000 # HTTP transport on port 3000\n mcp-outlook --tenant-id=xxx # Set tenant ID\n mcp-outlook --resource-store-uri=file:///tmp/emails # Custom resource store URI\n MS_CLIENT_ID=xxx mcp-outlook # Set client ID via env var\n`.trim();\n\n/**\n * Handle --version and --help flags before config parsing.\n * These should work without requiring any configuration.\n */\nexport function handleVersionHelp(args: string[]): { handled: boolean; output?: string } {\n const { values } = parseArgs({\n args,\n options: {\n version: { type: 'boolean' },\n help: { type: 'boolean' },\n },\n strict: false,\n });\n\n if (values.version) return { handled: true, output: pkg.version };\n if (values.help) return { handled: true, output: HELP_TEXT };\n return { handled: false };\n}\n\n/**\n * Parse Outlook server configuration from CLI arguments and environment.\n *\n * CLI Arguments (all optional):\n * - --auth=<mode> Authentication mode (default: loopback-oauth)\n * Modes: loopback-oauth, device-code, dcr\n * - --headless Disable browser auto-open, return auth URL instead\n * - --redirect-uri=<uri> OAuth redirect URI (default: ephemeral loopback)\n * - --tenant-id=<id> Microsoft tenant ID (overrides MS_TENANT_ID env var)\n * - --dcr-mode=<mode> DCR mode (self-hosted or external, default: self-hosted)\n * - --dcr-verify-url=<url> External verification endpoint (required for external mode)\n * - --dcr-store-uri=<uri> DCR client storage URI (required for self-hosted mode)\n * - --port=<port> Enable HTTP transport on specified port\n * - --stdio Enable stdio transport (default if no port)\n * - --log-level=<level> Logging level (default: info)\n * - --resource-store-uri=<uri> Resource store URI for CSV file storage (default: file://~/.mcp-z/mcp-outlook/files)\n * - --base-url=<url> Base URL for HTTP file serving (default: http://localhost for HTTP transports)\n *\n * Environment Variables:\n * - MS_CLIENT_ID OAuth client ID (REQUIRED)\n * - MS_TENANT_ID Microsoft tenant ID (REQUIRED)\n * - MS_CLIENT_SECRET OAuth client secret (optional)\n * - AUTH_MODE Default authentication mode (optional)\n * - HEADLESS Disable browser auto-open (optional)\n * - DCR_MODE DCR mode (optional, same format as --dcr-mode)\n * - DCR_VERIFY_URL External verification URL (optional, same as --dcr-verify-url)\n * - DCR_STORE_URI DCR storage URI (optional, same as --dcr-store-uri)\n * - TOKEN_STORE_URI Token storage URI (optional)\n * - PORT Default HTTP port (optional)\n * - LOG_LEVEL Default logging level (optional)\n * - RESOURCE_STORE_URI Resource store URI (optional, file://)\n * - BASE_URL Base URL for HTTP file serving (optional)\n *\n * OAuth Scopes (from constants.ts):\n * openid profile offline_access https://graph.microsoft.com/User.Read https://graph.microsoft.com/Mail.ReadWrite https://graph.microsoft.com/Mail.Send https://graph.microsoft.com/MailboxSettings.ReadWrite\n */\nexport function parseConfig(args: string[], env: Record<string, string | undefined>): ServerConfig {\n const transportConfig = parseTransportConfig(args, env);\n const oauthConfig = parseOAuthConfig(args, env);\n\n // Parse DCR configuration if DCR mode is enabled\n const dcrConfig = oauthConfig.auth === 'dcr' ? parseDcrConfig(args, env, MS_SCOPE) : undefined;\n\n // Parse application-level config (LOG_LEVEL, RESOURCE_STORE_URI, BASE_URL)\n const { values } = parseArgs({\n args,\n options: {\n 'log-level': { type: 'string' },\n 'base-url': { type: 'string' },\n 'resource-store-uri': { type: 'string' },\n },\n strict: false, // Allow other arguments\n allowPositionals: true,\n });\n\n const name = pkg.name.replace(/^@[^/]+\\//, '');\n // Parse repository URL from package.json, stripping git+ prefix and .git suffix\n const rawRepoUrl = typeof pkg.repository === 'object' ? pkg.repository.url : pkg.repository;\n const repositoryUrl = rawRepoUrl?.replace(/^git\\+/, '').replace(/\\.git$/, '') ?? `https://github.com/mcp-z/${name}`;\n let rootDir = homedir();\n try {\n const configPath = findConfigPath({ config: '.mcp.json', cwd: process.cwd(), stopDir: homedir() });\n rootDir = path.dirname(configPath);\n } catch {\n rootDir = homedir();\n }\n const baseDir = path.join(rootDir, '.mcp-z');\n const cliLogLevel = typeof values['log-level'] === 'string' ? values['log-level'] : undefined;\n const envLogLevel = env.LOG_LEVEL;\n const logLevel = cliLogLevel ?? envLogLevel ?? 'info';\n\n // Parse file storage configuration\n const cliResourceStoreUri = typeof values['resource-store-uri'] === 'string' ? values['resource-store-uri'] : undefined;\n const envResourceStoreUri = env.RESOURCE_STORE_URI;\n const defaultResourceStorePath = path.join(baseDir, name, 'files');\n const resourceStoreUri = normalizeResourceStoreUri(cliResourceStoreUri ?? envResourceStoreUri ?? defaultResourceStorePath);\n\n const cliBaseUrl = typeof values['base-url'] === 'string' ? values['base-url'] : undefined;\n const envBaseUrl = env.BASE_URL;\n const baseUrl = cliBaseUrl ?? envBaseUrl;\n\n // Combine configs\n const result: ServerConfig = {\n ...oauthConfig, // Includes clientId, auth, headless, redirectUri\n transport: transportConfig.transport,\n logLevel,\n baseDir,\n name,\n version: pkg.version,\n repositoryUrl,\n resourceStoreUri,\n };\n if (baseUrl !== undefined) result.baseUrl = baseUrl;\n if (dcrConfig !== undefined) result.dcrConfig = dcrConfig;\n return result;\n}\n\n/**\n * Build production configuration from process globals.\n * Entry point for production server.\n */\nexport function createConfig(): ServerConfig {\n return parseConfig(process.argv, process.env);\n}\n\nfunction normalizeResourceStoreUri(resourceStoreUri: string): string {\n const filePrefix = 'file://';\n if (resourceStoreUri.startsWith(filePrefix)) {\n const rawPath = resourceStoreUri.slice(filePrefix.length);\n const expandedPath = rawPath.startsWith('~') ? rawPath.replace(/^~/, homedir()) : rawPath;\n return `${filePrefix}${path.resolve(expandedPath)}`;\n }\n\n if (resourceStoreUri.includes('://')) return resourceStoreUri;\n\n const expandedPath = resourceStoreUri.startsWith('~') ? resourceStoreUri.replace(/^~/, homedir()) : resourceStoreUri;\n return `${filePrefix}${path.resolve(expandedPath)}`;\n}\n"],"names":["createConfig","handleVersionHelp","parseConfig","pkg","JSON","parse","fs","readFileSync","path","join","moduleRoot","url","fileURLToPath","HELP_TEXT","trim","args","values","parseArgs","options","version","type","help","strict","handled","output","env","cliLogLevel","cliResourceStoreUri","transportConfig","parseTransportConfig","oauthConfig","parseOAuthConfig","dcrConfig","auth","parseDcrConfig","MS_SCOPE","undefined","allowPositionals","name","replace","rawRepoUrl","repository","repositoryUrl","rootDir","homedir","configPath","findConfigPath","config","cwd","process","stopDir","dirname","baseDir","envLogLevel","LOG_LEVEL","logLevel","envResourceStoreUri","RESOURCE_STORE_URI","defaultResourceStorePath","resourceStoreUri","normalizeResourceStoreUri","cliBaseUrl","envBaseUrl","BASE_URL","baseUrl","result","transport","argv","filePrefix","startsWith","rawPath","slice","length","expandedPath","resolve","includes"],"mappings":"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"}
|
package/dist/cjs/setup/http.js
CHANGED
|
@@ -210,7 +210,7 @@ function createHTTPServer(config, overrides) {
|
|
|
210
210
|
logger.info('Mounted loopback OAuth callback router');
|
|
211
211
|
}
|
|
212
212
|
fileRouter = (0, _server.createFileServingRouter)({
|
|
213
|
-
|
|
213
|
+
resourceStoreUri: config.resourceStoreUri
|
|
214
214
|
}, {
|
|
215
215
|
contentType: 'text/csv',
|
|
216
216
|
contentDisposition: 'attachment'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/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 prompts = [...composed.prompts, ...runtime.deps.oauthAdapters.accountPrompts];\n\n const mcpServer = new McpServer({ name: config.name, version: config.version });\n registerTools(mcpServer, tools);\n registerResources(mcpServer, composed.resources);\n registerPrompts(mcpServer, prompts);\n\n const app = express();\n app.use(cors());\n app.use(express.json({ limit: '10mb' }));\n\n if (runtime.deps.oauthAdapters.loopbackRouter) {\n app.use('/', runtime.deps.oauthAdapters.loopbackRouter);\n logger.info('Mounted loopback OAuth callback router');\n }\n\n const fileRouter = createFileServingRouter({
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/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 prompts = [...composed.prompts, ...runtime.deps.oauthAdapters.accountPrompts];\n\n const mcpServer = new McpServer({ name: config.name, version: config.version });\n registerTools(mcpServer, tools);\n registerResources(mcpServer, composed.resources);\n registerPrompts(mcpServer, prompts);\n\n const app = express();\n app.use(cors());\n app.use(express.json({ limit: '10mb' }));\n\n if (runtime.deps.oauthAdapters.loopbackRouter) {\n app.use('/', runtime.deps.oauthAdapters.loopbackRouter);\n logger.info('Mounted loopback OAuth callback router');\n }\n\n const fileRouter = createFileServingRouter({ resourceStoreUri: config.resourceStoreUri }, { contentType: 'text/csv', contentDisposition: 'attachment' });\n app.use('/files', fileRouter);\n\n if (runtime.deps.oauthAdapters.dcrRouter) {\n app.use('/', runtime.deps.oauthAdapters.dcrRouter);\n logger.info('Mounted DCR router with OAuth endpoints');\n }\n\n logger.info(`Starting ${config.name} MCP server (http)`);\n const { close, httpServer } = await connectHttp(mcpServer, { logger, app, port });\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":["createHTTPServer","config","overrides","runtime","modules","layers","composed","logger","port","tools","prompts","mcpServer","app","fileRouter","close","httpServer","createDefaultRuntime","createDomainModules","middlewareFactories","map","factory","deps","composeMiddleware","transport","Error","oauthAdapters","accountTools","accountPrompts","McpServer","name","version","registerTools","registerResources","resources","registerPrompts","express","use","cors","json","limit","loopbackRouter","info","createFileServingRouter","resourceStoreUri","contentType","contentDisposition","dcrRouter","connectHttp"],"mappings":";;;;+BAOsBA;;;eAAAA;;;sBAPqG;mBACjG;2DACT;8DACG;yBAEiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAE9B,SAAeA,iBAAiBC,MAAoB,EAAEC,SAA4B;;YACjFC,SACAC,SACAC,QACAC,UACAC,QACAC,MAGAC,OACAC,SAEAC,WAKAC,KASAC,YASwB,MAAtBC,OAAOC;;;;oBAlCC;;wBAAMC,IAAAA,+BAAoB,EAACf,QAAQC;;;oBAA7CC,UAAU;oBACVC,UAAUD,QAAQc,mBAAmB;oBACrCZ,SAASF,QAAQe,mBAAmB,CAACC,GAAG,CAAC,SAACC;+BAAYA,QAAQjB,QAAQkB,IAAI;;oBAC1Ef,WAAWgB,IAAAA,yBAAiB,EAAClB,SAASC;oBACtCE,SAASJ,QAAQkB,IAAI,CAACd,MAAM;oBAC5BC,OAAOP,OAAOsB,SAAS,CAACf,IAAI;oBAClC,IAAI,CAACA,MAAM,MAAM,IAAIgB,MAAM;oBAErBf,QAAQ,AAAC,qBAAGH,SAASG,KAAK,SAAE,qBAAGN,QAAQkB,IAAI,CAACI,aAAa,CAACC,YAAY;oBACtEhB,UAAU,AAAC,qBAAGJ,SAASI,OAAO,SAAE,qBAAGP,QAAQkB,IAAI,CAACI,aAAa,CAACE,cAAc;oBAE5EhB,YAAY,IAAIiB,cAAS,CAAC;wBAAEC,MAAM5B,OAAO4B,IAAI;wBAAEC,SAAS7B,OAAO6B,OAAO;oBAAC;oBAC7EC,IAAAA,qBAAa,EAACpB,WAAWF;oBACzBuB,IAAAA,yBAAiB,EAACrB,WAAWL,SAAS2B,SAAS;oBAC/CC,IAAAA,uBAAe,EAACvB,WAAWD;oBAErBE,MAAMuB,IAAAA,gBAAO;oBACnBvB,IAAIwB,GAAG,CAACC,IAAAA,aAAI;oBACZzB,IAAIwB,GAAG,CAACD,gBAAO,CAACG,IAAI,CAAC;wBAAEC,OAAO;oBAAO;oBAErC,IAAIpC,QAAQkB,IAAI,CAACI,aAAa,CAACe,cAAc,EAAE;wBAC7C5B,IAAIwB,GAAG,CAAC,KAAKjC,QAAQkB,IAAI,CAACI,aAAa,CAACe,cAAc;wBACtDjC,OAAOkC,IAAI,CAAC;oBACd;oBAEM5B,aAAa6B,IAAAA,+BAAuB,EAAC;wBAAEC,kBAAkB1C,OAAO0C,gBAAgB;oBAAC,GAAG;wBAAEC,aAAa;wBAAYC,oBAAoB;oBAAa;oBACtJjC,IAAIwB,GAAG,CAAC,UAAUvB;oBAElB,IAAIV,QAAQkB,IAAI,CAACI,aAAa,CAACqB,SAAS,EAAE;wBACxClC,IAAIwB,GAAG,CAAC,KAAKjC,QAAQkB,IAAI,CAACI,aAAa,CAACqB,SAAS;wBACjDvC,OAAOkC,IAAI,CAAC;oBACd;oBAEAlC,OAAOkC,IAAI,CAAC,AAAC,YAAuB,OAAZxC,OAAO4B,IAAI,EAAC;oBACN;;wBAAMkB,IAAAA,mBAAW,EAACpC,WAAW;4BAAEJ,QAAAA;4BAAQK,KAAAA;4BAAKJ,MAAAA;wBAAK;;;oBAAjD,OAAA,eAAtBM,QAAsB,KAAtBA,OAAOC,aAAe,KAAfA;oBACfR,OAAOkC,IAAI,CAAC;oBAEZ;;wBAAO;4BACL1B,YAAAA;4BACAJ,WAAAA;4BACAJ,QAAAA;4BACAO,OAAO;;;;;gDACL;;oDAAMA;;;gDAAN;gDACA;;oDAAMX,QAAQW,KAAK;;;gDAAnB;;;;;;gCACF;;wBACF;;;;IACF"}
|
|
@@ -310,12 +310,12 @@ function createLogger(config) {
|
|
|
310
310
|
}
|
|
311
311
|
function createTokenStore(baseDir) {
|
|
312
312
|
return _async_to_generator(function() {
|
|
313
|
-
var
|
|
313
|
+
var tokenStoreUri;
|
|
314
314
|
return _ts_generator(this, function(_state) {
|
|
315
|
-
|
|
315
|
+
tokenStoreUri = process.env.TOKEN_STORE_URI || "file://".concat(_path.join(baseDir, 'tokens.json'));
|
|
316
316
|
return [
|
|
317
317
|
2,
|
|
318
|
-
(0, _createstorets.default)(
|
|
318
|
+
(0, _createstorets.default)(tokenStoreUri)
|
|
319
319
|
];
|
|
320
320
|
});
|
|
321
321
|
})();
|
|
@@ -391,8 +391,8 @@ function createStorageLayer(storageContext) {
|
|
|
391
391
|
};
|
|
392
392
|
}
|
|
393
393
|
function assertStorageConfig(config) {
|
|
394
|
-
if (!config.
|
|
395
|
-
throw new Error('outlook-messages-export-csv: Server configuration missing
|
|
394
|
+
if (!config.resourceStoreUri) {
|
|
395
|
+
throw new Error('outlook-messages-export-csv: Server configuration missing resourceStoreUri.');
|
|
396
396
|
}
|
|
397
397
|
if (config.transport.type === 'http' && !config.baseUrl && !config.transport.port) {
|
|
398
398
|
throw new Error('outlook-messages-export-csv: HTTP transport requires either baseUrl in server config or port in transport config. This is a server configuration error - please provide --base-url or --port.');
|
|
@@ -459,7 +459,7 @@ function createDefaultRuntime(config, overrides) {
|
|
|
459
459
|
},
|
|
460
460
|
function() {
|
|
461
461
|
return createStorageLayer({
|
|
462
|
-
|
|
462
|
+
resourceStoreUri: config.resourceStoreUri,
|
|
463
463
|
baseUrl: config.baseUrl,
|
|
464
464
|
transport: config.transport
|
|
465
465
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/src/setup/runtime.ts"],"sourcesContent":["import { sanitizeForLoggingFormatter } from '@mcp-z/oauth';\nimport type { Logger, MiddlewareLayer } from '@mcp-z/server';\nimport { createLoggingMiddleware } from '@mcp-z/server';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport pino from 'pino';\nimport createStore from '../lib/create-store.ts';\nimport * as mcp from '../mcp/index.ts';\nimport type { CommonRuntime, RuntimeDeps, RuntimeOverrides, ServerConfig, StorageContext } from '../types.ts';\nimport { createOAuthAdapters, type OAuthAdapters } from './oauth-microsoft.ts';\n\nexport function createLogger(config: ServerConfig): Logger {\n const hasStdio = config.transport.type === 'stdio';\n const logsPath = path.join(config.baseDir, 'logs', `${config.name}.log`);\n if (hasStdio) fs.mkdirSync(path.dirname(logsPath), { recursive: true });\n return pino({ level: config.logLevel ?? 'info', formatters: sanitizeForLoggingFormatter() }, hasStdio ? pino.destination({ dest: logsPath, sync: false }) : pino.destination(1));\n}\n\nexport async function createTokenStore(baseDir: string) {\n const
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/src/setup/runtime.ts"],"sourcesContent":["import { sanitizeForLoggingFormatter } from '@mcp-z/oauth';\nimport type { Logger, MiddlewareLayer } from '@mcp-z/server';\nimport { createLoggingMiddleware } from '@mcp-z/server';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport pino from 'pino';\nimport createStore from '../lib/create-store.ts';\nimport * as mcp from '../mcp/index.ts';\nimport type { CommonRuntime, RuntimeDeps, RuntimeOverrides, ServerConfig, StorageContext } from '../types.ts';\nimport { createOAuthAdapters, type OAuthAdapters } from './oauth-microsoft.ts';\n\nexport function createLogger(config: ServerConfig): Logger {\n const hasStdio = config.transport.type === 'stdio';\n const logsPath = path.join(config.baseDir, 'logs', `${config.name}.log`);\n if (hasStdio) fs.mkdirSync(path.dirname(logsPath), { recursive: true });\n return pino({ level: config.logLevel ?? 'info', formatters: sanitizeForLoggingFormatter() }, hasStdio ? pino.destination({ dest: logsPath, sync: false }) : pino.destination(1));\n}\n\nexport async function createTokenStore(baseDir: string) {\n const tokenStoreUri = process.env.TOKEN_STORE_URI || `file://${path.join(baseDir, 'tokens.json')}`;\n return createStore<unknown>(tokenStoreUri);\n}\n\nexport async function createDcrStore(baseDir: string, required: boolean) {\n if (!required) return undefined;\n const dcrStoreUri = process.env.DCR_STORE_URI || `file://${path.join(baseDir, 'dcr.json')}`;\n return createStore<unknown>(dcrStoreUri);\n}\n\nexport function createAuthLayer(authMiddleware: OAuthAdapters['middleware']): MiddlewareLayer {\n return {\n withTool: authMiddleware.withToolAuth,\n withResource: authMiddleware.withResourceAuth,\n withPrompt: authMiddleware.withPromptAuth,\n };\n}\n\nexport function createLoggingLayer(logger: Logger): MiddlewareLayer {\n const logging = createLoggingMiddleware({ logger });\n return {\n withTool: logging.withToolLogging,\n withResource: logging.withResourceLogging,\n withPrompt: logging.withPromptLogging,\n };\n}\n\nexport function createStorageLayer(storageContext: StorageContext): MiddlewareLayer {\n const wrapAtPosition = <T extends { name: string; handler: unknown; [key: string]: unknown }>(module: T, extraPosition: number): T => {\n const originalHandler = module.handler as (...args: unknown[]) => Promise<unknown>;\n\n const wrappedHandler = async (...allArgs: unknown[]) => {\n const extra = allArgs[extraPosition];\n (extra as { storageContext?: StorageContext }).storageContext = storageContext;\n return await originalHandler(...allArgs);\n };\n\n return {\n ...module,\n handler: wrappedHandler,\n } as T;\n };\n\n return {\n withTool: <T extends { name: string; config: unknown; handler: unknown }>(module: T): T => wrapAtPosition(module, 1) as T,\n };\n}\n\nexport function assertStorageConfig(config: ServerConfig) {\n if (!config.resourceStoreUri) {\n throw new Error('outlook-messages-export-csv: Server configuration missing resourceStoreUri.');\n }\n if (config.transport.type === 'http' && !config.baseUrl && !config.transport.port) {\n throw new Error('outlook-messages-export-csv: HTTP transport requires either baseUrl in server config or port in transport config. This is a server configuration error - please provide --base-url or --port.');\n }\n}\n\nexport async function createDefaultRuntime(config: ServerConfig, overrides?: RuntimeOverrides): Promise<CommonRuntime> {\n if (config.auth === 'dcr' && config.transport.type !== 'http') throw new Error('DCR mode requires an HTTP transport');\n\n assertStorageConfig(config);\n const logger = createLogger(config);\n const tokenStore = await createTokenStore(config.baseDir);\n const baseUrl = config.baseUrl ?? (config.transport.type === 'http' && config.transport.port ? `http://localhost:${config.transport.port}` : undefined);\n const dcrStore = await createDcrStore(config.baseDir, config.auth === 'dcr');\n const oauthAdapters = await createOAuthAdapters(config, { logger, tokenStore, dcrStore }, baseUrl);\n const deps: RuntimeDeps = { config, logger, tokenStore, oauthAdapters, baseUrl };\n const createDomainModules =\n overrides?.createDomainModules ??\n (() => ({\n tools: Object.values(mcp.toolFactories).map((factory) => factory()),\n resources: Object.values(mcp.resourceFactories).map((factory) => factory()),\n prompts: Object.values(mcp.promptFactories).map((factory) => factory()),\n }));\n const middlewareFactories = overrides?.middlewareFactories ?? [() => createAuthLayer(oauthAdapters.middleware), () => createLoggingLayer(logger), () => createStorageLayer({ resourceStoreUri: config.resourceStoreUri, baseUrl: config.baseUrl, transport: config.transport })];\n\n return {\n deps,\n middlewareFactories,\n createDomainModules,\n close: async () => {},\n };\n}\n"],"names":["assertStorageConfig","createAuthLayer","createDcrStore","createDefaultRuntime","createLogger","createLoggingLayer","createStorageLayer","createTokenStore","config","hasStdio","transport","type","logsPath","path","join","baseDir","name","fs","mkdirSync","dirname","recursive","pino","level","logLevel","formatters","sanitizeForLoggingFormatter","destination","dest","sync","tokenStoreUri","process","env","TOKEN_STORE_URI","createStore","required","dcrStoreUri","undefined","DCR_STORE_URI","authMiddleware","withTool","withToolAuth","withResource","withResourceAuth","withPrompt","withPromptAuth","logger","logging","createLoggingMiddleware","withToolLogging","withResourceLogging","withPromptLogging","storageContext","wrapAtPosition","module","extraPosition","originalHandler","handler","wrappedHandler","allArgs","extra","resourceStoreUri","Error","baseUrl","port","overrides","tokenStore","dcrStore","oauthAdapters","deps","createDomainModules","middlewareFactories","auth","createOAuthAdapters","tools","Object","values","mcp","toolFactories","map","factory","resources","resourceFactories","prompts","promptFactories","middleware","close"],"mappings":";;;;;;;;;;;QAmEgBA;eAAAA;;QAtCAC;eAAAA;;QANMC;eAAAA;;QAqDAC;eAAAA;;QAjENC;eAAAA;;QA0BAC;eAAAA;;QASAC;eAAAA;;QA5BMC;eAAAA;;;qBAlBsB;sBAEJ;0DACpB;4DACE;2DACL;oEACO;+DACH;gCAEmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEjD,SAASH,aAAaI,MAAoB;QAI1BA;IAHrB,IAAMC,WAAWD,OAAOE,SAAS,CAACC,IAAI,KAAK;IAC3C,IAAMC,WAAWC,MAAKC,IAAI,CAACN,OAAOO,OAAO,EAAE,QAAQ,AAAC,GAAc,OAAZP,OAAOQ,IAAI,EAAC;IAClE,IAAIP,UAAUQ,IAAGC,SAAS,CAACL,MAAKM,OAAO,CAACP,WAAW;QAAEQ,WAAW;IAAK;IACrE,OAAOC,IAAAA,aAAI,EAAC;QAAEC,KAAK,GAAEd,mBAAAA,OAAOe,QAAQ,cAAff,8BAAAA,mBAAmB;QAAQgB,YAAYC,IAAAA,kCAA2B;IAAG,GAAGhB,WAAWY,aAAI,CAACK,WAAW,CAAC;QAAEC,MAAMf;QAAUgB,MAAM;IAAM,KAAKP,aAAI,CAACK,WAAW,CAAC;AAC/K;AAEO,SAAenB,iBAAiBQ,OAAe;;YAC9Cc;;YAAAA,gBAAgBC,QAAQC,GAAG,CAACC,eAAe,IAAI,AAAC,UAA2C,OAAlCnB,MAAKC,IAAI,CAACC,SAAS;YAClF;;gBAAOkB,IAAAA,sBAAW,EAAUJ;;;IAC9B;;AAEO,SAAe3B,eAAea,OAAe,EAAEmB,QAAiB;;YAE/DC;;YADN,IAAI,CAACD,UAAU;;gBAAOE;;YAChBD,cAAcL,QAAQC,GAAG,CAACM,aAAa,IAAI,AAAC,UAAwC,OAA/BxB,MAAKC,IAAI,CAACC,SAAS;YAC9E;;gBAAOkB,IAAAA,sBAAW,EAAUE;;;IAC9B;;AAEO,SAASlC,gBAAgBqC,cAA2C;IACzE,OAAO;QACLC,UAAUD,eAAeE,YAAY;QACrCC,cAAcH,eAAeI,gBAAgB;QAC7CC,YAAYL,eAAeM,cAAc;IAC3C;AACF;AAEO,SAASvC,mBAAmBwC,MAAc;IAC/C,IAAMC,UAAUC,IAAAA,+BAAuB,EAAC;QAAEF,QAAAA;IAAO;IACjD,OAAO;QACLN,UAAUO,QAAQE,eAAe;QACjCP,cAAcK,QAAQG,mBAAmB;QACzCN,YAAYG,QAAQI,iBAAiB;IACvC;AACF;AAEO,SAAS5C,mBAAmB6C,cAA8B;IAC/D,IAAMC,iBAAiB,SAAuEC,QAAWC;QACvG,IAAMC,kBAAkBF,OAAOG,OAAO;QAEtC,IAAMC,iBAAiB;6CAAUC;gBAAAA;;;oBACzBC;;;;4BAAAA,QAAQD,OAAO,CAACJ,cAAc;4BACnCK,MAA8CR,cAAc,GAAGA;4BACzD;;gCAAMI,sBAAAA,KAAAA,GAAgB,qBAAGG;;;4BAAhC;;gCAAO;;;;YACT;;QAEA,OAAO,wCACFL;YACHG,SAASC;;IAEb;IAEA,OAAO;QACLlB,UAAU,SAAgEc;mBAAiBD,eAAeC,QAAQ;;IACpH;AACF;AAEO,SAASrD,oBAAoBQ,MAAoB;IACtD,IAAI,CAACA,OAAOoD,gBAAgB,EAAE;QAC5B,MAAM,IAAIC,MAAM;IAClB;IACA,IAAIrD,OAAOE,SAAS,CAACC,IAAI,KAAK,UAAU,CAACH,OAAOsD,OAAO,IAAI,CAACtD,OAAOE,SAAS,CAACqD,IAAI,EAAE;QACjF,MAAM,IAAIF,MAAM;IAClB;AACF;AAEO,SAAe1D,qBAAqBK,MAAoB,EAAEwD,SAA4B;;YAM3ExD,8BAFVqC,QACAoB,YACAH,SACAI,UACAC,eACAC,MACAC,qBAOAC;;;;oBAhBN,IAAI9D,OAAO+D,IAAI,KAAK,SAAS/D,OAAOE,SAAS,CAACC,IAAI,KAAK,QAAQ,MAAM,IAAIkD,MAAM;oBAE/E7D,oBAAoBQ;oBACdqC,SAASzC,aAAaI;oBACT;;wBAAMD,iBAAiBC,OAAOO,OAAO;;;oBAAlDkD,aAAa;oBACbH,WAAUtD,kBAAAA,OAAOsD,OAAO,cAAdtD,6BAAAA,kBAAmBA,OAAOE,SAAS,CAACC,IAAI,KAAK,UAAUH,OAAOE,SAAS,CAACqD,IAAI,GAAG,AAAC,oBAAyC,OAAtBvD,OAAOE,SAAS,CAACqD,IAAI,IAAK3B;oBAC5H;;wBAAMlC,eAAeM,OAAOO,OAAO,EAAEP,OAAO+D,IAAI,KAAK;;;oBAAhEL,WAAW;oBACK;;wBAAMM,IAAAA,qCAAmB,EAAChE,QAAQ;4BAAEqC,QAAAA;4BAAQoB,YAAAA;4BAAYC,UAAAA;wBAAS,GAAGJ;;;oBAApFK,gBAAgB;oBAChBC,OAAoB;wBAAE5D,QAAAA;wBAAQqC,QAAAA;wBAAQoB,YAAAA;wBAAYE,eAAAA;wBAAeL,SAAAA;oBAAQ;oBACzEO,8BACJL,sBAAAA,gCAAAA,UAAWK,mBAAmB,uCAC7B;+BAAO;4BACNI,OAAOC,OAAOC,MAAM,CAACC,SAAIC,aAAa,EAAEC,GAAG,CAAC,SAACC;uCAAYA;;4BACzDC,WAAWN,OAAOC,MAAM,CAACC,SAAIK,iBAAiB,EAAEH,GAAG,CAAC,SAACC;uCAAYA;;4BACjEG,SAASR,OAAOC,MAAM,CAACC,SAAIO,eAAe,EAAEL,GAAG,CAAC,SAACC;uCAAYA;;wBAC/D;;oBACIT,+BAAsBN,sBAAAA,gCAAAA,UAAWM,mBAAmB;wBAAK;mCAAMrE,gBAAgBkE,cAAciB,UAAU;;wBAAG;mCAAM/E,mBAAmBwC;;wBAAS;mCAAMvC,mBAAmB;gCAAEsD,kBAAkBpD,OAAOoD,gBAAgB;gCAAEE,SAAStD,OAAOsD,OAAO;gCAAEpD,WAAWF,OAAOE,SAAS;4BAAC;;;oBAE7Q;;wBAAO;4BACL0D,MAAAA;4BACAE,qBAAAA;4BACAD,qBAAAA;4BACAgB,OAAO;;;;;;;gCAAa;;wBACtB;;;;IACF"}
|
package/dist/cjs/types.d.cts
CHANGED
|
@@ -12,12 +12,12 @@ export interface ServerConfig extends BaseServerConfig, OAuthConfig {
|
|
|
12
12
|
name: string;
|
|
13
13
|
version: string;
|
|
14
14
|
repositoryUrl: string;
|
|
15
|
-
|
|
15
|
+
resourceStoreUri: string;
|
|
16
16
|
baseUrl?: string;
|
|
17
17
|
dcrConfig?: DcrConfig;
|
|
18
18
|
}
|
|
19
19
|
export interface StorageContext {
|
|
20
|
-
|
|
20
|
+
resourceStoreUri: string;
|
|
21
21
|
baseUrl?: string;
|
|
22
22
|
transport: BaseServerConfig['transport'];
|
|
23
23
|
}
|
package/dist/cjs/types.d.ts
CHANGED
|
@@ -12,12 +12,12 @@ export interface ServerConfig extends BaseServerConfig, OAuthConfig {
|
|
|
12
12
|
name: string;
|
|
13
13
|
version: string;
|
|
14
14
|
repositoryUrl: string;
|
|
15
|
-
|
|
15
|
+
resourceStoreUri: string;
|
|
16
16
|
baseUrl?: string;
|
|
17
17
|
dcrConfig?: DcrConfig;
|
|
18
18
|
}
|
|
19
19
|
export interface StorageContext {
|
|
20
|
-
|
|
20
|
+
resourceStoreUri: string;
|
|
21
21
|
baseUrl?: string;
|
|
22
22
|
transport: BaseServerConfig['transport'];
|
|
23
23
|
}
|
|
@@ -54,7 +54,7 @@ const config = {
|
|
|
54
54
|
*/ async function handler({ query, maxItems, filename, contentType, excludeThreadHistory }, extra) {
|
|
55
55
|
const logger = extra.logger;
|
|
56
56
|
const { storageContext } = extra;
|
|
57
|
-
const { transport,
|
|
57
|
+
const { transport, resourceStoreUri, baseUrl } = storageContext;
|
|
58
58
|
logger.info('outlook.messages.export-csv called', {
|
|
59
59
|
query,
|
|
60
60
|
maxItems,
|
|
@@ -63,7 +63,7 @@ const config = {
|
|
|
63
63
|
});
|
|
64
64
|
// Reserve file location for streaming write (creates directory, generates ID, formats filename)
|
|
65
65
|
const reservation = await reserveFile(filename, {
|
|
66
|
-
|
|
66
|
+
resourceStoreUri
|
|
67
67
|
});
|
|
68
68
|
const { storedName, fullPath } = reservation;
|
|
69
69
|
logger.info('outlook.messages.export-csv starting streaming export', {
|
|
@@ -219,7 +219,7 @@ const config = {
|
|
|
219
219
|
});
|
|
220
220
|
// Generate URI based on transport type (stdio: file://, HTTP: http://)
|
|
221
221
|
const uri = getFileUri(storedName, transport, {
|
|
222
|
-
|
|
222
|
+
resourceStoreUri,
|
|
223
223
|
...baseUrl && {
|
|
224
224
|
baseUrl
|
|
225
225
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/src/mcp/tools/messages-export-csv.ts"],"sourcesContent":["/** Outlook message CSV export tool - streams results to file without loading all data into context */\n\nimport { EmailContentTypeSchema, ExcludeThreadHistorySchema, extractCurrentMessageFromHtml, extractCurrentMessageFromHtmlToText } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-microsoft';\nimport { schemas } from '@mcp-z/oauth-microsoft';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { getFileUri, reserveFile, type ToolModule } from '@mcp-z/server';\nimport { Client } from '@microsoft/microsoft-graph-client';\nimport type * as MicrosoftGraph from '@microsoft/microsoft-graph-types';\nimport { type CallToolResult, ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\nimport { stringify } from 'csv-stringify/sync';\nimport { createWriteStream } from 'fs';\nimport { unlink } from 'fs/promises';\nimport { z } from 'zod';\nimport { executeQuery as executeOutlookQuery } from '../../email/querying/execute-query.ts';\nimport { OutlookQuerySchema } from '../../schemas/outlook-query-schema.ts';\nimport type { StorageExtra } from '../../types.ts';\n\nconst DEFAULT_PAGE_SIZE = 50;\nconst DEFAULT_MAX_ITEMS = 10000;\nconst MAX_EXPORT_ITEMS = 50000;\n\nconst ExportResultSchema = z.object({\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 inputSchema = z.object({\n query: OutlookQuerySchema.optional().describe('Structured query object for filtering messages. Use query-syntax prompt for reference.'),\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('outlook-messages.csv').describe('Output filename (default: outlook-messages.csv)'),\n contentType: EmailContentTypeSchema,\n excludeThreadHistory: ExcludeThreadHistorySchema,\n});\n\n// Success branch schema\nconst successBranchSchema = ExportResultSchema.extend({\n type: z.literal('success'),\n});\n\n// Output schema with auth_required support\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Export Outlook 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 outlook-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): Promise<CallToolResult> {\n const logger = extra.logger;\n const { storageContext } = extra;\n const { transport, storageDir, baseUrl } = storageContext;\n\n logger.info('outlook.messages.export-csv called', {\n query,\n maxItems,\n filename,\n accountId: extra.authContext.accountId,\n });\n\n // Reserve file location for streaming write (creates directory, generates ID, formats filename)\n const reservation = await reserveFile(filename, {\n storageDir,\n });\n const { storedName, fullPath } = reservation;\n\n logger.info('outlook.messages.export-csv starting streaming export', { path: fullPath, maxItems });\n\n try {\n const graph = Client.initWithMiddleware({ authProvider: 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: Array<{\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 metadata?: { nextPageToken?: string };\n } = await executeOutlookQuery(\n graph,\n query,\n {\n logger,\n pageSize,\n ...(nextPageToken !== undefined && { pageToken: nextPageToken }),\n includeBody: true, // Always include body for CSV export\n limit: pageSize,\n },\n (m: unknown) => {\n const message = m as MicrosoftGraph.Message;\n const to = Array.isArray(message?.toRecipients)\n ? message.toRecipients\n .map((r: MicrosoftGraph.Recipient) => r?.emailAddress?.address ?? (r as { address?: string })?.address)\n .filter(Boolean)\n .join(', ')\n : '';\n const cc = Array.isArray(message?.ccRecipients)\n ? message.ccRecipients\n .map((r: MicrosoftGraph.Recipient) => r?.emailAddress?.address ?? (r as { address?: string })?.address)\n .filter(Boolean)\n .join(', ')\n : '';\n const bcc = Array.isArray(message?.bccRecipients)\n ? message.bccRecipients\n .map((r: MicrosoftGraph.Recipient) => r?.emailAddress?.address ?? (r as { address?: string })?.address)\n .filter(Boolean)\n .join(', ')\n : '';\n const fromAddr = message?.from?.emailAddress?.address ?? (message?.from as { address?: string })?.address ?? '';\n const categories = Array.isArray(message?.categories) ? message.categories.join(';') : '';\n\n // Process body based on contentType and excludeThreadHistory options\n let body = message?.body?.content ?? '';\n const isHtml = message?.body?.contentType?.toLowerCase() === 'html';\n\n if (isHtml && excludeThreadHistory) {\n body = extractCurrentMessageFromHtml(body);\n }\n\n if (isHtml && contentType === 'text') {\n body = excludeThreadHistory ? extractCurrentMessageFromHtmlToText(body) : extractCurrentMessageFromHtmlToText(message?.body?.content ?? '');\n }\n\n return {\n id: String(message?.id ?? ''),\n threadId: message?.conversationId ? String(message.conversationId) : '',\n from: fromAddr,\n to,\n cc,\n bcc,\n subject: message?.subject ?? '',\n date: message?.receivedDateTime ?? '',\n snippet: message?.bodyPreview ?? '',\n body,\n provider: 'outlook' as const,\n labels: categories,\n };\n }\n );\n\n const csvRows = exec.items.map((item) => {\n return [item.id, item.threadId, item.from, item.to, item.cc, item.bcc, item.subject, item.date, item.snippet, item.body, item.provider, item.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('outlook.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('outlook.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 storageDir,\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('outlook.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","extractCurrentMessageFromHtml","extractCurrentMessageFromHtmlToText","schemas","AuthRequiredBranchSchema","getFileUri","reserveFile","Client","ErrorCode","McpError","stringify","createWriteStream","unlink","z","executeQuery","executeOutlookQuery","OutlookQuerySchema","DEFAULT_PAGE_SIZE","DEFAULT_MAX_ITEMS","MAX_EXPORT_ITEMS","ExportResultSchema","object","uri","string","describe","filename","rowCount","number","truncated","boolean","inputSchema","query","optional","maxItems","int","positive","max","default","trim","min","contentType","excludeThreadHistory","successBranchSchema","extend","type","literal","outputSchema","discriminatedUnion","config","description","result","handler","extra","logger","storageContext","transport","storageDir","baseUrl","info","accountId","authContext","reservation","storedName","fullPath","path","graph","initWithMiddleware","authProvider","auth","csvHeaders","writeStream","encoding","headerLine","header","quoted","quote","escape","write","totalRows","nextPageToken","started","Date","now","exec","remainingItems","pageSize","Math","undefined","pageToken","includeBody","limit","m","message","to","Array","isArray","toRecipients","map","r","emailAddress","address","filter","Boolean","join","cc","ccRecipients","bcc","bccRecipients","fromAddr","from","categories","body","content","isHtml","toLowerCase","id","String","threadId","conversationId","subject","date","receivedDateTime","snippet","bodyPreview","provider","labels","csvRows","items","item","length","rowsContent","metadata","batchSize","hasMore","Promise","resolve","reject","end","on","durationMs","endpoint","text","JSON","structuredContent","error","debug","_cleanupError","Error","InternalError","stack","createTool","name"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/src/mcp/tools/messages-export-csv.ts"],"sourcesContent":["/** Outlook message CSV export tool - streams results to file without loading all data into context */\n\nimport { EmailContentTypeSchema, ExcludeThreadHistorySchema, extractCurrentMessageFromHtml, extractCurrentMessageFromHtmlToText } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-microsoft';\nimport { schemas } from '@mcp-z/oauth-microsoft';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { getFileUri, reserveFile, type ToolModule } from '@mcp-z/server';\nimport { Client } from '@microsoft/microsoft-graph-client';\nimport type * as MicrosoftGraph from '@microsoft/microsoft-graph-types';\nimport { type CallToolResult, ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\nimport { stringify } from 'csv-stringify/sync';\nimport { createWriteStream } from 'fs';\nimport { unlink } from 'fs/promises';\nimport { z } from 'zod';\nimport { executeQuery as executeOutlookQuery } from '../../email/querying/execute-query.ts';\nimport { OutlookQuerySchema } from '../../schemas/outlook-query-schema.ts';\nimport type { StorageExtra } from '../../types.ts';\n\nconst DEFAULT_PAGE_SIZE = 50;\nconst DEFAULT_MAX_ITEMS = 10000;\nconst MAX_EXPORT_ITEMS = 50000;\n\nconst ExportResultSchema = z.object({\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 inputSchema = z.object({\n query: OutlookQuerySchema.optional().describe('Structured query object for filtering messages. Use query-syntax prompt for reference.'),\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('outlook-messages.csv').describe('Output filename (default: outlook-messages.csv)'),\n contentType: EmailContentTypeSchema,\n excludeThreadHistory: ExcludeThreadHistorySchema,\n});\n\n// Success branch schema\nconst successBranchSchema = ExportResultSchema.extend({\n type: z.literal('success'),\n});\n\n// Output schema with auth_required support\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Export Outlook 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 outlook-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): Promise<CallToolResult> {\n const logger = extra.logger;\n const { storageContext } = extra;\n const { transport, resourceStoreUri, baseUrl } = storageContext;\n\n logger.info('outlook.messages.export-csv called', {\n query,\n maxItems,\n filename,\n accountId: extra.authContext.accountId,\n });\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('outlook.messages.export-csv starting streaming export', { path: fullPath, maxItems });\n\n try {\n const graph = Client.initWithMiddleware({ authProvider: 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: Array<{\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 metadata?: { nextPageToken?: string };\n } = await executeOutlookQuery(\n graph,\n query,\n {\n logger,\n pageSize,\n ...(nextPageToken !== undefined && { pageToken: nextPageToken }),\n includeBody: true, // Always include body for CSV export\n limit: pageSize,\n },\n (m: unknown) => {\n const message = m as MicrosoftGraph.Message;\n const to = Array.isArray(message?.toRecipients)\n ? message.toRecipients\n .map((r: MicrosoftGraph.Recipient) => r?.emailAddress?.address ?? (r as { address?: string })?.address)\n .filter(Boolean)\n .join(', ')\n : '';\n const cc = Array.isArray(message?.ccRecipients)\n ? message.ccRecipients\n .map((r: MicrosoftGraph.Recipient) => r?.emailAddress?.address ?? (r as { address?: string })?.address)\n .filter(Boolean)\n .join(', ')\n : '';\n const bcc = Array.isArray(message?.bccRecipients)\n ? message.bccRecipients\n .map((r: MicrosoftGraph.Recipient) => r?.emailAddress?.address ?? (r as { address?: string })?.address)\n .filter(Boolean)\n .join(', ')\n : '';\n const fromAddr = message?.from?.emailAddress?.address ?? (message?.from as { address?: string })?.address ?? '';\n const categories = Array.isArray(message?.categories) ? message.categories.join(';') : '';\n\n // Process body based on contentType and excludeThreadHistory options\n let body = message?.body?.content ?? '';\n const isHtml = message?.body?.contentType?.toLowerCase() === 'html';\n\n if (isHtml && excludeThreadHistory) {\n body = extractCurrentMessageFromHtml(body);\n }\n\n if (isHtml && contentType === 'text') {\n body = excludeThreadHistory ? extractCurrentMessageFromHtmlToText(body) : extractCurrentMessageFromHtmlToText(message?.body?.content ?? '');\n }\n\n return {\n id: String(message?.id ?? ''),\n threadId: message?.conversationId ? String(message.conversationId) : '',\n from: fromAddr,\n to,\n cc,\n bcc,\n subject: message?.subject ?? '',\n date: message?.receivedDateTime ?? '',\n snippet: message?.bodyPreview ?? '',\n body,\n provider: 'outlook' as const,\n labels: categories,\n };\n }\n );\n\n const csvRows = exec.items.map((item) => {\n return [item.id, item.threadId, item.from, item.to, item.cc, item.bcc, item.subject, item.date, item.snippet, item.body, item.provider, item.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('outlook.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('outlook.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('outlook.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","extractCurrentMessageFromHtml","extractCurrentMessageFromHtmlToText","schemas","AuthRequiredBranchSchema","getFileUri","reserveFile","Client","ErrorCode","McpError","stringify","createWriteStream","unlink","z","executeQuery","executeOutlookQuery","OutlookQuerySchema","DEFAULT_PAGE_SIZE","DEFAULT_MAX_ITEMS","MAX_EXPORT_ITEMS","ExportResultSchema","object","uri","string","describe","filename","rowCount","number","truncated","boolean","inputSchema","query","optional","maxItems","int","positive","max","default","trim","min","contentType","excludeThreadHistory","successBranchSchema","extend","type","literal","outputSchema","discriminatedUnion","config","description","result","handler","extra","logger","storageContext","transport","resourceStoreUri","baseUrl","info","accountId","authContext","reservation","storedName","fullPath","path","graph","initWithMiddleware","authProvider","auth","csvHeaders","writeStream","encoding","headerLine","header","quoted","quote","escape","write","totalRows","nextPageToken","started","Date","now","exec","remainingItems","pageSize","Math","undefined","pageToken","includeBody","limit","m","message","to","Array","isArray","toRecipients","map","r","emailAddress","address","filter","Boolean","join","cc","ccRecipients","bcc","bccRecipients","fromAddr","from","categories","body","content","isHtml","toLowerCase","id","String","threadId","conversationId","subject","date","receivedDateTime","snippet","bodyPreview","provider","labels","csvRows","items","item","length","rowsContent","metadata","batchSize","hasMore","Promise","resolve","reject","end","on","durationMs","endpoint","text","JSON","structuredContent","error","debug","_cleanupError","Error","InternalError","stack","createTool","name"],"mappings":"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"}
|
|
@@ -22,7 +22,7 @@ export declare function handleVersionHelp(args: string[]): {
|
|
|
22
22
|
* - --port=<port> Enable HTTP transport on specified port
|
|
23
23
|
* - --stdio Enable stdio transport (default if no port)
|
|
24
24
|
* - --log-level=<level> Logging level (default: info)
|
|
25
|
-
* - --
|
|
25
|
+
* - --resource-store-uri=<uri> Resource store URI for CSV file storage (default: file://~/.mcp-z/mcp-outlook/files)
|
|
26
26
|
* - --base-url=<url> Base URL for HTTP file serving (default: http://localhost for HTTP transports)
|
|
27
27
|
*
|
|
28
28
|
* Environment Variables:
|
|
@@ -34,9 +34,10 @@ export declare function handleVersionHelp(args: string[]): {
|
|
|
34
34
|
* - DCR_MODE DCR mode (optional, same format as --dcr-mode)
|
|
35
35
|
* - DCR_VERIFY_URL External verification URL (optional, same as --dcr-verify-url)
|
|
36
36
|
* - DCR_STORE_URI DCR storage URI (optional, same as --dcr-store-uri)
|
|
37
|
+
* - TOKEN_STORE_URI Token storage URI (optional)
|
|
37
38
|
* - PORT Default HTTP port (optional)
|
|
38
39
|
* - LOG_LEVEL Default logging level (optional)
|
|
39
|
-
* -
|
|
40
|
+
* - RESOURCE_STORE_URI Resource store URI (optional, file://)
|
|
40
41
|
* - BASE_URL Base URL for HTTP file serving (optional)
|
|
41
42
|
*
|
|
42
43
|
* OAuth Scopes (from constants.ts):
|
package/dist/esm/setup/config.js
CHANGED
|
@@ -27,7 +27,7 @@ Options:
|
|
|
27
27
|
--port=<port> Enable HTTP transport on specified port
|
|
28
28
|
--stdio Enable stdio transport (default if no port)
|
|
29
29
|
--log-level=<level> Logging level (default: info)
|
|
30
|
-
--
|
|
30
|
+
--resource-store-uri=<uri> Resource store URI for CSV file storage (default: file://~/.mcp-z/mcp-outlook/files)
|
|
31
31
|
--base-url=<url> Base URL for HTTP file serving (default: http://localhost for HTTP transports)
|
|
32
32
|
|
|
33
33
|
Environment Variables:
|
|
@@ -39,9 +39,10 @@ Environment Variables:
|
|
|
39
39
|
DCR_MODE DCR mode (optional, same format as --dcr-mode)
|
|
40
40
|
DCR_VERIFY_URL External verification URL (optional, same as --dcr-verify-url)
|
|
41
41
|
DCR_STORE_URI DCR storage URI (optional, same as --dcr-store-uri)
|
|
42
|
+
TOKEN_STORE_URI Token storage URI (optional)
|
|
42
43
|
PORT Default HTTP port (optional)
|
|
43
44
|
LOG_LEVEL Default logging level (optional)
|
|
44
|
-
|
|
45
|
+
RESOURCE_STORE_URI Resource store URI (optional, file://)
|
|
45
46
|
BASE_URL Base URL for HTTP file serving (optional)
|
|
46
47
|
|
|
47
48
|
OAuth Scopes:
|
|
@@ -52,7 +53,7 @@ Examples:
|
|
|
52
53
|
mcp-outlook --auth=device-code # Use device code auth
|
|
53
54
|
mcp-outlook --port=3000 # HTTP transport on port 3000
|
|
54
55
|
mcp-outlook --tenant-id=xxx # Set tenant ID
|
|
55
|
-
mcp-outlook --
|
|
56
|
+
mcp-outlook --resource-store-uri=file:///tmp/emails # Custom resource store URI
|
|
56
57
|
MS_CLIENT_ID=xxx mcp-outlook # Set client ID via env var
|
|
57
58
|
`.trim();
|
|
58
59
|
/**
|
|
@@ -98,7 +99,7 @@ Examples:
|
|
|
98
99
|
* - --port=<port> Enable HTTP transport on specified port
|
|
99
100
|
* - --stdio Enable stdio transport (default if no port)
|
|
100
101
|
* - --log-level=<level> Logging level (default: info)
|
|
101
|
-
* - --
|
|
102
|
+
* - --resource-store-uri=<uri> Resource store URI for CSV file storage (default: file://~/.mcp-z/mcp-outlook/files)
|
|
102
103
|
* - --base-url=<url> Base URL for HTTP file serving (default: http://localhost for HTTP transports)
|
|
103
104
|
*
|
|
104
105
|
* Environment Variables:
|
|
@@ -110,9 +111,10 @@ Examples:
|
|
|
110
111
|
* - DCR_MODE DCR mode (optional, same format as --dcr-mode)
|
|
111
112
|
* - DCR_VERIFY_URL External verification URL (optional, same as --dcr-verify-url)
|
|
112
113
|
* - DCR_STORE_URI DCR storage URI (optional, same as --dcr-store-uri)
|
|
114
|
+
* - TOKEN_STORE_URI Token storage URI (optional)
|
|
113
115
|
* - PORT Default HTTP port (optional)
|
|
114
116
|
* - LOG_LEVEL Default logging level (optional)
|
|
115
|
-
* -
|
|
117
|
+
* - RESOURCE_STORE_URI Resource store URI (optional, file://)
|
|
116
118
|
* - BASE_URL Base URL for HTTP file serving (optional)
|
|
117
119
|
*
|
|
118
120
|
* OAuth Scopes (from constants.ts):
|
|
@@ -123,7 +125,7 @@ Examples:
|
|
|
123
125
|
const oauthConfig = parseOAuthConfig(args, env);
|
|
124
126
|
// Parse DCR configuration if DCR mode is enabled
|
|
125
127
|
const dcrConfig = oauthConfig.auth === 'dcr' ? parseDcrConfig(args, env, MS_SCOPE) : undefined;
|
|
126
|
-
// Parse application-level config (LOG_LEVEL,
|
|
128
|
+
// Parse application-level config (LOG_LEVEL, RESOURCE_STORE_URI, BASE_URL)
|
|
127
129
|
const { values } = parseArgs({
|
|
128
130
|
args,
|
|
129
131
|
options: {
|
|
@@ -133,7 +135,7 @@ Examples:
|
|
|
133
135
|
'base-url': {
|
|
134
136
|
type: 'string'
|
|
135
137
|
},
|
|
136
|
-
'
|
|
138
|
+
'resource-store-uri': {
|
|
137
139
|
type: 'string'
|
|
138
140
|
}
|
|
139
141
|
},
|
|
@@ -160,10 +162,10 @@ Examples:
|
|
|
160
162
|
const envLogLevel = env.LOG_LEVEL;
|
|
161
163
|
const logLevel = (_ref1 = cliLogLevel !== null && cliLogLevel !== void 0 ? cliLogLevel : envLogLevel) !== null && _ref1 !== void 0 ? _ref1 : 'info';
|
|
162
164
|
// Parse file storage configuration
|
|
163
|
-
const
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
165
|
+
const cliResourceStoreUri = typeof values['resource-store-uri'] === 'string' ? values['resource-store-uri'] : undefined;
|
|
166
|
+
const envResourceStoreUri = env.RESOURCE_STORE_URI;
|
|
167
|
+
const defaultResourceStorePath = path.join(baseDir, name, 'files');
|
|
168
|
+
const resourceStoreUri = normalizeResourceStoreUri((_ref2 = cliResourceStoreUri !== null && cliResourceStoreUri !== void 0 ? cliResourceStoreUri : envResourceStoreUri) !== null && _ref2 !== void 0 ? _ref2 : defaultResourceStorePath);
|
|
167
169
|
const cliBaseUrl = typeof values['base-url'] === 'string' ? values['base-url'] : undefined;
|
|
168
170
|
const envBaseUrl = env.BASE_URL;
|
|
169
171
|
const baseUrl = cliBaseUrl !== null && cliBaseUrl !== void 0 ? cliBaseUrl : envBaseUrl;
|
|
@@ -176,7 +178,7 @@ Examples:
|
|
|
176
178
|
name,
|
|
177
179
|
version: pkg.version,
|
|
178
180
|
repositoryUrl,
|
|
179
|
-
|
|
181
|
+
resourceStoreUri
|
|
180
182
|
};
|
|
181
183
|
if (baseUrl !== undefined) result.baseUrl = baseUrl;
|
|
182
184
|
if (dcrConfig !== undefined) result.dcrConfig = dcrConfig;
|
|
@@ -188,3 +190,14 @@ Examples:
|
|
|
188
190
|
*/ export function createConfig() {
|
|
189
191
|
return parseConfig(process.argv, process.env);
|
|
190
192
|
}
|
|
193
|
+
function normalizeResourceStoreUri(resourceStoreUri) {
|
|
194
|
+
const filePrefix = 'file://';
|
|
195
|
+
if (resourceStoreUri.startsWith(filePrefix)) {
|
|
196
|
+
const rawPath = resourceStoreUri.slice(filePrefix.length);
|
|
197
|
+
const expandedPath = rawPath.startsWith('~') ? rawPath.replace(/^~/, homedir()) : rawPath;
|
|
198
|
+
return `${filePrefix}${path.resolve(expandedPath)}`;
|
|
199
|
+
}
|
|
200
|
+
if (resourceStoreUri.includes('://')) return resourceStoreUri;
|
|
201
|
+
const expandedPath = resourceStoreUri.startsWith('~') ? resourceStoreUri.replace(/^~/, homedir()) : resourceStoreUri;
|
|
202
|
+
return `${filePrefix}${path.resolve(expandedPath)}`;
|
|
203
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/src/setup/config.ts"],"sourcesContent":["import { parseDcrConfig, parseConfig as parseOAuthConfig } from '@mcp-z/oauth-microsoft';\nimport { findConfigPath, parseConfig as parseTransportConfig } from '@mcp-z/server';\nimport * as fs from 'fs';\nimport moduleRoot from 'module-root-sync';\nimport { homedir } from 'os';\nimport * as path from 'path';\nimport * as url from 'url';\nimport { parseArgs } from 'util';\nimport { MS_SCOPE } from '../constants.ts';\nimport type { ServerConfig } from '../types.ts';\n\nconst pkg = JSON.parse(fs.readFileSync(path.join(moduleRoot(url.fileURLToPath(import.meta.url)), 'package.json'), 'utf-8'));\n\nconst HELP_TEXT = `\nUsage: mcp-outlook [options]\n\nMCP server for Outlook/Microsoft email management with OAuth authentication.\n\nOptions:\n --version Show version number\n --help Show this help message\n --auth=<mode> Authentication mode (default: loopback-oauth)\n Modes: loopback-oauth, device-code, dcr\n --headless Disable browser auto-open, return auth URL instead\n --redirect-uri=<uri> OAuth redirect URI (default: ephemeral loopback)\n --tenant-id=<id> Microsoft tenant ID (overrides MS_TENANT_ID env var)\n --dcr-mode=<mode> DCR mode (self-hosted or external, default: self-hosted)\n --dcr-verify-url=<url> External verification endpoint (required for external mode)\n --dcr-store-uri=<uri> DCR client storage URI (required for self-hosted mode)\n --port=<port> Enable HTTP transport on specified port\n --stdio Enable stdio transport (default if no port)\n --log-level=<level> Logging level (default: info)\n --storage-dir=<path> Directory for CSV file storage (default: .mcp-z/files)\n --base-url=<url> Base URL for HTTP file serving (default: http://localhost for HTTP transports)\n\nEnvironment Variables:\n MS_CLIENT_ID OAuth client ID (REQUIRED)\n MS_TENANT_ID Microsoft tenant ID (REQUIRED)\n MS_CLIENT_SECRET OAuth client secret (optional)\n AUTH_MODE Default authentication mode (optional)\n HEADLESS Disable browser auto-open (optional)\n DCR_MODE DCR mode (optional, same format as --dcr-mode)\n DCR_VERIFY_URL External verification URL (optional, same as --dcr-verify-url)\n DCR_STORE_URI DCR storage URI (optional, same as --dcr-store-uri)\n PORT Default HTTP port (optional)\n LOG_LEVEL Default logging level (optional)\n STORAGE_DIR Directory for CSV file storage (optional)\n BASE_URL Base URL for HTTP file serving (optional)\n\nOAuth Scopes:\n openid profile offline_access https://graph.microsoft.com/User.Read https://graph.microsoft.com/Mail.ReadWrite https://graph.microsoft.com/Mail.Send https://graph.microsoft.com/MailboxSettings.ReadWrite\n\nExamples:\n mcp-outlook # Use default settings\n mcp-outlook --auth=device-code # Use device code auth\n mcp-outlook --port=3000 # HTTP transport on port 3000\n mcp-outlook --tenant-id=xxx # Set tenant ID\n mcp-outlook --storage-dir=./emails # Custom storage directory\n MS_CLIENT_ID=xxx mcp-outlook # Set client ID via env var\n`.trim();\n\n/**\n * Handle --version and --help flags before config parsing.\n * These should work without requiring any configuration.\n */\nexport function handleVersionHelp(args: string[]): { handled: boolean; output?: string } {\n const { values } = parseArgs({\n args,\n options: {\n version: { type: 'boolean' },\n help: { type: 'boolean' },\n },\n strict: false,\n });\n\n if (values.version) return { handled: true, output: pkg.version };\n if (values.help) return { handled: true, output: HELP_TEXT };\n return { handled: false };\n}\n\n/**\n * Parse Outlook server configuration from CLI arguments and environment.\n *\n * CLI Arguments (all optional):\n * - --auth=<mode> Authentication mode (default: loopback-oauth)\n * Modes: loopback-oauth, device-code, dcr\n * - --headless Disable browser auto-open, return auth URL instead\n * - --redirect-uri=<uri> OAuth redirect URI (default: ephemeral loopback)\n * - --tenant-id=<id> Microsoft tenant ID (overrides MS_TENANT_ID env var)\n * - --dcr-mode=<mode> DCR mode (self-hosted or external, default: self-hosted)\n * - --dcr-verify-url=<url> External verification endpoint (required for external mode)\n * - --dcr-store-uri=<uri> DCR client storage URI (required for self-hosted mode)\n * - --port=<port> Enable HTTP transport on specified port\n * - --stdio Enable stdio transport (default if no port)\n * - --log-level=<level> Logging level (default: info)\n * - --storage-dir=<path> Directory for CSV file storage (default: .mcp-z/files)\n * - --base-url=<url> Base URL for HTTP file serving (default: http://localhost for HTTP transports)\n *\n * Environment Variables:\n * - MS_CLIENT_ID OAuth client ID (REQUIRED)\n * - MS_TENANT_ID Microsoft tenant ID (REQUIRED)\n * - MS_CLIENT_SECRET OAuth client secret (optional)\n * - AUTH_MODE Default authentication mode (optional)\n * - HEADLESS Disable browser auto-open (optional)\n * - DCR_MODE DCR mode (optional, same format as --dcr-mode)\n * - DCR_VERIFY_URL External verification URL (optional, same as --dcr-verify-url)\n * - DCR_STORE_URI DCR storage URI (optional, same as --dcr-store-uri)\n * - PORT Default HTTP port (optional)\n * - LOG_LEVEL Default logging level (optional)\n * - STORAGE_DIR Directory for CSV file storage (optional)\n * - BASE_URL Base URL for HTTP file serving (optional)\n *\n * OAuth Scopes (from constants.ts):\n * openid profile offline_access https://graph.microsoft.com/User.Read https://graph.microsoft.com/Mail.ReadWrite https://graph.microsoft.com/Mail.Send https://graph.microsoft.com/MailboxSettings.ReadWrite\n */\nexport function parseConfig(args: string[], env: Record<string, string | undefined>): ServerConfig {\n const transportConfig = parseTransportConfig(args, env);\n const oauthConfig = parseOAuthConfig(args, env);\n\n // Parse DCR configuration if DCR mode is enabled\n const dcrConfig = oauthConfig.auth === 'dcr' ? parseDcrConfig(args, env, MS_SCOPE) : undefined;\n\n // Parse application-level config (LOG_LEVEL, STORAGE_DIR, BASE_URL)\n const { values } = parseArgs({\n args,\n options: {\n 'log-level': { type: 'string' },\n 'base-url': { type: 'string' },\n 'storage-dir': { type: 'string' },\n },\n strict: false, // Allow other arguments\n allowPositionals: true,\n });\n\n const name = pkg.name.replace(/^@[^/]+\\//, '');\n // Parse repository URL from package.json, stripping git+ prefix and .git suffix\n const rawRepoUrl = typeof pkg.repository === 'object' ? pkg.repository.url : pkg.repository;\n const repositoryUrl = rawRepoUrl?.replace(/^git\\+/, '').replace(/\\.git$/, '') ?? `https://github.com/mcp-z/${name}`;\n let rootDir = homedir();\n try {\n const configPath = findConfigPath({ config: '.mcp.json', cwd: process.cwd(), stopDir: homedir() });\n rootDir = path.dirname(configPath);\n } catch {\n rootDir = homedir();\n }\n const baseDir = path.join(rootDir, '.mcp-z');\n const cliLogLevel = typeof values['log-level'] === 'string' ? values['log-level'] : undefined;\n const envLogLevel = env.LOG_LEVEL;\n const logLevel = cliLogLevel ?? envLogLevel ?? 'info';\n\n // Parse file storage configuration\n const cliStorageDir = typeof values['storage-dir'] === 'string' ? values['storage-dir'] : undefined;\n const envStorageDir = env.STORAGE_DIR;\n let storageDir = cliStorageDir ?? envStorageDir ?? path.join(baseDir, name, 'files');\n if (storageDir.startsWith('~')) storageDir = storageDir.replace(/^~/, homedir());\n\n const cliBaseUrl = typeof values['base-url'] === 'string' ? values['base-url'] : undefined;\n const envBaseUrl = env.BASE_URL;\n const baseUrl = cliBaseUrl ?? envBaseUrl;\n\n // Combine configs\n const result: ServerConfig = {\n ...oauthConfig, // Includes clientId, auth, headless, redirectUri\n transport: transportConfig.transport,\n logLevel,\n baseDir,\n name,\n version: pkg.version,\n repositoryUrl,\n storageDir: path.resolve(storageDir),\n };\n if (baseUrl !== undefined) result.baseUrl = baseUrl;\n if (dcrConfig !== undefined) result.dcrConfig = dcrConfig;\n return result;\n}\n\n/**\n * Build production configuration from process globals.\n * Entry point for production server.\n */\nexport function createConfig(): ServerConfig {\n return parseConfig(process.argv, process.env);\n}\n"],"names":["parseDcrConfig","parseConfig","parseOAuthConfig","findConfigPath","parseTransportConfig","fs","moduleRoot","homedir","path","url","parseArgs","MS_SCOPE","pkg","JSON","parse","readFileSync","join","fileURLToPath","HELP_TEXT","trim","handleVersionHelp","args","values","options","version","type","help","strict","handled","output","env","cliLogLevel","cliStorageDir","transportConfig","oauthConfig","dcrConfig","auth","undefined","allowPositionals","name","replace","rawRepoUrl","repository","repositoryUrl","rootDir","configPath","config","cwd","process","stopDir","dirname","baseDir","envLogLevel","LOG_LEVEL","logLevel","envStorageDir","STORAGE_DIR","storageDir","startsWith","cliBaseUrl","envBaseUrl","BASE_URL","baseUrl","result","transport","resolve","createConfig","argv"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/src/setup/config.ts"],"sourcesContent":["import { parseDcrConfig, parseConfig as parseOAuthConfig } from '@mcp-z/oauth-microsoft';\nimport { findConfigPath, parseConfig as parseTransportConfig } from '@mcp-z/server';\nimport * as fs from 'fs';\nimport moduleRoot from 'module-root-sync';\nimport { homedir } from 'os';\nimport * as path from 'path';\nimport * as url from 'url';\nimport { parseArgs } from 'util';\nimport { MS_SCOPE } from '../constants.ts';\nimport type { ServerConfig } from '../types.ts';\n\nconst pkg = JSON.parse(fs.readFileSync(path.join(moduleRoot(url.fileURLToPath(import.meta.url)), 'package.json'), 'utf-8'));\n\nconst HELP_TEXT = `\nUsage: mcp-outlook [options]\n\nMCP server for Outlook/Microsoft email management with OAuth authentication.\n\nOptions:\n --version Show version number\n --help Show this help message\n --auth=<mode> Authentication mode (default: loopback-oauth)\n Modes: loopback-oauth, device-code, dcr\n --headless Disable browser auto-open, return auth URL instead\n --redirect-uri=<uri> OAuth redirect URI (default: ephemeral loopback)\n --tenant-id=<id> Microsoft tenant ID (overrides MS_TENANT_ID env var)\n --dcr-mode=<mode> DCR mode (self-hosted or external, default: self-hosted)\n --dcr-verify-url=<url> External verification endpoint (required for external mode)\n --dcr-store-uri=<uri> DCR client storage URI (required for self-hosted mode)\n --port=<port> Enable HTTP transport on specified port\n --stdio Enable stdio transport (default if no port)\n --log-level=<level> Logging level (default: info)\n --resource-store-uri=<uri> Resource store URI for CSV file storage (default: file://~/.mcp-z/mcp-outlook/files)\n --base-url=<url> Base URL for HTTP file serving (default: http://localhost for HTTP transports)\n\nEnvironment Variables:\n MS_CLIENT_ID OAuth client ID (REQUIRED)\n MS_TENANT_ID Microsoft tenant ID (REQUIRED)\n MS_CLIENT_SECRET OAuth client secret (optional)\n AUTH_MODE Default authentication mode (optional)\n HEADLESS Disable browser auto-open (optional)\n DCR_MODE DCR mode (optional, same format as --dcr-mode)\n DCR_VERIFY_URL External verification URL (optional, same as --dcr-verify-url)\n DCR_STORE_URI DCR storage URI (optional, same as --dcr-store-uri)\n TOKEN_STORE_URI Token storage URI (optional)\n PORT Default HTTP port (optional)\n LOG_LEVEL Default logging level (optional)\n RESOURCE_STORE_URI Resource store URI (optional, file://)\n BASE_URL Base URL for HTTP file serving (optional)\n\nOAuth Scopes:\n openid profile offline_access https://graph.microsoft.com/User.Read https://graph.microsoft.com/Mail.ReadWrite https://graph.microsoft.com/Mail.Send https://graph.microsoft.com/MailboxSettings.ReadWrite\n\nExamples:\n mcp-outlook # Use default settings\n mcp-outlook --auth=device-code # Use device code auth\n mcp-outlook --port=3000 # HTTP transport on port 3000\n mcp-outlook --tenant-id=xxx # Set tenant ID\n mcp-outlook --resource-store-uri=file:///tmp/emails # Custom resource store URI\n MS_CLIENT_ID=xxx mcp-outlook # Set client ID via env var\n`.trim();\n\n/**\n * Handle --version and --help flags before config parsing.\n * These should work without requiring any configuration.\n */\nexport function handleVersionHelp(args: string[]): { handled: boolean; output?: string } {\n const { values } = parseArgs({\n args,\n options: {\n version: { type: 'boolean' },\n help: { type: 'boolean' },\n },\n strict: false,\n });\n\n if (values.version) return { handled: true, output: pkg.version };\n if (values.help) return { handled: true, output: HELP_TEXT };\n return { handled: false };\n}\n\n/**\n * Parse Outlook server configuration from CLI arguments and environment.\n *\n * CLI Arguments (all optional):\n * - --auth=<mode> Authentication mode (default: loopback-oauth)\n * Modes: loopback-oauth, device-code, dcr\n * - --headless Disable browser auto-open, return auth URL instead\n * - --redirect-uri=<uri> OAuth redirect URI (default: ephemeral loopback)\n * - --tenant-id=<id> Microsoft tenant ID (overrides MS_TENANT_ID env var)\n * - --dcr-mode=<mode> DCR mode (self-hosted or external, default: self-hosted)\n * - --dcr-verify-url=<url> External verification endpoint (required for external mode)\n * - --dcr-store-uri=<uri> DCR client storage URI (required for self-hosted mode)\n * - --port=<port> Enable HTTP transport on specified port\n * - --stdio Enable stdio transport (default if no port)\n * - --log-level=<level> Logging level (default: info)\n * - --resource-store-uri=<uri> Resource store URI for CSV file storage (default: file://~/.mcp-z/mcp-outlook/files)\n * - --base-url=<url> Base URL for HTTP file serving (default: http://localhost for HTTP transports)\n *\n * Environment Variables:\n * - MS_CLIENT_ID OAuth client ID (REQUIRED)\n * - MS_TENANT_ID Microsoft tenant ID (REQUIRED)\n * - MS_CLIENT_SECRET OAuth client secret (optional)\n * - AUTH_MODE Default authentication mode (optional)\n * - HEADLESS Disable browser auto-open (optional)\n * - DCR_MODE DCR mode (optional, same format as --dcr-mode)\n * - DCR_VERIFY_URL External verification URL (optional, same as --dcr-verify-url)\n * - DCR_STORE_URI DCR storage URI (optional, same as --dcr-store-uri)\n * - TOKEN_STORE_URI Token storage URI (optional)\n * - PORT Default HTTP port (optional)\n * - LOG_LEVEL Default logging level (optional)\n * - RESOURCE_STORE_URI Resource store URI (optional, file://)\n * - BASE_URL Base URL for HTTP file serving (optional)\n *\n * OAuth Scopes (from constants.ts):\n * openid profile offline_access https://graph.microsoft.com/User.Read https://graph.microsoft.com/Mail.ReadWrite https://graph.microsoft.com/Mail.Send https://graph.microsoft.com/MailboxSettings.ReadWrite\n */\nexport function parseConfig(args: string[], env: Record<string, string | undefined>): ServerConfig {\n const transportConfig = parseTransportConfig(args, env);\n const oauthConfig = parseOAuthConfig(args, env);\n\n // Parse DCR configuration if DCR mode is enabled\n const dcrConfig = oauthConfig.auth === 'dcr' ? parseDcrConfig(args, env, MS_SCOPE) : undefined;\n\n // Parse application-level config (LOG_LEVEL, RESOURCE_STORE_URI, BASE_URL)\n const { values } = parseArgs({\n args,\n options: {\n 'log-level': { type: 'string' },\n 'base-url': { type: 'string' },\n 'resource-store-uri': { type: 'string' },\n },\n strict: false, // Allow other arguments\n allowPositionals: true,\n });\n\n const name = pkg.name.replace(/^@[^/]+\\//, '');\n // Parse repository URL from package.json, stripping git+ prefix and .git suffix\n const rawRepoUrl = typeof pkg.repository === 'object' ? pkg.repository.url : pkg.repository;\n const repositoryUrl = rawRepoUrl?.replace(/^git\\+/, '').replace(/\\.git$/, '') ?? `https://github.com/mcp-z/${name}`;\n let rootDir = homedir();\n try {\n const configPath = findConfigPath({ config: '.mcp.json', cwd: process.cwd(), stopDir: homedir() });\n rootDir = path.dirname(configPath);\n } catch {\n rootDir = homedir();\n }\n const baseDir = path.join(rootDir, '.mcp-z');\n const cliLogLevel = typeof values['log-level'] === 'string' ? values['log-level'] : undefined;\n const envLogLevel = env.LOG_LEVEL;\n const logLevel = cliLogLevel ?? envLogLevel ?? 'info';\n\n // Parse file storage configuration\n const cliResourceStoreUri = typeof values['resource-store-uri'] === 'string' ? values['resource-store-uri'] : undefined;\n const envResourceStoreUri = env.RESOURCE_STORE_URI;\n const defaultResourceStorePath = path.join(baseDir, name, 'files');\n const resourceStoreUri = normalizeResourceStoreUri(cliResourceStoreUri ?? envResourceStoreUri ?? defaultResourceStorePath);\n\n const cliBaseUrl = typeof values['base-url'] === 'string' ? values['base-url'] : undefined;\n const envBaseUrl = env.BASE_URL;\n const baseUrl = cliBaseUrl ?? envBaseUrl;\n\n // Combine configs\n const result: ServerConfig = {\n ...oauthConfig, // Includes clientId, auth, headless, redirectUri\n transport: transportConfig.transport,\n logLevel,\n baseDir,\n name,\n version: pkg.version,\n repositoryUrl,\n resourceStoreUri,\n };\n if (baseUrl !== undefined) result.baseUrl = baseUrl;\n if (dcrConfig !== undefined) result.dcrConfig = dcrConfig;\n return result;\n}\n\n/**\n * Build production configuration from process globals.\n * Entry point for production server.\n */\nexport function createConfig(): ServerConfig {\n return parseConfig(process.argv, process.env);\n}\n\nfunction normalizeResourceStoreUri(resourceStoreUri: string): string {\n const filePrefix = 'file://';\n if (resourceStoreUri.startsWith(filePrefix)) {\n const rawPath = resourceStoreUri.slice(filePrefix.length);\n const expandedPath = rawPath.startsWith('~') ? rawPath.replace(/^~/, homedir()) : rawPath;\n return `${filePrefix}${path.resolve(expandedPath)}`;\n }\n\n if (resourceStoreUri.includes('://')) return resourceStoreUri;\n\n const expandedPath = resourceStoreUri.startsWith('~') ? resourceStoreUri.replace(/^~/, homedir()) : resourceStoreUri;\n return `${filePrefix}${path.resolve(expandedPath)}`;\n}\n"],"names":["parseDcrConfig","parseConfig","parseOAuthConfig","findConfigPath","parseTransportConfig","fs","moduleRoot","homedir","path","url","parseArgs","MS_SCOPE","pkg","JSON","parse","readFileSync","join","fileURLToPath","HELP_TEXT","trim","handleVersionHelp","args","values","options","version","type","help","strict","handled","output","env","cliLogLevel","cliResourceStoreUri","transportConfig","oauthConfig","dcrConfig","auth","undefined","allowPositionals","name","replace","rawRepoUrl","repository","repositoryUrl","rootDir","configPath","config","cwd","process","stopDir","dirname","baseDir","envLogLevel","LOG_LEVEL","logLevel","envResourceStoreUri","RESOURCE_STORE_URI","defaultResourceStorePath","resourceStoreUri","normalizeResourceStoreUri","cliBaseUrl","envBaseUrl","BASE_URL","baseUrl","result","transport","createConfig","argv","filePrefix","startsWith","rawPath","slice","length","expandedPath","resolve","includes"],"mappings":"AAAA,SAASA,cAAc,EAAEC,eAAeC,gBAAgB,QAAQ,yBAAyB;AACzF,SAASC,cAAc,EAAEF,eAAeG,oBAAoB,QAAQ,gBAAgB;AACpF,YAAYC,QAAQ,KAAK;AACzB,OAAOC,gBAAgB,mBAAmB;AAC1C,SAASC,OAAO,QAAQ,KAAK;AAC7B,YAAYC,UAAU,OAAO;AAC7B,YAAYC,SAAS,MAAM;AAC3B,SAASC,SAAS,QAAQ,OAAO;AACjC,SAASC,QAAQ,QAAQ,kBAAkB;AAG3C,MAAMC,MAAMC,KAAKC,KAAK,CAACT,GAAGU,YAAY,CAACP,KAAKQ,IAAI,CAACV,WAAWG,IAAIQ,aAAa,CAAC,YAAYR,GAAG,IAAI,iBAAiB;AAElH,MAAMS,YAAY,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+CnB,CAAC,CAACC,IAAI;AAEN;;;CAGC,GACD,OAAO,SAASC,kBAAkBC,IAAc;IAC9C,MAAM,EAAEC,MAAM,EAAE,GAAGZ,UAAU;QAC3BW;QACAE,SAAS;YACPC,SAAS;gBAAEC,MAAM;YAAU;YAC3BC,MAAM;gBAAED,MAAM;YAAU;QAC1B;QACAE,QAAQ;IACV;IAEA,IAAIL,OAAOE,OAAO,EAAE,OAAO;QAAEI,SAAS;QAAMC,QAAQjB,IAAIY,OAAO;IAAC;IAChE,IAAIF,OAAOI,IAAI,EAAE,OAAO;QAAEE,SAAS;QAAMC,QAAQX;IAAU;IAC3D,OAAO;QAAEU,SAAS;IAAM;AAC1B;AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCC,GACD,OAAO,SAAS3B,YAAYoB,IAAc,EAAES,GAAuC;cAiChEC,OAMkCC;IAtCnD,MAAMC,kBAAkB7B,qBAAqBiB,MAAMS;IACnD,MAAMI,cAAchC,iBAAiBmB,MAAMS;IAE3C,iDAAiD;IACjD,MAAMK,YAAYD,YAAYE,IAAI,KAAK,QAAQpC,eAAeqB,MAAMS,KAAKnB,YAAY0B;IAErF,2EAA2E;IAC3E,MAAM,EAAEf,MAAM,EAAE,GAAGZ,UAAU;QAC3BW;QACAE,SAAS;YACP,aAAa;gBAAEE,MAAM;YAAS;YAC9B,YAAY;gBAAEA,MAAM;YAAS;YAC7B,sBAAsB;gBAAEA,MAAM;YAAS;QACzC;QACAE,QAAQ;QACRW,kBAAkB;IACpB;IAEA,MAAMC,OAAO3B,IAAI2B,IAAI,CAACC,OAAO,CAAC,aAAa;IAC3C,gFAAgF;IAChF,MAAMC,aAAa,OAAO7B,IAAI8B,UAAU,KAAK,WAAW9B,IAAI8B,UAAU,CAACjC,GAAG,GAAGG,IAAI8B,UAAU;IAC3F,MAAMC,wBAAgBF,uBAAAA,iCAAAA,WAAYD,OAAO,CAAC,UAAU,IAAIA,OAAO,CAAC,UAAU,0CAAO,CAAC,yBAAyB,EAAED,MAAM;IACnH,IAAIK,UAAUrC;IACd,IAAI;QACF,MAAMsC,aAAa1C,eAAe;YAAE2C,QAAQ;YAAaC,KAAKC,QAAQD,GAAG;YAAIE,SAAS1C;QAAU;QAChGqC,UAAUpC,KAAK0C,OAAO,CAACL;IACzB,EAAE,OAAM;QACND,UAAUrC;IACZ;IACA,MAAM4C,UAAU3C,KAAKQ,IAAI,CAAC4B,SAAS;IACnC,MAAMb,cAAc,OAAOT,MAAM,CAAC,YAAY,KAAK,WAAWA,MAAM,CAAC,YAAY,GAAGe;IACpF,MAAMe,cAActB,IAAIuB,SAAS;IACjC,MAAMC,YAAWvB,QAAAA,wBAAAA,yBAAAA,cAAeqB,yBAAfrB,mBAAAA,QAA8B;IAE/C,mCAAmC;IACnC,MAAMC,sBAAsB,OAAOV,MAAM,CAAC,qBAAqB,KAAK,WAAWA,MAAM,CAAC,qBAAqB,GAAGe;IAC9G,MAAMkB,sBAAsBzB,IAAI0B,kBAAkB;IAClD,MAAMC,2BAA2BjD,KAAKQ,IAAI,CAACmC,SAASZ,MAAM;IAC1D,MAAMmB,mBAAmBC,2BAA0B3B,QAAAA,gCAAAA,iCAAAA,sBAAuBuB,iCAAvBvB,mBAAAA,QAA8CyB;IAEjG,MAAMG,aAAa,OAAOtC,MAAM,CAAC,WAAW,KAAK,WAAWA,MAAM,CAAC,WAAW,GAAGe;IACjF,MAAMwB,aAAa/B,IAAIgC,QAAQ;IAC/B,MAAMC,UAAUH,uBAAAA,wBAAAA,aAAcC;IAE9B,kBAAkB;IAClB,MAAMG,SAAuB;QAC3B,GAAG9B,WAAW;QACd+B,WAAWhC,gBAAgBgC,SAAS;QACpCX;QACAH;QACAZ;QACAf,SAASZ,IAAIY,OAAO;QACpBmB;QACAe;IACF;IACA,IAAIK,YAAY1B,WAAW2B,OAAOD,OAAO,GAAGA;IAC5C,IAAI5B,cAAcE,WAAW2B,OAAO7B,SAAS,GAAGA;IAChD,OAAO6B;AACT;AAEA;;;CAGC,GACD,OAAO,SAASE;IACd,OAAOjE,YAAY+C,QAAQmB,IAAI,EAAEnB,QAAQlB,GAAG;AAC9C;AAEA,SAAS6B,0BAA0BD,gBAAwB;IACzD,MAAMU,aAAa;IACnB,IAAIV,iBAAiBW,UAAU,CAACD,aAAa;QAC3C,MAAME,UAAUZ,iBAAiBa,KAAK,CAACH,WAAWI,MAAM;QACxD,MAAMC,eAAeH,QAAQD,UAAU,CAAC,OAAOC,QAAQ9B,OAAO,CAAC,MAAMjC,aAAa+D;QAClF,OAAO,GAAGF,aAAa5D,KAAKkE,OAAO,CAACD,eAAe;IACrD;IAEA,IAAIf,iBAAiBiB,QAAQ,CAAC,QAAQ,OAAOjB;IAE7C,MAAMe,eAAef,iBAAiBW,UAAU,CAAC,OAAOX,iBAAiBlB,OAAO,CAAC,MAAMjC,aAAamD;IACpG,OAAO,GAAGU,aAAa5D,KAAKkE,OAAO,CAACD,eAAe;AACrD"}
|
package/dist/esm/setup/http.js
CHANGED
|
@@ -36,7 +36,7 @@ export async function createHTTPServer(config, overrides) {
|
|
|
36
36
|
logger.info('Mounted loopback OAuth callback router');
|
|
37
37
|
}
|
|
38
38
|
const fileRouter = createFileServingRouter({
|
|
39
|
-
|
|
39
|
+
resourceStoreUri: config.resourceStoreUri
|
|
40
40
|
}, {
|
|
41
41
|
contentType: 'text/csv',
|
|
42
42
|
contentDisposition: 'attachment'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/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 prompts = [...composed.prompts, ...runtime.deps.oauthAdapters.accountPrompts];\n\n const mcpServer = new McpServer({ name: config.name, version: config.version });\n registerTools(mcpServer, tools);\n registerResources(mcpServer, composed.resources);\n registerPrompts(mcpServer, prompts);\n\n const app = express();\n app.use(cors());\n app.use(express.json({ limit: '10mb' }));\n\n if (runtime.deps.oauthAdapters.loopbackRouter) {\n app.use('/', runtime.deps.oauthAdapters.loopbackRouter);\n logger.info('Mounted loopback OAuth callback router');\n }\n\n const fileRouter = createFileServingRouter({
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/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 prompts = [...composed.prompts, ...runtime.deps.oauthAdapters.accountPrompts];\n\n const mcpServer = new McpServer({ name: config.name, version: config.version });\n registerTools(mcpServer, tools);\n registerResources(mcpServer, composed.resources);\n registerPrompts(mcpServer, prompts);\n\n const app = express();\n app.use(cors());\n app.use(express.json({ limit: '10mb' }));\n\n if (runtime.deps.oauthAdapters.loopbackRouter) {\n app.use('/', runtime.deps.oauthAdapters.loopbackRouter);\n logger.info('Mounted loopback OAuth callback router');\n }\n\n const fileRouter = createFileServingRouter({ resourceStoreUri: config.resourceStoreUri }, { contentType: 'text/csv', contentDisposition: 'attachment' });\n app.use('/files', fileRouter);\n\n if (runtime.deps.oauthAdapters.dcrRouter) {\n app.use('/', runtime.deps.oauthAdapters.dcrRouter);\n logger.info('Mounted DCR router with OAuth endpoints');\n }\n\n logger.info(`Starting ${config.name} MCP server (http)`);\n const { close, httpServer } = await connectHttp(mcpServer, { logger, app, port });\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","prompts","accountPrompts","mcpServer","name","version","resources","app","use","json","limit","loopbackRouter","info","fileRouter","resourceStoreUri","contentType","contentDisposition","dcrRouter","close","httpServer"],"mappings":"AAAA,SAASA,iBAAiB,EAAEC,WAAW,EAAEC,uBAAuB,EAAEC,eAAe,EAAEC,iBAAiB,EAAEC,aAAa,QAAQ,gBAAgB;AAC3I,SAASC,SAAS,QAAQ,0CAA0C;AACpE,OAAOC,UAAU,OAAO;AACxB,OAAOC,aAAa,UAAU;AAE9B,SAASC,oBAAoB,QAAQ,eAAe;AAEpD,OAAO,eAAeC,iBAAiBC,MAAoB,EAAEC,SAA4B;IACvF,MAAMC,UAAU,MAAMJ,qBAAqBE,QAAQC;IACnD,MAAME,UAAUD,QAAQE,mBAAmB;IAC3C,MAAMC,SAASH,QAAQI,mBAAmB,CAACC,GAAG,CAAC,CAACC,UAAYA,QAAQN,QAAQO,IAAI;IAChF,MAAMC,WAAWrB,kBAAkBc,SAASE;IAC5C,MAAMM,SAAST,QAAQO,IAAI,CAACE,MAAM;IAClC,MAAMC,OAAOZ,OAAOa,SAAS,CAACD,IAAI;IAClC,IAAI,CAACA,MAAM,MAAM,IAAIE,MAAM;IAE3B,MAAMC,QAAQ;WAAIL,SAASK,KAAK;WAAKb,QAAQO,IAAI,CAACO,aAAa,CAACC,YAAY;KAAC;IAC7E,MAAMC,UAAU;WAAIR,SAASQ,OAAO;WAAKhB,QAAQO,IAAI,CAACO,aAAa,CAACG,cAAc;KAAC;IAEnF,MAAMC,YAAY,IAAIzB,UAAU;QAAE0B,MAAMrB,OAAOqB,IAAI;QAAEC,SAAStB,OAAOsB,OAAO;IAAC;IAC7E5B,cAAc0B,WAAWL;IACzBtB,kBAAkB2B,WAAWV,SAASa,SAAS;IAC/C/B,gBAAgB4B,WAAWF;IAE3B,MAAMM,MAAM3B;IACZ2B,IAAIC,GAAG,CAAC7B;IACR4B,IAAIC,GAAG,CAAC5B,QAAQ6B,IAAI,CAAC;QAAEC,OAAO;IAAO;IAErC,IAAIzB,QAAQO,IAAI,CAACO,aAAa,CAACY,cAAc,EAAE;QAC7CJ,IAAIC,GAAG,CAAC,KAAKvB,QAAQO,IAAI,CAACO,aAAa,CAACY,cAAc;QACtDjB,OAAOkB,IAAI,CAAC;IACd;IAEA,MAAMC,aAAavC,wBAAwB;QAAEwC,kBAAkB/B,OAAO+B,gBAAgB;IAAC,GAAG;QAAEC,aAAa;QAAYC,oBAAoB;IAAa;IACtJT,IAAIC,GAAG,CAAC,UAAUK;IAElB,IAAI5B,QAAQO,IAAI,CAACO,aAAa,CAACkB,SAAS,EAAE;QACxCV,IAAIC,GAAG,CAAC,KAAKvB,QAAQO,IAAI,CAACO,aAAa,CAACkB,SAAS;QACjDvB,OAAOkB,IAAI,CAAC;IACd;IAEAlB,OAAOkB,IAAI,CAAC,CAAC,SAAS,EAAE7B,OAAOqB,IAAI,CAAC,kBAAkB,CAAC;IACvD,MAAM,EAAEc,KAAK,EAAEC,UAAU,EAAE,GAAG,MAAM9C,YAAY8B,WAAW;QAAET;QAAQa;QAAKZ;IAAK;IAC/ED,OAAOkB,IAAI,CAAC;IAEZ,OAAO;QACLO;QACAhB;QACAT;QACAwB,OAAO;YACL,MAAMA;YACN,MAAMjC,QAAQiC,KAAK;QACrB;IACF;AACF"}
|
|
@@ -22,8 +22,8 @@ export function createLogger(config) {
|
|
|
22
22
|
}) : pino.destination(1));
|
|
23
23
|
}
|
|
24
24
|
export async function createTokenStore(baseDir) {
|
|
25
|
-
const
|
|
26
|
-
return createStore(
|
|
25
|
+
const tokenStoreUri = process.env.TOKEN_STORE_URI || `file://${path.join(baseDir, 'tokens.json')}`;
|
|
26
|
+
return createStore(tokenStoreUri);
|
|
27
27
|
}
|
|
28
28
|
export async function createDcrStore(baseDir, required) {
|
|
29
29
|
if (!required) return undefined;
|
|
@@ -65,8 +65,8 @@ export function createStorageLayer(storageContext) {
|
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
67
|
export function assertStorageConfig(config) {
|
|
68
|
-
if (!config.
|
|
69
|
-
throw new Error('outlook-messages-export-csv: Server configuration missing
|
|
68
|
+
if (!config.resourceStoreUri) {
|
|
69
|
+
throw new Error('outlook-messages-export-csv: Server configuration missing resourceStoreUri.');
|
|
70
70
|
}
|
|
71
71
|
if (config.transport.type === 'http' && !config.baseUrl && !config.transport.port) {
|
|
72
72
|
throw new Error('outlook-messages-export-csv: HTTP transport requires either baseUrl in server config or port in transport config. This is a server configuration error - please provide --base-url or --port.');
|
|
@@ -101,7 +101,7 @@ export async function createDefaultRuntime(config, overrides) {
|
|
|
101
101
|
()=>createAuthLayer(oauthAdapters.middleware),
|
|
102
102
|
()=>createLoggingLayer(logger),
|
|
103
103
|
()=>createStorageLayer({
|
|
104
|
-
|
|
104
|
+
resourceStoreUri: config.resourceStoreUri,
|
|
105
105
|
baseUrl: config.baseUrl,
|
|
106
106
|
transport: config.transport
|
|
107
107
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/src/setup/runtime.ts"],"sourcesContent":["import { sanitizeForLoggingFormatter } from '@mcp-z/oauth';\nimport type { Logger, MiddlewareLayer } from '@mcp-z/server';\nimport { createLoggingMiddleware } from '@mcp-z/server';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport pino from 'pino';\nimport createStore from '../lib/create-store.ts';\nimport * as mcp from '../mcp/index.ts';\nimport type { CommonRuntime, RuntimeDeps, RuntimeOverrides, ServerConfig, StorageContext } from '../types.ts';\nimport { createOAuthAdapters, type OAuthAdapters } from './oauth-microsoft.ts';\n\nexport function createLogger(config: ServerConfig): Logger {\n const hasStdio = config.transport.type === 'stdio';\n const logsPath = path.join(config.baseDir, 'logs', `${config.name}.log`);\n if (hasStdio) fs.mkdirSync(path.dirname(logsPath), { recursive: true });\n return pino({ level: config.logLevel ?? 'info', formatters: sanitizeForLoggingFormatter() }, hasStdio ? pino.destination({ dest: logsPath, sync: false }) : pino.destination(1));\n}\n\nexport async function createTokenStore(baseDir: string) {\n const
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/src/setup/runtime.ts"],"sourcesContent":["import { sanitizeForLoggingFormatter } from '@mcp-z/oauth';\nimport type { Logger, MiddlewareLayer } from '@mcp-z/server';\nimport { createLoggingMiddleware } from '@mcp-z/server';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport pino from 'pino';\nimport createStore from '../lib/create-store.ts';\nimport * as mcp from '../mcp/index.ts';\nimport type { CommonRuntime, RuntimeDeps, RuntimeOverrides, ServerConfig, StorageContext } from '../types.ts';\nimport { createOAuthAdapters, type OAuthAdapters } from './oauth-microsoft.ts';\n\nexport function createLogger(config: ServerConfig): Logger {\n const hasStdio = config.transport.type === 'stdio';\n const logsPath = path.join(config.baseDir, 'logs', `${config.name}.log`);\n if (hasStdio) fs.mkdirSync(path.dirname(logsPath), { recursive: true });\n return pino({ level: config.logLevel ?? 'info', formatters: sanitizeForLoggingFormatter() }, hasStdio ? pino.destination({ dest: logsPath, sync: false }) : pino.destination(1));\n}\n\nexport async function createTokenStore(baseDir: string) {\n const tokenStoreUri = process.env.TOKEN_STORE_URI || `file://${path.join(baseDir, 'tokens.json')}`;\n return createStore<unknown>(tokenStoreUri);\n}\n\nexport async function createDcrStore(baseDir: string, required: boolean) {\n if (!required) return undefined;\n const dcrStoreUri = process.env.DCR_STORE_URI || `file://${path.join(baseDir, 'dcr.json')}`;\n return createStore<unknown>(dcrStoreUri);\n}\n\nexport function createAuthLayer(authMiddleware: OAuthAdapters['middleware']): MiddlewareLayer {\n return {\n withTool: authMiddleware.withToolAuth,\n withResource: authMiddleware.withResourceAuth,\n withPrompt: authMiddleware.withPromptAuth,\n };\n}\n\nexport function createLoggingLayer(logger: Logger): MiddlewareLayer {\n const logging = createLoggingMiddleware({ logger });\n return {\n withTool: logging.withToolLogging,\n withResource: logging.withResourceLogging,\n withPrompt: logging.withPromptLogging,\n };\n}\n\nexport function createStorageLayer(storageContext: StorageContext): MiddlewareLayer {\n const wrapAtPosition = <T extends { name: string; handler: unknown; [key: string]: unknown }>(module: T, extraPosition: number): T => {\n const originalHandler = module.handler as (...args: unknown[]) => Promise<unknown>;\n\n const wrappedHandler = async (...allArgs: unknown[]) => {\n const extra = allArgs[extraPosition];\n (extra as { storageContext?: StorageContext }).storageContext = storageContext;\n return await originalHandler(...allArgs);\n };\n\n return {\n ...module,\n handler: wrappedHandler,\n } as T;\n };\n\n return {\n withTool: <T extends { name: string; config: unknown; handler: unknown }>(module: T): T => wrapAtPosition(module, 1) as T,\n };\n}\n\nexport function assertStorageConfig(config: ServerConfig) {\n if (!config.resourceStoreUri) {\n throw new Error('outlook-messages-export-csv: Server configuration missing resourceStoreUri.');\n }\n if (config.transport.type === 'http' && !config.baseUrl && !config.transport.port) {\n throw new Error('outlook-messages-export-csv: HTTP transport requires either baseUrl in server config or port in transport config. This is a server configuration error - please provide --base-url or --port.');\n }\n}\n\nexport async function createDefaultRuntime(config: ServerConfig, overrides?: RuntimeOverrides): Promise<CommonRuntime> {\n if (config.auth === 'dcr' && config.transport.type !== 'http') throw new Error('DCR mode requires an HTTP transport');\n\n assertStorageConfig(config);\n const logger = createLogger(config);\n const tokenStore = await createTokenStore(config.baseDir);\n const baseUrl = config.baseUrl ?? (config.transport.type === 'http' && config.transport.port ? `http://localhost:${config.transport.port}` : undefined);\n const dcrStore = await createDcrStore(config.baseDir, config.auth === 'dcr');\n const oauthAdapters = await createOAuthAdapters(config, { logger, tokenStore, dcrStore }, baseUrl);\n const deps: RuntimeDeps = { config, logger, tokenStore, oauthAdapters, baseUrl };\n const createDomainModules =\n overrides?.createDomainModules ??\n (() => ({\n tools: Object.values(mcp.toolFactories).map((factory) => factory()),\n resources: Object.values(mcp.resourceFactories).map((factory) => factory()),\n prompts: Object.values(mcp.promptFactories).map((factory) => factory()),\n }));\n const middlewareFactories = overrides?.middlewareFactories ?? [() => createAuthLayer(oauthAdapters.middleware), () => createLoggingLayer(logger), () => createStorageLayer({ resourceStoreUri: config.resourceStoreUri, baseUrl: config.baseUrl, transport: config.transport })];\n\n return {\n deps,\n middlewareFactories,\n createDomainModules,\n close: async () => {},\n };\n}\n"],"names":["sanitizeForLoggingFormatter","createLoggingMiddleware","fs","path","pino","createStore","mcp","createOAuthAdapters","createLogger","config","hasStdio","transport","type","logsPath","join","baseDir","name","mkdirSync","dirname","recursive","level","logLevel","formatters","destination","dest","sync","createTokenStore","tokenStoreUri","process","env","TOKEN_STORE_URI","createDcrStore","required","undefined","dcrStoreUri","DCR_STORE_URI","createAuthLayer","authMiddleware","withTool","withToolAuth","withResource","withResourceAuth","withPrompt","withPromptAuth","createLoggingLayer","logger","logging","withToolLogging","withResourceLogging","withPromptLogging","createStorageLayer","storageContext","wrapAtPosition","module","extraPosition","originalHandler","handler","wrappedHandler","allArgs","extra","assertStorageConfig","resourceStoreUri","Error","baseUrl","port","createDefaultRuntime","overrides","auth","tokenStore","dcrStore","oauthAdapters","deps","createDomainModules","tools","Object","values","toolFactories","map","factory","resources","resourceFactories","prompts","promptFactories","middlewareFactories","middleware","close"],"mappings":"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"}
|
package/dist/esm/types.d.ts
CHANGED
|
@@ -12,12 +12,12 @@ export interface ServerConfig extends BaseServerConfig, OAuthConfig {
|
|
|
12
12
|
name: string;
|
|
13
13
|
version: string;
|
|
14
14
|
repositoryUrl: string;
|
|
15
|
-
|
|
15
|
+
resourceStoreUri: string;
|
|
16
16
|
baseUrl?: string;
|
|
17
17
|
dcrConfig?: DcrConfig;
|
|
18
18
|
}
|
|
19
19
|
export interface StorageContext {
|
|
20
|
-
|
|
20
|
+
resourceStoreUri: string;
|
|
21
21
|
baseUrl?: string;
|
|
22
22
|
transport: BaseServerConfig['transport'];
|
|
23
23
|
}
|
package/dist/esm/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/src/types.ts"],"sourcesContent":["import type { DcrConfig, OAuthConfig } from '@mcp-z/oauth-microsoft';\nimport type { BaseServerConfig, MiddlewareLayer, PromptModule, ResourceModule, Logger as ServerLogger, ToolModule } from '@mcp-z/server';\nimport type { Keyv } from 'keyv';\nimport type { OAuthAdapters } from './setup/oauth-microsoft.ts';\n\nexport type Logger = Pick<Console, 'info' | 'error' | 'warn' | 'debug'>;\n\n/**\n * Composes transport config, OAuth config, and application-level config\n */\nexport interface ServerConfig extends BaseServerConfig, OAuthConfig {\n logLevel: string;\n baseDir: string;\n name: string;\n version: string;\n repositoryUrl: string;\n\n // File serving configuration for CSV exports\n
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-outlook/src/types.ts"],"sourcesContent":["import type { DcrConfig, OAuthConfig } from '@mcp-z/oauth-microsoft';\nimport type { BaseServerConfig, MiddlewareLayer, PromptModule, ResourceModule, Logger as ServerLogger, ToolModule } from '@mcp-z/server';\nimport type { Keyv } from 'keyv';\nimport type { OAuthAdapters } from './setup/oauth-microsoft.ts';\n\nexport type Logger = Pick<Console, 'info' | 'error' | 'warn' | 'debug'>;\n\n/**\n * Composes transport config, OAuth config, and application-level config\n */\nexport interface ServerConfig extends BaseServerConfig, OAuthConfig {\n logLevel: string;\n baseDir: string;\n name: string;\n version: string;\n repositoryUrl: string;\n\n // File serving configuration for CSV exports\n resourceStoreUri: string;\n baseUrl?: string;\n\n // DCR configuration (when auth === 'dcr')\n dcrConfig?: DcrConfig;\n}\n\nexport interface StorageContext {\n resourceStoreUri: string;\n baseUrl?: string;\n transport: BaseServerConfig['transport'];\n}\n\nexport interface StorageExtra {\n storageContext: StorageContext;\n}\n\n/** Runtime dependencies exposed to middleware/factories. */\nexport interface RuntimeDeps {\n config: ServerConfig;\n logger: ServerLogger;\n tokenStore: Keyv<unknown>;\n oauthAdapters: OAuthAdapters;\n baseUrl?: string;\n}\n\n/** Collections of MCP modules produced by domain factories. */\nexport type DomainModules = {\n tools: ToolModule[];\n resources: ResourceModule[];\n prompts: PromptModule[];\n};\n\n/** Factory that produces a middleware layer given runtime dependencies. */\nexport type MiddlewareFactory = (deps: RuntimeDeps) => MiddlewareLayer;\n\n/** Shared runtime configuration returned by `createDefaultRuntime`. */\nexport interface CommonRuntime {\n deps: RuntimeDeps;\n middlewareFactories: MiddlewareFactory[];\n createDomainModules: () => DomainModules;\n close: () => Promise<void>;\n}\n\nexport interface RuntimeOverrides {\n middlewareFactories?: MiddlewareFactory[];\n createDomainModules?: () => DomainModules;\n}\n\nexport type { EmailAddress, OneDriveFile, OutlookAttachment, OutlookCalendarEvent, OutlookCategory, OutlookContact, OutlookFolder, OutlookMessage, OutlookQuery, OutlookSystemCategory, Recipient } from './schemas/index.ts';\n"],"names":[],"mappings":"AAmEA,WAA8N"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-z/mcp-outlook",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "MCP server for Outlook integration with OAuth authentication, message search, and batch operations",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"outlook",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"bin"
|
|
61
61
|
],
|
|
62
62
|
"scripts": {
|
|
63
|
-
"build": "
|
|
63
|
+
"build": "tsds validate",
|
|
64
64
|
"format": "tsds format",
|
|
65
65
|
"prepublish:check": "ncp",
|
|
66
66
|
"prepublishOnly": "tsds validate",
|
|
@@ -72,20 +72,20 @@
|
|
|
72
72
|
"version": "tsds version"
|
|
73
73
|
},
|
|
74
74
|
"dependencies": {
|
|
75
|
-
"@mcp-z/email": "^1.0.
|
|
76
|
-
"@mcp-z/oauth": "^1.0.
|
|
77
|
-
"@mcp-z/oauth-microsoft": "^1.0.
|
|
78
|
-
"@mcp-z/server": "^1.0.
|
|
79
|
-
"@microsoft/microsoft-graph-client": "^3.0.
|
|
80
|
-
"@microsoft/microsoft-graph-types": "^2.
|
|
81
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
82
|
-
"cors": "^2.
|
|
83
|
-
"csv-stringify": "^6.
|
|
84
|
-
"express": "^5.
|
|
85
|
-
"keyv-registry": "^0.
|
|
86
|
-
"module-root-sync": "^2.0.
|
|
87
|
-
"pino": "^10.
|
|
88
|
-
"zod": "^4.
|
|
75
|
+
"@mcp-z/email": "^1.0.0",
|
|
76
|
+
"@mcp-z/oauth": "^1.0.0",
|
|
77
|
+
"@mcp-z/oauth-microsoft": "^1.0.0",
|
|
78
|
+
"@mcp-z/server": "^1.0.0",
|
|
79
|
+
"@microsoft/microsoft-graph-client": "^3.0.0",
|
|
80
|
+
"@microsoft/microsoft-graph-types": "^2.0.0",
|
|
81
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
82
|
+
"cors": "^2.0.0",
|
|
83
|
+
"csv-stringify": "^6.0.0",
|
|
84
|
+
"express": "^5.0.0",
|
|
85
|
+
"keyv-registry": "^1.0.0",
|
|
86
|
+
"module-root-sync": "^2.0.0",
|
|
87
|
+
"pino": "^10.0.0",
|
|
88
|
+
"zod": "^4.0.0"
|
|
89
89
|
},
|
|
90
90
|
"devDependencies": {
|
|
91
91
|
"@mcp-z/client": "^1.0.5",
|
|
@@ -95,11 +95,10 @@
|
|
|
95
95
|
"@types/node": "^25.0.3",
|
|
96
96
|
"dotenv": "^17.2.3",
|
|
97
97
|
"get-port": "^7.1.0",
|
|
98
|
-
"keyv": "^5.
|
|
98
|
+
"keyv": "^5.0.0",
|
|
99
99
|
"node-version-use": "^2.4.7",
|
|
100
100
|
"ts-dev-stack": "^1.22.1",
|
|
101
|
-
"tsds-config": "^1.0.4"
|
|
102
|
-
"typescript": "^5.9.3"
|
|
101
|
+
"tsds-config": "^1.0.4"
|
|
103
102
|
},
|
|
104
103
|
"engines": {
|
|
105
104
|
"node": ">=20"
|