@mcp-z/mcp-drive 2.1.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/cjs/lib/google-auth.d.cts +1 -1
  2. package/dist/cjs/lib/google-auth.d.ts +1 -1
  3. package/dist/cjs/lib/google-auth.js +2 -2
  4. package/dist/cjs/lib/google-auth.js.map +1 -1
  5. package/dist/cjs/mcp/resources/file.js +2 -2
  6. package/dist/cjs/mcp/resources/file.js.map +1 -1
  7. package/dist/cjs/mcp/tools/file-move-to-trash.js +2 -2
  8. package/dist/cjs/mcp/tools/file-move-to-trash.js.map +1 -1
  9. package/dist/cjs/mcp/tools/file-move.js +2 -2
  10. package/dist/cjs/mcp/tools/file-move.js.map +1 -1
  11. package/dist/cjs/mcp/tools/file-upload.js +2 -2
  12. package/dist/cjs/mcp/tools/file-upload.js.map +1 -1
  13. package/dist/cjs/mcp/tools/files-search.js +2 -2
  14. package/dist/cjs/mcp/tools/files-search.js.map +1 -1
  15. package/dist/cjs/mcp/tools/folder-contents.js +2 -2
  16. package/dist/cjs/mcp/tools/folder-contents.js.map +1 -1
  17. package/dist/cjs/mcp/tools/folder-create.js +2 -2
  18. package/dist/cjs/mcp/tools/folder-create.js.map +1 -1
  19. package/dist/cjs/mcp/tools/folder-path.js +2 -2
  20. package/dist/cjs/mcp/tools/folder-path.js.map +1 -1
  21. package/dist/cjs/mcp/tools/folder-search.js +2 -2
  22. package/dist/cjs/mcp/tools/folder-search.js.map +1 -1
  23. package/dist/cjs/setup/http.d.cts +0 -2
  24. package/dist/cjs/setup/http.d.ts +0 -2
  25. package/dist/cjs/setup/http.js +16 -10
  26. package/dist/cjs/setup/http.js.map +1 -1
  27. package/dist/cjs/setup/stdio.d.cts +0 -2
  28. package/dist/cjs/setup/stdio.d.ts +0 -2
  29. package/dist/cjs/setup/stdio.js +16 -10
  30. package/dist/cjs/setup/stdio.js.map +1 -1
  31. package/dist/esm/lib/google-auth.d.ts +1 -1
  32. package/dist/esm/lib/google-auth.js +3 -3
  33. package/dist/esm/lib/google-auth.js.map +1 -1
  34. package/dist/esm/mcp/resources/file.js +2 -2
  35. package/dist/esm/mcp/resources/file.js.map +1 -1
  36. package/dist/esm/mcp/tools/file-move-to-trash.js +2 -2
  37. package/dist/esm/mcp/tools/file-move-to-trash.js.map +1 -1
  38. package/dist/esm/mcp/tools/file-move.js +2 -2
  39. package/dist/esm/mcp/tools/file-move.js.map +1 -1
  40. package/dist/esm/mcp/tools/file-upload.js +2 -2
  41. package/dist/esm/mcp/tools/file-upload.js.map +1 -1
  42. package/dist/esm/mcp/tools/files-search.js +2 -2
  43. package/dist/esm/mcp/tools/files-search.js.map +1 -1
  44. package/dist/esm/mcp/tools/folder-contents.js +2 -2
  45. package/dist/esm/mcp/tools/folder-contents.js.map +1 -1
  46. package/dist/esm/mcp/tools/folder-create.js +2 -2
  47. package/dist/esm/mcp/tools/folder-create.js.map +1 -1
  48. package/dist/esm/mcp/tools/folder-path.js +2 -2
  49. package/dist/esm/mcp/tools/folder-path.js.map +1 -1
  50. package/dist/esm/mcp/tools/folder-search.js +2 -2
  51. package/dist/esm/mcp/tools/folder-search.js.map +1 -1
  52. package/dist/esm/setup/http.d.ts +0 -2
  53. package/dist/esm/setup/http.js +15 -9
  54. package/dist/esm/setup/http.js.map +1 -1
  55. package/dist/esm/setup/stdio.d.ts +0 -2
  56. package/dist/esm/setup/stdio.js +15 -9
  57. package/dist/esm/setup/stdio.js.map +1 -1
  58. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-drive/src/mcp/tools/folder-path.ts"],"sourcesContent":["import type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { type CallToolResult, ProtocolError, ProtocolErrorCode } from '@mcp-z/server';\nimport type { drive_v3 } from 'googleapis';\nimport { google } from 'googleapis';\nimport { z } from 'zod';\nimport { googleAuth } from '../../lib/google-auth.ts';\nimport type { Logger } from '../../types.ts';\n\nconst inputSchema = z.object({\n folderId: z.string().min(1).describe('Folder ID to get path for (or \"root\")'),\n});\n\n// Success branch schema - uses items: for consistency with standard vocabulary\nconst successBranchSchema = z.object({\n type: z.literal('success'),\n path: z.string().describe('Full path from root (e.g., /Work/Projects/2024)'),\n items: z\n .array(\n z.object({\n id: z.string().describe('Folder ID'),\n name: z.string().describe('Folder name'),\n })\n )\n .describe('Path items from root to target folder'),\n});\n\n// Output schema with auth_required support\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n title: 'Get Folder Path',\n description: 'Get full path from folder to root. Returns human-readable path and items with IDs.',\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 * Resolves the full path for a folder by walking up the parent chain.\n * Returns both the path string and structured segments with IDs and names.\n */\nasync function resolveFolderPath(drive: drive_v3.Drive, folderId: string, logger: Logger): Promise<{ path: string; segments: Array<{ id: string; name: string }> }> {\n // Handle root specially\n if (folderId === 'root') {\n return {\n path: '/',\n segments: [{ id: 'root', name: 'My Drive' }],\n };\n }\n\n const segments: Array<{ id: string; name: string }> = [];\n let currentId = folderId;\n const visited = new Set<string>();\n\n // Walk up the parent chain\n while (currentId && currentId !== 'root') {\n // Prevent infinite loops\n if (visited.has(currentId)) {\n logger.info('Circular folder reference detected', {\n folderId: currentId,\n });\n break;\n }\n visited.add(currentId);\n\n // Fetch folder metadata\n try {\n const response = await drive.files.get({\n fileId: currentId,\n fields: 'id,name,parents',\n });\n\n const id = response.data.id as string;\n const name = (response.data.name as string) || id;\n const parents = response.data.parents as string[] | undefined;\n\n // Add to segments at beginning (we're walking from child to root)\n segments.unshift({ id, name });\n\n // Move to parent\n currentId = (parents && parents.length > 0 ? parents[0] : '') || '';\n } catch (e) {\n logger.info('Failed to resolve folder path', {\n folderId: currentId,\n error: e,\n });\n break;\n }\n }\n\n // Add root if we reached it\n if (currentId === 'root') {\n segments.unshift({ id: 'root', name: 'My Drive' });\n }\n\n // Build path string\n const pathParts = segments.slice(1).map((seg) => seg.name); // Skip root\n const path = pathParts.length > 0 ? `/${pathParts.join('/')}` : '/';\n\n return { path, segments };\n}\n\nasync function handler({ folderId }: Input, extra: EnrichedExtra): Promise<CallToolResult> {\n const logger = extra.logger;\n logger.info('drive.folder.path called', { folderId });\n\n try {\n const drive = google.drive({ version: 'v3', auth: googleAuth(extra.authContext.auth) });\n\n const pathResult = await resolveFolderPath(drive, folderId, logger);\n\n logger.info('drive.folder.path returning', {\n path: pathResult.path,\n segmentCount: pathResult.segments.length,\n });\n\n const result: Output = {\n type: 'success' as const,\n path: pathResult.path,\n items: pathResult.segments,\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error('drive.folder.path error', { error: message });\n\n // Throw ProtocolError\n throw new ProtocolError(ProtocolErrorCode.InternalError, `Error getting folder path: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'folder-path' as const,\n config,\n handler,\n };\n}\n"],"names":["schemas","AuthRequiredBranchSchema","ProtocolError","ProtocolErrorCode","google","z","googleAuth","inputSchema","object","folderId","string","min","describe","successBranchSchema","type","literal","path","items","array","id","name","outputSchema","discriminatedUnion","config","title","description","result","resolveFolderPath","drive","logger","segments","currentId","visited","Set","has","info","add","response","files","get","fileId","fields","data","parents","unshift","length","e","error","pathParts","slice","map","seg","join","handler","extra","version","auth","authContext","pathResult","segmentCount","content","text","JSON","stringify","structuredContent","message","Error","String","InternalError","stack","undefined","createTool"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-drive/src/mcp/tools/folder-path.ts"],"sourcesContent":["import type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport type { drive_v3 } from '@googleapis/drive';\nimport { drive as driveApi } from '@googleapis/drive';\nimport { type CallToolResult, ProtocolError, ProtocolErrorCode } from '@mcp-z/server';\nimport { z } from 'zod';\nimport { googleAuth } from '../../lib/google-auth.ts';\nimport type { Logger } from '../../types.ts';\n\nconst inputSchema = z.object({\n folderId: z.string().min(1).describe('Folder ID to get path for (or \"root\")'),\n});\n\n// Success branch schema - uses items: for consistency with standard vocabulary\nconst successBranchSchema = z.object({\n type: z.literal('success'),\n path: z.string().describe('Full path from root (e.g., /Work/Projects/2024)'),\n items: z\n .array(\n z.object({\n id: z.string().describe('Folder ID'),\n name: z.string().describe('Folder name'),\n })\n )\n .describe('Path items from root to target folder'),\n});\n\n// Output schema with auth_required support\nconst outputSchema = z.discriminatedUnion('type', [successBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n title: 'Get Folder Path',\n description: 'Get full path from folder to root. Returns human-readable path and items with IDs.',\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 * Resolves the full path for a folder by walking up the parent chain.\n * Returns both the path string and structured segments with IDs and names.\n */\nasync function resolveFolderPath(drive: drive_v3.Drive, folderId: string, logger: Logger): Promise<{ path: string; segments: Array<{ id: string; name: string }> }> {\n // Handle root specially\n if (folderId === 'root') {\n return {\n path: '/',\n segments: [{ id: 'root', name: 'My Drive' }],\n };\n }\n\n const segments: Array<{ id: string; name: string }> = [];\n let currentId = folderId;\n const visited = new Set<string>();\n\n // Walk up the parent chain\n while (currentId && currentId !== 'root') {\n // Prevent infinite loops\n if (visited.has(currentId)) {\n logger.info('Circular folder reference detected', {\n folderId: currentId,\n });\n break;\n }\n visited.add(currentId);\n\n // Fetch folder metadata\n try {\n const response = await drive.files.get({\n fileId: currentId,\n fields: 'id,name,parents',\n });\n\n const id = response.data.id as string;\n const name = (response.data.name as string) || id;\n const parents = response.data.parents as string[] | undefined;\n\n // Add to segments at beginning (we're walking from child to root)\n segments.unshift({ id, name });\n\n // Move to parent\n currentId = (parents && parents.length > 0 ? parents[0] : '') || '';\n } catch (e) {\n logger.info('Failed to resolve folder path', {\n folderId: currentId,\n error: e,\n });\n break;\n }\n }\n\n // Add root if we reached it\n if (currentId === 'root') {\n segments.unshift({ id: 'root', name: 'My Drive' });\n }\n\n // Build path string\n const pathParts = segments.slice(1).map((seg) => seg.name); // Skip root\n const path = pathParts.length > 0 ? `/${pathParts.join('/')}` : '/';\n\n return { path, segments };\n}\n\nasync function handler({ folderId }: Input, extra: EnrichedExtra): Promise<CallToolResult> {\n const logger = extra.logger;\n logger.info('drive.folder.path called', { folderId });\n\n try {\n const drive = driveApi({ version: 'v3', auth: googleAuth(extra.authContext.auth) });\n\n const pathResult = await resolveFolderPath(drive, folderId, logger);\n\n logger.info('drive.folder.path returning', {\n path: pathResult.path,\n segmentCount: pathResult.segments.length,\n });\n\n const result: Output = {\n type: 'success' as const,\n path: pathResult.path,\n items: pathResult.segments,\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error('drive.folder.path error', { error: message });\n\n // Throw ProtocolError\n throw new ProtocolError(ProtocolErrorCode.InternalError, `Error getting folder path: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'folder-path' as const,\n config,\n handler,\n };\n}\n"],"names":["schemas","AuthRequiredBranchSchema","drive","driveApi","ProtocolError","ProtocolErrorCode","z","googleAuth","inputSchema","object","folderId","string","min","describe","successBranchSchema","type","literal","path","items","array","id","name","outputSchema","discriminatedUnion","config","title","description","result","resolveFolderPath","logger","segments","currentId","visited","Set","has","info","add","response","files","get","fileId","fields","data","parents","unshift","length","e","error","pathParts","slice","map","seg","join","handler","extra","version","auth","authContext","pathResult","segmentCount","content","text","JSON","stringify","structuredContent","message","Error","String","InternalError","stack","undefined","createTool"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { schemas } from '@mcp-z/oauth-google';
2
2
  const { AuthRequiredBranchSchema } = schemas;
3
+ import { drive as driveApi } from '@googleapis/drive';
3
4
  import { createFieldsSchema, createPaginationSchema, createShapeSchema, filterFields, ProtocolError, ProtocolErrorCode, parseFields, toColumnarFormat } from '@mcp-z/server';
4
- import { google } from 'googleapis';
5
5
  import { z } from 'zod';
6
6
  import { googleAuth } from '../../lib/google-auth.js';
7
7
  import { toDriveQuery } from '../../lib/query-builder.js';
@@ -140,7 +140,7 @@ async function handler({ query, resolvePaths = false, pageSize = 50, pageToken,
140
140
  pageToken: pageToken ? '[provided]' : undefined,
141
141
  fields: fields || 'all'
142
142
  });
143
- const drive = google.drive({
143
+ const drive = driveApi({
144
144
  version: 'v3',
145
145
  auth: googleAuth(extra.authContext.auth)
146
146
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-drive/src/mcp/tools/folder-search.ts"],"sourcesContent":["import type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport { type CallToolResult, createFieldsSchema, createPaginationSchema, createShapeSchema, filterFields, ProtocolError, ProtocolErrorCode, parseFields, toColumnarFormat } from '@mcp-z/server';\nimport type { drive_v3 } from 'googleapis';\nimport { google } from 'googleapis';\nimport { z } from 'zod';\nimport { googleAuth } from '../../lib/google-auth.ts';\nimport { toDriveQuery } from '../../lib/query-builder.ts';\nimport { DRIVE_FILE_COMMON_PATTERNS, DRIVE_FILE_FIELD_DESCRIPTIONS, DRIVE_FILE_FIELDS, type DriveFile, DriveFileSchema, DriveQueryParameterSchema, parseDriveQueryParameter } from '../../schemas/index.ts';\nimport type { Logger } from '../../types.ts';\n\nconst inputSchema = z.object({\n query: DriveQueryParameterSchema.optional().describe('Structured Drive query object or JSON string. Use rawDriveQuery for raw Drive syntax.'),\n fields: createFieldsSchema({\n availableFields: [...DRIVE_FILE_FIELDS, 'path'] as const,\n fieldDescriptions: {\n ...DRIVE_FILE_FIELD_DESCRIPTIONS,\n path: 'Full folder path like /Work/Projects (requires resolvePaths=true)',\n },\n commonPatterns: DRIVE_FILE_COMMON_PATTERNS,\n resourceName: 'Drive folder',\n }),\n resolvePaths: z.boolean().optional().describe('Resolve full folder paths like /Work/Projects/2024 (requires additional API calls per result)'),\n ...createPaginationSchema({\n defaultPageSize: 50,\n maxPageSize: 1000,\n provider: 'drive',\n }).shape,\n shape: createShapeSchema(),\n});\n\n// Success branch schemas for different shapes\nconst successObjectsBranchSchema = z.object({\n type: z.literal('success'),\n shape: z.literal('objects'),\n items: z.array(DriveFileSchema.extend({ path: z.string().optional().describe('Full folder path (if resolvePaths=true)') })).describe('Matching Drive folders'),\n count: z.number().describe('Number of folders in this page'),\n nextPageToken: z.string().optional().describe('Token for fetching next page of results'),\n});\n\nconst successArraysBranchSchema = z.object({\n type: z.literal('success'),\n shape: z.literal('arrays'),\n columns: z.array(z.string()).describe('Column names in canonical order'),\n rows: z.array(z.array(z.unknown())).describe('Row data matching column order'),\n count: z.number().describe('Number of folders in this page'),\n nextPageToken: z.string().optional().describe('Token for fetching next page of results'),\n});\n\n// Output schema with auth_required support\n// Using z.union instead of discriminatedUnion since we have two success branches with different shapes\nconst outputSchema = z.union([successObjectsBranchSchema, successArraysBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n title: 'Search Folders',\n description: 'Search Google Drive folders with flexible field selection and optional path resolution.',\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// Type for the raw Google Drive API response\ntype DriveFolder = {\n id?: string;\n name?: string;\n mimeType?: string;\n webViewLink?: string;\n modifiedTime?: string;\n parents?: string[];\n shared?: boolean;\n starred?: boolean;\n owners?: Array<{\n displayName?: string;\n emailAddress?: string;\n kind?: string;\n me?: boolean;\n permissionId?: string;\n photoLink?: string;\n }>;\n};\n\ntype DriveFolderResponse = {\n files?: DriveFolder[];\n nextPageToken?: string;\n};\n\n/**\n * Resolves the full path for a folder by walking up the parent chain\n * Caches folder names to reduce redundant API calls\n */\nasync function resolveFolderPath(drive: drive_v3.Drive, folderId: string, folderCache: Map<string, string>, logger: Logger): Promise<string> {\n if (folderId === 'root') return '/';\n\n const pathParts: string[] = [];\n let currentId = folderId;\n const visited = new Set<string>();\n\n while (currentId && currentId !== 'root') {\n // Prevent infinite loops\n if (visited.has(currentId)) {\n logger.info('Circular folder reference detected', {\n folderId: currentId,\n });\n break;\n }\n visited.add(currentId);\n\n // Check cache first\n if (folderCache.has(currentId)) {\n const cachedName = folderCache.get(currentId);\n if (cachedName) {\n pathParts.unshift(cachedName);\n }\n\n // Get parent of cached folder\n try {\n const response = await drive.files.get({\n fileId: currentId,\n fields: 'parents',\n });\n const parents = response.data.parents as string[] | undefined;\n currentId = (parents && parents.length > 0 ? parents[0] : '') || '';\n } catch (_e) {\n logger.info('Failed to get parent for cached folder', {\n folderId: currentId,\n });\n break;\n }\n } else {\n // Fetch folder metadata\n try {\n const response = await drive.files.get({\n fileId: currentId,\n fields: 'name,parents',\n });\n const folderName = response.data.name as string | undefined;\n const parents = response.data.parents as string[] | undefined;\n\n if (folderName) {\n folderCache.set(currentId, folderName);\n pathParts.unshift(folderName);\n }\n\n currentId = (parents && parents.length > 0 ? parents[0] : '') || '';\n } catch (e) {\n logger.info('Failed to resolve folder path', {\n folderId: currentId,\n error: e,\n });\n break;\n }\n }\n }\n\n return `/${pathParts.join('/')}`;\n}\n\nasync function handler({ query, resolvePaths = false, pageSize = 50, pageToken, fields, shape = 'arrays' }: Input, extra: EnrichedExtra): Promise<CallToolResult> {\n const logger = extra.logger;\n\n try {\n const parsedQuery = parseDriveQueryParameter(query);\n const requestedFields = parseFields(fields, [...DRIVE_FILE_FIELDS, 'path'] as const);\n\n // Validate and clamp pageSize to Google Drive API limits (1-1000)\n const validPageSize = Math.max(1, Math.min(1000, Math.floor(pageSize || 50)));\n\n logger.info('drive.folder.search called', {\n query: parsedQuery,\n resolvePaths,\n pageSize: validPageSize,\n pageToken: pageToken ? '[provided]' : undefined,\n fields: fields || 'all',\n });\n\n const drive = google.drive({ version: 'v3', auth: googleAuth(extra.authContext.auth) });\n\n const folderMimeType = 'application/vnd.google-apps.folder';\n let qStr: string;\n\n if (parsedQuery && 'rawDriveQuery' in parsedQuery && parsedQuery.rawDriveQuery) {\n // Object with rawDriveQuery field - use it directly\n qStr = parsedQuery.rawDriveQuery;\n } else if (parsedQuery) {\n // Structured query object - convert to Drive query string\n const { q } = toDriveQuery(parsedQuery);\n qStr = q || '';\n } else {\n qStr = '';\n }\n\n qStr = qStr ? `(${qStr}) and mimeType='${folderMimeType}'` : `mimeType='${folderMimeType}'`;\n\n const listOptions: {\n q: string;\n pageSize: number;\n fields: string;\n orderBy: string;\n pageToken?: string;\n } = {\n q: qStr,\n pageSize: validPageSize,\n fields: 'files(id,name,mimeType,webViewLink,modifiedTime,parents,shared,starred,owners),nextPageToken',\n orderBy: 'modifiedTime desc',\n };\n if (pageToken && pageToken.trim().length > 0) {\n listOptions.pageToken = pageToken;\n }\n\n const response = await drive.files.list(listOptions);\n\n const res = response.data as DriveFolderResponse;\n const folders = Array.isArray(res?.files) ? res.files : [];\n\n const parentIds = new Set<string>();\n for (const f of folders) {\n if (f?.parents && f.parents.length > 0) {\n for (const parentId of f.parents) {\n if (parentId && parentId !== 'root') {\n parentIds.add(parentId);\n }\n }\n }\n }\n\n const parentNameMap = new Map<string, string>();\n if (parentIds.size > 0) {\n logger.info('Fetching parent names', { count: parentIds.size });\n const parentFetches = Array.from(parentIds).map(async (parentId) => {\n try {\n const parentRes = await drive.files.get({\n fileId: parentId,\n fields: 'id,name',\n });\n const parentName = (parentRes.data.name as string | undefined) || parentId;\n parentNameMap.set(parentId, parentName);\n } catch (e) {\n logger.info('Failed to fetch parent name', { parentId, error: e });\n parentNameMap.set(parentId, parentId); // Fallback to ID\n }\n });\n await Promise.all(parentFetches);\n }\n\n // Cache for folder names to reduce API calls during path resolution\n const folderCache = new Map<string, string>();\n\n const items: (DriveFile & { path?: string })[] = await Promise.all(\n folders.map(async (f: DriveFolder) => {\n const id = f?.id ? String(f.id) : 'unknown';\n const name = f?.name || id;\n const result: DriveFile & { path?: string } = { id, name };\n\n // Only include properties that have actual values\n if (f?.mimeType) result.mimeType = f.mimeType;\n if (f?.webViewLink) result.webViewLink = f.webViewLink;\n if (f?.modifiedTime) result.modifiedTime = f.modifiedTime;\n\n // Build parent objects with names\n if (f?.parents && f.parents.length > 0) {\n result.parents = f.parents.map((parentId) => {\n if (parentId === 'root') {\n return { id: 'root', name: 'My Drive' };\n }\n const parentName = parentNameMap.get(parentId) || parentId;\n return { id: parentId, name: parentName };\n });\n }\n\n if (f?.shared !== undefined) result.shared = f.shared;\n if (f?.starred !== undefined) result.starred = f.starred;\n\n if (f?.owners && f.owners.length > 0) {\n result.owners = f.owners.map((o) => {\n const owner: NonNullable<DriveFile['owners']>[number] = {};\n if (o?.displayName) owner.displayName = o.displayName;\n if (o?.emailAddress) owner.emailAddress = o.emailAddress;\n if (o?.kind) owner.kind = o.kind;\n if (o?.me !== undefined) owner.me = o.me;\n if (o?.permissionId) owner.permissionId = o.permissionId;\n if (o?.photoLink) owner.photoLink = o.photoLink;\n return owner;\n });\n }\n\n // Resolve path if requested\n if (resolvePaths && id !== 'unknown') {\n result.path = await resolveFolderPath(drive, id, folderCache, logger);\n }\n\n return result;\n })\n );\n\n const filteredItems = items.map((item) => filterFields(item, requestedFields));\n\n logger.info('drive.folder.search returning', {\n query: parsedQuery,\n pageSize,\n resultCount: filteredItems.length,\n resolvePaths,\n fields: fields || 'all',\n });\n\n const nextPageToken = res.nextPageToken && res.nextPageToken.trim().length > 0 ? res.nextPageToken : undefined;\n\n // Build result based on shape\n const result: Output =\n shape === 'arrays'\n ? {\n type: 'success' as const,\n shape: 'arrays' as const,\n ...toColumnarFormat(filteredItems, requestedFields, [...DRIVE_FILE_FIELDS, 'path'] as const),\n count: filteredItems.length,\n ...(nextPageToken && { nextPageToken }),\n }\n : {\n type: 'success' as const,\n shape: 'objects' as const,\n items: filteredItems,\n count: filteredItems.length,\n ...(nextPageToken && { nextPageToken }),\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error('drive.folder.search error', { error: message });\n\n // Throw ProtocolError for all errors so callers can see Drive validation details\n throw new ProtocolError(ProtocolErrorCode.InternalError, `Error searching folders: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'folder-search' as const,\n config,\n handler,\n };\n}\n"],"names":["schemas","AuthRequiredBranchSchema","createFieldsSchema","createPaginationSchema","createShapeSchema","filterFields","ProtocolError","ProtocolErrorCode","parseFields","toColumnarFormat","google","z","googleAuth","toDriveQuery","DRIVE_FILE_COMMON_PATTERNS","DRIVE_FILE_FIELD_DESCRIPTIONS","DRIVE_FILE_FIELDS","DriveFileSchema","DriveQueryParameterSchema","parseDriveQueryParameter","inputSchema","object","query","optional","describe","fields","availableFields","fieldDescriptions","path","commonPatterns","resourceName","resolvePaths","boolean","defaultPageSize","maxPageSize","provider","shape","successObjectsBranchSchema","type","literal","items","array","extend","string","count","number","nextPageToken","successArraysBranchSchema","columns","rows","unknown","outputSchema","union","config","title","description","result","resolveFolderPath","drive","folderId","folderCache","logger","pathParts","currentId","visited","Set","has","info","add","cachedName","get","unshift","response","files","fileId","parents","data","length","_e","folderName","name","set","e","error","join","handler","pageSize","pageToken","extra","parsedQuery","requestedFields","validPageSize","Math","max","min","floor","undefined","version","auth","authContext","folderMimeType","qStr","rawDriveQuery","q","listOptions","orderBy","trim","list","res","folders","Array","isArray","parentIds","f","parentId","parentNameMap","Map","size","parentFetches","from","map","parentRes","parentName","Promise","all","id","String","mimeType","webViewLink","modifiedTime","shared","starred","owners","o","owner","displayName","emailAddress","kind","me","permissionId","photoLink","filteredItems","item","resultCount","content","text","JSON","stringify","structuredContent","message","Error","InternalError","stack","createTool"],"mappings":"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"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-drive/src/mcp/tools/folder-search.ts"],"sourcesContent":["import type { EnrichedExtra } from '@mcp-z/oauth-google';\nimport { schemas } from '@mcp-z/oauth-google';\n\nconst { AuthRequiredBranchSchema } = schemas;\n\nimport type { drive_v3 } from '@googleapis/drive';\nimport { drive as driveApi } from '@googleapis/drive';\nimport { type CallToolResult, createFieldsSchema, createPaginationSchema, createShapeSchema, filterFields, ProtocolError, ProtocolErrorCode, parseFields, toColumnarFormat } from '@mcp-z/server';\nimport { z } from 'zod';\nimport { googleAuth } from '../../lib/google-auth.ts';\nimport { toDriveQuery } from '../../lib/query-builder.ts';\nimport { DRIVE_FILE_COMMON_PATTERNS, DRIVE_FILE_FIELD_DESCRIPTIONS, DRIVE_FILE_FIELDS, type DriveFile, DriveFileSchema, DriveQueryParameterSchema, parseDriveQueryParameter } from '../../schemas/index.ts';\nimport type { Logger } from '../../types.ts';\n\nconst inputSchema = z.object({\n query: DriveQueryParameterSchema.optional().describe('Structured Drive query object or JSON string. Use rawDriveQuery for raw Drive syntax.'),\n fields: createFieldsSchema({\n availableFields: [...DRIVE_FILE_FIELDS, 'path'] as const,\n fieldDescriptions: {\n ...DRIVE_FILE_FIELD_DESCRIPTIONS,\n path: 'Full folder path like /Work/Projects (requires resolvePaths=true)',\n },\n commonPatterns: DRIVE_FILE_COMMON_PATTERNS,\n resourceName: 'Drive folder',\n }),\n resolvePaths: z.boolean().optional().describe('Resolve full folder paths like /Work/Projects/2024 (requires additional API calls per result)'),\n ...createPaginationSchema({\n defaultPageSize: 50,\n maxPageSize: 1000,\n provider: 'drive',\n }).shape,\n shape: createShapeSchema(),\n});\n\n// Success branch schemas for different shapes\nconst successObjectsBranchSchema = z.object({\n type: z.literal('success'),\n shape: z.literal('objects'),\n items: z.array(DriveFileSchema.extend({ path: z.string().optional().describe('Full folder path (if resolvePaths=true)') })).describe('Matching Drive folders'),\n count: z.number().describe('Number of folders in this page'),\n nextPageToken: z.string().optional().describe('Token for fetching next page of results'),\n});\n\nconst successArraysBranchSchema = z.object({\n type: z.literal('success'),\n shape: z.literal('arrays'),\n columns: z.array(z.string()).describe('Column names in canonical order'),\n rows: z.array(z.array(z.unknown())).describe('Row data matching column order'),\n count: z.number().describe('Number of folders in this page'),\n nextPageToken: z.string().optional().describe('Token for fetching next page of results'),\n});\n\n// Output schema with auth_required support\n// Using z.union instead of discriminatedUnion since we have two success branches with different shapes\nconst outputSchema = z.union([successObjectsBranchSchema, successArraysBranchSchema, AuthRequiredBranchSchema]);\n\nconst config = {\n title: 'Search Folders',\n description: 'Search Google Drive folders with flexible field selection and optional path resolution.',\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// Type for the raw Google Drive API response\ntype DriveFolder = {\n id?: string;\n name?: string;\n mimeType?: string;\n webViewLink?: string;\n modifiedTime?: string;\n parents?: string[];\n shared?: boolean;\n starred?: boolean;\n owners?: Array<{\n displayName?: string;\n emailAddress?: string;\n kind?: string;\n me?: boolean;\n permissionId?: string;\n photoLink?: string;\n }>;\n};\n\ntype DriveFolderResponse = {\n files?: DriveFolder[];\n nextPageToken?: string;\n};\n\n/**\n * Resolves the full path for a folder by walking up the parent chain\n * Caches folder names to reduce redundant API calls\n */\nasync function resolveFolderPath(drive: drive_v3.Drive, folderId: string, folderCache: Map<string, string>, logger: Logger): Promise<string> {\n if (folderId === 'root') return '/';\n\n const pathParts: string[] = [];\n let currentId = folderId;\n const visited = new Set<string>();\n\n while (currentId && currentId !== 'root') {\n // Prevent infinite loops\n if (visited.has(currentId)) {\n logger.info('Circular folder reference detected', {\n folderId: currentId,\n });\n break;\n }\n visited.add(currentId);\n\n // Check cache first\n if (folderCache.has(currentId)) {\n const cachedName = folderCache.get(currentId);\n if (cachedName) {\n pathParts.unshift(cachedName);\n }\n\n // Get parent of cached folder\n try {\n const response = await drive.files.get({\n fileId: currentId,\n fields: 'parents',\n });\n const parents = response.data.parents as string[] | undefined;\n currentId = (parents && parents.length > 0 ? parents[0] : '') || '';\n } catch (_e) {\n logger.info('Failed to get parent for cached folder', {\n folderId: currentId,\n });\n break;\n }\n } else {\n // Fetch folder metadata\n try {\n const response = await drive.files.get({\n fileId: currentId,\n fields: 'name,parents',\n });\n const folderName = response.data.name as string | undefined;\n const parents = response.data.parents as string[] | undefined;\n\n if (folderName) {\n folderCache.set(currentId, folderName);\n pathParts.unshift(folderName);\n }\n\n currentId = (parents && parents.length > 0 ? parents[0] : '') || '';\n } catch (e) {\n logger.info('Failed to resolve folder path', {\n folderId: currentId,\n error: e,\n });\n break;\n }\n }\n }\n\n return `/${pathParts.join('/')}`;\n}\n\nasync function handler({ query, resolvePaths = false, pageSize = 50, pageToken, fields, shape = 'arrays' }: Input, extra: EnrichedExtra): Promise<CallToolResult> {\n const logger = extra.logger;\n\n try {\n const parsedQuery = parseDriveQueryParameter(query);\n const requestedFields = parseFields(fields, [...DRIVE_FILE_FIELDS, 'path'] as const);\n\n // Validate and clamp pageSize to Google Drive API limits (1-1000)\n const validPageSize = Math.max(1, Math.min(1000, Math.floor(pageSize || 50)));\n\n logger.info('drive.folder.search called', {\n query: parsedQuery,\n resolvePaths,\n pageSize: validPageSize,\n pageToken: pageToken ? '[provided]' : undefined,\n fields: fields || 'all',\n });\n\n const drive = driveApi({ version: 'v3', auth: googleAuth(extra.authContext.auth) });\n\n const folderMimeType = 'application/vnd.google-apps.folder';\n let qStr: string;\n\n if (parsedQuery && 'rawDriveQuery' in parsedQuery && parsedQuery.rawDriveQuery) {\n // Object with rawDriveQuery field - use it directly\n qStr = parsedQuery.rawDriveQuery;\n } else if (parsedQuery) {\n // Structured query object - convert to Drive query string\n const { q } = toDriveQuery(parsedQuery);\n qStr = q || '';\n } else {\n qStr = '';\n }\n\n qStr = qStr ? `(${qStr}) and mimeType='${folderMimeType}'` : `mimeType='${folderMimeType}'`;\n\n const listOptions: {\n q: string;\n pageSize: number;\n fields: string;\n orderBy: string;\n pageToken?: string;\n } = {\n q: qStr,\n pageSize: validPageSize,\n fields: 'files(id,name,mimeType,webViewLink,modifiedTime,parents,shared,starred,owners),nextPageToken',\n orderBy: 'modifiedTime desc',\n };\n if (pageToken && pageToken.trim().length > 0) {\n listOptions.pageToken = pageToken;\n }\n\n const response = await drive.files.list(listOptions);\n\n const res = response.data as DriveFolderResponse;\n const folders = Array.isArray(res?.files) ? res.files : [];\n\n const parentIds = new Set<string>();\n for (const f of folders) {\n if (f?.parents && f.parents.length > 0) {\n for (const parentId of f.parents) {\n if (parentId && parentId !== 'root') {\n parentIds.add(parentId);\n }\n }\n }\n }\n\n const parentNameMap = new Map<string, string>();\n if (parentIds.size > 0) {\n logger.info('Fetching parent names', { count: parentIds.size });\n const parentFetches = Array.from(parentIds).map(async (parentId) => {\n try {\n const parentRes = await drive.files.get({\n fileId: parentId,\n fields: 'id,name',\n });\n const parentName = (parentRes.data.name as string | undefined) || parentId;\n parentNameMap.set(parentId, parentName);\n } catch (e) {\n logger.info('Failed to fetch parent name', { parentId, error: e });\n parentNameMap.set(parentId, parentId); // Fallback to ID\n }\n });\n await Promise.all(parentFetches);\n }\n\n // Cache for folder names to reduce API calls during path resolution\n const folderCache = new Map<string, string>();\n\n const items: (DriveFile & { path?: string })[] = await Promise.all(\n folders.map(async (f: DriveFolder) => {\n const id = f?.id ? String(f.id) : 'unknown';\n const name = f?.name || id;\n const result: DriveFile & { path?: string } = { id, name };\n\n // Only include properties that have actual values\n if (f?.mimeType) result.mimeType = f.mimeType;\n if (f?.webViewLink) result.webViewLink = f.webViewLink;\n if (f?.modifiedTime) result.modifiedTime = f.modifiedTime;\n\n // Build parent objects with names\n if (f?.parents && f.parents.length > 0) {\n result.parents = f.parents.map((parentId) => {\n if (parentId === 'root') {\n return { id: 'root', name: 'My Drive' };\n }\n const parentName = parentNameMap.get(parentId) || parentId;\n return { id: parentId, name: parentName };\n });\n }\n\n if (f?.shared !== undefined) result.shared = f.shared;\n if (f?.starred !== undefined) result.starred = f.starred;\n\n if (f?.owners && f.owners.length > 0) {\n result.owners = f.owners.map((o) => {\n const owner: NonNullable<DriveFile['owners']>[number] = {};\n if (o?.displayName) owner.displayName = o.displayName;\n if (o?.emailAddress) owner.emailAddress = o.emailAddress;\n if (o?.kind) owner.kind = o.kind;\n if (o?.me !== undefined) owner.me = o.me;\n if (o?.permissionId) owner.permissionId = o.permissionId;\n if (o?.photoLink) owner.photoLink = o.photoLink;\n return owner;\n });\n }\n\n // Resolve path if requested\n if (resolvePaths && id !== 'unknown') {\n result.path = await resolveFolderPath(drive, id, folderCache, logger);\n }\n\n return result;\n })\n );\n\n const filteredItems = items.map((item) => filterFields(item, requestedFields));\n\n logger.info('drive.folder.search returning', {\n query: parsedQuery,\n pageSize,\n resultCount: filteredItems.length,\n resolvePaths,\n fields: fields || 'all',\n });\n\n const nextPageToken = res.nextPageToken && res.nextPageToken.trim().length > 0 ? res.nextPageToken : undefined;\n\n // Build result based on shape\n const result: Output =\n shape === 'arrays'\n ? {\n type: 'success' as const,\n shape: 'arrays' as const,\n ...toColumnarFormat(filteredItems, requestedFields, [...DRIVE_FILE_FIELDS, 'path'] as const),\n count: filteredItems.length,\n ...(nextPageToken && { nextPageToken }),\n }\n : {\n type: 'success' as const,\n shape: 'objects' as const,\n items: filteredItems,\n count: filteredItems.length,\n ...(nextPageToken && { nextPageToken }),\n };\n\n return {\n content: [\n {\n type: 'text' as const,\n text: JSON.stringify(result),\n },\n ],\n structuredContent: { result },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n logger.error('drive.folder.search error', { error: message });\n\n // Throw ProtocolError for all errors so callers can see Drive validation details\n throw new ProtocolError(ProtocolErrorCode.InternalError, `Error searching folders: ${message}`, {\n stack: error instanceof Error ? error.stack : undefined,\n });\n }\n}\n\nexport default function createTool() {\n return {\n name: 'folder-search' as const,\n config,\n handler,\n };\n}\n"],"names":["schemas","AuthRequiredBranchSchema","drive","driveApi","createFieldsSchema","createPaginationSchema","createShapeSchema","filterFields","ProtocolError","ProtocolErrorCode","parseFields","toColumnarFormat","z","googleAuth","toDriveQuery","DRIVE_FILE_COMMON_PATTERNS","DRIVE_FILE_FIELD_DESCRIPTIONS","DRIVE_FILE_FIELDS","DriveFileSchema","DriveQueryParameterSchema","parseDriveQueryParameter","inputSchema","object","query","optional","describe","fields","availableFields","fieldDescriptions","path","commonPatterns","resourceName","resolvePaths","boolean","defaultPageSize","maxPageSize","provider","shape","successObjectsBranchSchema","type","literal","items","array","extend","string","count","number","nextPageToken","successArraysBranchSchema","columns","rows","unknown","outputSchema","union","config","title","description","result","resolveFolderPath","folderId","folderCache","logger","pathParts","currentId","visited","Set","has","info","add","cachedName","get","unshift","response","files","fileId","parents","data","length","_e","folderName","name","set","e","error","join","handler","pageSize","pageToken","extra","parsedQuery","requestedFields","validPageSize","Math","max","min","floor","undefined","version","auth","authContext","folderMimeType","qStr","rawDriveQuery","q","listOptions","orderBy","trim","list","res","folders","Array","isArray","parentIds","f","parentId","parentNameMap","Map","size","parentFetches","from","map","parentRes","parentName","Promise","all","id","String","mimeType","webViewLink","modifiedTime","shared","starred","owners","o","owner","displayName","emailAddress","kind","me","permissionId","photoLink","filteredItems","item","resultCount","content","text","JSON","stringify","structuredContent","message","Error","InternalError","stack","createTool"],"mappings":"AACA,SAASA,OAAO,QAAQ,sBAAsB;AAE9C,MAAM,EAAEC,wBAAwB,EAAE,GAAGD;AAGrC,SAASE,SAASC,QAAQ,QAAQ,oBAAoB;AACtD,SAA8BC,kBAAkB,EAAEC,sBAAsB,EAAEC,iBAAiB,EAAEC,YAAY,EAAEC,aAAa,EAAEC,iBAAiB,EAAEC,WAAW,EAAEC,gBAAgB,QAAQ,gBAAgB;AAClM,SAASC,CAAC,QAAQ,MAAM;AACxB,SAASC,UAAU,QAAQ,2BAA2B;AACtD,SAASC,YAAY,QAAQ,6BAA6B;AAC1D,SAASC,0BAA0B,EAAEC,6BAA6B,EAAEC,iBAAiB,EAAkBC,eAAe,EAAEC,yBAAyB,EAAEC,wBAAwB,QAAQ,yBAAyB;AAG5M,MAAMC,cAAcT,EAAEU,MAAM,CAAC;IAC3BC,OAAOJ,0BAA0BK,QAAQ,GAAGC,QAAQ,CAAC;IACrDC,QAAQtB,mBAAmB;QACzBuB,iBAAiB;eAAIV;YAAmB;SAAO;QAC/CW,mBAAmB;YACjB,GAAGZ,6BAA6B;YAChCa,MAAM;QACR;QACAC,gBAAgBf;QAChBgB,cAAc;IAChB;IACAC,cAAcpB,EAAEqB,OAAO,GAAGT,QAAQ,GAAGC,QAAQ,CAAC;IAC9C,GAAGpB,uBAAuB;QACxB6B,iBAAiB;QACjBC,aAAa;QACbC,UAAU;IACZ,GAAGC,KAAK;IACRA,OAAO/B;AACT;AAEA,8CAA8C;AAC9C,MAAMgC,6BAA6B1B,EAAEU,MAAM,CAAC;IAC1CiB,MAAM3B,EAAE4B,OAAO,CAAC;IAChBH,OAAOzB,EAAE4B,OAAO,CAAC;IACjBC,OAAO7B,EAAE8B,KAAK,CAACxB,gBAAgByB,MAAM,CAAC;QAAEd,MAAMjB,EAAEgC,MAAM,GAAGpB,QAAQ,GAAGC,QAAQ,CAAC;IAA2C,IAAIA,QAAQ,CAAC;IACrIoB,OAAOjC,EAAEkC,MAAM,GAAGrB,QAAQ,CAAC;IAC3BsB,eAAenC,EAAEgC,MAAM,GAAGpB,QAAQ,GAAGC,QAAQ,CAAC;AAChD;AAEA,MAAMuB,4BAA4BpC,EAAEU,MAAM,CAAC;IACzCiB,MAAM3B,EAAE4B,OAAO,CAAC;IAChBH,OAAOzB,EAAE4B,OAAO,CAAC;IACjBS,SAASrC,EAAE8B,KAAK,CAAC9B,EAAEgC,MAAM,IAAInB,QAAQ,CAAC;IACtCyB,MAAMtC,EAAE8B,KAAK,CAAC9B,EAAE8B,KAAK,CAAC9B,EAAEuC,OAAO,KAAK1B,QAAQ,CAAC;IAC7CoB,OAAOjC,EAAEkC,MAAM,GAAGrB,QAAQ,CAAC;IAC3BsB,eAAenC,EAAEgC,MAAM,GAAGpB,QAAQ,GAAGC,QAAQ,CAAC;AAChD;AAEA,2CAA2C;AAC3C,uGAAuG;AACvG,MAAM2B,eAAexC,EAAEyC,KAAK,CAAC;IAACf;IAA4BU;IAA2B/C;CAAyB;AAE9G,MAAMqD,SAAS;IACbC,OAAO;IACPC,aAAa;IACbnC,aAAaA;IACb+B,cAAcxC,EAAEU,MAAM,CAAC;QACrBmC,QAAQL;IACV;AACF;AA8BA;;;CAGC,GACD,eAAeM,kBAAkBxD,KAAqB,EAAEyD,QAAgB,EAAEC,WAAgC,EAAEC,MAAc;IACxH,IAAIF,aAAa,QAAQ,OAAO;IAEhC,MAAMG,YAAsB,EAAE;IAC9B,IAAIC,YAAYJ;IAChB,MAAMK,UAAU,IAAIC;IAEpB,MAAOF,aAAaA,cAAc,OAAQ;QACxC,yBAAyB;QACzB,IAAIC,QAAQE,GAAG,CAACH,YAAY;YAC1BF,OAAOM,IAAI,CAAC,sCAAsC;gBAChDR,UAAUI;YACZ;YACA;QACF;QACAC,QAAQI,GAAG,CAACL;QAEZ,oBAAoB;QACpB,IAAIH,YAAYM,GAAG,CAACH,YAAY;YAC9B,MAAMM,aAAaT,YAAYU,GAAG,CAACP;YACnC,IAAIM,YAAY;gBACdP,UAAUS,OAAO,CAACF;YACpB;YAEA,8BAA8B;YAC9B,IAAI;gBACF,MAAMG,WAAW,MAAMtE,MAAMuE,KAAK,CAACH,GAAG,CAAC;oBACrCI,QAAQX;oBACRrC,QAAQ;gBACV;gBACA,MAAMiD,UAAUH,SAASI,IAAI,CAACD,OAAO;gBACrCZ,YAAY,AAACY,CAAAA,WAAWA,QAAQE,MAAM,GAAG,IAAIF,OAAO,CAAC,EAAE,GAAG,EAAC,KAAM;YACnE,EAAE,OAAOG,IAAI;gBACXjB,OAAOM,IAAI,CAAC,0CAA0C;oBACpDR,UAAUI;gBACZ;gBACA;YACF;QACF,OAAO;YACL,wBAAwB;YACxB,IAAI;gBACF,MAAMS,WAAW,MAAMtE,MAAMuE,KAAK,CAACH,GAAG,CAAC;oBACrCI,QAAQX;oBACRrC,QAAQ;gBACV;gBACA,MAAMqD,aAAaP,SAASI,IAAI,CAACI,IAAI;gBACrC,MAAML,UAAUH,SAASI,IAAI,CAACD,OAAO;gBAErC,IAAII,YAAY;oBACdnB,YAAYqB,GAAG,CAAClB,WAAWgB;oBAC3BjB,UAAUS,OAAO,CAACQ;gBACpB;gBAEAhB,YAAY,AAACY,CAAAA,WAAWA,QAAQE,MAAM,GAAG,IAAIF,OAAO,CAAC,EAAE,GAAG,EAAC,KAAM;YACnE,EAAE,OAAOO,GAAG;gBACVrB,OAAOM,IAAI,CAAC,iCAAiC;oBAC3CR,UAAUI;oBACVoB,OAAOD;gBACT;gBACA;YACF;QACF;IACF;IAEA,OAAO,CAAC,CAAC,EAAEpB,UAAUsB,IAAI,CAAC,MAAM;AAClC;AAEA,eAAeC,QAAQ,EAAE9D,KAAK,EAAES,eAAe,KAAK,EAAEsD,WAAW,EAAE,EAAEC,SAAS,EAAE7D,MAAM,EAAEW,QAAQ,QAAQ,EAAS,EAAEmD,KAAoB;IACrI,MAAM3B,SAAS2B,MAAM3B,MAAM;IAE3B,IAAI;QACF,MAAM4B,cAAcrE,yBAAyBG;QAC7C,MAAMmE,kBAAkBhF,YAAYgB,QAAQ;eAAIT;YAAmB;SAAO;QAE1E,kEAAkE;QAClE,MAAM0E,gBAAgBC,KAAKC,GAAG,CAAC,GAAGD,KAAKE,GAAG,CAAC,MAAMF,KAAKG,KAAK,CAACT,YAAY;QAExEzB,OAAOM,IAAI,CAAC,8BAA8B;YACxC5C,OAAOkE;YACPzD;YACAsD,UAAUK;YACVJ,WAAWA,YAAY,eAAeS;YACtCtE,QAAQA,UAAU;QACpB;QAEA,MAAMxB,QAAQC,SAAS;YAAE8F,SAAS;YAAMC,MAAMrF,WAAW2E,MAAMW,WAAW,CAACD,IAAI;QAAE;QAEjF,MAAME,iBAAiB;QACvB,IAAIC;QAEJ,IAAIZ,eAAe,mBAAmBA,eAAeA,YAAYa,aAAa,EAAE;YAC9E,oDAAoD;YACpDD,OAAOZ,YAAYa,aAAa;QAClC,OAAO,IAAIb,aAAa;YACtB,0DAA0D;YAC1D,MAAM,EAAEc,CAAC,EAAE,GAAGzF,aAAa2E;YAC3BY,OAAOE,KAAK;QACd,OAAO;YACLF,OAAO;QACT;QAEAA,OAAOA,OAAO,CAAC,CAAC,EAAEA,KAAK,gBAAgB,EAAED,eAAe,CAAC,CAAC,GAAG,CAAC,UAAU,EAAEA,eAAe,CAAC,CAAC;QAE3F,MAAMI,cAMF;YACFD,GAAGF;YACHf,UAAUK;YACVjE,QAAQ;YACR+E,SAAS;QACX;QACA,IAAIlB,aAAaA,UAAUmB,IAAI,GAAG7B,MAAM,GAAG,GAAG;YAC5C2B,YAAYjB,SAAS,GAAGA;QAC1B;QAEA,MAAMf,WAAW,MAAMtE,MAAMuE,KAAK,CAACkC,IAAI,CAACH;QAExC,MAAMI,MAAMpC,SAASI,IAAI;QACzB,MAAMiC,UAAUC,MAAMC,OAAO,CAACH,gBAAAA,0BAAAA,IAAKnC,KAAK,IAAImC,IAAInC,KAAK,GAAG,EAAE;QAE1D,MAAMuC,YAAY,IAAI/C;QACtB,KAAK,MAAMgD,KAAKJ,QAAS;YACvB,IAAII,CAAAA,cAAAA,wBAAAA,EAAGtC,OAAO,KAAIsC,EAAEtC,OAAO,CAACE,MAAM,GAAG,GAAG;gBACtC,KAAK,MAAMqC,YAAYD,EAAEtC,OAAO,CAAE;oBAChC,IAAIuC,YAAYA,aAAa,QAAQ;wBACnCF,UAAU5C,GAAG,CAAC8C;oBAChB;gBACF;YACF;QACF;QAEA,MAAMC,gBAAgB,IAAIC;QAC1B,IAAIJ,UAAUK,IAAI,GAAG,GAAG;YACtBxD,OAAOM,IAAI,CAAC,yBAAyB;gBAAEtB,OAAOmE,UAAUK,IAAI;YAAC;YAC7D,MAAMC,gBAAgBR,MAAMS,IAAI,CAACP,WAAWQ,GAAG,CAAC,OAAON;gBACrD,IAAI;oBACF,MAAMO,YAAY,MAAMvH,MAAMuE,KAAK,CAACH,GAAG,CAAC;wBACtCI,QAAQwC;wBACRxF,QAAQ;oBACV;oBACA,MAAMgG,aAAa,AAACD,UAAU7C,IAAI,CAACI,IAAI,IAA2BkC;oBAClEC,cAAclC,GAAG,CAACiC,UAAUQ;gBAC9B,EAAE,OAAOxC,GAAG;oBACVrB,OAAOM,IAAI,CAAC,+BAA+B;wBAAE+C;wBAAU/B,OAAOD;oBAAE;oBAChEiC,cAAclC,GAAG,CAACiC,UAAUA,WAAW,iBAAiB;gBAC1D;YACF;YACA,MAAMS,QAAQC,GAAG,CAACN;QACpB;QAEA,oEAAoE;QACpE,MAAM1D,cAAc,IAAIwD;QAExB,MAAM3E,QAA2C,MAAMkF,QAAQC,GAAG,CAChEf,QAAQW,GAAG,CAAC,OAAOP;YACjB,MAAMY,KAAKZ,CAAAA,cAAAA,wBAAAA,EAAGY,EAAE,IAAGC,OAAOb,EAAEY,EAAE,IAAI;YAClC,MAAM7C,OAAOiC,CAAAA,cAAAA,wBAAAA,EAAGjC,IAAI,KAAI6C;YACxB,MAAMpE,SAAwC;gBAAEoE;gBAAI7C;YAAK;YAEzD,kDAAkD;YAClD,IAAIiC,cAAAA,wBAAAA,EAAGc,QAAQ,EAAEtE,OAAOsE,QAAQ,GAAGd,EAAEc,QAAQ;YAC7C,IAAId,cAAAA,wBAAAA,EAAGe,WAAW,EAAEvE,OAAOuE,WAAW,GAAGf,EAAEe,WAAW;YACtD,IAAIf,cAAAA,wBAAAA,EAAGgB,YAAY,EAAExE,OAAOwE,YAAY,GAAGhB,EAAEgB,YAAY;YAEzD,kCAAkC;YAClC,IAAIhB,CAAAA,cAAAA,wBAAAA,EAAGtC,OAAO,KAAIsC,EAAEtC,OAAO,CAACE,MAAM,GAAG,GAAG;gBACtCpB,OAAOkB,OAAO,GAAGsC,EAAEtC,OAAO,CAAC6C,GAAG,CAAC,CAACN;oBAC9B,IAAIA,aAAa,QAAQ;wBACvB,OAAO;4BAAEW,IAAI;4BAAQ7C,MAAM;wBAAW;oBACxC;oBACA,MAAM0C,aAAaP,cAAc7C,GAAG,CAAC4C,aAAaA;oBAClD,OAAO;wBAAEW,IAAIX;wBAAUlC,MAAM0C;oBAAW;gBAC1C;YACF;YAEA,IAAIT,CAAAA,cAAAA,wBAAAA,EAAGiB,MAAM,MAAKlC,WAAWvC,OAAOyE,MAAM,GAAGjB,EAAEiB,MAAM;YACrD,IAAIjB,CAAAA,cAAAA,wBAAAA,EAAGkB,OAAO,MAAKnC,WAAWvC,OAAO0E,OAAO,GAAGlB,EAAEkB,OAAO;YAExD,IAAIlB,CAAAA,cAAAA,wBAAAA,EAAGmB,MAAM,KAAInB,EAAEmB,MAAM,CAACvD,MAAM,GAAG,GAAG;gBACpCpB,OAAO2E,MAAM,GAAGnB,EAAEmB,MAAM,CAACZ,GAAG,CAAC,CAACa;oBAC5B,MAAMC,QAAkD,CAAC;oBACzD,IAAID,cAAAA,wBAAAA,EAAGE,WAAW,EAAED,MAAMC,WAAW,GAAGF,EAAEE,WAAW;oBACrD,IAAIF,cAAAA,wBAAAA,EAAGG,YAAY,EAAEF,MAAME,YAAY,GAAGH,EAAEG,YAAY;oBACxD,IAAIH,cAAAA,wBAAAA,EAAGI,IAAI,EAAEH,MAAMG,IAAI,GAAGJ,EAAEI,IAAI;oBAChC,IAAIJ,CAAAA,cAAAA,wBAAAA,EAAGK,EAAE,MAAK1C,WAAWsC,MAAMI,EAAE,GAAGL,EAAEK,EAAE;oBACxC,IAAIL,cAAAA,wBAAAA,EAAGM,YAAY,EAAEL,MAAMK,YAAY,GAAGN,EAAEM,YAAY;oBACxD,IAAIN,cAAAA,wBAAAA,EAAGO,SAAS,EAAEN,MAAMM,SAAS,GAAGP,EAAEO,SAAS;oBAC/C,OAAON;gBACT;YACF;YAEA,4BAA4B;YAC5B,IAAItG,gBAAgB6F,OAAO,WAAW;gBACpCpE,OAAO5B,IAAI,GAAG,MAAM6B,kBAAkBxD,OAAO2H,IAAIjE,aAAaC;YAChE;YAEA,OAAOJ;QACT;QAGF,MAAMoF,gBAAgBpG,MAAM+E,GAAG,CAAC,CAACsB,OAASvI,aAAauI,MAAMpD;QAE7D7B,OAAOM,IAAI,CAAC,iCAAiC;YAC3C5C,OAAOkE;YACPH;YACAyD,aAAaF,cAAchE,MAAM;YACjC7C;YACAN,QAAQA,UAAU;QACpB;QAEA,MAAMqB,gBAAgB6D,IAAI7D,aAAa,IAAI6D,IAAI7D,aAAa,CAAC2D,IAAI,GAAG7B,MAAM,GAAG,IAAI+B,IAAI7D,aAAa,GAAGiD;QAErG,8BAA8B;QAC9B,MAAMvC,SACJpB,UAAU,WACN;YACEE,MAAM;YACNF,OAAO;YACP,GAAG1B,iBAAiBkI,eAAenD,iBAAiB;mBAAIzE;gBAAmB;aAAO,CAAU;YAC5F4B,OAAOgG,cAAchE,MAAM;YAC3B,GAAI9B,iBAAiB;gBAAEA;YAAc,CAAC;QACxC,IACA;YACER,MAAM;YACNF,OAAO;YACPI,OAAOoG;YACPhG,OAAOgG,cAAchE,MAAM;YAC3B,GAAI9B,iBAAiB;gBAAEA;YAAc,CAAC;QACxC;QAEN,OAAO;YACLiG,SAAS;gBACP;oBACEzG,MAAM;oBACN0G,MAAMC,KAAKC,SAAS,CAAC1F;gBACvB;aACD;YACD2F,mBAAmB;gBAAE3F;YAAO;QAC9B;IACF,EAAE,OAAO0B,OAAO;QACd,MAAMkE,UAAUlE,iBAAiBmE,QAAQnE,MAAMkE,OAAO,GAAGvB,OAAO3C;QAChEtB,OAAOsB,KAAK,CAAC,6BAA6B;YAAEA,OAAOkE;QAAQ;QAE3D,iFAAiF;QACjF,MAAM,IAAI7I,cAAcC,kBAAkB8I,aAAa,EAAE,CAAC,yBAAyB,EAAEF,SAAS,EAAE;YAC9FG,OAAOrE,iBAAiBmE,QAAQnE,MAAMqE,KAAK,GAAGxD;QAChD;IACF;AACF;AAEA,eAAe,SAASyD;IACtB,OAAO;QACLzE,MAAM;QACN1B;QACA+B;IACF;AACF"}
@@ -1,8 +1,6 @@
1
- import { McpServer } from '@mcp-z/server';
2
1
  import type { RuntimeOverrides, ServerConfig } from '../types.js';
3
2
  export declare function createHTTPServer(config: ServerConfig, overrides?: RuntimeOverrides): Promise<{
4
3
  httpServer: import("node:http").Server<typeof import("node:http").IncomingMessage, typeof import("node:http").ServerResponse>;
5
- mcpServer: McpServer;
6
4
  logger: import("@mcp-z/server").Logger;
7
5
  close: () => Promise<void>;
8
6
  }>;
@@ -18,13 +18,20 @@ export async function createHTTPServer(config, overrides) {
18
18
  ...composed.prompts,
19
19
  ...runtime.deps.oauthAdapters.accountPrompts
20
20
  ];
21
- const mcpServer = new McpServer({
22
- name: config.name,
23
- version: config.version
24
- });
25
- registerTools(mcpServer, tools);
26
- registerResources(mcpServer, composed.resources);
27
- registerPrompts(mcpServer, prompts);
21
+ // Built per request (HTTP) and per connection (stdio), not shared. The SDK caches the
22
+ // negotiated protocol revision on the McpServer instance - its own docs say a negotiated
23
+ // session never re-routes a method onto the other era - so one shared instance pins itself
24
+ // to whichever revision reaches it first and answers the other with -32601.
25
+ const buildServer = ()=>{
26
+ const mcpServer = new McpServer({
27
+ name: config.name,
28
+ version: config.version
29
+ });
30
+ registerTools(mcpServer, tools);
31
+ registerResources(mcpServer, composed.resources);
32
+ registerPrompts(mcpServer, prompts);
33
+ return mcpServer;
34
+ };
28
35
  const app = express();
29
36
  app.use(express.json({
30
37
  limit: '10mb'
@@ -33,7 +40,7 @@ export async function createHTTPServer(config, overrides) {
33
40
  // preflight first; pass baseUrl's origin/host below or a public deployment 403s itself.
34
41
  const publicUrl = config.baseUrl ? new URL(config.baseUrl) : undefined;
35
42
  logger.info(`Starting ${config.name} MCP server (http)`);
36
- const { close, httpServer } = await connectHttp(mcpServer, {
43
+ const { close, httpServer } = await connectHttp(buildServer, {
37
44
  logger,
38
45
  app,
39
46
  port,
@@ -58,7 +65,6 @@ export async function createHTTPServer(config, overrides) {
58
65
  logger.info('http transport ready');
59
66
  return {
60
67
  httpServer,
61
- mcpServer,
62
68
  logger,
63
69
  close: async ()=>{
64
70
  await close();
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-drive/src/setup/http.ts"],"sourcesContent":["import { composeMiddleware, connectHttp, McpServer, registerPrompts, registerResources, registerTools } from '@mcp-z/server';\nimport cors from 'cors';\nimport express from 'express';\nimport type { RuntimeOverrides, ServerConfig } from '../types.ts';\nimport { createDefaultRuntime } from './runtime.ts';\n\nexport async function createHTTPServer(config: ServerConfig, overrides?: RuntimeOverrides) {\n const runtime = await createDefaultRuntime(config, overrides);\n const modules = runtime.createDomainModules();\n const layers = runtime.middlewareFactories.map((factory) => factory(runtime.deps));\n const composed = composeMiddleware(modules, layers);\n const logger = runtime.deps.logger;\n const port = config.transport.port;\n if (!port) throw new Error('Port is required for HTTP transport');\n\n const tools = [...composed.tools, ...runtime.deps.oauthAdapters.accountTools];\n const 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(express.json({ limit: '10mb' }));\n\n // Must mount '/mcp' before any permissive app-level cors(), or that layer answers its\n // preflight first; pass baseUrl's origin/host below or a public deployment 403s itself.\n const publicUrl = config.baseUrl ? new URL(config.baseUrl) : undefined;\n logger.info(`Starting ${config.name} MCP server (http)`);\n const { close, httpServer } = await connectHttp(mcpServer, {\n logger,\n app,\n port,\n allowedOrigins: publicUrl ? [publicUrl.origin] : undefined,\n allowedHosts: publicUrl ? [publicUrl.host] : undefined,\n });\n\n // The loopback OAuth callback and the DCR discovery/registration endpoints are\n // meant to be reached from a browser on another origin. Keep cors() for them,\n // scoped to their own routes - never in front of '/mcp'.\n if (runtime.deps.oauthAdapters.loopbackRouter) {\n app.use('/', cors(), runtime.deps.oauthAdapters.loopbackRouter);\n logger.info('Mounted loopback OAuth callback router');\n }\n\n if (runtime.deps.oauthAdapters.dcrRouter) {\n app.use('/', cors(), runtime.deps.oauthAdapters.dcrRouter);\n logger.info('Mounted DCR router with OAuth endpoints');\n }\n\n logger.info('http transport ready');\n\n return {\n httpServer,\n mcpServer,\n logger,\n close: async () => {\n await close();\n await runtime.close();\n },\n };\n}\n"],"names":["composeMiddleware","connectHttp","McpServer","registerPrompts","registerResources","registerTools","cors","express","createDefaultRuntime","createHTTPServer","config","overrides","runtime","modules","createDomainModules","layers","middlewareFactories","map","factory","deps","composed","logger","port","transport","Error","tools","oauthAdapters","accountTools","prompts","accountPrompts","mcpServer","name","version","resources","app","use","json","limit","publicUrl","baseUrl","URL","undefined","info","close","httpServer","allowedOrigins","origin","allowedHosts","host","loopbackRouter","dcrRouter"],"mappings":"AAAA,SAASA,iBAAiB,EAAEC,WAAW,EAAEC,SAAS,EAAEC,eAAe,EAAEC,iBAAiB,EAAEC,aAAa,QAAQ,gBAAgB;AAC7H,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,WAAWpB,kBAAkBa,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,IAAI5B,UAAU;QAAE6B,MAAMrB,OAAOqB,IAAI;QAAEC,SAAStB,OAAOsB,OAAO;IAAC;IAC7E3B,cAAcyB,WAAWL;IACzBrB,kBAAkB0B,WAAWV,SAASa,SAAS;IAC/C9B,gBAAgB2B,WAAWF;IAE3B,MAAMM,MAAM3B;IACZ2B,IAAIC,GAAG,CAAC5B,QAAQ6B,IAAI,CAAC;QAAEC,OAAO;IAAO;IAErC,sFAAsF;IACtF,wFAAwF;IACxF,MAAMC,YAAY5B,OAAO6B,OAAO,GAAG,IAAIC,IAAI9B,OAAO6B,OAAO,IAAIE;IAC7DpB,OAAOqB,IAAI,CAAC,CAAC,SAAS,EAAEhC,OAAOqB,IAAI,CAAC,kBAAkB,CAAC;IACvD,MAAM,EAAEY,KAAK,EAAEC,UAAU,EAAE,GAAG,MAAM3C,YAAY6B,WAAW;QACzDT;QACAa;QACAZ;QACAuB,gBAAgBP,YAAY;YAACA,UAAUQ,MAAM;SAAC,GAAGL;QACjDM,cAAcT,YAAY;YAACA,UAAUU,IAAI;SAAC,GAAGP;IAC/C;IAEA,+EAA+E;IAC/E,8EAA8E;IAC9E,yDAAyD;IACzD,IAAI7B,QAAQO,IAAI,CAACO,aAAa,CAACuB,cAAc,EAAE;QAC7Cf,IAAIC,GAAG,CAAC,KAAK7B,QAAQM,QAAQO,IAAI,CAACO,aAAa,CAACuB,cAAc;QAC9D5B,OAAOqB,IAAI,CAAC;IACd;IAEA,IAAI9B,QAAQO,IAAI,CAACO,aAAa,CAACwB,SAAS,EAAE;QACxChB,IAAIC,GAAG,CAAC,KAAK7B,QAAQM,QAAQO,IAAI,CAACO,aAAa,CAACwB,SAAS;QACzD7B,OAAOqB,IAAI,CAAC;IACd;IAEArB,OAAOqB,IAAI,CAAC;IAEZ,OAAO;QACLE;QACAd;QACAT;QACAsB,OAAO;YACL,MAAMA;YACN,MAAM/B,QAAQ+B,KAAK;QACrB;IACF;AACF"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-drive/src/setup/http.ts"],"sourcesContent":["import { composeMiddleware, connectHttp, McpServer, registerPrompts, registerResources, registerTools } from '@mcp-z/server';\nimport cors from 'cors';\nimport express from 'express';\nimport type { RuntimeOverrides, ServerConfig } from '../types.ts';\nimport { createDefaultRuntime } from './runtime.ts';\n\nexport async function createHTTPServer(config: ServerConfig, overrides?: RuntimeOverrides) {\n const runtime = await createDefaultRuntime(config, overrides);\n const modules = runtime.createDomainModules();\n const layers = runtime.middlewareFactories.map((factory) => factory(runtime.deps));\n const composed = composeMiddleware(modules, layers);\n const logger = runtime.deps.logger;\n const port = config.transport.port;\n if (!port) throw new Error('Port is required for HTTP transport');\n\n const tools = [...composed.tools, ...runtime.deps.oauthAdapters.accountTools];\n const prompts = [...composed.prompts, ...runtime.deps.oauthAdapters.accountPrompts];\n\n // Built per request (HTTP) and per connection (stdio), not shared. The SDK caches the\n // negotiated protocol revision on the McpServer instance - its own docs say a negotiated\n // session never re-routes a method onto the other era - so one shared instance pins itself\n // to whichever revision reaches it first and answers the other with -32601.\n const buildServer = () => {\n const mcpServer = new McpServer({ name: config.name, version: config.version });\n registerTools(mcpServer, tools);\n registerResources(mcpServer, composed.resources);\n registerPrompts(mcpServer, prompts);\n return mcpServer;\n };\n\n const app = express();\n app.use(express.json({ limit: '10mb' }));\n\n // Must mount '/mcp' before any permissive app-level cors(), or that layer answers its\n // preflight first; pass baseUrl's origin/host below or a public deployment 403s itself.\n const publicUrl = config.baseUrl ? new URL(config.baseUrl) : undefined;\n logger.info(`Starting ${config.name} MCP server (http)`);\n const { close, httpServer } = await connectHttp(buildServer, {\n logger,\n app,\n port,\n allowedOrigins: publicUrl ? [publicUrl.origin] : undefined,\n allowedHosts: publicUrl ? [publicUrl.host] : undefined,\n });\n\n // The loopback OAuth callback and the DCR discovery/registration endpoints are\n // meant to be reached from a browser on another origin. Keep cors() for them,\n // scoped to their own routes - never in front of '/mcp'.\n if (runtime.deps.oauthAdapters.loopbackRouter) {\n app.use('/', cors(), runtime.deps.oauthAdapters.loopbackRouter);\n logger.info('Mounted loopback OAuth callback router');\n }\n\n if (runtime.deps.oauthAdapters.dcrRouter) {\n app.use('/', cors(), runtime.deps.oauthAdapters.dcrRouter);\n logger.info('Mounted DCR router with OAuth endpoints');\n }\n\n logger.info('http transport ready');\n\n return {\n httpServer,\n logger,\n close: async () => {\n await close();\n await runtime.close();\n },\n };\n}\n"],"names":["composeMiddleware","connectHttp","McpServer","registerPrompts","registerResources","registerTools","cors","express","createDefaultRuntime","createHTTPServer","config","overrides","runtime","modules","createDomainModules","layers","middlewareFactories","map","factory","deps","composed","logger","port","transport","Error","tools","oauthAdapters","accountTools","prompts","accountPrompts","buildServer","mcpServer","name","version","resources","app","use","json","limit","publicUrl","baseUrl","URL","undefined","info","close","httpServer","allowedOrigins","origin","allowedHosts","host","loopbackRouter","dcrRouter"],"mappings":"AAAA,SAASA,iBAAiB,EAAEC,WAAW,EAAEC,SAAS,EAAEC,eAAe,EAAEC,iBAAiB,EAAEC,aAAa,QAAQ,gBAAgB;AAC7H,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,WAAWpB,kBAAkBa,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,sFAAsF;IACtF,yFAAyF;IACzF,2FAA2F;IAC3F,4EAA4E;IAC5E,MAAMC,cAAc;QAClB,MAAMC,YAAY,IAAI7B,UAAU;YAAE8B,MAAMtB,OAAOsB,IAAI;YAAEC,SAASvB,OAAOuB,OAAO;QAAC;QAC7E5B,cAAc0B,WAAWN;QACzBrB,kBAAkB2B,WAAWX,SAASc,SAAS;QAC/C/B,gBAAgB4B,WAAWH;QAC3B,OAAOG;IACT;IAEA,MAAMI,MAAM5B;IACZ4B,IAAIC,GAAG,CAAC7B,QAAQ8B,IAAI,CAAC;QAAEC,OAAO;IAAO;IAErC,sFAAsF;IACtF,wFAAwF;IACxF,MAAMC,YAAY7B,OAAO8B,OAAO,GAAG,IAAIC,IAAI/B,OAAO8B,OAAO,IAAIE;IAC7DrB,OAAOsB,IAAI,CAAC,CAAC,SAAS,EAAEjC,OAAOsB,IAAI,CAAC,kBAAkB,CAAC;IACvD,MAAM,EAAEY,KAAK,EAAEC,UAAU,EAAE,GAAG,MAAM5C,YAAY6B,aAAa;QAC3DT;QACAc;QACAb;QACAwB,gBAAgBP,YAAY;YAACA,UAAUQ,MAAM;SAAC,GAAGL;QACjDM,cAAcT,YAAY;YAACA,UAAUU,IAAI;SAAC,GAAGP;IAC/C;IAEA,+EAA+E;IAC/E,8EAA8E;IAC9E,yDAAyD;IACzD,IAAI9B,QAAQO,IAAI,CAACO,aAAa,CAACwB,cAAc,EAAE;QAC7Cf,IAAIC,GAAG,CAAC,KAAK9B,QAAQM,QAAQO,IAAI,CAACO,aAAa,CAACwB,cAAc;QAC9D7B,OAAOsB,IAAI,CAAC;IACd;IAEA,IAAI/B,QAAQO,IAAI,CAACO,aAAa,CAACyB,SAAS,EAAE;QACxChB,IAAIC,GAAG,CAAC,KAAK9B,QAAQM,QAAQO,IAAI,CAACO,aAAa,CAACyB,SAAS;QACzD9B,OAAOsB,IAAI,CAAC;IACd;IAEAtB,OAAOsB,IAAI,CAAC;IAEZ,OAAO;QACLE;QACAxB;QACAuB,OAAO;YACL,MAAMA;YACN,MAAMhC,QAAQgC,KAAK;QACrB;IACF;AACF"}
@@ -1,7 +1,5 @@
1
- import { McpServer } from '@mcp-z/server';
2
1
  import type { RuntimeOverrides, ServerConfig } from '../types.js';
3
2
  export declare function createStdioServer(config: ServerConfig, overrides?: RuntimeOverrides): Promise<{
4
- mcpServer: McpServer;
5
3
  logger: import("@mcp-z/server").Logger;
6
4
  close: () => Promise<void>;
7
5
  }>;
@@ -14,20 +14,26 @@ export async function createStdioServer(config, overrides) {
14
14
  ...composed.prompts,
15
15
  ...runtime.deps.oauthAdapters.accountPrompts
16
16
  ];
17
- const mcpServer = new McpServer({
18
- name: config.name,
19
- version: config.version
20
- });
21
- registerTools(mcpServer, tools);
22
- registerResources(mcpServer, composed.resources);
23
- registerPrompts(mcpServer, prompts);
17
+ // Built per request (HTTP) and per connection (stdio), not shared. The SDK caches the
18
+ // negotiated protocol revision on the McpServer instance - its own docs say a negotiated
19
+ // session never re-routes a method onto the other era - so one shared instance pins itself
20
+ // to whichever revision reaches it first and answers the other with -32601.
21
+ const buildServer = ()=>{
22
+ const mcpServer = new McpServer({
23
+ name: config.name,
24
+ version: config.version
25
+ });
26
+ registerTools(mcpServer, tools);
27
+ registerResources(mcpServer, composed.resources);
28
+ registerPrompts(mcpServer, prompts);
29
+ return mcpServer;
30
+ };
24
31
  logger.info(`Starting ${config.name} MCP server (stdio)`);
25
- const { close } = await connectStdio(mcpServer, {
32
+ const { close } = await connectStdio(buildServer, {
26
33
  logger
27
34
  });
28
35
  logger.info('stdio transport ready');
29
36
  return {
30
- mcpServer,
31
37
  logger,
32
38
  close: async ()=>{
33
39
  await close();
@@ -1 +1 @@
1
- {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-drive/src/setup/stdio.ts"],"sourcesContent":["import { composeMiddleware, connectStdio, McpServer, registerPrompts, registerResources, registerTools } from '@mcp-z/server';\nimport type { RuntimeOverrides, ServerConfig } from '../types.ts';\nimport { createDefaultRuntime } from './runtime.ts';\n\nexport async function createStdioServer(config: ServerConfig, overrides?: RuntimeOverrides) {\n const runtime = await createDefaultRuntime(config, overrides);\n const modules = runtime.createDomainModules();\n const layers = runtime.middlewareFactories.map((factory) => factory(runtime.deps));\n const composed = composeMiddleware(modules, layers);\n const logger = runtime.deps.logger;\n\n const tools = [...composed.tools, ...runtime.deps.oauthAdapters.accountTools];\n const 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 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","McpServer","registerPrompts","registerResources","registerTools","createDefaultRuntime","createStdioServer","config","overrides","runtime","modules","createDomainModules","layers","middlewareFactories","map","factory","deps","composed","logger","tools","oauthAdapters","accountTools","prompts","accountPrompts","mcpServer","name","version","resources","info","close"],"mappings":"AAAA,SAASA,iBAAiB,EAAEC,YAAY,EAAEC,SAAS,EAAEC,eAAe,EAAEC,iBAAiB,EAAEC,aAAa,QAAQ,gBAAgB;AAE9H,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,UAAU;WAAIL,SAASK,OAAO;WAAKb,QAAQO,IAAI,CAACI,aAAa,CAACG,cAAc;KAAC;IAEnF,MAAMC,YAAY,IAAIvB,UAAU;QAAEwB,MAAMlB,OAAOkB,IAAI;QAAEC,SAASnB,OAAOmB,OAAO;IAAC;IAC7EtB,cAAcoB,WAAWL;IACzBhB,kBAAkBqB,WAAWP,SAASU,SAAS;IAC/CzB,gBAAgBsB,WAAWF;IAE3BJ,OAAOU,IAAI,CAAC,CAAC,SAAS,EAAErB,OAAOkB,IAAI,CAAC,mBAAmB,CAAC;IACxD,MAAM,EAAEI,KAAK,EAAE,GAAG,MAAM7B,aAAawB,WAAW;QAAEN;IAAO;IACzDA,OAAOU,IAAI,CAAC;IAEZ,OAAO;QACLJ;QACAN;QACAW,OAAO;YACL,MAAMA;YACN,MAAMpB,QAAQoB,KAAK;QACrB;IACF;AACF"}
1
+ {"version":3,"sources":["/Users/kevin/Dev/OpenSource/ai/mcp-z/mcp-drive/src/setup/stdio.ts"],"sourcesContent":["import { composeMiddleware, connectStdio, McpServer, registerPrompts, registerResources, registerTools } from '@mcp-z/server';\nimport type { RuntimeOverrides, ServerConfig } from '../types.ts';\nimport { createDefaultRuntime } from './runtime.ts';\n\nexport async function createStdioServer(config: ServerConfig, overrides?: RuntimeOverrides) {\n const runtime = await createDefaultRuntime(config, overrides);\n const modules = runtime.createDomainModules();\n const layers = runtime.middlewareFactories.map((factory) => factory(runtime.deps));\n const composed = composeMiddleware(modules, layers);\n const logger = runtime.deps.logger;\n\n const tools = [...composed.tools, ...runtime.deps.oauthAdapters.accountTools];\n const prompts = [...composed.prompts, ...runtime.deps.oauthAdapters.accountPrompts];\n\n // Built per request (HTTP) and per connection (stdio), not shared. The SDK caches the\n // negotiated protocol revision on the McpServer instance - its own docs say a negotiated\n // session never re-routes a method onto the other era - so one shared instance pins itself\n // to whichever revision reaches it first and answers the other with -32601.\n const buildServer = () => {\n const mcpServer = new McpServer({ name: config.name, version: config.version });\n registerTools(mcpServer, tools);\n registerResources(mcpServer, composed.resources);\n registerPrompts(mcpServer, prompts);\n return mcpServer;\n };\n\n logger.info(`Starting ${config.name} MCP server (stdio)`);\n const { close } = await connectStdio(buildServer, { logger });\n logger.info('stdio transport ready');\n\n return {\n logger,\n close: async () => {\n await close();\n await runtime.close();\n },\n };\n}\n"],"names":["composeMiddleware","connectStdio","McpServer","registerPrompts","registerResources","registerTools","createDefaultRuntime","createStdioServer","config","overrides","runtime","modules","createDomainModules","layers","middlewareFactories","map","factory","deps","composed","logger","tools","oauthAdapters","accountTools","prompts","accountPrompts","buildServer","mcpServer","name","version","resources","info","close"],"mappings":"AAAA,SAASA,iBAAiB,EAAEC,YAAY,EAAEC,SAAS,EAAEC,eAAe,EAAEC,iBAAiB,EAAEC,aAAa,QAAQ,gBAAgB;AAE9H,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,UAAU;WAAIL,SAASK,OAAO;WAAKb,QAAQO,IAAI,CAACI,aAAa,CAACG,cAAc;KAAC;IAEnF,sFAAsF;IACtF,yFAAyF;IACzF,2FAA2F;IAC3F,4EAA4E;IAC5E,MAAMC,cAAc;QAClB,MAAMC,YAAY,IAAIxB,UAAU;YAAEyB,MAAMnB,OAAOmB,IAAI;YAAEC,SAASpB,OAAOoB,OAAO;QAAC;QAC7EvB,cAAcqB,WAAWN;QACzBhB,kBAAkBsB,WAAWR,SAASW,SAAS;QAC/C1B,gBAAgBuB,WAAWH;QAC3B,OAAOG;IACT;IAEAP,OAAOW,IAAI,CAAC,CAAC,SAAS,EAAEtB,OAAOmB,IAAI,CAAC,mBAAmB,CAAC;IACxD,MAAM,EAAEI,KAAK,EAAE,GAAG,MAAM9B,aAAawB,aAAa;QAAEN;IAAO;IAC3DA,OAAOW,IAAI,CAAC;IAEZ,OAAO;QACLX;QACAY,OAAO;YACL,MAAMA;YACN,MAAMrB,QAAQqB,KAAK;QACrB;IACF;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-z/mcp-drive",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "MCP server for Google Drive integration with file operations, folder navigation, search capabilities, and sharing management",
5
5
  "keywords": [
6
6
  "drive",
@@ -68,12 +68,12 @@
68
68
  "version": "tsds version"
69
69
  },
70
70
  "dependencies": {
71
+ "@googleapis/drive": "^22.0.0",
71
72
  "@mcp-z/oauth": "^2.0.0",
72
73
  "@mcp-z/oauth-google": "^2.0.1",
73
- "@mcp-z/server": "^2.0.0",
74
+ "@mcp-z/server": "^2.1.0",
74
75
  "cors": "^2.0.0",
75
76
  "express": "^5.0.0",
76
- "googleapis": "174.0.1",
77
77
  "keyv-file": "5.3.3",
78
78
  "keyv-registry": "^2.0.0",
79
79
  "module-root-sync": "^2.0.0",