@mcp-z/mcp-gmail 1.0.4 → 1.0.6
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/README.md +1 -0
- 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 +15 -9
- package/dist/cjs/setup/http.js.map +1 -1
- package/dist/cjs/setup/runtime.d.cts +1 -1
- package/dist/cjs/setup/runtime.d.ts +1 -1
- package/dist/cjs/setup/runtime.js +20 -13
- package/dist/cjs/setup/runtime.js.map +1 -1
- package/dist/cjs/setup/stdio.js +6 -2
- package/dist/cjs/setup/stdio.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 +12 -8
- package/dist/esm/setup/http.js.map +1 -1
- package/dist/esm/setup/runtime.d.ts +1 -1
- package/dist/esm/setup/runtime.js +19 -11
- package/dist/esm/setup/runtime.js.map +1 -1
- package/dist/esm/setup/stdio.js +3 -1
- package/dist/esm/setup/stdio.js.map +1 -1
- package/dist/esm/types.d.ts +2 -2
- package/dist/esm/types.js.map +1 -1
- package/package.json +17 -18
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/setup/stdio.ts"],"sourcesContent":["import { composeMiddleware, connectStdio, registerPrompts, registerResources, registerTools } from '@mcp-z/server';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { RuntimeOverrides, ServerConfig } from '../types.ts';\nimport { createDefaultRuntime } from './runtime.ts';\n\nexport async function createStdioServer(config: ServerConfig, overrides?: RuntimeOverrides) {\n const runtime = await createDefaultRuntime(config, overrides);\n const modules = runtime.createDomainModules();\n const layers = runtime.middlewareFactories.map((factory) => factory(runtime.deps));\n const composed = composeMiddleware(modules, layers);\n const logger = runtime.deps.logger;\n\n const tools = [...composed.tools, ...runtime.deps.oauthAdapters.accountTools];\n const prompts = [...composed.prompts, ...runtime.deps.oauthAdapters.accountPrompts];\n\n const mcpServer = new McpServer({ name: config.name, version: config.version });\n registerTools(mcpServer,
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/setup/stdio.ts"],"sourcesContent":["import { composeMiddleware, connectStdio, registerPrompts, registerResources, registerTools } from '@mcp-z/server';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { RuntimeOverrides, ServerConfig } from '../types.ts';\nimport { createDefaultRuntime } from './runtime.ts';\n\nexport async function createStdioServer(config: ServerConfig, overrides?: RuntimeOverrides) {\n const runtime = await createDefaultRuntime(config, overrides);\n const modules = runtime.createDomainModules();\n const layers = runtime.middlewareFactories.map((factory) => factory(runtime.deps));\n const composed = composeMiddleware(modules, layers);\n const logger = runtime.deps.logger;\n\n const tools = [...composed.tools, ...runtime.deps.oauthAdapters.accountTools];\n const filteredTools =\n config.auth === 'dcr'\n ? tools.filter((tool) => tool.name !== 'messages-export-csv') // No file storage in DCR (public cloud responsibility)\n : tools;\n const prompts = [...composed.prompts, ...runtime.deps.oauthAdapters.accountPrompts];\n\n const mcpServer = new McpServer({ name: config.name, version: config.version });\n registerTools(mcpServer, filteredTools);\n registerResources(mcpServer, composed.resources);\n registerPrompts(mcpServer, prompts);\n\n logger.info(`Starting ${config.name} MCP server (stdio)`);\n const { close } = await connectStdio(mcpServer, { logger });\n logger.info('stdio transport ready');\n\n return {\n mcpServer,\n logger,\n close: async () => {\n await close();\n await runtime.close();\n },\n };\n}\n"],"names":["createStdioServer","config","overrides","runtime","modules","layers","composed","logger","tools","filteredTools","prompts","mcpServer","close","createDefaultRuntime","createDomainModules","middlewareFactories","map","factory","deps","composeMiddleware","oauthAdapters","accountTools","auth","filter","tool","name","accountPrompts","McpServer","version","registerTools","registerResources","resources","registerPrompts","info","connectStdio"],"mappings":";;;;+BAKsBA;;;eAAAA;;;sBAL6E;mBACzE;yBAEW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAE9B,SAAeA,kBAAkBC,MAAoB,EAAEC,SAA4B;;YAClFC,SACAC,SACAC,QACAC,UACAC,QAEAC,OACAC,eAIAC,SAEAC,WAMEC;;;;oBAnBQ;;wBAAMC,IAAAA,+BAAoB,EAACZ,QAAQC;;;oBAA7CC,UAAU;oBACVC,UAAUD,QAAQW,mBAAmB;oBACrCT,SAASF,QAAQY,mBAAmB,CAACC,GAAG,CAAC,SAACC;+BAAYA,QAAQd,QAAQe,IAAI;;oBAC1EZ,WAAWa,IAAAA,yBAAiB,EAACf,SAASC;oBACtCE,SAASJ,QAAQe,IAAI,CAACX,MAAM;oBAE5BC,QAAQ,AAAC,qBAAGF,SAASE,KAAK,SAAE,qBAAGL,QAAQe,IAAI,CAACE,aAAa,CAACC,YAAY;oBACtEZ,gBACJR,OAAOqB,IAAI,KAAK,QACZd,MAAMe,MAAM,CAAC,SAACC;+BAASA,KAAKC,IAAI,KAAK;uBAAuB,uDAAuD;uBACnHjB;oBACAE,UAAU,AAAC,qBAAGJ,SAASI,OAAO,SAAE,qBAAGP,QAAQe,IAAI,CAACE,aAAa,CAACM,cAAc;oBAE5Ef,YAAY,IAAIgB,cAAS,CAAC;wBAAEF,MAAMxB,OAAOwB,IAAI;wBAAEG,SAAS3B,OAAO2B,OAAO;oBAAC;oBAC7EC,IAAAA,qBAAa,EAAClB,WAAWF;oBACzBqB,IAAAA,yBAAiB,EAACnB,WAAWL,SAASyB,SAAS;oBAC/CC,IAAAA,uBAAe,EAACrB,WAAWD;oBAE3BH,OAAO0B,IAAI,CAAC,AAAC,YAAuB,OAAZhC,OAAOwB,IAAI,EAAC;oBAClB;;wBAAMS,IAAAA,oBAAY,EAACvB,WAAW;4BAAEJ,QAAAA;wBAAO;;;oBAAjDK,QAAU,cAAVA;oBACRL,OAAO0B,IAAI,CAAC;oBAEZ;;wBAAO;4BACLtB,WAAAA;4BACAJ,QAAAA;4BACAK,OAAO;;;;;gDACL;;oDAAMA;;;gDAAN;gDACA;;oDAAMT,QAAQS,KAAK;;;gDAAnB;;;;;;gCACF;;wBACF;;;;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
|
}
|
|
@@ -51,7 +51,7 @@ const config = {
|
|
|
51
51
|
*/ async function handler({ query, maxItems, filename, contentType, excludeThreadHistory }, extra) {
|
|
52
52
|
const logger = extra.logger;
|
|
53
53
|
const { storageContext } = extra;
|
|
54
|
-
const { transport,
|
|
54
|
+
const { transport, resourceStoreUri, baseUrl } = storageContext;
|
|
55
55
|
logger.info('gmail.messages.export-csv called', {
|
|
56
56
|
query,
|
|
57
57
|
maxItems,
|
|
@@ -60,7 +60,7 @@ const config = {
|
|
|
60
60
|
});
|
|
61
61
|
// Reserve file location for streaming write (creates directory, generates ID, formats filename)
|
|
62
62
|
const reservation = await reserveFile(filename, {
|
|
63
|
-
|
|
63
|
+
resourceStoreUri
|
|
64
64
|
});
|
|
65
65
|
const { storedName, fullPath } = reservation;
|
|
66
66
|
logger.info('gmail.messages.export-csv starting streaming export', {
|
|
@@ -207,7 +207,7 @@ const config = {
|
|
|
207
207
|
});
|
|
208
208
|
// Generate URI based on transport type (stdio: file://, HTTP: http://)
|
|
209
209
|
const uri = getFileUri(storedName, transport, {
|
|
210
|
-
|
|
210
|
+
resourceStoreUri,
|
|
211
211
|
...baseUrl && {
|
|
212
212
|
baseUrl
|
|
213
213
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/mcp/tools/messages-export-csv.ts"],"sourcesContent":["import { EmailContentTypeSchema, ExcludeThreadHistorySchema } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { getFileUri, reserveFile, type ToolModule } from '@mcp-z/server';\nimport { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\n\nimport { stringify } from 'csv-stringify/sync';\nimport { createWriteStream } from 'fs';\nimport { unlink } from 'fs/promises';\nimport { type gmail_v1, google } from 'googleapis';\nimport { z } from 'zod';\nimport { DEFAULT_PAGE_SIZE } from '../../constants.ts';\nimport { extractBodyFromPayload } from '../../email/parsing/html-processing.ts';\nimport { executeQuery as executeGmailQuery } from '../../email/querying/execute-query.ts';\nimport { GmailQuerySchema } from '../../schemas/gmail-query-schema.ts';\nimport type { StorageExtra } from '../../types.ts';\n\nconst DEFAULT_MAX_ITEMS = 10000;\nconst MAX_EXPORT_ITEMS = 50000;\n\n/**\n * CSV row format based on EmailDetail\n * All fields are strings (empty string instead of undefined)\n * Includes additional CSV-specific fields: provider and labels\n */\ninterface CsvRow {\n id: string;\n threadId: string;\n from: string;\n to: string;\n cc: string;\n bcc: string;\n subject: string;\n date: string;\n snippet: string;\n body: string;\n provider: string;\n labels: string;\n}\n\nconst inputSchema = z.object({\n query: GmailQuerySchema.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('gmail-messages.csv').describe('Output filename (default: gmail-messages.csv)'),\n contentType: EmailContentTypeSchema,\n excludeThreadHistory: ExcludeThreadHistorySchema,\n});\n\nconst successBranchSchema = z.object({\n type: z.literal('success'),\n uri: z.string().describe('File URI (file:// or http://)'),\n filename: z.string().describe('Stored filename'),\n rowCount: z.number().describe('Number of messages exported'),\n truncated: z.boolean().describe('Whether export was truncated at maxItems'),\n});\n\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Export Gmail messages to CSV with streaming pagination. Returns file URI. Use query-syntax prompt for query reference.',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\n/**\n * Handler for gmail-messages-export-csv tool\n *\n * CRITICAL: Streaming implementation per user requirements\n * - Generate UUID upfront\n * - Write CSV header immediately\n * - Append rows as batches arrive\n * - Delete partial file on error\n * - NO RETRIES (fail fast on error)\n */\nasync function handler({ query, maxItems, filename, contentType, excludeThreadHistory }: Input, extra: EnrichedExtra & StorageExtra) {\n const logger = extra.logger;\n const { storageContext } = extra;\n const { transport, storageDir, baseUrl } = storageContext;\n\n logger.info('gmail.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('gmail.messages.export-csv starting streaming export', { path: fullPath, maxItems });\n\n try {\n const gmail = google.gmail({ version: 'v1', auth: extra.authContext.auth });\n\n // Create CSV headers (all email fields)\n const csvHeaders = ['id', 'threadId', 'from', 'to', 'cc', 'bcc', 'subject', 'date', 'snippet', 'body', 'provider', 'labels'];\n\n // Create write stream and write headers immediately\n const writeStream = createWriteStream(fullPath, { encoding: 'utf-8' });\n const headerLine = stringify([csvHeaders], { header: false, quoted: true, quote: '\"', escape: '\"' });\n writeStream.write(headerLine);\n\n // Internal pagination loop - append to CSV with each batch\n // NO RETRIES: If any error occurs, fail the whole operation and clean up\n let totalRows = 0;\n let nextPageToken: string | undefined;\n const started = Date.now();\n\n while (totalRows < maxItems) {\n const remainingItems = maxItems - totalRows;\n const pageSize = Math.min(remainingItems, DEFAULT_PAGE_SIZE);\n\n const exec: {\n items: CsvRow[];\n metadata?: { nextPageToken?: string };\n } = await executeGmailQuery(\n query,\n {\n client: gmail,\n logger,\n pageSize,\n ...(nextPageToken !== undefined && { pageToken: nextPageToken }),\n includeBody: true, // Always include body for CSV export\n },\n (full: unknown): CsvRow => {\n // Type-safe property access with guards\n const fullData = full as {\n id?: unknown;\n threadId?: unknown;\n snippet?: unknown;\n labelIds?: unknown[];\n payload?: { headers?: unknown[] };\n };\n\n const headersArray = Array.isArray(fullData?.payload?.headers) ? fullData.payload.headers : [];\n const headers = Object.fromEntries(\n headersArray.map((h: unknown) => {\n const header = h as { name?: unknown; value?: unknown };\n return [String(header.name ?? ''), String(header.value ?? '')];\n })\n );\n\n const payload = fullData?.payload;\n // Cast to Schema$MessagePart for extractBodyFromPayload\n const body = payload ? extractBodyFromPayload(payload as gmail_v1.Schema$MessagePart, { contentType, excludeThreadHistory }) : '';\n\n const labelIds = Array.isArray(fullData?.labelIds) ? fullData.labelIds.map((id) => String(id ?? '')) : [];\n\n return {\n id: String(fullData?.id ?? ''),\n threadId: fullData?.threadId ? String(fullData.threadId) : '',\n from: headers?.From || '',\n to: headers?.To || '',\n cc: headers?.Cc || '',\n bcc: headers?.Bcc || '',\n subject: headers?.Subject || '',\n date: headers?.Date || '',\n snippet: fullData?.snippet ? String(fullData.snippet) : '',\n body,\n provider: 'gmail',\n labels: labelIds.join(';'),\n };\n }\n );\n\n // Type-safe CSV row mapping\n const csvRows = exec.items.map((row) => {\n return [row.id, row.threadId, row.from, row.to, row.cc, row.bcc, row.subject, row.date, row.snippet, row.body, row.provider, row.labels];\n });\n\n // Append rows to CSV file immediately\n if (csvRows.length > 0) {\n const rowsContent = stringify(csvRows, { header: false, quoted: true, quote: '\"', escape: '\"' });\n writeStream.write(rowsContent);\n }\n\n totalRows += exec.items.length;\n nextPageToken = exec.metadata?.nextPageToken;\n\n logger.info('gmail.messages.export-csv batch written', {\n batchSize: exec.items.length,\n totalRows,\n hasMore: Boolean(nextPageToken),\n });\n\n // Exit if no more results or reached maxItems\n if (!nextPageToken || exec.items.length === 0) {\n break;\n }\n }\n\n // Close write stream\n await new Promise<void>((resolve, reject) => {\n writeStream.end(() => resolve());\n writeStream.on('error', reject);\n });\n\n const durationMs = Date.now() - started;\n const truncated = totalRows >= maxItems && Boolean(nextPageToken);\n\n logger.info('gmail.messages.export-csv completed', {\n rowCount: totalRows,\n truncated,\n durationMs,\n filename: storedName,\n });\n\n // Generate URI based on transport type (stdio: file://, HTTP: http://)\n const uri = getFileUri(storedName, transport, {\n 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('gmail.messages.export-csv error', { error: message });\n\n throw new McpError(ErrorCode.InternalError, `Error exporting messages to CSV: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'messages-export-csv',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["EmailContentTypeSchema","ExcludeThreadHistorySchema","schemas","AuthRequiredBranchSchema","getFileUri","reserveFile","ErrorCode","McpError","stringify","createWriteStream","unlink","google","z","DEFAULT_PAGE_SIZE","extractBodyFromPayload","executeQuery","executeGmailQuery","GmailQuerySchema","DEFAULT_MAX_ITEMS","MAX_EXPORT_ITEMS","inputSchema","object","query","optional","describe","maxItems","number","int","positive","max","default","filename","string","trim","min","contentType","excludeThreadHistory","successBranchSchema","type","literal","uri","rowCount","truncated","boolean","outputSchema","discriminatedUnion","config","description","result","handler","extra","logger","storageContext","transport","storageDir","baseUrl","info","accountId","authContext","reservation","storedName","fullPath","path","gmail","version","auth","csvHeaders","writeStream","encoding","headerLine","header","quoted","quote","escape","write","totalRows","nextPageToken","started","Date","now","exec","remainingItems","pageSize","Math","client","undefined","pageToken","includeBody","full","fullData","headersArray","Array","isArray","payload","headers","Object","fromEntries","map","h","String","name","value","body","labelIds","id","threadId","from","From","to","To","cc","Cc","bcc","Bcc","subject","Subject","date","snippet","provider","labels","join","csvRows","items","row","length","rowsContent","metadata","batchSize","hasMore","Boolean","Promise","resolve","reject","end","on","durationMs","endpoint","content","text","JSON","structuredContent","error","debug","_cleanupError","message","Error","InternalError","stack","createTool"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/mcp/tools/messages-export-csv.ts"],"sourcesContent":["import { EmailContentTypeSchema, ExcludeThreadHistorySchema } from '@mcp-z/email';\nimport type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { getFileUri, reserveFile, type ToolModule } from '@mcp-z/server';\nimport { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';\n\nimport { stringify } from 'csv-stringify/sync';\nimport { createWriteStream } from 'fs';\nimport { unlink } from 'fs/promises';\nimport { type gmail_v1, google } from 'googleapis';\nimport { z } from 'zod';\nimport { DEFAULT_PAGE_SIZE } from '../../constants.ts';\nimport { extractBodyFromPayload } from '../../email/parsing/html-processing.ts';\nimport { executeQuery as executeGmailQuery } from '../../email/querying/execute-query.ts';\nimport { GmailQuerySchema } from '../../schemas/gmail-query-schema.ts';\nimport type { StorageExtra } from '../../types.ts';\n\nconst DEFAULT_MAX_ITEMS = 10000;\nconst MAX_EXPORT_ITEMS = 50000;\n\n/**\n * CSV row format based on EmailDetail\n * All fields are strings (empty string instead of undefined)\n * Includes additional CSV-specific fields: provider and labels\n */\ninterface CsvRow {\n id: string;\n threadId: string;\n from: string;\n to: string;\n cc: string;\n bcc: string;\n subject: string;\n date: string;\n snippet: string;\n body: string;\n provider: string;\n labels: string;\n}\n\nconst inputSchema = z.object({\n query: GmailQuerySchema.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('gmail-messages.csv').describe('Output filename (default: gmail-messages.csv)'),\n contentType: EmailContentTypeSchema,\n excludeThreadHistory: ExcludeThreadHistorySchema,\n});\n\nconst successBranchSchema = z.object({\n type: z.literal('success'),\n uri: z.string().describe('File URI (file:// or http://)'),\n filename: z.string().describe('Stored filename'),\n rowCount: z.number().describe('Number of messages exported'),\n truncated: z.boolean().describe('Whether export was truncated at maxItems'),\n});\n\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n description: 'Export Gmail messages to CSV with streaming pagination. Returns file URI. Use query-syntax prompt for query reference.',\n inputSchema: inputSchema,\n outputSchema: z.object({\n result: outputSchema,\n }),\n} as const;\n\nexport type Input = z.infer<typeof inputSchema>;\nexport type Output = z.infer<typeof outputSchema>;\n\n/**\n * Handler for gmail-messages-export-csv tool\n *\n * CRITICAL: Streaming implementation per user requirements\n * - Generate UUID upfront\n * - Write CSV header immediately\n * - Append rows as batches arrive\n * - Delete partial file on error\n * - NO RETRIES (fail fast on error)\n */\nasync function handler({ query, maxItems, filename, contentType, excludeThreadHistory }: Input, extra: EnrichedExtra & StorageExtra) {\n const logger = extra.logger;\n const { storageContext } = extra;\n const { transport, resourceStoreUri, baseUrl } = storageContext;\n\n logger.info('gmail.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('gmail.messages.export-csv starting streaming export', { path: fullPath, maxItems });\n\n try {\n const gmail = google.gmail({ version: 'v1', auth: extra.authContext.auth });\n\n // Create CSV headers (all email fields)\n const csvHeaders = ['id', 'threadId', 'from', 'to', 'cc', 'bcc', 'subject', 'date', 'snippet', 'body', 'provider', 'labels'];\n\n // Create write stream and write headers immediately\n const writeStream = createWriteStream(fullPath, { encoding: 'utf-8' });\n const headerLine = stringify([csvHeaders], { header: false, quoted: true, quote: '\"', escape: '\"' });\n writeStream.write(headerLine);\n\n // Internal pagination loop - append to CSV with each batch\n // NO RETRIES: If any error occurs, fail the whole operation and clean up\n let totalRows = 0;\n let nextPageToken: string | undefined;\n const started = Date.now();\n\n while (totalRows < maxItems) {\n const remainingItems = maxItems - totalRows;\n const pageSize = Math.min(remainingItems, DEFAULT_PAGE_SIZE);\n\n const exec: {\n items: CsvRow[];\n metadata?: { nextPageToken?: string };\n } = await executeGmailQuery(\n query,\n {\n client: gmail,\n logger,\n pageSize,\n ...(nextPageToken !== undefined && { pageToken: nextPageToken }),\n includeBody: true, // Always include body for CSV export\n },\n (full: unknown): CsvRow => {\n // Type-safe property access with guards\n const fullData = full as {\n id?: unknown;\n threadId?: unknown;\n snippet?: unknown;\n labelIds?: unknown[];\n payload?: { headers?: unknown[] };\n };\n\n const headersArray = Array.isArray(fullData?.payload?.headers) ? fullData.payload.headers : [];\n const headers = Object.fromEntries(\n headersArray.map((h: unknown) => {\n const header = h as { name?: unknown; value?: unknown };\n return [String(header.name ?? ''), String(header.value ?? '')];\n })\n );\n\n const payload = fullData?.payload;\n // Cast to Schema$MessagePart for extractBodyFromPayload\n const body = payload ? extractBodyFromPayload(payload as gmail_v1.Schema$MessagePart, { contentType, excludeThreadHistory }) : '';\n\n const labelIds = Array.isArray(fullData?.labelIds) ? fullData.labelIds.map((id) => String(id ?? '')) : [];\n\n return {\n id: String(fullData?.id ?? ''),\n threadId: fullData?.threadId ? String(fullData.threadId) : '',\n from: headers?.From || '',\n to: headers?.To || '',\n cc: headers?.Cc || '',\n bcc: headers?.Bcc || '',\n subject: headers?.Subject || '',\n date: headers?.Date || '',\n snippet: fullData?.snippet ? String(fullData.snippet) : '',\n body,\n provider: 'gmail',\n labels: labelIds.join(';'),\n };\n }\n );\n\n // Type-safe CSV row mapping\n const csvRows = exec.items.map((row) => {\n return [row.id, row.threadId, row.from, row.to, row.cc, row.bcc, row.subject, row.date, row.snippet, row.body, row.provider, row.labels];\n });\n\n // Append rows to CSV file immediately\n if (csvRows.length > 0) {\n const rowsContent = stringify(csvRows, { header: false, quoted: true, quote: '\"', escape: '\"' });\n writeStream.write(rowsContent);\n }\n\n totalRows += exec.items.length;\n nextPageToken = exec.metadata?.nextPageToken;\n\n logger.info('gmail.messages.export-csv batch written', {\n batchSize: exec.items.length,\n totalRows,\n hasMore: Boolean(nextPageToken),\n });\n\n // Exit if no more results or reached maxItems\n if (!nextPageToken || exec.items.length === 0) {\n break;\n }\n }\n\n // Close write stream\n await new Promise<void>((resolve, reject) => {\n writeStream.end(() => resolve());\n writeStream.on('error', reject);\n });\n\n const durationMs = Date.now() - started;\n const truncated = totalRows >= maxItems && Boolean(nextPageToken);\n\n logger.info('gmail.messages.export-csv completed', {\n rowCount: totalRows,\n truncated,\n durationMs,\n filename: storedName,\n });\n\n // Generate URI based on transport type (stdio: file://, HTTP: http://)\n const uri = getFileUri(storedName, transport, {\n resourceStoreUri,\n ...(baseUrl && { baseUrl }),\n endpoint: '/files',\n });\n\n const result: Output = {\n type: 'success' as const,\n uri,\n filename: storedName,\n rowCount: totalRows,\n truncated,\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n // CRITICAL: Clean up partial CSV file on error\n try {\n await unlink(fullPath);\n logger.debug('Cleaned up partial CSV file after error', { path: fullPath });\n } catch (_cleanupError) {\n logger.debug('Could not clean up CSV file (may not exist)', { path: fullPath });\n }\n\n const message = error instanceof Error ? error.message : String(error);\n logger.error('gmail.messages.export-csv error', { error: message });\n\n throw new McpError(ErrorCode.InternalError, `Error exporting messages to CSV: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'messages-export-csv',\n config,\n handler,\n } satisfies ToolModule;\n}\n"],"names":["EmailContentTypeSchema","ExcludeThreadHistorySchema","schemas","AuthRequiredBranchSchema","getFileUri","reserveFile","ErrorCode","McpError","stringify","createWriteStream","unlink","google","z","DEFAULT_PAGE_SIZE","extractBodyFromPayload","executeQuery","executeGmailQuery","GmailQuerySchema","DEFAULT_MAX_ITEMS","MAX_EXPORT_ITEMS","inputSchema","object","query","optional","describe","maxItems","number","int","positive","max","default","filename","string","trim","min","contentType","excludeThreadHistory","successBranchSchema","type","literal","uri","rowCount","truncated","boolean","outputSchema","discriminatedUnion","config","description","result","handler","extra","logger","storageContext","transport","resourceStoreUri","baseUrl","info","accountId","authContext","reservation","storedName","fullPath","path","gmail","version","auth","csvHeaders","writeStream","encoding","headerLine","header","quoted","quote","escape","write","totalRows","nextPageToken","started","Date","now","exec","remainingItems","pageSize","Math","client","undefined","pageToken","includeBody","full","fullData","headersArray","Array","isArray","payload","headers","Object","fromEntries","map","h","String","name","value","body","labelIds","id","threadId","from","From","to","To","cc","Cc","bcc","Bcc","subject","Subject","date","snippet","provider","labels","join","csvRows","items","row","length","rowsContent","metadata","batchSize","hasMore","Boolean","Promise","resolve","reject","end","on","durationMs","endpoint","content","text","JSON","structuredContent","error","debug","_cleanupError","message","Error","InternalError","stack","createTool"],"mappings":"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"}
|
|
@@ -21,7 +21,7 @@ export declare function handleVersionHelp(args: string[]): {
|
|
|
21
21
|
* - --port=<port> Enable HTTP transport on specified port
|
|
22
22
|
* - --stdio Enable stdio transport (default if no port)
|
|
23
23
|
* - --log-level=<level> Logging level (default: info)
|
|
24
|
-
* - --
|
|
24
|
+
* - --resource-store-uri=<uri> Resource store URI for CSV file storage (default: file://~/.mcp-z/mcp-gmail/files)
|
|
25
25
|
* - --base-url=<url> Base URL for HTTP file serving (optional)
|
|
26
26
|
*
|
|
27
27
|
* Environment Variables:
|
|
@@ -32,9 +32,10 @@ export declare function handleVersionHelp(args: string[]): {
|
|
|
32
32
|
* - DCR_MODE DCR mode (optional, same format as --dcr-mode)
|
|
33
33
|
* - DCR_VERIFY_URL External verification URL (optional, same as --dcr-verify-url)
|
|
34
34
|
* - DCR_STORE_URI DCR storage URI (optional, same as --dcr-store-uri)
|
|
35
|
+
* - TOKEN_STORE_URI Token storage URI (optional)
|
|
35
36
|
* - PORT Default HTTP port (optional)
|
|
36
37
|
* - LOG_LEVEL Default logging level (optional)
|
|
37
|
-
* -
|
|
38
|
+
* - RESOURCE_STORE_URI Resource store URI (optional, file://)
|
|
38
39
|
* - BASE_URL Default base URL for file serving (optional)
|
|
39
40
|
*
|
|
40
41
|
* OAuth Scopes (from constants.ts):
|
package/dist/esm/setup/config.js
CHANGED
|
@@ -26,7 +26,7 @@ Options:
|
|
|
26
26
|
--port=<port> Enable HTTP transport on specified port
|
|
27
27
|
--stdio Enable stdio transport (default if no port)
|
|
28
28
|
--log-level=<level> Logging level (default: info)
|
|
29
|
-
--
|
|
29
|
+
--resource-store-uri=<uri> Resource store URI for CSV file storage (default: file://~/.mcp-z/mcp-gmail/files)
|
|
30
30
|
--base-url=<url> Base URL for HTTP file serving (optional)
|
|
31
31
|
|
|
32
32
|
Environment Variables:
|
|
@@ -37,9 +37,10 @@ Environment Variables:
|
|
|
37
37
|
DCR_MODE DCR mode (optional, same format as --dcr-mode)
|
|
38
38
|
DCR_VERIFY_URL External verification URL (optional, same as --dcr-verify-url)
|
|
39
39
|
DCR_STORE_URI DCR storage URI (optional, same as --dcr-store-uri)
|
|
40
|
+
TOKEN_STORE_URI Token storage URI (optional)
|
|
40
41
|
PORT Default HTTP port (optional)
|
|
41
42
|
LOG_LEVEL Default logging level (optional)
|
|
42
|
-
|
|
43
|
+
RESOURCE_STORE_URI Resource store URI (optional, file://)
|
|
43
44
|
BASE_URL Default base URL for file serving (optional)
|
|
44
45
|
|
|
45
46
|
OAuth Scopes:
|
|
@@ -49,7 +50,7 @@ Examples:
|
|
|
49
50
|
mcp-gmail # Use default settings
|
|
50
51
|
mcp-gmail --auth=service-account # Use service account auth
|
|
51
52
|
mcp-gmail --port=3000 # HTTP transport on port 3000
|
|
52
|
-
mcp-gmail --
|
|
53
|
+
mcp-gmail --resource-store-uri=file:///tmp/emails # Custom resource store URI
|
|
53
54
|
GOOGLE_CLIENT_ID=xxx mcp-gmail # Set client ID via env var
|
|
54
55
|
`.trim();
|
|
55
56
|
/**
|
|
@@ -94,7 +95,7 @@ Examples:
|
|
|
94
95
|
* - --port=<port> Enable HTTP transport on specified port
|
|
95
96
|
* - --stdio Enable stdio transport (default if no port)
|
|
96
97
|
* - --log-level=<level> Logging level (default: info)
|
|
97
|
-
* - --
|
|
98
|
+
* - --resource-store-uri=<uri> Resource store URI for CSV file storage (default: file://~/.mcp-z/mcp-gmail/files)
|
|
98
99
|
* - --base-url=<url> Base URL for HTTP file serving (optional)
|
|
99
100
|
*
|
|
100
101
|
* Environment Variables:
|
|
@@ -105,9 +106,10 @@ Examples:
|
|
|
105
106
|
* - DCR_MODE DCR mode (optional, same format as --dcr-mode)
|
|
106
107
|
* - DCR_VERIFY_URL External verification URL (optional, same as --dcr-verify-url)
|
|
107
108
|
* - DCR_STORE_URI DCR storage URI (optional, same as --dcr-store-uri)
|
|
109
|
+
* - TOKEN_STORE_URI Token storage URI (optional)
|
|
108
110
|
* - PORT Default HTTP port (optional)
|
|
109
111
|
* - LOG_LEVEL Default logging level (optional)
|
|
110
|
-
* -
|
|
112
|
+
* - RESOURCE_STORE_URI Resource store URI (optional, file://)
|
|
111
113
|
* - BASE_URL Default base URL for file serving (optional)
|
|
112
114
|
*
|
|
113
115
|
* OAuth Scopes (from constants.ts):
|
|
@@ -118,7 +120,7 @@ Examples:
|
|
|
118
120
|
const oauthConfig = parseOAuthConfig(args, env);
|
|
119
121
|
// Parse DCR configuration if DCR mode is enabled
|
|
120
122
|
const dcrConfig = oauthConfig.auth === 'dcr' ? parseDcrConfig(args, env, GOOGLE_SCOPE) : undefined;
|
|
121
|
-
// Parse application-level config (LOG_LEVEL,
|
|
123
|
+
// Parse application-level config (LOG_LEVEL, RESOURCE_STORE_URI, BASE_URL)
|
|
122
124
|
const { values } = parseArgs({
|
|
123
125
|
args,
|
|
124
126
|
options: {
|
|
@@ -128,7 +130,7 @@ Examples:
|
|
|
128
130
|
'base-url': {
|
|
129
131
|
type: 'string'
|
|
130
132
|
},
|
|
131
|
-
'
|
|
133
|
+
'resource-store-uri': {
|
|
132
134
|
type: 'string'
|
|
133
135
|
}
|
|
134
136
|
},
|
|
@@ -155,10 +157,10 @@ Examples:
|
|
|
155
157
|
const envLogLevel = env.LOG_LEVEL;
|
|
156
158
|
const logLevel = (_ref1 = cliLogLevel !== null && cliLogLevel !== void 0 ? cliLogLevel : envLogLevel) !== null && _ref1 !== void 0 ? _ref1 : 'info';
|
|
157
159
|
// Parse storage configuration
|
|
158
|
-
const
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
160
|
+
const cliResourceStoreUri = typeof values['resource-store-uri'] === 'string' ? values['resource-store-uri'] : undefined;
|
|
161
|
+
const envResourceStoreUri = env.RESOURCE_STORE_URI;
|
|
162
|
+
const defaultResourceStorePath = path.join(baseDir, name, 'files');
|
|
163
|
+
const resourceStoreUri = normalizeResourceStoreUri((_ref2 = cliResourceStoreUri !== null && cliResourceStoreUri !== void 0 ? cliResourceStoreUri : envResourceStoreUri) !== null && _ref2 !== void 0 ? _ref2 : defaultResourceStorePath);
|
|
162
164
|
const cliBaseUrl = typeof values['base-url'] === 'string' ? values['base-url'] : undefined;
|
|
163
165
|
const envBaseUrl = env.BASE_URL;
|
|
164
166
|
const baseUrl = cliBaseUrl !== null && cliBaseUrl !== void 0 ? cliBaseUrl : envBaseUrl;
|
|
@@ -171,7 +173,7 @@ Examples:
|
|
|
171
173
|
name,
|
|
172
174
|
version: pkg.version,
|
|
173
175
|
repositoryUrl,
|
|
174
|
-
|
|
176
|
+
resourceStoreUri
|
|
175
177
|
};
|
|
176
178
|
if (baseUrl) result.baseUrl = baseUrl;
|
|
177
179
|
if (dcrConfig !== undefined) result.dcrConfig = dcrConfig;
|
|
@@ -183,3 +185,14 @@ Examples:
|
|
|
183
185
|
*/ export function createConfig() {
|
|
184
186
|
return parseConfig(process.argv, process.env);
|
|
185
187
|
}
|
|
188
|
+
function normalizeResourceStoreUri(resourceStoreUri) {
|
|
189
|
+
const filePrefix = 'file://';
|
|
190
|
+
if (resourceStoreUri.startsWith(filePrefix)) {
|
|
191
|
+
const rawPath = resourceStoreUri.slice(filePrefix.length);
|
|
192
|
+
const expandedPath = rawPath.startsWith('~') ? rawPath.replace(/^~/, homedir()) : rawPath;
|
|
193
|
+
return `${filePrefix}${path.resolve(expandedPath)}`;
|
|
194
|
+
}
|
|
195
|
+
if (resourceStoreUri.includes('://')) return resourceStoreUri;
|
|
196
|
+
const expandedPath = resourceStoreUri.startsWith('~') ? resourceStoreUri.replace(/^~/, homedir()) : resourceStoreUri;
|
|
197
|
+
return `${filePrefix}${path.resolve(expandedPath)}`;
|
|
198
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/setup/config.ts"],"sourcesContent":["import { parseDcrConfig, parseConfig as parseOAuthConfig } from '@mcp-z/oauth-google';\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 { GOOGLE_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-gmail [options]\n\nMCP server for Gmail 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, service-account, dcr\n --headless Disable browser auto-open, return auth URL instead\n --redirect-uri=<uri> OAuth redirect URI (default: ephemeral loopback)\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 (optional)\n\nEnvironment Variables:\n GOOGLE_CLIENT_ID OAuth client ID (REQUIRED)\n GOOGLE_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 Default storage directory (optional)\n BASE_URL Default base URL for file serving (optional)\n\nOAuth Scopes:\n openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email https://mail.google.com/\n\nExamples:\n mcp-gmail # Use default settings\n mcp-gmail --auth=service-account # Use service account auth\n mcp-gmail --port=3000 # HTTP transport on port 3000\n mcp-gmail --storage-dir=./emails # Custom storage directory\n GOOGLE_CLIENT_ID=xxx mcp-gmail # 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 Gmail 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, service-account, dcr\n * - --headless Disable browser auto-open, return auth URL instead\n * - --redirect-uri=<uri> OAuth redirect URI (default: ephemeral loopback)\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 (optional)\n *\n * Environment Variables:\n * - GOOGLE_CLIENT_ID OAuth client ID (REQUIRED)\n * - GOOGLE_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 Default storage directory (optional)\n * - BASE_URL Default base URL for file serving (optional)\n *\n * OAuth Scopes (from constants.ts):\n * openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email https://mail.google.com/\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, GOOGLE_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 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, serviceAccountKeyFile\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) 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","GOOGLE_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-gmail/src/setup/config.ts"],"sourcesContent":["import { parseDcrConfig, parseConfig as parseOAuthConfig } from '@mcp-z/oauth-google';\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 { GOOGLE_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-gmail [options]\n\nMCP server for Gmail 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, service-account, dcr\n --headless Disable browser auto-open, return auth URL instead\n --redirect-uri=<uri> OAuth redirect URI (default: ephemeral loopback)\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-gmail/files)\n --base-url=<url> Base URL for HTTP file serving (optional)\n\nEnvironment Variables:\n GOOGLE_CLIENT_ID OAuth client ID (REQUIRED)\n GOOGLE_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 Default base URL for file serving (optional)\n\nOAuth Scopes:\n openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email https://mail.google.com/\n\nExamples:\n mcp-gmail # Use default settings\n mcp-gmail --auth=service-account # Use service account auth\n mcp-gmail --port=3000 # HTTP transport on port 3000\n mcp-gmail --resource-store-uri=file:///tmp/emails # Custom resource store URI\n GOOGLE_CLIENT_ID=xxx mcp-gmail # 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 Gmail 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, service-account, dcr\n * - --headless Disable browser auto-open, return auth URL instead\n * - --redirect-uri=<uri> OAuth redirect URI (default: ephemeral loopback)\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-gmail/files)\n * - --base-url=<url> Base URL for HTTP file serving (optional)\n *\n * Environment Variables:\n * - GOOGLE_CLIENT_ID OAuth client ID (REQUIRED)\n * - GOOGLE_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 Default base URL for file serving (optional)\n *\n * OAuth Scopes (from constants.ts):\n * openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email https://mail.google.com/\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, GOOGLE_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 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, serviceAccountKeyFile\n transport: transportConfig.transport,\n logLevel,\n baseDir,\n name,\n version: pkg.version,\n repositoryUrl,\n resourceStoreUri,\n };\n if (baseUrl) 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","GOOGLE_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":"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"}
|
package/dist/esm/setup/http.js
CHANGED
|
@@ -15,6 +15,8 @@ export async function createHTTPServer(config, overrides) {
|
|
|
15
15
|
...composed.tools,
|
|
16
16
|
...runtime.deps.oauthAdapters.accountTools
|
|
17
17
|
];
|
|
18
|
+
const filteredTools = config.auth === 'dcr' ? tools.filter((tool)=>tool.name !== 'messages-export-csv') // No file storage in DCR (public cloud responsibility)
|
|
19
|
+
: tools;
|
|
18
20
|
const prompts = [
|
|
19
21
|
...composed.prompts,
|
|
20
22
|
...runtime.deps.oauthAdapters.accountPrompts
|
|
@@ -23,7 +25,7 @@ export async function createHTTPServer(config, overrides) {
|
|
|
23
25
|
name: config.name,
|
|
24
26
|
version: config.version
|
|
25
27
|
});
|
|
26
|
-
registerTools(mcpServer,
|
|
28
|
+
registerTools(mcpServer, filteredTools);
|
|
27
29
|
registerResources(mcpServer, composed.resources);
|
|
28
30
|
registerPrompts(mcpServer, prompts);
|
|
29
31
|
const app = express();
|
|
@@ -35,13 +37,15 @@ export async function createHTTPServer(config, overrides) {
|
|
|
35
37
|
app.use('/', runtime.deps.oauthAdapters.loopbackRouter);
|
|
36
38
|
logger.info('Mounted loopback OAuth callback router');
|
|
37
39
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
if (config.auth !== 'dcr') {
|
|
41
|
+
const fileRouter = createFileServingRouter({
|
|
42
|
+
resourceStoreUri: config.resourceStoreUri
|
|
43
|
+
}, {
|
|
44
|
+
contentType: 'text/csv',
|
|
45
|
+
contentDisposition: 'attachment'
|
|
46
|
+
});
|
|
47
|
+
app.use('/files', fileRouter);
|
|
48
|
+
}
|
|
45
49
|
if (runtime.deps.oauthAdapters.dcrRouter) {
|
|
46
50
|
app.use('/', runtime.deps.oauthAdapters.dcrRouter);
|
|
47
51
|
logger.info('Mounted DCR router with OAuth endpoints');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/setup/http.ts"],"sourcesContent":["import { composeMiddleware, connectHttp, createFileServingRouter, registerPrompts, registerResources, registerTools } from '@mcp-z/server';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport cors from 'cors';\nimport express from 'express';\nimport type { RuntimeOverrides, ServerConfig } from '../types.ts';\nimport { createDefaultRuntime } from './runtime.ts';\n\nexport async function createHTTPServer(config: ServerConfig, overrides?: RuntimeOverrides) {\n const runtime = await createDefaultRuntime(config, overrides);\n const modules = runtime.createDomainModules();\n const layers = runtime.middlewareFactories.map((factory) => factory(runtime.deps));\n const composed = composeMiddleware(modules, layers);\n const logger = runtime.deps.logger;\n const port = config.transport.port;\n if (!port) throw new Error('Port is required for HTTP transport');\n\n const tools = [...composed.tools, ...runtime.deps.oauthAdapters.accountTools];\n const prompts = [...composed.prompts, ...runtime.deps.oauthAdapters.accountPrompts];\n\n const mcpServer = new McpServer({ name: config.name, version: config.version });\n registerTools(mcpServer,
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/setup/http.ts"],"sourcesContent":["import { composeMiddleware, connectHttp, createFileServingRouter, registerPrompts, registerResources, registerTools } from '@mcp-z/server';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport cors from 'cors';\nimport express from 'express';\nimport type { RuntimeOverrides, ServerConfig } from '../types.ts';\nimport { createDefaultRuntime } from './runtime.ts';\n\nexport async function createHTTPServer(config: ServerConfig, overrides?: RuntimeOverrides) {\n const runtime = await createDefaultRuntime(config, overrides);\n const modules = runtime.createDomainModules();\n const layers = runtime.middlewareFactories.map((factory) => factory(runtime.deps));\n const composed = composeMiddleware(modules, layers);\n const logger = runtime.deps.logger;\n const port = config.transport.port;\n if (!port) throw new Error('Port is required for HTTP transport');\n\n const tools = [...composed.tools, ...runtime.deps.oauthAdapters.accountTools];\n const filteredTools =\n config.auth === 'dcr'\n ? tools.filter((tool) => tool.name !== 'messages-export-csv') // No file storage in DCR (public cloud responsibility)\n : tools;\n const prompts = [...composed.prompts, ...runtime.deps.oauthAdapters.accountPrompts];\n\n const mcpServer = new McpServer({ name: config.name, version: config.version });\n registerTools(mcpServer, filteredTools);\n registerResources(mcpServer, composed.resources);\n registerPrompts(mcpServer, prompts);\n\n const app = express();\n app.use(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 if (config.auth !== 'dcr') {\n const fileRouter = createFileServingRouter({ resourceStoreUri: config.resourceStoreUri }, { contentType: 'text/csv', contentDisposition: 'attachment' });\n app.use('/files', fileRouter);\n }\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","filteredTools","auth","filter","tool","name","prompts","accountPrompts","mcpServer","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,gBACJlB,OAAOmB,IAAI,KAAK,QACZJ,MAAMK,MAAM,CAAC,CAACC,OAASA,KAAKC,IAAI,KAAK,uBAAuB,uDAAuD;OACnHP;IACN,MAAMQ,UAAU;WAAIb,SAASa,OAAO;WAAKrB,QAAQO,IAAI,CAACO,aAAa,CAACQ,cAAc;KAAC;IAEnF,MAAMC,YAAY,IAAI9B,UAAU;QAAE2B,MAAMtB,OAAOsB,IAAI;QAAEI,SAAS1B,OAAO0B,OAAO;IAAC;IAC7EhC,cAAc+B,WAAWP;IACzBzB,kBAAkBgC,WAAWf,SAASiB,SAAS;IAC/CnC,gBAAgBiC,WAAWF;IAE3B,MAAMK,MAAM/B;IACZ+B,IAAIC,GAAG,CAACjC;IACRgC,IAAIC,GAAG,CAAChC,QAAQiC,IAAI,CAAC;QAAEC,OAAO;IAAO;IAErC,IAAI7B,QAAQO,IAAI,CAACO,aAAa,CAACgB,cAAc,EAAE;QAC7CJ,IAAIC,GAAG,CAAC,KAAK3B,QAAQO,IAAI,CAACO,aAAa,CAACgB,cAAc;QACtDrB,OAAOsB,IAAI,CAAC;IACd;IAEA,IAAIjC,OAAOmB,IAAI,KAAK,OAAO;QACzB,MAAMe,aAAa3C,wBAAwB;YAAE4C,kBAAkBnC,OAAOmC,gBAAgB;QAAC,GAAG;YAAEC,aAAa;YAAYC,oBAAoB;QAAa;QACtJT,IAAIC,GAAG,CAAC,UAAUK;IACpB;IAEA,IAAIhC,QAAQO,IAAI,CAACO,aAAa,CAACsB,SAAS,EAAE;QACxCV,IAAIC,GAAG,CAAC,KAAK3B,QAAQO,IAAI,CAACO,aAAa,CAACsB,SAAS;QACjD3B,OAAOsB,IAAI,CAAC;IACd;IAEAtB,OAAOsB,IAAI,CAAC,CAAC,SAAS,EAAEjC,OAAOsB,IAAI,CAAC,kBAAkB,CAAC;IACvD,MAAM,EAAEiB,KAAK,EAAEC,UAAU,EAAE,GAAG,MAAMlD,YAAYmC,WAAW;QAAEd;QAAQiB;QAAKhB;IAAK;IAC/ED,OAAOsB,IAAI,CAAC;IAEZ,OAAO;QACLO;QACAf;QACAd;QACA4B,OAAO;YACL,MAAMA;YACN,MAAMrC,QAAQqC,KAAK;QACrB;IACF;AACF"}
|
|
@@ -8,5 +8,5 @@ export declare function createDcrStore(baseDir: string, required: boolean): Prom
|
|
|
8
8
|
export declare function createAuthLayer(authMiddleware: OAuthAdapters['middleware']): MiddlewareLayer;
|
|
9
9
|
export declare function createLoggingLayer(logger: Logger): MiddlewareLayer;
|
|
10
10
|
export declare function createStorageLayer(storageContext: StorageContext): MiddlewareLayer;
|
|
11
|
-
export declare function
|
|
11
|
+
export declare function validateStorageConfig(config: ServerConfig, logger: Logger): void;
|
|
12
12
|
export declare function createDefaultRuntime(config: ServerConfig, overrides?: RuntimeOverrides): Promise<CommonRuntime>;
|
|
@@ -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;
|
|
@@ -64,9 +64,15 @@ export function createStorageLayer(storageContext) {
|
|
|
64
64
|
withTool: (module)=>wrapAtPosition(module, 1)
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
|
-
export function
|
|
68
|
-
if (
|
|
69
|
-
|
|
67
|
+
export function validateStorageConfig(config, logger) {
|
|
68
|
+
if (config.auth === 'dcr') {
|
|
69
|
+
if (config.resourceStoreUri) {
|
|
70
|
+
logger.warn('DCR mode does not support file storage; resourceStoreUri will be ignored.');
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (!config.resourceStoreUri) {
|
|
75
|
+
throw new Error('gmail-messages-export-csv: Server configuration missing resourceStoreUri.');
|
|
70
76
|
}
|
|
71
77
|
if (config.transport.type === 'http' && !config.baseUrl && !config.transport.port) {
|
|
72
78
|
throw new Error('gmail-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.');
|
|
@@ -75,8 +81,8 @@ export function assertStorageConfig(config) {
|
|
|
75
81
|
export async function createDefaultRuntime(config, overrides) {
|
|
76
82
|
var _config_baseUrl, _ref, _ref1;
|
|
77
83
|
if (config.auth === 'dcr' && config.transport.type !== 'http') throw new Error('DCR mode requires an HTTP transport');
|
|
78
|
-
assertStorageConfig(config);
|
|
79
84
|
const logger = createLogger(config);
|
|
85
|
+
validateStorageConfig(config, logger);
|
|
80
86
|
const tokenStore = await createTokenStore(config.baseDir);
|
|
81
87
|
const baseUrl = (_config_baseUrl = config.baseUrl) !== null && _config_baseUrl !== void 0 ? _config_baseUrl : config.transport.type === 'http' && config.transport.port ? `http://localhost:${config.transport.port}` : undefined;
|
|
82
88
|
const dcrStore = await createDcrStore(config.baseDir, config.auth === 'dcr');
|
|
@@ -100,11 +106,13 @@ export async function createDefaultRuntime(config, overrides) {
|
|
|
100
106
|
const middlewareFactories = (_ref1 = overrides === null || overrides === void 0 ? void 0 : overrides.middlewareFactories) !== null && _ref1 !== void 0 ? _ref1 : [
|
|
101
107
|
()=>createAuthLayer(oauthAdapters.middleware),
|
|
102
108
|
()=>createLoggingLayer(logger),
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
109
|
+
...config.auth === 'dcr' ? [] : [
|
|
110
|
+
()=>createStorageLayer({
|
|
111
|
+
resourceStoreUri: config.resourceStoreUri,
|
|
112
|
+
baseUrl: config.baseUrl,
|
|
113
|
+
transport: config.transport
|
|
114
|
+
})
|
|
115
|
+
]
|
|
108
116
|
];
|
|
109
117
|
return {
|
|
110
118
|
deps,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/setup/runtime.ts"],"sourcesContent":["import { sanitizeForLoggingFormatter } from '@mcp-z/oauth';\nimport type { CachedToken } from '@mcp-z/oauth-google';\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-google.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-gmail/src/setup/runtime.ts"],"sourcesContent":["import { sanitizeForLoggingFormatter } from '@mcp-z/oauth';\nimport type { CachedToken } from '@mcp-z/oauth-google';\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-google.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<CachedToken>(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 validateStorageConfig(config: ServerConfig, logger: Logger) {\n if (config.auth === 'dcr') {\n if (config.resourceStoreUri) {\n logger.warn('DCR mode does not support file storage; resourceStoreUri will be ignored.');\n }\n return;\n }\n if (!config.resourceStoreUri) {\n throw new Error('gmail-messages-export-csv: Server configuration missing resourceStoreUri.');\n }\n if (config.transport.type === 'http' && !config.baseUrl && !config.transport.port) {\n throw new Error('gmail-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 const logger = createLogger(config);\n validateStorageConfig(config, logger);\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), ...(config.auth === 'dcr' ? [] : [() => 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","validateStorageConfig","auth","resourceStoreUri","warn","Error","baseUrl","port","createDefaultRuntime","overrides","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/setup/stdio.js
CHANGED
|
@@ -11,6 +11,8 @@ export async function createStdioServer(config, overrides) {
|
|
|
11
11
|
...composed.tools,
|
|
12
12
|
...runtime.deps.oauthAdapters.accountTools
|
|
13
13
|
];
|
|
14
|
+
const filteredTools = config.auth === 'dcr' ? tools.filter((tool)=>tool.name !== 'messages-export-csv') // No file storage in DCR (public cloud responsibility)
|
|
15
|
+
: tools;
|
|
14
16
|
const prompts = [
|
|
15
17
|
...composed.prompts,
|
|
16
18
|
...runtime.deps.oauthAdapters.accountPrompts
|
|
@@ -19,7 +21,7 @@ export async function createStdioServer(config, overrides) {
|
|
|
19
21
|
name: config.name,
|
|
20
22
|
version: config.version
|
|
21
23
|
});
|
|
22
|
-
registerTools(mcpServer,
|
|
24
|
+
registerTools(mcpServer, filteredTools);
|
|
23
25
|
registerResources(mcpServer, composed.resources);
|
|
24
26
|
registerPrompts(mcpServer, prompts);
|
|
25
27
|
logger.info(`Starting ${config.name} MCP server (stdio)`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/setup/stdio.ts"],"sourcesContent":["import { composeMiddleware, connectStdio, registerPrompts, registerResources, registerTools } from '@mcp-z/server';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { RuntimeOverrides, ServerConfig } from '../types.ts';\nimport { createDefaultRuntime } from './runtime.ts';\n\nexport async function createStdioServer(config: ServerConfig, overrides?: RuntimeOverrides) {\n const runtime = await createDefaultRuntime(config, overrides);\n const modules = runtime.createDomainModules();\n const layers = runtime.middlewareFactories.map((factory) => factory(runtime.deps));\n const composed = composeMiddleware(modules, layers);\n const logger = runtime.deps.logger;\n\n const tools = [...composed.tools, ...runtime.deps.oauthAdapters.accountTools];\n const prompts = [...composed.prompts, ...runtime.deps.oauthAdapters.accountPrompts];\n\n const mcpServer = new McpServer({ name: config.name, version: config.version });\n registerTools(mcpServer,
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/Projects/mcp-z/mcp-gmail/src/setup/stdio.ts"],"sourcesContent":["import { composeMiddleware, connectStdio, registerPrompts, registerResources, registerTools } from '@mcp-z/server';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { RuntimeOverrides, ServerConfig } from '../types.ts';\nimport { createDefaultRuntime } from './runtime.ts';\n\nexport async function createStdioServer(config: ServerConfig, overrides?: RuntimeOverrides) {\n const runtime = await createDefaultRuntime(config, overrides);\n const modules = runtime.createDomainModules();\n const layers = runtime.middlewareFactories.map((factory) => factory(runtime.deps));\n const composed = composeMiddleware(modules, layers);\n const logger = runtime.deps.logger;\n\n const tools = [...composed.tools, ...runtime.deps.oauthAdapters.accountTools];\n const filteredTools =\n config.auth === 'dcr'\n ? tools.filter((tool) => tool.name !== 'messages-export-csv') // No file storage in DCR (public cloud responsibility)\n : tools;\n const prompts = [...composed.prompts, ...runtime.deps.oauthAdapters.accountPrompts];\n\n const mcpServer = new McpServer({ name: config.name, version: config.version });\n registerTools(mcpServer, filteredTools);\n registerResources(mcpServer, composed.resources);\n registerPrompts(mcpServer, prompts);\n\n logger.info(`Starting ${config.name} MCP server (stdio)`);\n const { close } = await connectStdio(mcpServer, { logger });\n logger.info('stdio transport ready');\n\n return {\n mcpServer,\n logger,\n close: async () => {\n await close();\n await runtime.close();\n },\n };\n}\n"],"names":["composeMiddleware","connectStdio","registerPrompts","registerResources","registerTools","McpServer","createDefaultRuntime","createStdioServer","config","overrides","runtime","modules","createDomainModules","layers","middlewareFactories","map","factory","deps","composed","logger","tools","oauthAdapters","accountTools","filteredTools","auth","filter","tool","name","prompts","accountPrompts","mcpServer","version","resources","info","close"],"mappings":"AAAA,SAASA,iBAAiB,EAAEC,YAAY,EAAEC,eAAe,EAAEC,iBAAiB,EAAEC,aAAa,QAAQ,gBAAgB;AACnH,SAASC,SAAS,QAAQ,0CAA0C;AAEpE,SAASC,oBAAoB,QAAQ,eAAe;AAEpD,OAAO,eAAeC,kBAAkBC,MAAoB,EAAEC,SAA4B;IACxF,MAAMC,UAAU,MAAMJ,qBAAqBE,QAAQC;IACnD,MAAME,UAAUD,QAAQE,mBAAmB;IAC3C,MAAMC,SAASH,QAAQI,mBAAmB,CAACC,GAAG,CAAC,CAACC,UAAYA,QAAQN,QAAQO,IAAI;IAChF,MAAMC,WAAWlB,kBAAkBW,SAASE;IAC5C,MAAMM,SAAST,QAAQO,IAAI,CAACE,MAAM;IAElC,MAAMC,QAAQ;WAAIF,SAASE,KAAK;WAAKV,QAAQO,IAAI,CAACI,aAAa,CAACC,YAAY;KAAC;IAC7E,MAAMC,gBACJf,OAAOgB,IAAI,KAAK,QACZJ,MAAMK,MAAM,CAAC,CAACC,OAASA,KAAKC,IAAI,KAAK,uBAAuB,uDAAuD;OACnHP;IACN,MAAMQ,UAAU;WAAIV,SAASU,OAAO;WAAKlB,QAAQO,IAAI,CAACI,aAAa,CAACQ,cAAc;KAAC;IAEnF,MAAMC,YAAY,IAAIzB,UAAU;QAAEsB,MAAMnB,OAAOmB,IAAI;QAAEI,SAASvB,OAAOuB,OAAO;IAAC;IAC7E3B,cAAc0B,WAAWP;IACzBpB,kBAAkB2B,WAAWZ,SAASc,SAAS;IAC/C9B,gBAAgB4B,WAAWF;IAE3BT,OAAOc,IAAI,CAAC,CAAC,SAAS,EAAEzB,OAAOmB,IAAI,CAAC,mBAAmB,CAAC;IACxD,MAAM,EAAEO,KAAK,EAAE,GAAG,MAAMjC,aAAa6B,WAAW;QAAEX;IAAO;IACzDA,OAAOc,IAAI,CAAC;IAEZ,OAAO;QACLH;QACAX;QACAe,OAAO;YACL,MAAMA;YACN,MAAMxB,QAAQwB,KAAK;QACrB;IACF;AACF"}
|