@nerviq/cli 1.17.3 → 1.19.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 (190) hide show
  1. package/LICENSE +23 -23
  2. package/README.md +4 -4
  3. package/bin/cli.js +61 -274
  4. package/package.json +60 -60
  5. package/src/activity.js +1039 -1039
  6. package/src/adoption-advisor.js +299 -299
  7. package/src/aider/config-parser.js +166 -166
  8. package/src/aider/context.js +158 -158
  9. package/src/aider/deep-review.js +316 -316
  10. package/src/aider/domain-packs.js +303 -303
  11. package/src/aider/freshness.js +93 -93
  12. package/src/aider/governance.js +253 -253
  13. package/src/aider/interactive.js +334 -334
  14. package/src/aider/mcp-packs.js +329 -329
  15. package/src/aider/patch.js +214 -214
  16. package/src/aider/plans.js +186 -186
  17. package/src/aider/premium.js +360 -360
  18. package/src/aider/setup.js +404 -404
  19. package/src/aider/techniques.js +16 -16
  20. package/src/analyze.js +951 -951
  21. package/src/anti-patterns.js +485 -485
  22. package/src/audit/instruction-files.js +180 -180
  23. package/src/audit/recommendations.js +577 -577
  24. package/src/auto-suggest.js +154 -154
  25. package/src/badge.js +13 -13
  26. package/src/behavioral-drift.js +801 -801
  27. package/src/benchmark.js +67 -67
  28. package/src/catalog.js +103 -103
  29. package/src/certification.js +128 -128
  30. package/src/codex/config-parser.js +183 -183
  31. package/src/codex/context.js +223 -223
  32. package/src/codex/deep-review.js +493 -493
  33. package/src/codex/domain-packs.js +394 -394
  34. package/src/codex/freshness.js +84 -84
  35. package/src/codex/governance.js +192 -192
  36. package/src/codex/interactive.js +618 -618
  37. package/src/codex/mcp-packs.js +914 -914
  38. package/src/codex/patch.js +209 -209
  39. package/src/codex/plans.js +251 -251
  40. package/src/codex/premium.js +614 -614
  41. package/src/codex/setup.js +591 -591
  42. package/src/context.js +320 -320
  43. package/src/continuous-ops.js +681 -681
  44. package/src/copilot/activity.js +309 -309
  45. package/src/copilot/config-parser.js +280 -226
  46. package/src/copilot/context.js +218 -197
  47. package/src/copilot/deep-review.js +346 -346
  48. package/src/copilot/domain-packs.js +372 -372
  49. package/src/copilot/freshness.js +57 -57
  50. package/src/copilot/governance.js +222 -222
  51. package/src/copilot/interactive.js +406 -406
  52. package/src/copilot/mcp-packs.js +826 -826
  53. package/src/copilot/plans.js +253 -253
  54. package/src/copilot/premium.js +451 -451
  55. package/src/copilot/setup.js +488 -488
  56. package/src/copilot/techniques.js +219 -78
  57. package/src/cost-tracking.js +61 -61
  58. package/src/cursor/activity.js +301 -301
  59. package/src/cursor/config-parser.js +265 -265
  60. package/src/cursor/context.js +256 -256
  61. package/src/cursor/deep-review.js +334 -334
  62. package/src/cursor/domain-packs.js +368 -368
  63. package/src/cursor/freshness.js +65 -65
  64. package/src/cursor/governance.js +229 -229
  65. package/src/cursor/interactive.js +391 -391
  66. package/src/cursor/mcp-packs.js +828 -828
  67. package/src/cursor/plans.js +254 -254
  68. package/src/cursor/premium.js +469 -469
  69. package/src/cursor/setup.js +488 -488
  70. package/src/dashboard.js +493 -493
  71. package/src/deep-review.js +428 -428
  72. package/src/deprecation.js +98 -98
  73. package/src/diff-only.js +280 -280
  74. package/src/doctor.js +119 -119
  75. package/src/domain-pack-expansion.js +1033 -1033
  76. package/src/domain-packs.js +387 -387
  77. package/src/feedback.js +178 -178
  78. package/src/fix-engine.js +783 -0
  79. package/src/fix-prompts.js +122 -122
  80. package/src/formatters/sarif.js +115 -115
  81. package/src/freshness.js +74 -74
  82. package/src/gemini/config-parser.js +275 -275
  83. package/src/gemini/context.js +221 -221
  84. package/src/gemini/deep-review.js +559 -559
  85. package/src/gemini/domain-packs.js +393 -393
  86. package/src/gemini/freshness.js +66 -66
  87. package/src/gemini/governance.js +201 -201
  88. package/src/gemini/interactive.js +860 -860
  89. package/src/gemini/mcp-packs.js +915 -915
  90. package/src/gemini/plans.js +269 -269
  91. package/src/gemini/premium.js +760 -760
  92. package/src/gemini/setup.js +692 -692
  93. package/src/gemini/techniques.js +14 -14
  94. package/src/governance.js +72 -72
  95. package/src/harmony/add.js +68 -68
  96. package/src/harmony/advisor.js +333 -333
  97. package/src/harmony/canon.js +565 -565
  98. package/src/harmony/cli.js +591 -591
  99. package/src/harmony/drift.js +401 -401
  100. package/src/harmony/governance.js +313 -313
  101. package/src/harmony/memory.js +239 -239
  102. package/src/harmony/sync.js +475 -475
  103. package/src/harmony/watch.js +370 -370
  104. package/src/hook-validation.js +342 -342
  105. package/src/index.js +271 -271
  106. package/src/init.js +184 -184
  107. package/src/instruction-surfaces.js +185 -185
  108. package/src/integrations.js +144 -144
  109. package/src/interactive.js +118 -118
  110. package/src/locales/en.json +1 -1
  111. package/src/locales/es.json +1 -1
  112. package/src/mcp-packs.js +830 -830
  113. package/src/mcp-server.js +726 -726
  114. package/src/mcp-validation.js +337 -337
  115. package/src/nerviq-sync.json +7 -7
  116. package/src/opencode/config-parser.js +109 -109
  117. package/src/opencode/context.js +247 -247
  118. package/src/opencode/deep-review.js +313 -313
  119. package/src/opencode/domain-packs.js +262 -262
  120. package/src/opencode/freshness.js +66 -66
  121. package/src/opencode/governance.js +159 -159
  122. package/src/opencode/interactive.js +392 -392
  123. package/src/opencode/mcp-packs.js +705 -705
  124. package/src/opencode/patch.js +184 -184
  125. package/src/opencode/plans.js +231 -231
  126. package/src/opencode/premium.js +413 -413
  127. package/src/opencode/setup.js +449 -449
  128. package/src/opencode/techniques.js +27 -27
  129. package/src/operating-profile.js +574 -574
  130. package/src/org.js +152 -152
  131. package/src/permission-rules.js +218 -218
  132. package/src/plans.js +839 -839
  133. package/src/platform-change-manifest.js +86 -86
  134. package/src/plugins.js +110 -110
  135. package/src/policy-layers.js +210 -210
  136. package/src/profiles.js +124 -124
  137. package/src/prompt-injection.js +74 -74
  138. package/src/public-api.js +173 -173
  139. package/src/recommendation-rules.js +84 -84
  140. package/src/repo-archetype.js +386 -386
  141. package/src/secret-patterns.js +39 -39
  142. package/src/server.js +527 -527
  143. package/src/setup/analysis.js +607 -607
  144. package/src/setup/runtime.js +172 -172
  145. package/src/setup.js +677 -677
  146. package/src/shared/capabilities.js +194 -194
  147. package/src/source-urls.js +132 -132
  148. package/src/stack-checks.js +565 -565
  149. package/src/supplemental-checks.js +13 -13
  150. package/src/synergy/adaptive.js +261 -261
  151. package/src/synergy/compensation.js +137 -137
  152. package/src/synergy/evidence.js +193 -193
  153. package/src/synergy/learning.js +199 -199
  154. package/src/synergy/patterns.js +227 -227
  155. package/src/synergy/ranking.js +83 -83
  156. package/src/synergy/report.js +165 -165
  157. package/src/synergy/routing.js +146 -146
  158. package/src/techniques/api.js +407 -407
  159. package/src/techniques/automation.js +316 -316
  160. package/src/techniques/compliance.js +257 -257
  161. package/src/techniques/hygiene.js +294 -294
  162. package/src/techniques/instructions.js +243 -243
  163. package/src/techniques/observability.js +226 -226
  164. package/src/techniques/optimization.js +142 -142
  165. package/src/techniques/quality.js +318 -318
  166. package/src/techniques/security.js +237 -237
  167. package/src/techniques/shared.js +443 -443
  168. package/src/techniques/stacks.js +2294 -2294
  169. package/src/techniques/tools.js +106 -106
  170. package/src/techniques/workflow.js +413 -413
  171. package/src/techniques.js +81 -81
  172. package/src/terminology.js +73 -73
  173. package/src/token-estimate.js +35 -35
  174. package/src/usage-patterns.js +99 -99
  175. package/src/verification-metadata.js +145 -145
  176. package/src/watch.js +247 -247
  177. package/src/windsurf/activity.js +302 -302
  178. package/src/windsurf/config-parser.js +267 -267
  179. package/src/windsurf/context.js +249 -249
  180. package/src/windsurf/deep-review.js +337 -337
  181. package/src/windsurf/domain-packs.js +370 -370
  182. package/src/windsurf/freshness.js +36 -36
  183. package/src/windsurf/governance.js +231 -231
  184. package/src/windsurf/interactive.js +388 -388
  185. package/src/windsurf/mcp-packs.js +792 -792
  186. package/src/windsurf/plans.js +247 -247
  187. package/src/windsurf/premium.js +468 -468
  188. package/src/windsurf/setup.js +471 -471
  189. package/src/windsurf/techniques.js +17 -17
  190. package/src/workspace.js +375 -375
package/src/mcp-packs.js CHANGED
@@ -1,830 +1,830 @@
1
- const MCP_PACKS = [
2
- {
3
- key: 'context7-docs',
4
- label: 'Context7 Docs',
5
- useWhen: 'Repos that benefit from live, current framework and library documentation during Claude sessions.',
6
- adoption: 'Safe default docs pack for most application repos.',
7
- servers: {
8
- context7: {
9
- command: 'npx',
10
- args: ['-y', '@upstash/context7-mcp@latest'],
11
- },
12
- },
13
- },
14
- {
15
- key: 'next-devtools',
16
- label: 'Next.js Devtools',
17
- useWhen: 'Next.js repos that need runtime-aware debugging and framework-specific tooling.',
18
- adoption: 'Useful companion pack for frontend-ui repos running Next.js.',
19
- servers: {
20
- 'next-devtools': {
21
- command: 'npx',
22
- args: ['-y', 'next-devtools-mcp@latest'],
23
- },
24
- },
25
- },
26
- {
27
- key: 'github-mcp',
28
- label: 'GitHub',
29
- useWhen: 'Repos hosted on GitHub that benefit from issue, PR, and repository context during Claude sessions.',
30
- adoption: 'Recommended for any GitHub-hosted project. Requires GITHUB_PERSONAL_ACCESS_TOKEN env var.',
31
- servers: {
32
- github: {
33
- command: 'npx',
34
- args: ['-y', '@modelcontextprotocol/server-github'],
35
- env: { GITHUB_PERSONAL_ACCESS_TOKEN: '${GITHUB_PERSONAL_ACCESS_TOKEN}' },
36
- },
37
- },
38
- },
39
- {
40
- key: 'postgres-mcp',
41
- label: 'PostgreSQL',
42
- useWhen: 'Repos with PostgreSQL databases that benefit from schema inspection and query assistance.',
43
- adoption: 'Useful for backend-api and data-pipeline repos. Pass connection string as CLI argument.',
44
- servers: {
45
- postgres: {
46
- command: 'npx',
47
- args: ['-y', '@modelcontextprotocol/server-postgres', '${DATABASE_URL}'],
48
- },
49
- },
50
- },
51
- {
52
- key: 'memory-mcp',
53
- label: 'Memory / Knowledge Graph',
54
- useWhen: 'Long-running projects that benefit from persistent entity and relationship tracking across sessions.',
55
- adoption: 'Useful for complex projects with many interconnected concepts. Stores data locally.',
56
- servers: {
57
- memory: {
58
- command: 'npx',
59
- args: ['-y', '@modelcontextprotocol/server-memory'],
60
- },
61
- },
62
- },
63
- {
64
- key: 'playwright-mcp',
65
- label: 'Playwright Browser',
66
- useWhen: 'Frontend repos that need browser automation, E2E testing, or visual QA during Claude sessions.',
67
- adoption: 'Recommended for frontend-ui repos with E2E tests. No auth required.',
68
- servers: {
69
- playwright: {
70
- command: 'npx',
71
- args: ['-y', '@playwright/mcp@latest'],
72
- },
73
- },
74
- },
75
- {
76
- key: 'docker-mcp',
77
- label: 'Docker',
78
- useWhen: 'Repos with containerized workflows that benefit from container management during Claude sessions.',
79
- adoption: 'Community Docker MCP server. Requires Docker running locally. Note: community-maintained package.',
80
- servers: {
81
- docker: {
82
- command: 'npx',
83
- args: ['-y', '@hypnosis/docker-mcp-server'],
84
- },
85
- },
86
- },
87
- {
88
- key: 'notion-mcp',
89
- label: 'Notion',
90
- useWhen: 'Teams using Notion for documentation, wikis, or knowledge bases that Claude should reference.',
91
- adoption: 'Useful for teams with Notion-based docs. Requires NOTION_API_KEY env var.',
92
- servers: {
93
- notion: {
94
- command: 'npx',
95
- args: ['-y', '@notionhq/notion-mcp-server'],
96
- env: { NOTION_API_KEY: '${NOTION_API_KEY}' },
97
- },
98
- },
99
- },
100
- {
101
- key: 'linear-mcp',
102
- label: 'Linear',
103
- useWhen: 'Teams using Linear for issue tracking that want Claude to read and create issues.',
104
- adoption: 'Useful for teams managing sprints in Linear. Requires LINEAR_API_KEY env var.',
105
- servers: {
106
- linear: {
107
- command: 'npx',
108
- args: ['-y', '@mseep/linear-mcp'],
109
- env: { LINEAR_API_KEY: '${LINEAR_API_KEY}' },
110
- },
111
- },
112
- },
113
- {
114
- key: 'sentry-mcp',
115
- label: 'Sentry',
116
- useWhen: 'Repos with Sentry error tracking that benefit from error context during debugging sessions.',
117
- adoption: 'Useful for production repos. Requires SENTRY_AUTH_TOKEN env var.',
118
- servers: {
119
- sentry: {
120
- command: 'npx',
121
- args: ['-y', '@sentry/mcp-server'],
122
- env: { SENTRY_AUTH_TOKEN: '${SENTRY_AUTH_TOKEN}' },
123
- },
124
- },
125
- },
126
- {
127
- key: 'slack-mcp',
128
- label: 'Slack',
129
- useWhen: 'Teams using Slack that want Claude to draft, preview, or post messages.',
130
- adoption: 'Community Slack MCP server (supports OAuth and stealth mode). Requires SLACK_BOT_TOKEN or SLACK_COOKIES env var.',
131
- servers: {
132
- slack: {
133
- command: 'npx',
134
- args: ['-y', 'slack-mcp-server'],
135
- env: { SLACK_BOT_TOKEN: '${SLACK_BOT_TOKEN}' },
136
- },
137
- },
138
- },
139
- {
140
- key: 'stripe-mcp',
141
- label: 'Stripe',
142
- useWhen: 'Repos with Stripe integration for payments, subscriptions, or billing workflows.',
143
- adoption: 'Useful for e-commerce and SaaS repos. Requires STRIPE_API_KEY env var.',
144
- servers: {
145
- stripe: {
146
- command: 'npx',
147
- args: ['-y', '@stripe/mcp'],
148
- env: { STRIPE_API_KEY: '${STRIPE_API_KEY}' },
149
- },
150
- },
151
- },
152
- {
153
- key: 'figma-mcp',
154
- label: 'Figma',
155
- useWhen: 'Design-heavy repos where Claude needs access to Figma designs and components.',
156
- adoption: 'Community Figma MCP server. Requires FIGMA_ACCESS_TOKEN env var. Note: community-maintained package.',
157
- servers: {
158
- figma: {
159
- command: 'npx',
160
- args: ['-y', 'claude-talk-to-figma-mcp'],
161
- env: { FIGMA_ACCESS_TOKEN: '${FIGMA_ACCESS_TOKEN}' },
162
- },
163
- },
164
- },
165
- {
166
- key: 'mcp-security',
167
- label: 'MCP Security Scanner',
168
- useWhen: 'Any repo using MCP servers that should be scanned for tool poisoning and prompt injection.',
169
- adoption: 'Recommended as a safety companion for any repo with 2+ MCP servers.',
170
- servers: {
171
- 'mcp-scan': {
172
- command: 'npx',
173
- args: ['-y', 'mcp-scan@latest'],
174
- },
175
- },
176
- },
177
- {
178
- key: 'composio-mcp',
179
- label: 'Composio Universal',
180
- useWhen: 'Teams needing 500+ integrations through a single MCP gateway with centralized OAuth.',
181
- adoption: 'Useful for enterprise or integration-heavy repos. Requires COMPOSIO_API_KEY env var.',
182
- servers: {
183
- composio: {
184
- command: 'npx',
185
- args: ['-y', '@composio/mcp'],
186
- env: { COMPOSIO_API_KEY: '${COMPOSIO_API_KEY}' },
187
- },
188
- },
189
- },
190
- {
191
- key: 'sequential-thinking',
192
- label: 'Sequential Thinking',
193
- useWhen: 'Complex problem-solving sessions that benefit from structured step-by-step reasoning.',
194
- adoption: 'Safe default for any repo. No auth required.',
195
- servers: {
196
- 'sequential-thinking': {
197
- command: 'npx',
198
- args: ['-y', '@modelcontextprotocol/server-sequential-thinking'],
199
- },
200
- },
201
- },
202
- {
203
- key: 'jira-confluence',
204
- label: 'Jira',
205
- useWhen: 'Teams using Atlassian Jira for issue tracking and project management.',
206
- adoption: 'Requires ATLASSIAN_API_TOKEN and ATLASSIAN_EMAIL env vars.',
207
- servers: {
208
- jira: {
209
- command: 'npx',
210
- args: ['-y', 'jira-mcp'],
211
- env: { ATLASSIAN_API_TOKEN: '${ATLASSIAN_API_TOKEN}', ATLASSIAN_EMAIL: '${ATLASSIAN_EMAIL}' },
212
- },
213
- },
214
- },
215
- {
216
- key: 'ga4-analytics',
217
- label: 'Google Analytics 4',
218
- useWhen: 'Repos with web analytics needs — live GA4 data, attribution, and audience insights.',
219
- adoption: 'Requires GA4_PROPERTY_ID and either GOOGLE_APPLICATION_CREDENTIALS or ADC for auth.',
220
- servers: {
221
- ga4: {
222
- command: 'npx',
223
- args: ['-y', 'mcp-server-ga4'],
224
- env: { GA4_PROPERTY_ID: '${GA4_PROPERTY_ID}', GOOGLE_APPLICATION_CREDENTIALS: '${GOOGLE_APPLICATION_CREDENTIALS}' },
225
- },
226
- },
227
- },
228
- {
229
- key: 'search-console',
230
- label: 'Google Search Console',
231
- useWhen: 'SEO-focused repos that need search performance data, indexing status, and sitemap insights.',
232
- adoption: 'Requires Google OAuth client credentials (client ID + secret). Uses OAuth consent flow.',
233
- servers: {
234
- gsc: {
235
- command: 'npx',
236
- args: ['-y', 'mcp-gsc@latest'],
237
- env: { GOOGLE_CLIENT_ID: '${GOOGLE_CLIENT_ID}', GOOGLE_CLIENT_SECRET: '${GOOGLE_CLIENT_SECRET}' },
238
- },
239
- },
240
- },
241
- {
242
- key: 'n8n-workflows',
243
- label: 'n8n Workflow Automation',
244
- useWhen: 'Teams using n8n for workflow automation with 1,396 integration nodes.',
245
- adoption: 'Requires n8n instance URL and API key.',
246
- servers: {
247
- n8n: {
248
- command: 'npx',
249
- args: ['-y', 'n8n-mcp-server@latest'],
250
- env: { N8N_URL: '${N8N_URL}', N8N_API_KEY: '${N8N_API_KEY}' },
251
- },
252
- },
253
- },
254
- {
255
- key: 'zendesk-mcp',
256
- label: 'Zendesk',
257
- useWhen: 'Support teams using Zendesk for ticket management and help center content.',
258
- adoption: 'Requires ZENDESK_API_TOKEN and ZENDESK_SUBDOMAIN env vars.',
259
- servers: {
260
- zendesk: {
261
- command: 'npx',
262
- args: ['-y', 'zendesk-mcp'],
263
- env: { ZENDESK_API_TOKEN: '${ZENDESK_API_TOKEN}', ZENDESK_SUBDOMAIN: '${ZENDESK_SUBDOMAIN}' },
264
- },
265
- },
266
- },
267
- {
268
- key: 'infisical-secrets',
269
- label: 'Infisical Secrets',
270
- useWhen: 'Repos using Infisical for secrets management with auto-rotation.',
271
- adoption: 'Requires INFISICAL_TOKEN env var.',
272
- servers: {
273
- infisical: {
274
- command: 'npx',
275
- args: ['-y', '@infisical/mcp'],
276
- env: { INFISICAL_TOKEN: '${INFISICAL_TOKEN}' },
277
- },
278
- },
279
- },
280
- {
281
- key: 'shopify-mcp',
282
- label: 'Shopify',
283
- useWhen: 'Shopify stores and apps that need API schema access and deployment tooling.',
284
- adoption: 'Community Shopify MCP server for GraphQL API access. Requires SHOPIFY_ACCESS_TOKEN env var.',
285
- servers: {
286
- shopify: {
287
- command: 'npx',
288
- args: ['-y', 'shopify-mcp'],
289
- env: { SHOPIFY_ACCESS_TOKEN: '${SHOPIFY_ACCESS_TOKEN}' },
290
- },
291
- },
292
- },
293
- {
294
- key: 'huggingface-mcp',
295
- label: 'Hugging Face',
296
- useWhen: 'AI/ML repos that need model search, dataset discovery, and Spaces integration.',
297
- adoption: 'Useful for ai-ml domain repos. Requires HF_TOKEN env var.',
298
- servers: {
299
- huggingface: {
300
- command: 'npx',
301
- args: ['-y', 'huggingface-mcp-server'],
302
- env: { HF_TOKEN: '${HF_TOKEN}' },
303
- },
304
- },
305
- },
306
- {
307
- key: 'blender-mcp',
308
- label: 'Blender 3D',
309
- useWhen: '3D modeling, animation, or rendering repos that use Blender.',
310
- adoption: 'Requires Blender installed locally. Python bridge.',
311
- servers: {
312
- blender: {
313
- command: 'npx',
314
- args: ['-y', '@glutamateapp/blender-mcp-ts'],
315
- },
316
- },
317
- },
318
- {
319
- key: 'wordpress-mcp',
320
- label: 'WordPress',
321
- useWhen: 'WordPress sites needing content management, site ops, and plugin workflows.',
322
- adoption: 'Requires WP_URL and WP_AUTH_TOKEN env vars.',
323
- servers: {
324
- wordpress: {
325
- command: 'npx',
326
- args: ['-y', 'wordpress-mcp-server@latest'],
327
- env: { WP_URL: '${WP_URL}', WP_AUTH_TOKEN: '${WP_AUTH_TOKEN}' },
328
- },
329
- },
330
- },
331
- // ── 24 new packs ─────────────────────────────────────────────────────────
332
- {
333
- key: 'supabase-mcp',
334
- label: 'Supabase',
335
- useWhen: 'Repos using Supabase for database, auth, or storage.',
336
- adoption: 'Recommended for full-stack repos using Supabase. Requires SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY.',
337
- servers: { supabase: { command: 'npx', args: ['-y', '@supabase/mcp-server-supabase@latest'], env: { SUPABASE_URL: '${SUPABASE_URL}', SUPABASE_SERVICE_ROLE_KEY: '${SUPABASE_SERVICE_ROLE_KEY}' } } },
338
- },
339
- {
340
- key: 'prisma-mcp',
341
- label: 'Prisma ORM',
342
- useWhen: 'Repos using Prisma for database schema management and migrations.',
343
- adoption: 'Recommended for any repo with a Prisma schema. No auth required beyond DATABASE_URL.',
344
- servers: { prisma: { command: 'npx', args: ['-y', 'prisma-mcp-server@latest'], env: { DATABASE_URL: '${DATABASE_URL}' } } },
345
- },
346
- {
347
- key: 'vercel-mcp',
348
- label: 'Vercel',
349
- useWhen: 'Repos deployed on Vercel that benefit from deployment management and log access.',
350
- adoption: 'Recommended for Next.js and other Vercel-hosted repos. Requires VERCEL_TOKEN.',
351
- servers: { vercel: { command: 'npx', args: ['-y', '@vercel/mcp-server@latest'], env: { VERCEL_TOKEN: '${VERCEL_TOKEN}' } } },
352
- },
353
- {
354
- key: 'cloudflare-mcp',
355
- label: 'Cloudflare',
356
- useWhen: 'Repos using Cloudflare Workers, KV, R2, or D1.',
357
- adoption: 'Recommended for edge-compute repos. Requires CLOUDFLARE_API_TOKEN.',
358
- servers: { cloudflare: { command: 'npx', args: ['-y', '@cloudflare/mcp-server-cloudflare@latest'], env: { CLOUDFLARE_API_TOKEN: '${CLOUDFLARE_API_TOKEN}' } } },
359
- },
360
- {
361
- key: 'aws-mcp',
362
- label: 'AWS (S3, Lambda, DynamoDB)',
363
- useWhen: 'Repos using AWS services — S3, Lambda, DynamoDB, or CloudFormation.',
364
- adoption: 'Recommended for cloud-infra repos. Requires AWS credentials.',
365
- servers: { aws: { command: 'npx', args: ['-y', '@aws-samples/mcp-server-aws@latest'], env: { AWS_ACCESS_KEY_ID: '${AWS_ACCESS_KEY_ID}', AWS_SECRET_ACCESS_KEY: '${AWS_SECRET_ACCESS_KEY}', AWS_REGION: '${AWS_REGION}' } } },
366
- },
367
- {
368
- key: 'redis-mcp',
369
- label: 'Redis',
370
- useWhen: 'Repos using Redis for caching, sessions, or pub/sub.',
371
- adoption: 'Recommended for performance-critical repos with Redis. Requires REDIS_URL.',
372
- servers: { redis: { command: 'npx', args: ['-y', 'redis-mcp-server@latest'], env: { REDIS_URL: '${REDIS_URL}' } } },
373
- },
374
- {
375
- key: 'mongodb-mcp',
376
- label: 'MongoDB',
377
- useWhen: 'Repos using MongoDB as document database.',
378
- adoption: 'Recommended for document-model repos. Requires MONGODB_URI.',
379
- servers: { mongodb: { command: 'npx', args: ['-y', '@mongodb-js/mongodb-mcp-server@latest'], env: { MONGODB_URI: '${MONGODB_URI}' } } },
380
- },
381
- {
382
- key: 'twilio-mcp',
383
- label: 'Twilio',
384
- useWhen: 'Repos integrating SMS, voice, or messaging via Twilio.',
385
- adoption: 'Recommended for communication-feature repos. Requires TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN.',
386
- servers: { twilio: { command: 'npx', args: ['-y', 'twilio-mcp-server@latest'], env: { TWILIO_ACCOUNT_SID: '${TWILIO_ACCOUNT_SID}', TWILIO_AUTH_TOKEN: '${TWILIO_AUTH_TOKEN}' } } },
387
- },
388
- {
389
- key: 'sendgrid-mcp',
390
- label: 'SendGrid',
391
- useWhen: 'Repos using SendGrid for transactional or marketing email.',
392
- adoption: 'Recommended for repos with email delivery workflows. Requires SENDGRID_API_KEY.',
393
- servers: { sendgrid: { command: 'npx', args: ['-y', 'sendgrid-mcp-server@latest'], env: { SENDGRID_API_KEY: '${SENDGRID_API_KEY}' } } },
394
- },
395
- {
396
- key: 'algolia-mcp',
397
- label: 'Algolia Search',
398
- useWhen: 'Repos using Algolia for search indexing and discovery.',
399
- adoption: 'Recommended for e-commerce and content-heavy repos. Requires ALGOLIA_APP_ID and ALGOLIA_API_KEY.',
400
- servers: { algolia: { command: 'npx', args: ['-y', 'algolia-mcp-server@latest'], env: { ALGOLIA_APP_ID: '${ALGOLIA_APP_ID}', ALGOLIA_API_KEY: '${ALGOLIA_API_KEY}' } } },
401
- },
402
- {
403
- key: 'planetscale-mcp',
404
- label: 'PlanetScale',
405
- useWhen: 'Repos using PlanetScale serverless MySQL database.',
406
- adoption: 'Recommended for MySQL-based repos on PlanetScale. Requires PLANETSCALE_TOKEN.',
407
- servers: { planetscale: { command: 'npx', args: ['-y', 'planetscale-mcp-server@latest'], env: { PLANETSCALE_TOKEN: '${PLANETSCALE_TOKEN}' } } },
408
- },
409
- {
410
- key: 'neon-mcp',
411
- label: 'Neon Serverless Postgres',
412
- useWhen: 'Repos using Neon for serverless PostgreSQL.',
413
- adoption: 'Recommended for serverless and edge Postgres repos. Requires NEON_API_KEY.',
414
- servers: { neon: { command: 'npx', args: ['-y', '@neondatabase/mcp-server-neon@latest'], env: { NEON_API_KEY: '${NEON_API_KEY}' } } },
415
- },
416
- {
417
- key: 'turso-mcp',
418
- label: 'Turso Edge SQLite',
419
- useWhen: 'Repos using Turso for distributed edge SQLite.',
420
- adoption: 'Recommended for edge and multi-region apps. Requires TURSO_DATABASE_URL and TURSO_AUTH_TOKEN.',
421
- servers: { turso: { command: 'npx', args: ['-y', 'turso-mcp-server@latest'], env: { TURSO_DATABASE_URL: '${TURSO_DATABASE_URL}', TURSO_AUTH_TOKEN: '${TURSO_AUTH_TOKEN}' } } },
422
- },
423
- {
424
- key: 'upstash-mcp',
425
- label: 'Upstash (Redis + Kafka)',
426
- useWhen: 'Repos using Upstash for serverless Redis, Kafka, or QStash.',
427
- adoption: 'Recommended for serverless caching and messaging. Requires UPSTASH_REDIS_REST_URL.',
428
- servers: { upstash: { command: 'npx', args: ['-y', '@upstash/mcp-server@latest'], env: { UPSTASH_REDIS_REST_URL: '${UPSTASH_REDIS_REST_URL}', UPSTASH_REDIS_REST_TOKEN: '${UPSTASH_REDIS_REST_TOKEN}' } } },
429
- },
430
- {
431
- key: 'convex-mcp',
432
- label: 'Convex',
433
- useWhen: 'Repos using Convex as reactive backend-as-a-service.',
434
- adoption: 'Recommended for real-time full-stack repos on Convex. Requires CONVEX_DEPLOYMENT.',
435
- servers: { convex: { command: 'npx', args: ['-y', '@convex-dev/mcp-server@latest'], env: { CONVEX_DEPLOYMENT: '${CONVEX_DEPLOYMENT}' } } },
436
- },
437
- {
438
- key: 'clerk-mcp',
439
- label: 'Clerk Authentication',
440
- useWhen: 'Repos using Clerk for user authentication and session management.',
441
- adoption: 'Recommended for SaaS repos with Clerk auth. Requires CLERK_SECRET_KEY.',
442
- servers: { clerk: { command: 'npx', args: ['-y', '@clerk/mcp-server@latest'], env: { CLERK_SECRET_KEY: '${CLERK_SECRET_KEY}' } } },
443
- },
444
- {
445
- key: 'resend-mcp',
446
- label: 'Resend Email',
447
- useWhen: 'Repos using Resend for developer-focused transactional email.',
448
- adoption: 'Recommended for modern full-stack repos using Resend. Requires RESEND_API_KEY.',
449
- servers: { resend: { command: 'npx', args: ['-y', 'resend-mcp-server@latest'], env: { RESEND_API_KEY: '${RESEND_API_KEY}' } } },
450
- },
451
- {
452
- key: 'temporal-mcp',
453
- label: 'Temporal Workflow',
454
- useWhen: 'Repos using Temporal for durable workflow orchestration.',
455
- adoption: 'Recommended for async-workflow and microservice repos. Requires TEMPORAL_ADDRESS.',
456
- servers: { temporal: { command: 'npx', args: ['-y', 'temporal-mcp-server@latest'], env: { TEMPORAL_ADDRESS: '${TEMPORAL_ADDRESS}' } } },
457
- },
458
- {
459
- key: 'launchdarkly-mcp',
460
- label: 'LaunchDarkly Feature Flags',
461
- useWhen: 'Repos using LaunchDarkly for feature flags and experimentation.',
462
- adoption: 'Recommended for feature-flag-driven development. Requires LAUNCHDARKLY_ACCESS_TOKEN.',
463
- servers: { launchdarkly: { command: 'npx', args: ['-y', 'launchdarkly-mcp-server@latest'], env: { LAUNCHDARKLY_ACCESS_TOKEN: '${LAUNCHDARKLY_ACCESS_TOKEN}' } } },
464
- },
465
- {
466
- key: 'datadog-mcp',
467
- label: 'Datadog',
468
- useWhen: 'Repos using Datadog for monitoring, APM, and log management.',
469
- adoption: 'Recommended for production repos with Datadog observability. Requires DATADOG_API_KEY.',
470
- servers: { datadog: { command: 'npx', args: ['-y', '@datadog/mcp-server@latest'], env: { DATADOG_API_KEY: '${DATADOG_API_KEY}', DATADOG_APP_KEY: '${DATADOG_APP_KEY}' } } },
471
- },
472
- {
473
- key: 'grafana-mcp',
474
- label: 'Grafana',
475
- useWhen: 'Repos using Grafana for dashboards and observability.',
476
- adoption: 'Recommended for observability-focused repos. Requires GRAFANA_URL and GRAFANA_API_KEY.',
477
- servers: { grafana: { command: 'npx', args: ['-y', 'grafana-mcp-server@latest'], env: { GRAFANA_URL: '${GRAFANA_URL}', GRAFANA_API_KEY: '${GRAFANA_API_KEY}' } } },
478
- },
479
- {
480
- key: 'circleci-mcp',
481
- label: 'CircleCI',
482
- useWhen: 'Repos using CircleCI for CI/CD pipelines.',
483
- adoption: 'Recommended for CircleCI-powered projects. Requires CIRCLECI_TOKEN.',
484
- servers: { circleci: { command: 'npx', args: ['-y', 'circleci-mcp-server@latest'], env: { CIRCLECI_TOKEN: '${CIRCLECI_TOKEN}' } } },
485
- },
486
- {
487
- key: 'anthropic-mcp',
488
- label: 'Anthropic Claude API',
489
- useWhen: 'Repos that build on or integrate the Anthropic Claude API.',
490
- adoption: 'Recommended for AI-powered apps using Claude. Requires ANTHROPIC_API_KEY.',
491
- servers: { anthropic: { command: 'npx', args: ['-y', '@anthropic-ai/mcp-server@latest'], env: { ANTHROPIC_API_KEY: '${ANTHROPIC_API_KEY}' } } },
492
- },
493
- ];
494
-
495
- function clone(value) {
496
- return JSON.parse(JSON.stringify(value));
497
- }
498
-
499
- function hasDependency(deps, name) {
500
- return Object.prototype.hasOwnProperty.call(deps || {}, name);
501
- }
502
-
503
- function hasFileContentMatch(ctx, filePath, pattern) {
504
- if (!ctx) return false;
505
- const content = ctx.fileContent(filePath);
506
- return !!(content && pattern.test(content));
507
- }
508
-
509
- function getProjectDependencies(ctx) {
510
- if (!ctx) return {};
511
- if (typeof ctx.projectDependencies === 'function') {
512
- return ctx.projectDependencies();
513
- }
514
- const pkg = ctx.jsonFile('package.json') || {};
515
- return {
516
- ...(pkg.dependencies || {}),
517
- ...(pkg.devDependencies || {}),
518
- };
519
- }
520
-
521
- function hasPostgresSignals(ctx, deps = {}) {
522
- if (
523
- hasDependency(deps, 'pg') ||
524
- hasDependency(deps, 'postgres') ||
525
- hasDependency(deps, 'pg-promise') ||
526
- hasDependency(deps, 'postgres.js') ||
527
- hasDependency(deps, 'slonik') ||
528
- hasDependency(deps, '@neondatabase/serverless') ||
529
- hasDependency(deps, '@vercel/postgres')
530
- ) {
531
- return true;
532
- }
533
-
534
- return (
535
- hasFileContentMatch(ctx, 'prisma/schema.prisma', /provider\s*=\s*["']postgresql["']/i) ||
536
- hasFileContentMatch(ctx, 'docker-compose.yml', /\bpostgres\b/i) ||
537
- hasFileContentMatch(ctx, 'docker-compose.yaml', /\bpostgres\b/i) ||
538
- hasFileContentMatch(ctx, 'compose.yml', /\bpostgres\b/i) ||
539
- hasFileContentMatch(ctx, 'compose.yaml', /\bpostgres\b/i) ||
540
- hasFileContentMatch(ctx, '.env', /postgres(?:ql)?:\/\//i) ||
541
- hasFileContentMatch(ctx, '.env.local', /postgres(?:ql)?:\/\//i) ||
542
- hasFileContentMatch(ctx, '.env.example', /postgres(?:ql)?:\/\//i)
543
- );
544
- }
545
-
546
- function hasObservabilitySignals(ctx, deps = {}) {
547
- if (
548
- hasDependency(deps, '@sentry/nextjs') ||
549
- hasDependency(deps, '@sentry/node') ||
550
- hasDependency(deps, '@sentry/react') ||
551
- hasDependency(deps, '@sentry/vue') ||
552
- hasDependency(deps, '@sentry/browser')
553
- ) {
554
- return true;
555
- }
556
-
557
- return (
558
- hasFileContentMatch(ctx, 'sentry.client.config.js', /\S/) ||
559
- hasFileContentMatch(ctx, 'sentry.client.config.ts', /\S/) ||
560
- hasFileContentMatch(ctx, 'sentry.server.config.js', /\S/) ||
561
- hasFileContentMatch(ctx, 'sentry.server.config.ts', /\S/) ||
562
- hasFileContentMatch(ctx, 'instrumentation.ts', /sentry/i) ||
563
- hasFileContentMatch(ctx, 'instrumentation.js', /sentry/i)
564
- );
565
- }
566
-
567
- function getMcpPack(key) {
568
- return MCP_PACKS.find(pack => pack.key === key) || null;
569
- }
570
-
571
- function normalizeMcpPackKeys(keys = []) {
572
- return [...new Set((Array.isArray(keys) ? keys : [])
573
- .map(key => `${key}`.trim())
574
- .filter(Boolean))]
575
- .filter(key => !!getMcpPack(key));
576
- }
577
-
578
- function mergeMcpServers(existing = {}, packKeys = []) {
579
- const merged = clone(existing || {});
580
- for (const key of normalizeMcpPackKeys(packKeys)) {
581
- const pack = getMcpPack(key);
582
- if (!pack) continue;
583
- for (const [serverName, serverConfig] of Object.entries(pack.servers || {})) {
584
- if (!merged[serverName]) {
585
- merged[serverName] = clone(serverConfig);
586
- }
587
- }
588
- }
589
- return merged;
590
- }
591
-
592
- function getRequiredEnvVars(packKeys = []) {
593
- const required = new Set();
594
- for (const key of normalizeMcpPackKeys(packKeys)) {
595
- const pack = getMcpPack(key);
596
- if (!pack) continue;
597
- for (const serverConfig of Object.values(pack.servers || {})) {
598
- for (const envKey of Object.keys(serverConfig.env || {})) {
599
- required.add(envKey);
600
- }
601
- }
602
- }
603
- return [...required].sort();
604
- }
605
-
606
- function getMcpPackPreflight(packKeys = [], env = process.env) {
607
- return normalizeMcpPackKeys(packKeys)
608
- .map((key) => {
609
- const pack = getMcpPack(key);
610
- if (!pack) return null;
611
- const requiredEnvVars = getRequiredEnvVars([key]);
612
- if (requiredEnvVars.length === 0) return null;
613
- const missingEnvVars = requiredEnvVars.filter((envKey) => {
614
- const value = env && Object.prototype.hasOwnProperty.call(env, envKey) ? env[envKey] : '';
615
- return !`${value || ''}`.trim();
616
- });
617
- return {
618
- key,
619
- label: pack.label,
620
- requiredEnvVars,
621
- missingEnvVars,
622
- };
623
- })
624
- .filter(Boolean);
625
- }
626
-
627
- function recommendMcpPacks(stacks = [], domainPacks = [], options = {}) {
628
- const recommended = new Set();
629
- const stackKeys = new Set(stacks.map(stack => stack.key));
630
- const ctx = options.ctx || null;
631
- const deps = getProjectDependencies(ctx);
632
-
633
- for (const pack of domainPacks) {
634
- for (const key of pack.recommendedMcpPacks || []) {
635
- recommended.add(key);
636
- }
637
- }
638
-
639
- if (stackKeys.has('nextjs')) {
640
- recommended.add('next-devtools');
641
- }
642
- if (stackKeys.size > 0) {
643
- recommended.add('context7-docs');
644
- }
645
-
646
- const domainKeys = new Set(domainPacks.map(p => p.key));
647
-
648
- // GitHub MCP for collaborative repos
649
- if (domainKeys.has('oss-library') || domainKeys.has('enterprise-governed') || domainKeys.has('monorepo')) {
650
- recommended.add('github-mcp');
651
- }
652
-
653
- // Postgres MCP only when there are explicit Postgres signals
654
- if ((domainKeys.has('data-pipeline') || domainKeys.has('backend-api')) && hasPostgresSignals(ctx, deps)) {
655
- recommended.add('postgres-mcp');
656
- }
657
-
658
- // Memory MCP for complex projects
659
- if (domainKeys.has('monorepo') || domainKeys.has('enterprise-governed')) {
660
- recommended.add('memory-mcp');
661
- }
662
-
663
- // Playwright for frontend repos
664
- if (domainKeys.has('frontend-ui') || stackKeys.has('react') || stackKeys.has('vue') || stackKeys.has('angular') || stackKeys.has('svelte')) {
665
- recommended.add('playwright-mcp');
666
- }
667
-
668
- // Docker for infra repos
669
- if (domainKeys.has('infra-platform') || stackKeys.has('docker')) {
670
- recommended.add('docker-mcp');
671
- }
672
-
673
- // Sentry when the repo already shows observability signals or has stricter operational needs
674
- if (
675
- (domainKeys.has('backend-api') || domainKeys.has('frontend-ui')) &&
676
- (
677
- hasObservabilitySignals(ctx, deps) ||
678
- domainKeys.has('enterprise-governed') ||
679
- domainKeys.has('security-focused') ||
680
- domainKeys.has('ecommerce')
681
- )
682
- ) {
683
- recommended.add('sentry-mcp');
684
- }
685
-
686
- // Figma only when design-system signals are present
687
- if (domainKeys.has('design-system')) {
688
- recommended.add('figma-mcp');
689
- }
690
-
691
- // Stripe for e-commerce
692
- if (domainKeys.has('ecommerce')) {
693
- recommended.add('stripe-mcp');
694
- }
695
-
696
- // Jira for enterprise teams
697
- if (domainKeys.has('enterprise-governed')) {
698
- recommended.add('jira-confluence');
699
- }
700
-
701
- // Analytics for ecommerce (docs-content repos rarely need GA4/GSC)
702
- if (domainKeys.has('ecommerce')) {
703
- recommended.add('ga4-analytics');
704
- recommended.add('search-console');
705
- }
706
-
707
- // Shopify only when Shopify signals are present
708
- if (domainKeys.has('ecommerce') && ctx && (
709
- hasDependency(deps, 'shopify') || hasDependency(deps, '@shopify/shopify-api') ||
710
- hasFileContentMatch(ctx, '.env', /shopify/i) || hasFileContentMatch(ctx, '.env.example', /shopify/i)
711
- )) {
712
- recommended.add('shopify-mcp');
713
- }
714
-
715
- // HuggingFace for AI/ML
716
- if (domainKeys.has('ai-ml')) {
717
- recommended.add('huggingface-mcp');
718
- recommended.add('sequential-thinking');
719
- if (
720
- hasDependency(deps, 'langgraph') ||
721
- hasDependency(deps, 'langchain') ||
722
- hasDependency(deps, '@langchain/core') ||
723
- hasDependency(deps, 'chromadb') ||
724
- hasDependency(deps, 'qdrant-client') ||
725
- hasFileContentMatch(ctx, 'langgraph.json', /\S/) ||
726
- ctx?.hasDir('rag') ||
727
- ctx?.hasDir('retrievers')
728
- ) {
729
- recommended.add('memory-mcp');
730
- }
731
- }
732
-
733
- // Zendesk only when Zendesk signals are present
734
- if (domainKeys.has('enterprise-governed') && ctx && (
735
- hasDependency(deps, 'zendesk') || hasDependency(deps, 'node-zendesk') ||
736
- hasFileContentMatch(ctx, '.env', /zendesk/i) || hasFileContentMatch(ctx, '.env.example', /zendesk/i)
737
- )) {
738
- recommended.add('zendesk-mcp');
739
- }
740
-
741
- // Infisical for security-focused
742
- if (domainKeys.has('security-focused') || domainKeys.has('regulated-lite')) {
743
- recommended.add('infisical-secrets');
744
- }
745
-
746
- // ── New 24 packs recommendation logic ──────────────────────────────────────
747
- if (ctx && (hasDependency(deps, '@supabase/supabase-js') || hasDependency(deps, '@supabase/auth-helpers-nextjs') || hasFileContentMatch(ctx, '.env', /SUPABASE/i) || hasFileContentMatch(ctx, '.env.example', /SUPABASE/i))) {
748
- recommended.add('supabase-mcp');
749
- }
750
- if (ctx && (hasFileContentMatch(ctx, 'schema.prisma', /\S/) || hasDependency(deps, '@prisma/client') || hasDependency(deps, 'prisma'))) {
751
- recommended.add('prisma-mcp');
752
- }
753
- if (ctx && (ctx.files.includes('vercel.json') || ctx.files.includes('.vercel') || hasFileContentMatch(ctx, 'package.json', /"deploy":\s*"vercel/i) || hasFileContentMatch(ctx, '.env', /VERCEL_TOKEN/i))) {
754
- recommended.add('vercel-mcp');
755
- }
756
- if (ctx && (hasFileContentMatch(ctx, 'wrangler.toml', /\S/) || hasFileContentMatch(ctx, 'wrangler.json', /\S/) || hasDependency(deps, 'wrangler') || hasFileContentMatch(ctx, '.env', /CLOUDFLARE/i))) {
757
- recommended.add('cloudflare-mcp');
758
- }
759
- if (ctx && (hasFileContentMatch(ctx, '.env', /AWS_ACCESS_KEY/i) || hasFileContentMatch(ctx, '.env.example', /AWS_/i) || ctx.files.some(f => /serverless\.yml|template\.ya?ml|cdk\.json/.test(f)))) {
760
- recommended.add('aws-mcp');
761
- }
762
- if (ctx && (hasDependency(deps, 'redis') || hasDependency(deps, 'ioredis') || hasDependency(deps, '@redis/client') || hasFileContentMatch(ctx, '.env', /REDIS_URL/i))) {
763
- recommended.add('redis-mcp');
764
- }
765
- if (ctx && (hasDependency(deps, 'mongoose') || hasDependency(deps, 'mongodb') || hasFileContentMatch(ctx, '.env', /MONGODB_URI/i) || hasFileContentMatch(ctx, '.env.example', /MONGO/i))) {
766
- recommended.add('mongodb-mcp');
767
- }
768
- if (ctx && (hasDependency(deps, 'twilio') || hasFileContentMatch(ctx, '.env', /TWILIO_/i) || hasFileContentMatch(ctx, '.env.example', /TWILIO_/i))) {
769
- recommended.add('twilio-mcp');
770
- }
771
- if (ctx && (hasDependency(deps, '@sendgrid/mail') || hasDependency(deps, 'sendgrid') || hasFileContentMatch(ctx, '.env', /SENDGRID_API_KEY/i))) {
772
- recommended.add('sendgrid-mcp');
773
- }
774
- if (ctx && (hasDependency(deps, 'algoliasearch') || hasDependency(deps, '@algolia/client-search') || hasFileContentMatch(ctx, '.env', /ALGOLIA_/i))) {
775
- recommended.add('algolia-mcp');
776
- }
777
- if (ctx && (hasFileContentMatch(ctx, '.env', /PLANETSCALE_TOKEN/i) || hasFileContentMatch(ctx, '.env.example', /PLANETSCALE/i))) {
778
- recommended.add('planetscale-mcp');
779
- }
780
- if (ctx && (hasDependency(deps, '@neondatabase/serverless') || hasFileContentMatch(ctx, '.env', /NEON_/i) || hasFileContentMatch(ctx, '.env.example', /NEON_/i))) {
781
- recommended.add('neon-mcp');
782
- }
783
- if (ctx && (hasDependency(deps, '@libsql/client') || hasFileContentMatch(ctx, '.env', /TURSO_/i) || hasFileContentMatch(ctx, '.env.example', /TURSO_/i))) {
784
- recommended.add('turso-mcp');
785
- }
786
- if (ctx && (hasDependency(deps, '@upstash/redis') || hasDependency(deps, '@upstash/kafka') || hasFileContentMatch(ctx, '.env', /UPSTASH_/i))) {
787
- recommended.add('upstash-mcp');
788
- }
789
- if (ctx && (hasDependency(deps, 'convex') || hasDependency(deps, 'convex-dev') || hasFileContentMatch(ctx, 'convex.json', /\S/) || hasFileContentMatch(ctx, '.env', /CONVEX_/i))) {
790
- recommended.add('convex-mcp');
791
- }
792
- if (ctx && (hasDependency(deps, '@clerk/nextjs') || hasDependency(deps, '@clerk/clerk-sdk-node') || hasDependency(deps, '@clerk/backend') || hasFileContentMatch(ctx, '.env', /CLERK_/i))) {
793
- recommended.add('clerk-mcp');
794
- }
795
- if (ctx && (hasDependency(deps, 'resend') || hasFileContentMatch(ctx, '.env', /RESEND_API_KEY/i) || hasFileContentMatch(ctx, '.env.example', /RESEND_/i))) {
796
- recommended.add('resend-mcp');
797
- }
798
- if (ctx && (hasDependency(deps, '@temporalio/client') || hasDependency(deps, '@temporalio/worker') || hasFileContentMatch(ctx, '.env', /TEMPORAL_/i))) {
799
- recommended.add('temporal-mcp');
800
- }
801
- if (ctx && (hasDependency(deps, '@launchdarkly/node-server-sdk') || hasDependency(deps, 'launchdarkly-js-client-sdk') || hasFileContentMatch(ctx, '.env', /LAUNCHDARKLY_/i))) {
802
- recommended.add('launchdarkly-mcp');
803
- }
804
- if (ctx && (hasDependency(deps, 'dd-trace') || hasDependency(deps, 'datadog-metrics') || hasFileContentMatch(ctx, '.env', /DATADOG_/i))) {
805
- recommended.add('datadog-mcp');
806
- }
807
- if (ctx && (hasFileContentMatch(ctx, 'docker-compose.yml', /grafana/i) || hasFileContentMatch(ctx, '.env', /GRAFANA_/i) || ctx.files.some(f => /grafana/.test(f)))) {
808
- recommended.add('grafana-mcp');
809
- }
810
- if (ctx && (ctx.files.some(f => /\.circleci\/config/.test(f)) || hasFileContentMatch(ctx, '.env', /CIRCLECI_/i))) {
811
- recommended.add('circleci-mcp');
812
- }
813
- if (ctx && (hasDependency(deps, '@anthropic-ai/sdk') || hasDependency(deps, 'anthropic') || hasFileContentMatch(ctx, '.env', /ANTHROPIC_API_KEY/i) || hasFileContentMatch(ctx, '.env.example', /ANTHROPIC_/i))) {
814
- recommended.add('anthropic-mcp');
815
- }
816
-
817
- return MCP_PACKS
818
- .filter(pack => recommended.has(pack.key))
819
- .map(pack => clone(pack));
820
- }
821
-
822
- module.exports = {
823
- MCP_PACKS,
824
- getMcpPack,
825
- normalizeMcpPackKeys,
826
- mergeMcpServers,
827
- getRequiredEnvVars,
828
- getMcpPackPreflight,
829
- recommendMcpPacks,
830
- };
1
+ const MCP_PACKS = [
2
+ {
3
+ key: 'context7-docs',
4
+ label: 'Context7 Docs',
5
+ useWhen: 'Repos that benefit from live, current framework and library documentation during Claude sessions.',
6
+ adoption: 'Safe default docs pack for most application repos.',
7
+ servers: {
8
+ context7: {
9
+ command: 'npx',
10
+ args: ['-y', '@upstash/context7-mcp@latest'],
11
+ },
12
+ },
13
+ },
14
+ {
15
+ key: 'next-devtools',
16
+ label: 'Next.js Devtools',
17
+ useWhen: 'Next.js repos that need runtime-aware debugging and framework-specific tooling.',
18
+ adoption: 'Useful companion pack for frontend-ui repos running Next.js.',
19
+ servers: {
20
+ 'next-devtools': {
21
+ command: 'npx',
22
+ args: ['-y', 'next-devtools-mcp@latest'],
23
+ },
24
+ },
25
+ },
26
+ {
27
+ key: 'github-mcp',
28
+ label: 'GitHub',
29
+ useWhen: 'Repos hosted on GitHub that benefit from issue, PR, and repository context during Claude sessions.',
30
+ adoption: 'Recommended for any GitHub-hosted project. Requires GITHUB_PERSONAL_ACCESS_TOKEN env var.',
31
+ servers: {
32
+ github: {
33
+ command: 'npx',
34
+ args: ['-y', '@modelcontextprotocol/server-github'],
35
+ env: { GITHUB_PERSONAL_ACCESS_TOKEN: '${GITHUB_PERSONAL_ACCESS_TOKEN}' },
36
+ },
37
+ },
38
+ },
39
+ {
40
+ key: 'postgres-mcp',
41
+ label: 'PostgreSQL',
42
+ useWhen: 'Repos with PostgreSQL databases that benefit from schema inspection and query assistance.',
43
+ adoption: 'Useful for backend-api and data-pipeline repos. Pass connection string as CLI argument.',
44
+ servers: {
45
+ postgres: {
46
+ command: 'npx',
47
+ args: ['-y', '@modelcontextprotocol/server-postgres', '${DATABASE_URL}'],
48
+ },
49
+ },
50
+ },
51
+ {
52
+ key: 'memory-mcp',
53
+ label: 'Memory / Knowledge Graph',
54
+ useWhen: 'Long-running projects that benefit from persistent entity and relationship tracking across sessions.',
55
+ adoption: 'Useful for complex projects with many interconnected concepts. Stores data locally.',
56
+ servers: {
57
+ memory: {
58
+ command: 'npx',
59
+ args: ['-y', '@modelcontextprotocol/server-memory'],
60
+ },
61
+ },
62
+ },
63
+ {
64
+ key: 'playwright-mcp',
65
+ label: 'Playwright Browser',
66
+ useWhen: 'Frontend repos that need browser automation, E2E testing, or visual QA during Claude sessions.',
67
+ adoption: 'Recommended for frontend-ui repos with E2E tests. No auth required.',
68
+ servers: {
69
+ playwright: {
70
+ command: 'npx',
71
+ args: ['-y', '@playwright/mcp@latest'],
72
+ },
73
+ },
74
+ },
75
+ {
76
+ key: 'docker-mcp',
77
+ label: 'Docker',
78
+ useWhen: 'Repos with containerized workflows that benefit from container management during Claude sessions.',
79
+ adoption: 'Community Docker MCP server. Requires Docker running locally. Note: community-maintained package.',
80
+ servers: {
81
+ docker: {
82
+ command: 'npx',
83
+ args: ['-y', '@hypnosis/docker-mcp-server'],
84
+ },
85
+ },
86
+ },
87
+ {
88
+ key: 'notion-mcp',
89
+ label: 'Notion',
90
+ useWhen: 'Teams using Notion for documentation, wikis, or knowledge bases that Claude should reference.',
91
+ adoption: 'Useful for teams with Notion-based docs. Requires NOTION_API_KEY env var.',
92
+ servers: {
93
+ notion: {
94
+ command: 'npx',
95
+ args: ['-y', '@notionhq/notion-mcp-server'],
96
+ env: { NOTION_API_KEY: '${NOTION_API_KEY}' },
97
+ },
98
+ },
99
+ },
100
+ {
101
+ key: 'linear-mcp',
102
+ label: 'Linear',
103
+ useWhen: 'Teams using Linear for issue tracking that want Claude to read and create issues.',
104
+ adoption: 'Useful for teams managing sprints in Linear. Requires LINEAR_API_KEY env var.',
105
+ servers: {
106
+ linear: {
107
+ command: 'npx',
108
+ args: ['-y', '@mseep/linear-mcp'],
109
+ env: { LINEAR_API_KEY: '${LINEAR_API_KEY}' },
110
+ },
111
+ },
112
+ },
113
+ {
114
+ key: 'sentry-mcp',
115
+ label: 'Sentry',
116
+ useWhen: 'Repos with Sentry error tracking that benefit from error context during debugging sessions.',
117
+ adoption: 'Useful for production repos. Requires SENTRY_AUTH_TOKEN env var.',
118
+ servers: {
119
+ sentry: {
120
+ command: 'npx',
121
+ args: ['-y', '@sentry/mcp-server'],
122
+ env: { SENTRY_AUTH_TOKEN: '${SENTRY_AUTH_TOKEN}' },
123
+ },
124
+ },
125
+ },
126
+ {
127
+ key: 'slack-mcp',
128
+ label: 'Slack',
129
+ useWhen: 'Teams using Slack that want Claude to draft, preview, or post messages.',
130
+ adoption: 'Community Slack MCP server (supports OAuth and stealth mode). Requires SLACK_BOT_TOKEN or SLACK_COOKIES env var.',
131
+ servers: {
132
+ slack: {
133
+ command: 'npx',
134
+ args: ['-y', 'slack-mcp-server'],
135
+ env: { SLACK_BOT_TOKEN: '${SLACK_BOT_TOKEN}' },
136
+ },
137
+ },
138
+ },
139
+ {
140
+ key: 'stripe-mcp',
141
+ label: 'Stripe',
142
+ useWhen: 'Repos with Stripe integration for payments, subscriptions, or billing workflows.',
143
+ adoption: 'Useful for e-commerce and SaaS repos. Requires STRIPE_API_KEY env var.',
144
+ servers: {
145
+ stripe: {
146
+ command: 'npx',
147
+ args: ['-y', '@stripe/mcp'],
148
+ env: { STRIPE_API_KEY: '${STRIPE_API_KEY}' },
149
+ },
150
+ },
151
+ },
152
+ {
153
+ key: 'figma-mcp',
154
+ label: 'Figma',
155
+ useWhen: 'Design-heavy repos where Claude needs access to Figma designs and components.',
156
+ adoption: 'Community Figma MCP server. Requires FIGMA_ACCESS_TOKEN env var. Note: community-maintained package.',
157
+ servers: {
158
+ figma: {
159
+ command: 'npx',
160
+ args: ['-y', 'claude-talk-to-figma-mcp'],
161
+ env: { FIGMA_ACCESS_TOKEN: '${FIGMA_ACCESS_TOKEN}' },
162
+ },
163
+ },
164
+ },
165
+ {
166
+ key: 'mcp-security',
167
+ label: 'MCP Security Scanner',
168
+ useWhen: 'Any repo using MCP servers that should be scanned for tool poisoning and prompt injection.',
169
+ adoption: 'Recommended as a safety companion for any repo with 2+ MCP servers.',
170
+ servers: {
171
+ 'mcp-scan': {
172
+ command: 'npx',
173
+ args: ['-y', 'mcp-scan@latest'],
174
+ },
175
+ },
176
+ },
177
+ {
178
+ key: 'composio-mcp',
179
+ label: 'Composio Universal',
180
+ useWhen: 'Teams needing 500+ integrations through a single MCP gateway with centralized OAuth.',
181
+ adoption: 'Useful for enterprise or integration-heavy repos. Requires COMPOSIO_API_KEY env var.',
182
+ servers: {
183
+ composio: {
184
+ command: 'npx',
185
+ args: ['-y', '@composio/mcp'],
186
+ env: { COMPOSIO_API_KEY: '${COMPOSIO_API_KEY}' },
187
+ },
188
+ },
189
+ },
190
+ {
191
+ key: 'sequential-thinking',
192
+ label: 'Sequential Thinking',
193
+ useWhen: 'Complex problem-solving sessions that benefit from structured step-by-step reasoning.',
194
+ adoption: 'Safe default for any repo. No auth required.',
195
+ servers: {
196
+ 'sequential-thinking': {
197
+ command: 'npx',
198
+ args: ['-y', '@modelcontextprotocol/server-sequential-thinking'],
199
+ },
200
+ },
201
+ },
202
+ {
203
+ key: 'jira-confluence',
204
+ label: 'Jira',
205
+ useWhen: 'Teams using Atlassian Jira for issue tracking and project management.',
206
+ adoption: 'Requires ATLASSIAN_API_TOKEN and ATLASSIAN_EMAIL env vars.',
207
+ servers: {
208
+ jira: {
209
+ command: 'npx',
210
+ args: ['-y', 'jira-mcp'],
211
+ env: { ATLASSIAN_API_TOKEN: '${ATLASSIAN_API_TOKEN}', ATLASSIAN_EMAIL: '${ATLASSIAN_EMAIL}' },
212
+ },
213
+ },
214
+ },
215
+ {
216
+ key: 'ga4-analytics',
217
+ label: 'Google Analytics 4',
218
+ useWhen: 'Repos with web analytics needs — live GA4 data, attribution, and audience insights.',
219
+ adoption: 'Requires GA4_PROPERTY_ID and either GOOGLE_APPLICATION_CREDENTIALS or ADC for auth.',
220
+ servers: {
221
+ ga4: {
222
+ command: 'npx',
223
+ args: ['-y', 'mcp-server-ga4'],
224
+ env: { GA4_PROPERTY_ID: '${GA4_PROPERTY_ID}', GOOGLE_APPLICATION_CREDENTIALS: '${GOOGLE_APPLICATION_CREDENTIALS}' },
225
+ },
226
+ },
227
+ },
228
+ {
229
+ key: 'search-console',
230
+ label: 'Google Search Console',
231
+ useWhen: 'SEO-focused repos that need search performance data, indexing status, and sitemap insights.',
232
+ adoption: 'Requires Google OAuth client credentials (client ID + secret). Uses OAuth consent flow.',
233
+ servers: {
234
+ gsc: {
235
+ command: 'npx',
236
+ args: ['-y', 'mcp-gsc@latest'],
237
+ env: { GOOGLE_CLIENT_ID: '${GOOGLE_CLIENT_ID}', GOOGLE_CLIENT_SECRET: '${GOOGLE_CLIENT_SECRET}' },
238
+ },
239
+ },
240
+ },
241
+ {
242
+ key: 'n8n-workflows',
243
+ label: 'n8n Workflow Automation',
244
+ useWhen: 'Teams using n8n for workflow automation with 1,396 integration nodes.',
245
+ adoption: 'Requires n8n instance URL and API key.',
246
+ servers: {
247
+ n8n: {
248
+ command: 'npx',
249
+ args: ['-y', 'n8n-mcp-server@latest'],
250
+ env: { N8N_URL: '${N8N_URL}', N8N_API_KEY: '${N8N_API_KEY}' },
251
+ },
252
+ },
253
+ },
254
+ {
255
+ key: 'zendesk-mcp',
256
+ label: 'Zendesk',
257
+ useWhen: 'Support teams using Zendesk for ticket management and help center content.',
258
+ adoption: 'Requires ZENDESK_API_TOKEN and ZENDESK_SUBDOMAIN env vars.',
259
+ servers: {
260
+ zendesk: {
261
+ command: 'npx',
262
+ args: ['-y', 'zendesk-mcp'],
263
+ env: { ZENDESK_API_TOKEN: '${ZENDESK_API_TOKEN}', ZENDESK_SUBDOMAIN: '${ZENDESK_SUBDOMAIN}' },
264
+ },
265
+ },
266
+ },
267
+ {
268
+ key: 'infisical-secrets',
269
+ label: 'Infisical Secrets',
270
+ useWhen: 'Repos using Infisical for secrets management with auto-rotation.',
271
+ adoption: 'Requires INFISICAL_TOKEN env var.',
272
+ servers: {
273
+ infisical: {
274
+ command: 'npx',
275
+ args: ['-y', '@infisical/mcp'],
276
+ env: { INFISICAL_TOKEN: '${INFISICAL_TOKEN}' },
277
+ },
278
+ },
279
+ },
280
+ {
281
+ key: 'shopify-mcp',
282
+ label: 'Shopify',
283
+ useWhen: 'Shopify stores and apps that need API schema access and deployment tooling.',
284
+ adoption: 'Community Shopify MCP server for GraphQL API access. Requires SHOPIFY_ACCESS_TOKEN env var.',
285
+ servers: {
286
+ shopify: {
287
+ command: 'npx',
288
+ args: ['-y', 'shopify-mcp'],
289
+ env: { SHOPIFY_ACCESS_TOKEN: '${SHOPIFY_ACCESS_TOKEN}' },
290
+ },
291
+ },
292
+ },
293
+ {
294
+ key: 'huggingface-mcp',
295
+ label: 'Hugging Face',
296
+ useWhen: 'AI/ML repos that need model search, dataset discovery, and Spaces integration.',
297
+ adoption: 'Useful for ai-ml domain repos. Requires HF_TOKEN env var.',
298
+ servers: {
299
+ huggingface: {
300
+ command: 'npx',
301
+ args: ['-y', 'huggingface-mcp-server'],
302
+ env: { HF_TOKEN: '${HF_TOKEN}' },
303
+ },
304
+ },
305
+ },
306
+ {
307
+ key: 'blender-mcp',
308
+ label: 'Blender 3D',
309
+ useWhen: '3D modeling, animation, or rendering repos that use Blender.',
310
+ adoption: 'Requires Blender installed locally. Python bridge.',
311
+ servers: {
312
+ blender: {
313
+ command: 'npx',
314
+ args: ['-y', '@glutamateapp/blender-mcp-ts'],
315
+ },
316
+ },
317
+ },
318
+ {
319
+ key: 'wordpress-mcp',
320
+ label: 'WordPress',
321
+ useWhen: 'WordPress sites needing content management, site ops, and plugin workflows.',
322
+ adoption: 'Requires WP_URL and WP_AUTH_TOKEN env vars.',
323
+ servers: {
324
+ wordpress: {
325
+ command: 'npx',
326
+ args: ['-y', 'wordpress-mcp-server@latest'],
327
+ env: { WP_URL: '${WP_URL}', WP_AUTH_TOKEN: '${WP_AUTH_TOKEN}' },
328
+ },
329
+ },
330
+ },
331
+ // ── 24 new packs ─────────────────────────────────────────────────────────
332
+ {
333
+ key: 'supabase-mcp',
334
+ label: 'Supabase',
335
+ useWhen: 'Repos using Supabase for database, auth, or storage.',
336
+ adoption: 'Recommended for full-stack repos using Supabase. Requires SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY.',
337
+ servers: { supabase: { command: 'npx', args: ['-y', '@supabase/mcp-server-supabase@latest'], env: { SUPABASE_URL: '${SUPABASE_URL}', SUPABASE_SERVICE_ROLE_KEY: '${SUPABASE_SERVICE_ROLE_KEY}' } } },
338
+ },
339
+ {
340
+ key: 'prisma-mcp',
341
+ label: 'Prisma ORM',
342
+ useWhen: 'Repos using Prisma for database schema management and migrations.',
343
+ adoption: 'Recommended for any repo with a Prisma schema. No auth required beyond DATABASE_URL.',
344
+ servers: { prisma: { command: 'npx', args: ['-y', 'prisma-mcp-server@latest'], env: { DATABASE_URL: '${DATABASE_URL}' } } },
345
+ },
346
+ {
347
+ key: 'vercel-mcp',
348
+ label: 'Vercel',
349
+ useWhen: 'Repos deployed on Vercel that benefit from deployment management and log access.',
350
+ adoption: 'Recommended for Next.js and other Vercel-hosted repos. Requires VERCEL_TOKEN.',
351
+ servers: { vercel: { command: 'npx', args: ['-y', '@vercel/mcp-server@latest'], env: { VERCEL_TOKEN: '${VERCEL_TOKEN}' } } },
352
+ },
353
+ {
354
+ key: 'cloudflare-mcp',
355
+ label: 'Cloudflare',
356
+ useWhen: 'Repos using Cloudflare Workers, KV, R2, or D1.',
357
+ adoption: 'Recommended for edge-compute repos. Requires CLOUDFLARE_API_TOKEN.',
358
+ servers: { cloudflare: { command: 'npx', args: ['-y', '@cloudflare/mcp-server-cloudflare@latest'], env: { CLOUDFLARE_API_TOKEN: '${CLOUDFLARE_API_TOKEN}' } } },
359
+ },
360
+ {
361
+ key: 'aws-mcp',
362
+ label: 'AWS (S3, Lambda, DynamoDB)',
363
+ useWhen: 'Repos using AWS services — S3, Lambda, DynamoDB, or CloudFormation.',
364
+ adoption: 'Recommended for cloud-infra repos. Requires AWS credentials.',
365
+ servers: { aws: { command: 'npx', args: ['-y', '@aws-samples/mcp-server-aws@latest'], env: { AWS_ACCESS_KEY_ID: '${AWS_ACCESS_KEY_ID}', AWS_SECRET_ACCESS_KEY: '${AWS_SECRET_ACCESS_KEY}', AWS_REGION: '${AWS_REGION}' } } },
366
+ },
367
+ {
368
+ key: 'redis-mcp',
369
+ label: 'Redis',
370
+ useWhen: 'Repos using Redis for caching, sessions, or pub/sub.',
371
+ adoption: 'Recommended for performance-critical repos with Redis. Requires REDIS_URL.',
372
+ servers: { redis: { command: 'npx', args: ['-y', 'redis-mcp-server@latest'], env: { REDIS_URL: '${REDIS_URL}' } } },
373
+ },
374
+ {
375
+ key: 'mongodb-mcp',
376
+ label: 'MongoDB',
377
+ useWhen: 'Repos using MongoDB as document database.',
378
+ adoption: 'Recommended for document-model repos. Requires MONGODB_URI.',
379
+ servers: { mongodb: { command: 'npx', args: ['-y', '@mongodb-js/mongodb-mcp-server@latest'], env: { MONGODB_URI: '${MONGODB_URI}' } } },
380
+ },
381
+ {
382
+ key: 'twilio-mcp',
383
+ label: 'Twilio',
384
+ useWhen: 'Repos integrating SMS, voice, or messaging via Twilio.',
385
+ adoption: 'Recommended for communication-feature repos. Requires TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN.',
386
+ servers: { twilio: { command: 'npx', args: ['-y', 'twilio-mcp-server@latest'], env: { TWILIO_ACCOUNT_SID: '${TWILIO_ACCOUNT_SID}', TWILIO_AUTH_TOKEN: '${TWILIO_AUTH_TOKEN}' } } },
387
+ },
388
+ {
389
+ key: 'sendgrid-mcp',
390
+ label: 'SendGrid',
391
+ useWhen: 'Repos using SendGrid for transactional or marketing email.',
392
+ adoption: 'Recommended for repos with email delivery workflows. Requires SENDGRID_API_KEY.',
393
+ servers: { sendgrid: { command: 'npx', args: ['-y', 'sendgrid-mcp-server@latest'], env: { SENDGRID_API_KEY: '${SENDGRID_API_KEY}' } } },
394
+ },
395
+ {
396
+ key: 'algolia-mcp',
397
+ label: 'Algolia Search',
398
+ useWhen: 'Repos using Algolia for search indexing and discovery.',
399
+ adoption: 'Recommended for e-commerce and content-heavy repos. Requires ALGOLIA_APP_ID and ALGOLIA_API_KEY.',
400
+ servers: { algolia: { command: 'npx', args: ['-y', 'algolia-mcp-server@latest'], env: { ALGOLIA_APP_ID: '${ALGOLIA_APP_ID}', ALGOLIA_API_KEY: '${ALGOLIA_API_KEY}' } } },
401
+ },
402
+ {
403
+ key: 'planetscale-mcp',
404
+ label: 'PlanetScale',
405
+ useWhen: 'Repos using PlanetScale serverless MySQL database.',
406
+ adoption: 'Recommended for MySQL-based repos on PlanetScale. Requires PLANETSCALE_TOKEN.',
407
+ servers: { planetscale: { command: 'npx', args: ['-y', 'planetscale-mcp-server@latest'], env: { PLANETSCALE_TOKEN: '${PLANETSCALE_TOKEN}' } } },
408
+ },
409
+ {
410
+ key: 'neon-mcp',
411
+ label: 'Neon Serverless Postgres',
412
+ useWhen: 'Repos using Neon for serverless PostgreSQL.',
413
+ adoption: 'Recommended for serverless and edge Postgres repos. Requires NEON_API_KEY.',
414
+ servers: { neon: { command: 'npx', args: ['-y', '@neondatabase/mcp-server-neon@latest'], env: { NEON_API_KEY: '${NEON_API_KEY}' } } },
415
+ },
416
+ {
417
+ key: 'turso-mcp',
418
+ label: 'Turso Edge SQLite',
419
+ useWhen: 'Repos using Turso for distributed edge SQLite.',
420
+ adoption: 'Recommended for edge and multi-region apps. Requires TURSO_DATABASE_URL and TURSO_AUTH_TOKEN.',
421
+ servers: { turso: { command: 'npx', args: ['-y', 'turso-mcp-server@latest'], env: { TURSO_DATABASE_URL: '${TURSO_DATABASE_URL}', TURSO_AUTH_TOKEN: '${TURSO_AUTH_TOKEN}' } } },
422
+ },
423
+ {
424
+ key: 'upstash-mcp',
425
+ label: 'Upstash (Redis + Kafka)',
426
+ useWhen: 'Repos using Upstash for serverless Redis, Kafka, or QStash.',
427
+ adoption: 'Recommended for serverless caching and messaging. Requires UPSTASH_REDIS_REST_URL.',
428
+ servers: { upstash: { command: 'npx', args: ['-y', '@upstash/mcp-server@latest'], env: { UPSTASH_REDIS_REST_URL: '${UPSTASH_REDIS_REST_URL}', UPSTASH_REDIS_REST_TOKEN: '${UPSTASH_REDIS_REST_TOKEN}' } } },
429
+ },
430
+ {
431
+ key: 'convex-mcp',
432
+ label: 'Convex',
433
+ useWhen: 'Repos using Convex as reactive backend-as-a-service.',
434
+ adoption: 'Recommended for real-time full-stack repos on Convex. Requires CONVEX_DEPLOYMENT.',
435
+ servers: { convex: { command: 'npx', args: ['-y', '@convex-dev/mcp-server@latest'], env: { CONVEX_DEPLOYMENT: '${CONVEX_DEPLOYMENT}' } } },
436
+ },
437
+ {
438
+ key: 'clerk-mcp',
439
+ label: 'Clerk Authentication',
440
+ useWhen: 'Repos using Clerk for user authentication and session management.',
441
+ adoption: 'Recommended for SaaS repos with Clerk auth. Requires CLERK_SECRET_KEY.',
442
+ servers: { clerk: { command: 'npx', args: ['-y', '@clerk/mcp-server@latest'], env: { CLERK_SECRET_KEY: '${CLERK_SECRET_KEY}' } } },
443
+ },
444
+ {
445
+ key: 'resend-mcp',
446
+ label: 'Resend Email',
447
+ useWhen: 'Repos using Resend for developer-focused transactional email.',
448
+ adoption: 'Recommended for modern full-stack repos using Resend. Requires RESEND_API_KEY.',
449
+ servers: { resend: { command: 'npx', args: ['-y', 'resend-mcp-server@latest'], env: { RESEND_API_KEY: '${RESEND_API_KEY}' } } },
450
+ },
451
+ {
452
+ key: 'temporal-mcp',
453
+ label: 'Temporal Workflow',
454
+ useWhen: 'Repos using Temporal for durable workflow orchestration.',
455
+ adoption: 'Recommended for async-workflow and microservice repos. Requires TEMPORAL_ADDRESS.',
456
+ servers: { temporal: { command: 'npx', args: ['-y', 'temporal-mcp-server@latest'], env: { TEMPORAL_ADDRESS: '${TEMPORAL_ADDRESS}' } } },
457
+ },
458
+ {
459
+ key: 'launchdarkly-mcp',
460
+ label: 'LaunchDarkly Feature Flags',
461
+ useWhen: 'Repos using LaunchDarkly for feature flags and experimentation.',
462
+ adoption: 'Recommended for feature-flag-driven development. Requires LAUNCHDARKLY_ACCESS_TOKEN.',
463
+ servers: { launchdarkly: { command: 'npx', args: ['-y', 'launchdarkly-mcp-server@latest'], env: { LAUNCHDARKLY_ACCESS_TOKEN: '${LAUNCHDARKLY_ACCESS_TOKEN}' } } },
464
+ },
465
+ {
466
+ key: 'datadog-mcp',
467
+ label: 'Datadog',
468
+ useWhen: 'Repos using Datadog for monitoring, APM, and log management.',
469
+ adoption: 'Recommended for production repos with Datadog observability. Requires DATADOG_API_KEY.',
470
+ servers: { datadog: { command: 'npx', args: ['-y', '@datadog/mcp-server@latest'], env: { DATADOG_API_KEY: '${DATADOG_API_KEY}', DATADOG_APP_KEY: '${DATADOG_APP_KEY}' } } },
471
+ },
472
+ {
473
+ key: 'grafana-mcp',
474
+ label: 'Grafana',
475
+ useWhen: 'Repos using Grafana for dashboards and observability.',
476
+ adoption: 'Recommended for observability-focused repos. Requires GRAFANA_URL and GRAFANA_API_KEY.',
477
+ servers: { grafana: { command: 'npx', args: ['-y', 'grafana-mcp-server@latest'], env: { GRAFANA_URL: '${GRAFANA_URL}', GRAFANA_API_KEY: '${GRAFANA_API_KEY}' } } },
478
+ },
479
+ {
480
+ key: 'circleci-mcp',
481
+ label: 'CircleCI',
482
+ useWhen: 'Repos using CircleCI for CI/CD pipelines.',
483
+ adoption: 'Recommended for CircleCI-powered projects. Requires CIRCLECI_TOKEN.',
484
+ servers: { circleci: { command: 'npx', args: ['-y', 'circleci-mcp-server@latest'], env: { CIRCLECI_TOKEN: '${CIRCLECI_TOKEN}' } } },
485
+ },
486
+ {
487
+ key: 'anthropic-mcp',
488
+ label: 'Anthropic Claude API',
489
+ useWhen: 'Repos that build on or integrate the Anthropic Claude API.',
490
+ adoption: 'Recommended for AI-powered apps using Claude. Requires ANTHROPIC_API_KEY.',
491
+ servers: { anthropic: { command: 'npx', args: ['-y', '@anthropic-ai/mcp-server@latest'], env: { ANTHROPIC_API_KEY: '${ANTHROPIC_API_KEY}' } } },
492
+ },
493
+ ];
494
+
495
+ function clone(value) {
496
+ return JSON.parse(JSON.stringify(value));
497
+ }
498
+
499
+ function hasDependency(deps, name) {
500
+ return Object.prototype.hasOwnProperty.call(deps || {}, name);
501
+ }
502
+
503
+ function hasFileContentMatch(ctx, filePath, pattern) {
504
+ if (!ctx) return false;
505
+ const content = ctx.fileContent(filePath);
506
+ return !!(content && pattern.test(content));
507
+ }
508
+
509
+ function getProjectDependencies(ctx) {
510
+ if (!ctx) return {};
511
+ if (typeof ctx.projectDependencies === 'function') {
512
+ return ctx.projectDependencies();
513
+ }
514
+ const pkg = ctx.jsonFile('package.json') || {};
515
+ return {
516
+ ...(pkg.dependencies || {}),
517
+ ...(pkg.devDependencies || {}),
518
+ };
519
+ }
520
+
521
+ function hasPostgresSignals(ctx, deps = {}) {
522
+ if (
523
+ hasDependency(deps, 'pg') ||
524
+ hasDependency(deps, 'postgres') ||
525
+ hasDependency(deps, 'pg-promise') ||
526
+ hasDependency(deps, 'postgres.js') ||
527
+ hasDependency(deps, 'slonik') ||
528
+ hasDependency(deps, '@neondatabase/serverless') ||
529
+ hasDependency(deps, '@vercel/postgres')
530
+ ) {
531
+ return true;
532
+ }
533
+
534
+ return (
535
+ hasFileContentMatch(ctx, 'prisma/schema.prisma', /provider\s*=\s*["']postgresql["']/i) ||
536
+ hasFileContentMatch(ctx, 'docker-compose.yml', /\bpostgres\b/i) ||
537
+ hasFileContentMatch(ctx, 'docker-compose.yaml', /\bpostgres\b/i) ||
538
+ hasFileContentMatch(ctx, 'compose.yml', /\bpostgres\b/i) ||
539
+ hasFileContentMatch(ctx, 'compose.yaml', /\bpostgres\b/i) ||
540
+ hasFileContentMatch(ctx, '.env', /postgres(?:ql)?:\/\//i) ||
541
+ hasFileContentMatch(ctx, '.env.local', /postgres(?:ql)?:\/\//i) ||
542
+ hasFileContentMatch(ctx, '.env.example', /postgres(?:ql)?:\/\//i)
543
+ );
544
+ }
545
+
546
+ function hasObservabilitySignals(ctx, deps = {}) {
547
+ if (
548
+ hasDependency(deps, '@sentry/nextjs') ||
549
+ hasDependency(deps, '@sentry/node') ||
550
+ hasDependency(deps, '@sentry/react') ||
551
+ hasDependency(deps, '@sentry/vue') ||
552
+ hasDependency(deps, '@sentry/browser')
553
+ ) {
554
+ return true;
555
+ }
556
+
557
+ return (
558
+ hasFileContentMatch(ctx, 'sentry.client.config.js', /\S/) ||
559
+ hasFileContentMatch(ctx, 'sentry.client.config.ts', /\S/) ||
560
+ hasFileContentMatch(ctx, 'sentry.server.config.js', /\S/) ||
561
+ hasFileContentMatch(ctx, 'sentry.server.config.ts', /\S/) ||
562
+ hasFileContentMatch(ctx, 'instrumentation.ts', /sentry/i) ||
563
+ hasFileContentMatch(ctx, 'instrumentation.js', /sentry/i)
564
+ );
565
+ }
566
+
567
+ function getMcpPack(key) {
568
+ return MCP_PACKS.find(pack => pack.key === key) || null;
569
+ }
570
+
571
+ function normalizeMcpPackKeys(keys = []) {
572
+ return [...new Set((Array.isArray(keys) ? keys : [])
573
+ .map(key => `${key}`.trim())
574
+ .filter(Boolean))]
575
+ .filter(key => !!getMcpPack(key));
576
+ }
577
+
578
+ function mergeMcpServers(existing = {}, packKeys = []) {
579
+ const merged = clone(existing || {});
580
+ for (const key of normalizeMcpPackKeys(packKeys)) {
581
+ const pack = getMcpPack(key);
582
+ if (!pack) continue;
583
+ for (const [serverName, serverConfig] of Object.entries(pack.servers || {})) {
584
+ if (!merged[serverName]) {
585
+ merged[serverName] = clone(serverConfig);
586
+ }
587
+ }
588
+ }
589
+ return merged;
590
+ }
591
+
592
+ function getRequiredEnvVars(packKeys = []) {
593
+ const required = new Set();
594
+ for (const key of normalizeMcpPackKeys(packKeys)) {
595
+ const pack = getMcpPack(key);
596
+ if (!pack) continue;
597
+ for (const serverConfig of Object.values(pack.servers || {})) {
598
+ for (const envKey of Object.keys(serverConfig.env || {})) {
599
+ required.add(envKey);
600
+ }
601
+ }
602
+ }
603
+ return [...required].sort();
604
+ }
605
+
606
+ function getMcpPackPreflight(packKeys = [], env = process.env) {
607
+ return normalizeMcpPackKeys(packKeys)
608
+ .map((key) => {
609
+ const pack = getMcpPack(key);
610
+ if (!pack) return null;
611
+ const requiredEnvVars = getRequiredEnvVars([key]);
612
+ if (requiredEnvVars.length === 0) return null;
613
+ const missingEnvVars = requiredEnvVars.filter((envKey) => {
614
+ const value = env && Object.prototype.hasOwnProperty.call(env, envKey) ? env[envKey] : '';
615
+ return !`${value || ''}`.trim();
616
+ });
617
+ return {
618
+ key,
619
+ label: pack.label,
620
+ requiredEnvVars,
621
+ missingEnvVars,
622
+ };
623
+ })
624
+ .filter(Boolean);
625
+ }
626
+
627
+ function recommendMcpPacks(stacks = [], domainPacks = [], options = {}) {
628
+ const recommended = new Set();
629
+ const stackKeys = new Set(stacks.map(stack => stack.key));
630
+ const ctx = options.ctx || null;
631
+ const deps = getProjectDependencies(ctx);
632
+
633
+ for (const pack of domainPacks) {
634
+ for (const key of pack.recommendedMcpPacks || []) {
635
+ recommended.add(key);
636
+ }
637
+ }
638
+
639
+ if (stackKeys.has('nextjs')) {
640
+ recommended.add('next-devtools');
641
+ }
642
+ if (stackKeys.size > 0) {
643
+ recommended.add('context7-docs');
644
+ }
645
+
646
+ const domainKeys = new Set(domainPacks.map(p => p.key));
647
+
648
+ // GitHub MCP for collaborative repos
649
+ if (domainKeys.has('oss-library') || domainKeys.has('enterprise-governed') || domainKeys.has('monorepo')) {
650
+ recommended.add('github-mcp');
651
+ }
652
+
653
+ // Postgres MCP only when there are explicit Postgres signals
654
+ if ((domainKeys.has('data-pipeline') || domainKeys.has('backend-api')) && hasPostgresSignals(ctx, deps)) {
655
+ recommended.add('postgres-mcp');
656
+ }
657
+
658
+ // Memory MCP for complex projects
659
+ if (domainKeys.has('monorepo') || domainKeys.has('enterprise-governed')) {
660
+ recommended.add('memory-mcp');
661
+ }
662
+
663
+ // Playwright for frontend repos
664
+ if (domainKeys.has('frontend-ui') || stackKeys.has('react') || stackKeys.has('vue') || stackKeys.has('angular') || stackKeys.has('svelte')) {
665
+ recommended.add('playwright-mcp');
666
+ }
667
+
668
+ // Docker for infra repos
669
+ if (domainKeys.has('infra-platform') || stackKeys.has('docker')) {
670
+ recommended.add('docker-mcp');
671
+ }
672
+
673
+ // Sentry when the repo already shows observability signals or has stricter operational needs
674
+ if (
675
+ (domainKeys.has('backend-api') || domainKeys.has('frontend-ui')) &&
676
+ (
677
+ hasObservabilitySignals(ctx, deps) ||
678
+ domainKeys.has('enterprise-governed') ||
679
+ domainKeys.has('security-focused') ||
680
+ domainKeys.has('ecommerce')
681
+ )
682
+ ) {
683
+ recommended.add('sentry-mcp');
684
+ }
685
+
686
+ // Figma only when design-system signals are present
687
+ if (domainKeys.has('design-system')) {
688
+ recommended.add('figma-mcp');
689
+ }
690
+
691
+ // Stripe for e-commerce
692
+ if (domainKeys.has('ecommerce')) {
693
+ recommended.add('stripe-mcp');
694
+ }
695
+
696
+ // Jira for enterprise teams
697
+ if (domainKeys.has('enterprise-governed')) {
698
+ recommended.add('jira-confluence');
699
+ }
700
+
701
+ // Analytics for ecommerce (docs-content repos rarely need GA4/GSC)
702
+ if (domainKeys.has('ecommerce')) {
703
+ recommended.add('ga4-analytics');
704
+ recommended.add('search-console');
705
+ }
706
+
707
+ // Shopify only when Shopify signals are present
708
+ if (domainKeys.has('ecommerce') && ctx && (
709
+ hasDependency(deps, 'shopify') || hasDependency(deps, '@shopify/shopify-api') ||
710
+ hasFileContentMatch(ctx, '.env', /shopify/i) || hasFileContentMatch(ctx, '.env.example', /shopify/i)
711
+ )) {
712
+ recommended.add('shopify-mcp');
713
+ }
714
+
715
+ // HuggingFace for AI/ML
716
+ if (domainKeys.has('ai-ml')) {
717
+ recommended.add('huggingface-mcp');
718
+ recommended.add('sequential-thinking');
719
+ if (
720
+ hasDependency(deps, 'langgraph') ||
721
+ hasDependency(deps, 'langchain') ||
722
+ hasDependency(deps, '@langchain/core') ||
723
+ hasDependency(deps, 'chromadb') ||
724
+ hasDependency(deps, 'qdrant-client') ||
725
+ hasFileContentMatch(ctx, 'langgraph.json', /\S/) ||
726
+ ctx?.hasDir('rag') ||
727
+ ctx?.hasDir('retrievers')
728
+ ) {
729
+ recommended.add('memory-mcp');
730
+ }
731
+ }
732
+
733
+ // Zendesk only when Zendesk signals are present
734
+ if (domainKeys.has('enterprise-governed') && ctx && (
735
+ hasDependency(deps, 'zendesk') || hasDependency(deps, 'node-zendesk') ||
736
+ hasFileContentMatch(ctx, '.env', /zendesk/i) || hasFileContentMatch(ctx, '.env.example', /zendesk/i)
737
+ )) {
738
+ recommended.add('zendesk-mcp');
739
+ }
740
+
741
+ // Infisical for security-focused
742
+ if (domainKeys.has('security-focused') || domainKeys.has('regulated-lite')) {
743
+ recommended.add('infisical-secrets');
744
+ }
745
+
746
+ // ── New 24 packs recommendation logic ──────────────────────────────────────
747
+ if (ctx && (hasDependency(deps, '@supabase/supabase-js') || hasDependency(deps, '@supabase/auth-helpers-nextjs') || hasFileContentMatch(ctx, '.env', /SUPABASE/i) || hasFileContentMatch(ctx, '.env.example', /SUPABASE/i))) {
748
+ recommended.add('supabase-mcp');
749
+ }
750
+ if (ctx && (hasFileContentMatch(ctx, 'schema.prisma', /\S/) || hasDependency(deps, '@prisma/client') || hasDependency(deps, 'prisma'))) {
751
+ recommended.add('prisma-mcp');
752
+ }
753
+ if (ctx && (ctx.files.includes('vercel.json') || ctx.files.includes('.vercel') || hasFileContentMatch(ctx, 'package.json', /"deploy":\s*"vercel/i) || hasFileContentMatch(ctx, '.env', /VERCEL_TOKEN/i))) {
754
+ recommended.add('vercel-mcp');
755
+ }
756
+ if (ctx && (hasFileContentMatch(ctx, 'wrangler.toml', /\S/) || hasFileContentMatch(ctx, 'wrangler.json', /\S/) || hasDependency(deps, 'wrangler') || hasFileContentMatch(ctx, '.env', /CLOUDFLARE/i))) {
757
+ recommended.add('cloudflare-mcp');
758
+ }
759
+ if (ctx && (hasFileContentMatch(ctx, '.env', /AWS_ACCESS_KEY/i) || hasFileContentMatch(ctx, '.env.example', /AWS_/i) || ctx.files.some(f => /serverless\.yml|template\.ya?ml|cdk\.json/.test(f)))) {
760
+ recommended.add('aws-mcp');
761
+ }
762
+ if (ctx && (hasDependency(deps, 'redis') || hasDependency(deps, 'ioredis') || hasDependency(deps, '@redis/client') || hasFileContentMatch(ctx, '.env', /REDIS_URL/i))) {
763
+ recommended.add('redis-mcp');
764
+ }
765
+ if (ctx && (hasDependency(deps, 'mongoose') || hasDependency(deps, 'mongodb') || hasFileContentMatch(ctx, '.env', /MONGODB_URI/i) || hasFileContentMatch(ctx, '.env.example', /MONGO/i))) {
766
+ recommended.add('mongodb-mcp');
767
+ }
768
+ if (ctx && (hasDependency(deps, 'twilio') || hasFileContentMatch(ctx, '.env', /TWILIO_/i) || hasFileContentMatch(ctx, '.env.example', /TWILIO_/i))) {
769
+ recommended.add('twilio-mcp');
770
+ }
771
+ if (ctx && (hasDependency(deps, '@sendgrid/mail') || hasDependency(deps, 'sendgrid') || hasFileContentMatch(ctx, '.env', /SENDGRID_API_KEY/i))) {
772
+ recommended.add('sendgrid-mcp');
773
+ }
774
+ if (ctx && (hasDependency(deps, 'algoliasearch') || hasDependency(deps, '@algolia/client-search') || hasFileContentMatch(ctx, '.env', /ALGOLIA_/i))) {
775
+ recommended.add('algolia-mcp');
776
+ }
777
+ if (ctx && (hasFileContentMatch(ctx, '.env', /PLANETSCALE_TOKEN/i) || hasFileContentMatch(ctx, '.env.example', /PLANETSCALE/i))) {
778
+ recommended.add('planetscale-mcp');
779
+ }
780
+ if (ctx && (hasDependency(deps, '@neondatabase/serverless') || hasFileContentMatch(ctx, '.env', /NEON_/i) || hasFileContentMatch(ctx, '.env.example', /NEON_/i))) {
781
+ recommended.add('neon-mcp');
782
+ }
783
+ if (ctx && (hasDependency(deps, '@libsql/client') || hasFileContentMatch(ctx, '.env', /TURSO_/i) || hasFileContentMatch(ctx, '.env.example', /TURSO_/i))) {
784
+ recommended.add('turso-mcp');
785
+ }
786
+ if (ctx && (hasDependency(deps, '@upstash/redis') || hasDependency(deps, '@upstash/kafka') || hasFileContentMatch(ctx, '.env', /UPSTASH_/i))) {
787
+ recommended.add('upstash-mcp');
788
+ }
789
+ if (ctx && (hasDependency(deps, 'convex') || hasDependency(deps, 'convex-dev') || hasFileContentMatch(ctx, 'convex.json', /\S/) || hasFileContentMatch(ctx, '.env', /CONVEX_/i))) {
790
+ recommended.add('convex-mcp');
791
+ }
792
+ if (ctx && (hasDependency(deps, '@clerk/nextjs') || hasDependency(deps, '@clerk/clerk-sdk-node') || hasDependency(deps, '@clerk/backend') || hasFileContentMatch(ctx, '.env', /CLERK_/i))) {
793
+ recommended.add('clerk-mcp');
794
+ }
795
+ if (ctx && (hasDependency(deps, 'resend') || hasFileContentMatch(ctx, '.env', /RESEND_API_KEY/i) || hasFileContentMatch(ctx, '.env.example', /RESEND_/i))) {
796
+ recommended.add('resend-mcp');
797
+ }
798
+ if (ctx && (hasDependency(deps, '@temporalio/client') || hasDependency(deps, '@temporalio/worker') || hasFileContentMatch(ctx, '.env', /TEMPORAL_/i))) {
799
+ recommended.add('temporal-mcp');
800
+ }
801
+ if (ctx && (hasDependency(deps, '@launchdarkly/node-server-sdk') || hasDependency(deps, 'launchdarkly-js-client-sdk') || hasFileContentMatch(ctx, '.env', /LAUNCHDARKLY_/i))) {
802
+ recommended.add('launchdarkly-mcp');
803
+ }
804
+ if (ctx && (hasDependency(deps, 'dd-trace') || hasDependency(deps, 'datadog-metrics') || hasFileContentMatch(ctx, '.env', /DATADOG_/i))) {
805
+ recommended.add('datadog-mcp');
806
+ }
807
+ if (ctx && (hasFileContentMatch(ctx, 'docker-compose.yml', /grafana/i) || hasFileContentMatch(ctx, '.env', /GRAFANA_/i) || ctx.files.some(f => /grafana/.test(f)))) {
808
+ recommended.add('grafana-mcp');
809
+ }
810
+ if (ctx && (ctx.files.some(f => /\.circleci\/config/.test(f)) || hasFileContentMatch(ctx, '.env', /CIRCLECI_/i))) {
811
+ recommended.add('circleci-mcp');
812
+ }
813
+ if (ctx && (hasDependency(deps, '@anthropic-ai/sdk') || hasDependency(deps, 'anthropic') || hasFileContentMatch(ctx, '.env', /ANTHROPIC_API_KEY/i) || hasFileContentMatch(ctx, '.env.example', /ANTHROPIC_/i))) {
814
+ recommended.add('anthropic-mcp');
815
+ }
816
+
817
+ return MCP_PACKS
818
+ .filter(pack => recommended.has(pack.key))
819
+ .map(pack => clone(pack));
820
+ }
821
+
822
+ module.exports = {
823
+ MCP_PACKS,
824
+ getMcpPack,
825
+ normalizeMcpPackKeys,
826
+ mergeMcpServers,
827
+ getRequiredEnvVars,
828
+ getMcpPackPreflight,
829
+ recommendMcpPacks,
830
+ };