github-to-mcp-monorepo 1.0.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 (388) hide show
  1. package/.env.example +8 -0
  2. package/.github/CODEOWNERS +6 -0
  3. package/.husky/pre-commit +1 -0
  4. package/.nvmrc +1 -0
  5. package/.prettierignore +5 -0
  6. package/.prettierrc +7 -0
  7. package/.vscode/settings.json +4 -0
  8. package/ARCHITECTURE.md +1429 -0
  9. package/CHANGELOG.md +167 -0
  10. package/CONTRIBUTING.md +327 -0
  11. package/LICENSE +201 -0
  12. package/README.md +1028 -0
  13. package/SECURITY.md +248 -0
  14. package/VISUAL_GUIDE.md +437 -0
  15. package/apps/vscode/IMPLEMENTATION.md +480 -0
  16. package/apps/vscode/README.md +248 -0
  17. package/apps/vscode/package.json +381 -0
  18. package/apps/vscode/resources/icon.png +0 -0
  19. package/apps/vscode/resources/icon.svg +5 -0
  20. package/apps/vscode/src/commands/browseRegistry.ts +211 -0
  21. package/apps/vscode/src/commands/configureClaudeDesktop.ts +332 -0
  22. package/apps/vscode/src/commands/convert.ts +82 -0
  23. package/apps/vscode/src/commands/convertCurrentRepo.ts +109 -0
  24. package/apps/vscode/src/commands/convertFromUrl.ts +138 -0
  25. package/apps/vscode/src/commands/index.ts +121 -0
  26. package/apps/vscode/src/commands/validate.ts +197 -0
  27. package/apps/vscode/src/extension.ts +464 -0
  28. package/apps/vscode/src/global.d.ts +36 -0
  29. package/apps/vscode/src/test/extension.test.ts +73 -0
  30. package/apps/vscode/src/utils/file-generator.ts +529 -0
  31. package/apps/vscode/src/utils/github-api.ts +335 -0
  32. package/apps/vscode/src/utils/index.ts +29 -0
  33. package/apps/vscode/src/utils/mcp-config.ts +334 -0
  34. package/apps/vscode/src/utils/storage.ts +87 -0
  35. package/apps/vscode/src/views/McpServersTreeView.ts +160 -0
  36. package/apps/vscode/src/views/OutputChannelView.ts +195 -0
  37. package/apps/vscode/src/views/StatusBarItem.ts +251 -0
  38. package/apps/vscode/src/views/ToolsExplorerView.ts +314 -0
  39. package/apps/vscode/src/views/historyProvider.ts +75 -0
  40. package/apps/vscode/src/views/index.ts +12 -0
  41. package/apps/vscode/src/views/resultsPanel.ts +330 -0
  42. package/apps/vscode/src/webviews/ConversionPanel.ts +350 -0
  43. package/apps/vscode/src/webviews/ToolDetailsPanel.ts +448 -0
  44. package/apps/vscode/src/webviews/index.ts +9 -0
  45. package/apps/vscode/src/webviews/webview-ui/styles.ts +492 -0
  46. package/apps/vscode/tsconfig.json +20 -0
  47. package/apps/web/PLAYGROUND_GUIDE.md +499 -0
  48. package/apps/web/README.md +505 -0
  49. package/apps/web/app/api/convert/route.ts +100 -0
  50. package/apps/web/app/api/convert/stream/route.ts +198 -0
  51. package/apps/web/app/api/deploy/route.ts +157 -0
  52. package/apps/web/app/api/edge/route.ts +308 -0
  53. package/apps/web/app/api/export-docker/route.ts +284 -0
  54. package/apps/web/app/api/generate-openapi/route.ts +119 -0
  55. package/apps/web/app/api/mcp/[serverId]/route.ts +263 -0
  56. package/apps/web/app/api/playground/connect/route.ts +143 -0
  57. package/apps/web/app/api/playground/disconnect/route.ts +78 -0
  58. package/apps/web/app/api/playground/execute/route.ts +135 -0
  59. package/apps/web/app/api/playground/sessions/route.ts +103 -0
  60. package/apps/web/app/api/playground/tools/route.ts +117 -0
  61. package/apps/web/app/api/playground/v2/connect/route.ts +96 -0
  62. package/apps/web/app/api/playground/v2/disconnect/route.ts +88 -0
  63. package/apps/web/app/api/playground/v2/health/route.ts +80 -0
  64. package/apps/web/app/api/playground/v2/prompts/route.ts +160 -0
  65. package/apps/web/app/api/playground/v2/resources/route.ts +159 -0
  66. package/apps/web/app/api/playground/v2/sessions/route.ts +184 -0
  67. package/apps/web/app/api/playground/v2/tools/route.ts +167 -0
  68. package/apps/web/app/api/stream/route.ts +232 -0
  69. package/apps/web/app/batch/BatchConvertClient.tsx +190 -0
  70. package/apps/web/app/batch/page.tsx +37 -0
  71. package/apps/web/app/convert/page.tsx +269 -0
  72. package/apps/web/app/dashboard/page.tsx +380 -0
  73. package/apps/web/app/globals.css +622 -0
  74. package/apps/web/app/layout.tsx +120 -0
  75. package/apps/web/app/manifest.ts +31 -0
  76. package/apps/web/app/opengraph-image.tsx +112 -0
  77. package/apps/web/app/page.old.tsx +924 -0
  78. package/apps/web/app/page.tsx +77 -0
  79. package/apps/web/app/playground/page.tsx +306 -0
  80. package/apps/web/app/playground/v2/error.tsx +163 -0
  81. package/apps/web/app/playground/v2/layout.tsx +58 -0
  82. package/apps/web/app/playground/v2/loading.tsx +152 -0
  83. package/apps/web/app/playground/v2/page.tsx +644 -0
  84. package/apps/web/app/playground/v2/providers.tsx +214 -0
  85. package/apps/web/app/playground/v2/use-shortcuts.ts +209 -0
  86. package/apps/web/app/playground/v2/use-url-state.ts +296 -0
  87. package/apps/web/app/providers.tsx +22 -0
  88. package/apps/web/app/sitemap.ts +32 -0
  89. package/apps/web/app/twitter-image.tsx +112 -0
  90. package/apps/web/components/BranchSelector.tsx +401 -0
  91. package/apps/web/components/ClaudeConfigExport.tsx +226 -0
  92. package/apps/web/components/Features.tsx +84 -0
  93. package/apps/web/components/Footer.tsx +119 -0
  94. package/apps/web/components/GenerationProgress.tsx +248 -0
  95. package/apps/web/components/GithubUrlInput.tsx +483 -0
  96. package/apps/web/components/Header.tsx +175 -0
  97. package/apps/web/components/Hero.tsx +117 -0
  98. package/apps/web/components/HowItWorks.tsx +119 -0
  99. package/apps/web/components/InstallBanner.tsx +158 -0
  100. package/apps/web/components/Logo.tsx +116 -0
  101. package/apps/web/components/ParticleBackground.tsx +105 -0
  102. package/apps/web/components/Playground.tsx +472 -0
  103. package/apps/web/components/PlaygroundToolTester.tsx +410 -0
  104. package/apps/web/components/ProductCards.tsx +179 -0
  105. package/apps/web/components/SplitView.tsx +194 -0
  106. package/apps/web/components/ToolFilter.tsx +260 -0
  107. package/apps/web/components/ToolList.tsx +325 -0
  108. package/apps/web/components/batch/BatchConvert.tsx +785 -0
  109. package/apps/web/components/batch/index.ts +7 -0
  110. package/apps/web/components/convert/ConfigTabs.tsx +230 -0
  111. package/apps/web/components/convert/ConversionResult.tsx +482 -0
  112. package/apps/web/components/convert/InlinePlayground.tsx +259 -0
  113. package/apps/web/components/convert/LoadingSteps.tsx +311 -0
  114. package/apps/web/components/convert/OneClickInstall.tsx +224 -0
  115. package/apps/web/components/convert/ToolCard.tsx +189 -0
  116. package/apps/web/components/convert/TryInPlayground.tsx +242 -0
  117. package/apps/web/components/convert/index.ts +12 -0
  118. package/apps/web/components/deploy/DeployButton.tsx +369 -0
  119. package/apps/web/components/deploy/index.ts +7 -0
  120. package/apps/web/components/docker/DockerExport.tsx +690 -0
  121. package/apps/web/components/docker/index.ts +7 -0
  122. package/apps/web/components/install/OneClickInstall.tsx +676 -0
  123. package/apps/web/components/install/index.ts +7 -0
  124. package/apps/web/components/playground/CapabilityTabs.tsx +150 -0
  125. package/apps/web/components/playground/ConnectionStatusV2.tsx +322 -0
  126. package/apps/web/components/playground/EmptyStates.tsx +305 -0
  127. package/apps/web/components/playground/ExecutionLog.tsx +260 -0
  128. package/apps/web/components/playground/ExecutionLogV2.tsx +378 -0
  129. package/apps/web/components/playground/JsonViewer.tsx +388 -0
  130. package/apps/web/components/playground/PlaygroundLayout.tsx +244 -0
  131. package/apps/web/components/playground/PromptsPanel.tsx +385 -0
  132. package/apps/web/components/playground/ResourcesPanel.tsx +378 -0
  133. package/apps/web/components/playground/SchemaForm.tsx +477 -0
  134. package/apps/web/components/playground/ServerStatus.tsx +151 -0
  135. package/apps/web/components/playground/ShareButton.tsx +239 -0
  136. package/apps/web/components/playground/ToolsPanel.tsx +309 -0
  137. package/apps/web/components/playground/TransportConfigurator.tsx +563 -0
  138. package/apps/web/components/playground/index.ts +74 -0
  139. package/apps/web/components/playground/types.ts +202 -0
  140. package/apps/web/components/streaming/StreamingProgress.tsx +441 -0
  141. package/apps/web/components/streaming/index.ts +7 -0
  142. package/apps/web/components/ui/badge.tsx +42 -0
  143. package/apps/web/components/ui/button.tsx +88 -0
  144. package/apps/web/components/ui/card.tsx +75 -0
  145. package/apps/web/components/ui/code-block.tsx +122 -0
  146. package/apps/web/components/ui/index.ts +12 -0
  147. package/apps/web/components/ui/input.tsx +55 -0
  148. package/apps/web/components/ui/tabs.tsx +61 -0
  149. package/apps/web/hooks/index.ts +85 -0
  150. package/apps/web/hooks/types.ts +1173 -0
  151. package/apps/web/hooks/use-conversion.ts +133 -0
  152. package/apps/web/hooks/use-execution-history.ts +376 -0
  153. package/apps/web/hooks/use-generation-progress.ts +147 -0
  154. package/apps/web/hooks/use-local-storage.ts +88 -0
  155. package/apps/web/hooks/use-mcp-client.ts +623 -0
  156. package/apps/web/hooks/use-mcp-connection.ts +500 -0
  157. package/apps/web/hooks/use-mcp-execution.ts +282 -0
  158. package/apps/web/hooks/use-mcp-prompts.ts +441 -0
  159. package/apps/web/hooks/use-mcp-resources.ts +430 -0
  160. package/apps/web/hooks/use-mcp-tools.ts +540 -0
  161. package/apps/web/hooks/use-playground-store.ts +299 -0
  162. package/apps/web/hooks/use-playground.ts +184 -0
  163. package/apps/web/hooks/use-streaming-conversion.ts +227 -0
  164. package/apps/web/hooks/useBatchConversion.ts +271 -0
  165. package/apps/web/hooks/useDockerConfig.ts +161 -0
  166. package/apps/web/hooks/usePlatformDetection.ts +80 -0
  167. package/apps/web/hooks/useStreaming.ts +199 -0
  168. package/apps/web/lib/api/errors.ts +386 -0
  169. package/apps/web/lib/api/index.ts +137 -0
  170. package/apps/web/lib/api/logger.ts +187 -0
  171. package/apps/web/lib/api/middleware.ts +364 -0
  172. package/apps/web/lib/api/openapi.ts +977 -0
  173. package/apps/web/lib/api/session-manager.ts +594 -0
  174. package/apps/web/lib/api/types.ts +433 -0
  175. package/apps/web/lib/api/validation.ts +523 -0
  176. package/apps/web/lib/constants.ts +114 -0
  177. package/apps/web/lib/mcp/client.ts +1137 -0
  178. package/apps/web/lib/mcp/events.ts +651 -0
  179. package/apps/web/lib/mcp/index.ts +347 -0
  180. package/apps/web/lib/mcp/logger.ts +428 -0
  181. package/apps/web/lib/mcp/metrics.ts +703 -0
  182. package/apps/web/lib/mcp/retry.ts +616 -0
  183. package/apps/web/lib/mcp/session-manager.ts +779 -0
  184. package/apps/web/lib/mcp/transports.ts +988 -0
  185. package/apps/web/lib/mcp/types.ts +594 -0
  186. package/apps/web/lib/mcp-client-enhanced.ts +871 -0
  187. package/apps/web/lib/mcp-client.ts +778 -0
  188. package/apps/web/lib/mcp-errors.ts +489 -0
  189. package/apps/web/lib/mcp-sandbox.ts +593 -0
  190. package/apps/web/lib/mcp-testing.ts +428 -0
  191. package/apps/web/lib/mcp-types.ts +448 -0
  192. package/apps/web/lib/playground-store.tsx +1147 -0
  193. package/apps/web/lib/utils.ts +439 -0
  194. package/apps/web/next-env.d.ts +5 -0
  195. package/apps/web/next.config.js +23 -0
  196. package/apps/web/package.json +55 -0
  197. package/apps/web/postcss.config.js +6 -0
  198. package/apps/web/public/.well-known/ai-plugin.json +17 -0
  199. package/apps/web/public/logo.svg +6 -0
  200. package/apps/web/public/robots.txt +22 -0
  201. package/apps/web/public/schema.json +27 -0
  202. package/apps/web/tailwind.config.js +26 -0
  203. package/apps/web/tailwind.config.ts +123 -0
  204. package/apps/web/tsconfig.json +20 -0
  205. package/apps/web/types/deploy.ts +139 -0
  206. package/apps/web/types/index.ts +247 -0
  207. package/apps/web/vercel.json +39 -0
  208. package/eslint.config.mjs +23 -0
  209. package/llms.txt +102 -0
  210. package/mkdocs/docs/api/core.md +318 -0
  211. package/mkdocs/docs/api/index.md +128 -0
  212. package/mkdocs/docs/api/mcp-server.md +301 -0
  213. package/mkdocs/docs/api/openapi-parser.md +254 -0
  214. package/mkdocs/docs/assets/logo.svg +7 -0
  215. package/mkdocs/docs/changelog.md +118 -0
  216. package/mkdocs/docs/cli/generate.md +148 -0
  217. package/mkdocs/docs/cli/index.md +52 -0
  218. package/mkdocs/docs/cli/inspect.md +164 -0
  219. package/mkdocs/docs/cli/serve.md +136 -0
  220. package/mkdocs/docs/concepts/classification.md +254 -0
  221. package/mkdocs/docs/concepts/how-it-works.md +299 -0
  222. package/mkdocs/docs/concepts/index.md +77 -0
  223. package/mkdocs/docs/concepts/mcp-protocol.md +362 -0
  224. package/mkdocs/docs/concepts/tool-types.md +382 -0
  225. package/mkdocs/docs/contributing/architecture.md +262 -0
  226. package/mkdocs/docs/contributing/development.md +245 -0
  227. package/mkdocs/docs/contributing/index.md +73 -0
  228. package/mkdocs/docs/contributing/testing.md +320 -0
  229. package/mkdocs/docs/getting-started/configuration.md +235 -0
  230. package/mkdocs/docs/getting-started/index.md +54 -0
  231. package/mkdocs/docs/getting-started/installation.md +145 -0
  232. package/mkdocs/docs/getting-started/quickstart.md +160 -0
  233. package/mkdocs/docs/guides/batch.md +375 -0
  234. package/mkdocs/docs/guides/claude-desktop.md +227 -0
  235. package/mkdocs/docs/guides/cursor.md +188 -0
  236. package/mkdocs/docs/guides/custom-tools.md +367 -0
  237. package/mkdocs/docs/guides/index.md +78 -0
  238. package/mkdocs/docs/guides/private-repos.md +221 -0
  239. package/mkdocs/docs/guides/vscode.md +247 -0
  240. package/mkdocs/docs/index.md +175 -0
  241. package/mkdocs/docs/reference/config.md +223 -0
  242. package/mkdocs/docs/reference/env.md +192 -0
  243. package/mkdocs/docs/reference/index.md +102 -0
  244. package/mkdocs/docs/reference/tools.md +309 -0
  245. package/mkdocs/docs/stylesheets/extra.css +231 -0
  246. package/mkdocs/mkdocs.yml +204 -0
  247. package/mkdocs/overrides/.gitkeep +1 -0
  248. package/mkdocs/overrides/main.html +7 -0
  249. package/mkdocs/python-deps.txt +7 -0
  250. package/mkdocs/vercel.json +11 -0
  251. package/package.json +63 -0
  252. package/packages/core/package.json +61 -0
  253. package/packages/core/src/__tests__/bitbucket-client.test.ts +366 -0
  254. package/packages/core/src/__tests__/cli.test.ts +235 -0
  255. package/packages/core/src/__tests__/code-extractor.test.ts +378 -0
  256. package/packages/core/src/__tests__/docker-generator.test.ts +255 -0
  257. package/packages/core/src/__tests__/github-client.test.ts +390 -0
  258. package/packages/core/src/__tests__/gitlab-client.test.ts +319 -0
  259. package/packages/core/src/__tests__/go-extractor.test.ts +351 -0
  260. package/packages/core/src/__tests__/graphql-extractor.test.ts +330 -0
  261. package/packages/core/src/__tests__/java-extractor.test.ts +497 -0
  262. package/packages/core/src/__tests__/plugins.test.ts +467 -0
  263. package/packages/core/src/__tests__/readme-extractor.test.ts +258 -0
  264. package/packages/core/src/__tests__/redis-cache.test.ts +307 -0
  265. package/packages/core/src/__tests__/rust-extractor.test.ts +252 -0
  266. package/packages/core/src/__tests__/streaming.test.ts +251 -0
  267. package/packages/core/src/additional-extractors.ts +333 -0
  268. package/packages/core/src/cache/cache-interface.ts +179 -0
  269. package/packages/core/src/cache/index.ts +210 -0
  270. package/packages/core/src/cache/redis-cache.ts +291 -0
  271. package/packages/core/src/cache/upstash-cache.ts +379 -0
  272. package/packages/core/src/cache.ts +251 -0
  273. package/packages/core/src/cli.ts +822 -0
  274. package/packages/core/src/code-extractor.ts +696 -0
  275. package/packages/core/src/docker-generator.ts +470 -0
  276. package/packages/core/src/edge-compatible.ts +491 -0
  277. package/packages/core/src/extractors/go-extractor.ts +791 -0
  278. package/packages/core/src/extractors/index.ts +9 -0
  279. package/packages/core/src/extractors/java-extractor.ts +937 -0
  280. package/packages/core/src/extractors/rust-extractor.ts +744 -0
  281. package/packages/core/src/github-client.ts +319 -0
  282. package/packages/core/src/go-generator.ts +356 -0
  283. package/packages/core/src/graphql-extractor.ts +358 -0
  284. package/packages/core/src/index.ts +797 -0
  285. package/packages/core/src/langchain-exporter.ts +617 -0
  286. package/packages/core/src/language-parsers.ts +1114 -0
  287. package/packages/core/src/mcp-introspector.ts +279 -0
  288. package/packages/core/src/monorepo-detector.ts +378 -0
  289. package/packages/core/src/plugins/index.ts +370 -0
  290. package/packages/core/src/plugins/registry.ts +404 -0
  291. package/packages/core/src/plugins/types.ts +215 -0
  292. package/packages/core/src/providers/base-provider.ts +246 -0
  293. package/packages/core/src/providers/bitbucket-client.ts +464 -0
  294. package/packages/core/src/providers/gitlab-client.ts +388 -0
  295. package/packages/core/src/providers/index.ts +176 -0
  296. package/packages/core/src/python-generator.ts +260 -0
  297. package/packages/core/src/queue/index.ts +100 -0
  298. package/packages/core/src/queue/memory-queue.ts +445 -0
  299. package/packages/core/src/queue/redis-queue.ts +578 -0
  300. package/packages/core/src/queue/types.ts +251 -0
  301. package/packages/core/src/readme-extractor.ts +409 -0
  302. package/packages/core/src/schema-generator.ts +638 -0
  303. package/packages/core/src/streaming.ts +999 -0
  304. package/packages/core/src/types.ts +289 -0
  305. package/packages/core/tsconfig.json +9 -0
  306. package/packages/core/tsup.config.ts +25 -0
  307. package/packages/mcp-server/README.md +297 -0
  308. package/packages/mcp-server/package.json +55 -0
  309. package/packages/mcp-server/src/__tests__/mcp-server.test.ts +177 -0
  310. package/packages/mcp-server/src/__tests__/tools.test.ts +217 -0
  311. package/packages/mcp-server/src/index.ts +1206 -0
  312. package/packages/mcp-server/src/prompts/index.ts +601 -0
  313. package/packages/mcp-server/src/tools/export-docker.ts +362 -0
  314. package/packages/mcp-server/src/tools/generate-openapi.ts +162 -0
  315. package/packages/mcp-server/src/tools/monitor-mcp-server.ts +448 -0
  316. package/packages/mcp-server/src/tools/stream-convert.ts +398 -0
  317. package/packages/mcp-server/src/tools/test-mcp-tool.ts +531 -0
  318. package/packages/mcp-server/tsconfig.json +12 -0
  319. package/packages/mcp-server/tsup.config.ts +14 -0
  320. package/packages/openapi-parser/package-lock.json +3028 -0
  321. package/packages/openapi-parser/package.json +41 -0
  322. package/packages/openapi-parser/src/analyzer.ts +700 -0
  323. package/packages/openapi-parser/src/asyncapi-parser.ts +475 -0
  324. package/packages/openapi-parser/src/cli.ts +302 -0
  325. package/packages/openapi-parser/src/generator.ts +570 -0
  326. package/packages/openapi-parser/src/generators/express-analyzer.ts +649 -0
  327. package/packages/openapi-parser/src/generators/fastapi-analyzer.ts +960 -0
  328. package/packages/openapi-parser/src/generators/index.ts +200 -0
  329. package/packages/openapi-parser/src/generators/nextjs-analyzer.ts +768 -0
  330. package/packages/openapi-parser/src/generators/openapi-builder.ts +527 -0
  331. package/packages/openapi-parser/src/generators/types.ts +298 -0
  332. package/packages/openapi-parser/src/graphql-parser.ts +462 -0
  333. package/packages/openapi-parser/src/grpc-parser.ts +649 -0
  334. package/packages/openapi-parser/src/har-parser.ts +723 -0
  335. package/packages/openapi-parser/src/index.ts +635 -0
  336. package/packages/openapi-parser/src/insomnia-parser.ts +614 -0
  337. package/packages/openapi-parser/src/parser.ts +231 -0
  338. package/packages/openapi-parser/src/postman-parser.ts +611 -0
  339. package/packages/openapi-parser/src/ref-resolver.ts +313 -0
  340. package/packages/openapi-parser/src/transformer.ts +459 -0
  341. package/packages/openapi-parser/tests/generators/express.test.ts +209 -0
  342. package/packages/openapi-parser/tests/generators/fastapi.test.ts +236 -0
  343. package/packages/openapi-parser/tests/generators/nextjs.test.ts +273 -0
  344. package/packages/openapi-parser/tests/parsers.test.ts +847 -0
  345. package/packages/openapi-parser/tsconfig.json +9 -0
  346. package/packages/openapi-parser/tsup.config.ts +11 -0
  347. package/packages/registry/package.json +59 -0
  348. package/packages/registry/src/cli.ts +456 -0
  349. package/packages/registry/src/index.ts +44 -0
  350. package/packages/registry/src/popular/github.json +47 -0
  351. package/packages/registry/src/popular/index.ts +55 -0
  352. package/packages/registry/src/popular/linear.json +42 -0
  353. package/packages/registry/src/popular/notion.json +42 -0
  354. package/packages/registry/src/popular/openai.json +40 -0
  355. package/packages/registry/src/popular/resend.json +38 -0
  356. package/packages/registry/src/popular/slack.json +42 -0
  357. package/packages/registry/src/popular/stripe.json +163 -0
  358. package/packages/registry/src/popular/supabase.json +42 -0
  359. package/packages/registry/src/popular/twilio.json +40 -0
  360. package/packages/registry/src/popular/vercel.json +40 -0
  361. package/packages/registry/src/registry.ts +492 -0
  362. package/packages/registry/src/storage.ts +334 -0
  363. package/packages/registry/src/types.ts +275 -0
  364. package/packages/registry/src/updater.ts +208 -0
  365. package/packages/registry/tsconfig.json +10 -0
  366. package/packages/registry/tsup.config.ts +11 -0
  367. package/pnpm-workspace.yaml +3 -0
  368. package/scripts/build-docs.sh +16 -0
  369. package/server.json +9 -0
  370. package/templates/Dockerfile.python.template +60 -0
  371. package/templates/Dockerfile.typescript.template +60 -0
  372. package/templates/docker-compose.template.yml +68 -0
  373. package/tests/fixtures/express-app/index.js +34 -0
  374. package/tests/fixtures/express-app/routes/posts.js +43 -0
  375. package/tests/fixtures/express-app/routes/users.js +58 -0
  376. package/tests/fixtures/fastapi-app/main.py +125 -0
  377. package/tests/fixtures/fastapi-app/routes/admin.py +42 -0
  378. package/tests/fixtures/graphql/simple-schema.graphql +65 -0
  379. package/tests/fixtures/mocks/github-api-responses.json +63 -0
  380. package/tests/fixtures/nextjs-app/app/api/posts/route.ts +55 -0
  381. package/tests/fixtures/nextjs-app/app/api/users/[id]/route.ts +63 -0
  382. package/tests/fixtures/nextjs-app/app/api/users/route.ts +44 -0
  383. package/tests/fixtures/nextjs-app/pages/api/health.ts +28 -0
  384. package/tests/fixtures/openapi/petstore.yaml +179 -0
  385. package/tests/integration/langchain-export.test.ts +405 -0
  386. package/tests/integration/openapi-conversion.test.ts +221 -0
  387. package/tsconfig.json +18 -0
  388. package/vitest.config.ts +32 -0
@@ -0,0 +1,616 @@
1
+ /**
2
+ * MCP Retry Utilities - Exponential backoff and circuit breaker patterns
3
+ * @copyright 2024-2026 nirholas
4
+ * @license MIT
5
+ */
6
+
7
+ import type { Logger } from './logger.js';
8
+ import { NoopLogger } from './logger.js';
9
+
10
+ // ============================================================================
11
+ // Retry Configuration
12
+ // ============================================================================
13
+
14
+ /**
15
+ * Retry strategy configuration
16
+ */
17
+ export interface RetryConfig {
18
+ /** Maximum number of retry attempts (default: 3) */
19
+ readonly maxAttempts: number;
20
+ /** Initial delay in milliseconds (default: 1000) */
21
+ readonly initialDelayMs: number;
22
+ /** Maximum delay in milliseconds (default: 30000) */
23
+ readonly maxDelayMs: number;
24
+ /** Backoff multiplier (default: 2.0) */
25
+ readonly backoffMultiplier: number;
26
+ /** Whether to add jitter to delays (default: true) */
27
+ readonly jitter: boolean;
28
+ /** Jitter factor (0-1) (default: 0.25) */
29
+ readonly jitterFactor: number;
30
+ /** Timeout for each attempt in milliseconds (default: 30000) */
31
+ readonly attemptTimeoutMs: number;
32
+ /** Whether to retry on timeout errors (default: true) */
33
+ readonly retryOnTimeout: boolean;
34
+ }
35
+
36
+ /**
37
+ * Default retry configuration
38
+ */
39
+ export const DEFAULT_RETRY_CONFIG: Readonly<RetryConfig> = {
40
+ maxAttempts: 3,
41
+ initialDelayMs: 1000,
42
+ maxDelayMs: 30_000,
43
+ backoffMultiplier: 2.0,
44
+ jitter: true,
45
+ jitterFactor: 0.25,
46
+ attemptTimeoutMs: 30_000,
47
+ retryOnTimeout: true,
48
+ } as const;
49
+
50
+ /**
51
+ * Partial retry configuration for customization
52
+ */
53
+ export type RetryOptions = Partial<RetryConfig>;
54
+
55
+ // ============================================================================
56
+ // Retry Context
57
+ // ============================================================================
58
+
59
+ /**
60
+ * Context passed to retry callbacks
61
+ */
62
+ export interface RetryContext {
63
+ /** Current attempt number (1-based) */
64
+ readonly attempt: number;
65
+ /** Total attempts allowed */
66
+ readonly maxAttempts: number;
67
+ /** Time since first attempt in ms */
68
+ readonly elapsedMs: number;
69
+ /** Previous error if any */
70
+ readonly lastError?: Error;
71
+ /** Whether this is the last attempt */
72
+ readonly isLastAttempt: boolean;
73
+ }
74
+
75
+ /**
76
+ * Retry result with attempt details
77
+ */
78
+ export interface RetryResult<T> {
79
+ /** Whether the operation succeeded */
80
+ readonly success: boolean;
81
+ /** Result value if successful */
82
+ readonly value?: T;
83
+ /** Error if failed */
84
+ readonly error?: Error;
85
+ /** Number of attempts made */
86
+ readonly attempts: number;
87
+ /** Total time elapsed in ms */
88
+ readonly elapsedMs: number;
89
+ /** Whether retries were exhausted */
90
+ readonly retriesExhausted: boolean;
91
+ }
92
+
93
+ /**
94
+ * Function type for retry predicate
95
+ */
96
+ export type RetryPredicate = (error: Error, context: RetryContext) => boolean;
97
+
98
+ /**
99
+ * Function type for delay customization
100
+ */
101
+ export type DelayFunction = (attempt: number, config: RetryConfig) => number;
102
+
103
+ // ============================================================================
104
+ // Retry Implementation
105
+ // ============================================================================
106
+
107
+ /**
108
+ * Calculate delay with exponential backoff and optional jitter
109
+ *
110
+ * @param attempt - Current attempt number (1-based)
111
+ * @param config - Retry configuration
112
+ * @returns Delay in milliseconds
113
+ */
114
+ export function calculateBackoffDelay(attempt: number, config: RetryConfig): number {
115
+ // Exponential backoff: initialDelay * multiplier^(attempt-1)
116
+ const exponentialDelay = config.initialDelayMs * Math.pow(config.backoffMultiplier, attempt - 1);
117
+
118
+ // Clamp to maxDelay
119
+ let delay = Math.min(exponentialDelay, config.maxDelayMs);
120
+
121
+ // Add jitter if enabled
122
+ if (config.jitter) {
123
+ const jitterRange = delay * config.jitterFactor;
124
+ const jitter = (Math.random() - 0.5) * 2 * jitterRange;
125
+ delay = Math.max(0, delay + jitter);
126
+ }
127
+
128
+ return Math.round(delay);
129
+ }
130
+
131
+ /**
132
+ * Default retry predicate - retries on all errors except AbortError
133
+ */
134
+ export const defaultRetryPredicate: RetryPredicate = (error: Error, context: RetryContext) => {
135
+ // Don't retry if this was the last attempt
136
+ if (context.isLastAttempt) {
137
+ return false;
138
+ }
139
+
140
+ // Don't retry abort errors
141
+ if (error.name === 'AbortError') {
142
+ return false;
143
+ }
144
+
145
+ // Don't retry authentication errors
146
+ if (error.message.toLowerCase().includes('unauthorized') ||
147
+ error.message.toLowerCase().includes('forbidden') ||
148
+ error.message.toLowerCase().includes('authentication')) {
149
+ return false;
150
+ }
151
+
152
+ // Retry all other errors
153
+ return true;
154
+ };
155
+
156
+ /**
157
+ * Create a retry predicate that only retries specific error types
158
+ */
159
+ export function createRetryPredicate(
160
+ retryableErrors: (new (...args: unknown[]) => Error)[]
161
+ ): RetryPredicate {
162
+ return (error: Error, context: RetryContext) => {
163
+ if (context.isLastAttempt) {
164
+ return false;
165
+ }
166
+ return retryableErrors.some((ErrorType) => error instanceof ErrorType);
167
+ };
168
+ }
169
+
170
+ /**
171
+ * Sleep for a specified duration
172
+ */
173
+ function sleep(ms: number, signal?: AbortSignal): Promise<void> {
174
+ return new Promise((resolve, reject) => {
175
+ if (signal?.aborted) {
176
+ reject(new DOMException('Aborted', 'AbortError'));
177
+ return;
178
+ }
179
+
180
+ const timeoutId = setTimeout(resolve, ms);
181
+
182
+ signal?.addEventListener('abort', () => {
183
+ clearTimeout(timeoutId);
184
+ reject(new DOMException('Aborted', 'AbortError'));
185
+ }, { once: true });
186
+ });
187
+ }
188
+
189
+ /**
190
+ * Execute an operation with retry logic
191
+ *
192
+ * @param operation - Async operation to execute
193
+ * @param options - Retry options
194
+ * @param shouldRetry - Optional custom retry predicate
195
+ * @param signal - Optional abort signal
196
+ * @param logger - Optional logger
197
+ * @returns Retry result
198
+ *
199
+ * @example
200
+ * ```typescript
201
+ * const result = await retry(
202
+ * async () => {
203
+ * const response = await fetch('https://api.example.com/data');
204
+ * if (!response.ok) throw new Error(`HTTP ${response.status}`);
205
+ * return response.json();
206
+ * },
207
+ * { maxAttempts: 5, initialDelayMs: 500 }
208
+ * );
209
+ *
210
+ * if (result.success) {
211
+ * console.log('Data:', result.value);
212
+ * } else {
213
+ * console.error('Failed after', result.attempts, 'attempts:', result.error);
214
+ * }
215
+ * ```
216
+ */
217
+ export async function retry<T>(
218
+ operation: (context: RetryContext) => Promise<T>,
219
+ options: RetryOptions = {},
220
+ shouldRetry: RetryPredicate = defaultRetryPredicate,
221
+ signal?: AbortSignal,
222
+ logger: Logger = new NoopLogger()
223
+ ): Promise<RetryResult<T>> {
224
+ const config: RetryConfig = { ...DEFAULT_RETRY_CONFIG, ...options };
225
+ const startTime = Date.now();
226
+ let lastError: Error | undefined;
227
+
228
+ for (let attempt = 1; attempt <= config.maxAttempts; attempt++) {
229
+ const context: RetryContext = {
230
+ attempt,
231
+ maxAttempts: config.maxAttempts,
232
+ elapsedMs: Date.now() - startTime,
233
+ lastError,
234
+ isLastAttempt: attempt === config.maxAttempts,
235
+ };
236
+
237
+ try {
238
+ // Check abort signal
239
+ if (signal?.aborted) {
240
+ throw new DOMException('Operation aborted', 'AbortError');
241
+ }
242
+
243
+ logger.debug(`Attempt ${attempt}/${config.maxAttempts}`, { data: { attempt } });
244
+
245
+ // Execute with timeout
246
+ const value = await executeWithTimeout(
247
+ () => operation(context),
248
+ config.attemptTimeoutMs,
249
+ signal
250
+ );
251
+
252
+ return {
253
+ success: true,
254
+ value,
255
+ attempts: attempt,
256
+ elapsedMs: Date.now() - startTime,
257
+ retriesExhausted: false,
258
+ };
259
+ } catch (error) {
260
+ lastError = error instanceof Error ? error : new Error(String(error));
261
+
262
+ // Update context with error
263
+ const errorContext: RetryContext = {
264
+ ...context,
265
+ lastError,
266
+ };
267
+
268
+ logger.debug(`Attempt ${attempt} failed: ${lastError.message}`, {
269
+ data: { attempt, error: lastError.message },
270
+ });
271
+
272
+ // Check if we should retry
273
+ if (!shouldRetry(lastError, errorContext)) {
274
+ logger.debug('Not retrying - predicate returned false');
275
+ return {
276
+ success: false,
277
+ error: lastError,
278
+ attempts: attempt,
279
+ elapsedMs: Date.now() - startTime,
280
+ retriesExhausted: false,
281
+ };
282
+ }
283
+
284
+ // Don't delay after the last attempt
285
+ if (attempt < config.maxAttempts) {
286
+ const delay = calculateBackoffDelay(attempt, config);
287
+ logger.debug(`Waiting ${delay}ms before retry`, { data: { delay } });
288
+
289
+ try {
290
+ await sleep(delay, signal);
291
+ } catch (sleepError) {
292
+ // Abort signal was triggered during sleep
293
+ return {
294
+ success: false,
295
+ error: sleepError instanceof Error ? sleepError : new Error(String(sleepError)),
296
+ attempts: attempt,
297
+ elapsedMs: Date.now() - startTime,
298
+ retriesExhausted: false,
299
+ };
300
+ }
301
+ }
302
+ }
303
+ }
304
+
305
+ // All retries exhausted
306
+ return {
307
+ success: false,
308
+ error: lastError ?? new Error('Unknown error'),
309
+ attempts: config.maxAttempts,
310
+ elapsedMs: Date.now() - startTime,
311
+ retriesExhausted: true,
312
+ };
313
+ }
314
+
315
+ /**
316
+ * Execute an operation with timeout
317
+ */
318
+ async function executeWithTimeout<T>(
319
+ operation: () => Promise<T>,
320
+ timeoutMs: number,
321
+ signal?: AbortSignal
322
+ ): Promise<T> {
323
+ // Create timeout promise
324
+ const timeoutPromise = new Promise<never>((_, reject) => {
325
+ const timeoutId = setTimeout(() => {
326
+ reject(new Error(`Operation timed out after ${timeoutMs}ms`));
327
+ }, timeoutMs);
328
+
329
+ // Clean up timeout if signal is aborted
330
+ signal?.addEventListener('abort', () => clearTimeout(timeoutId), { once: true });
331
+ });
332
+
333
+ return Promise.race([operation(), timeoutPromise]);
334
+ }
335
+
336
+ // ============================================================================
337
+ // Circuit Breaker
338
+ // ============================================================================
339
+
340
+ /**
341
+ * Circuit breaker state
342
+ */
343
+ export type CircuitState = 'closed' | 'open' | 'half-open';
344
+
345
+ /**
346
+ * Circuit breaker configuration
347
+ */
348
+ export interface CircuitBreakerConfig {
349
+ /** Number of failures before opening circuit (default: 5) */
350
+ readonly failureThreshold: number;
351
+ /** Time in ms before attempting to close circuit (default: 60000) */
352
+ readonly resetTimeoutMs: number;
353
+ /** Number of successes needed to close circuit from half-open (default: 2) */
354
+ readonly successThreshold: number;
355
+ /** Timeout for operations in ms (default: 30000) */
356
+ readonly operationTimeoutMs: number;
357
+ }
358
+
359
+ /**
360
+ * Default circuit breaker configuration
361
+ */
362
+ export const DEFAULT_CIRCUIT_BREAKER_CONFIG: Readonly<CircuitBreakerConfig> = {
363
+ failureThreshold: 5,
364
+ resetTimeoutMs: 60_000,
365
+ successThreshold: 2,
366
+ operationTimeoutMs: 30_000,
367
+ } as const;
368
+
369
+ /**
370
+ * Circuit breaker statistics
371
+ */
372
+ export interface CircuitBreakerStats {
373
+ readonly state: CircuitState;
374
+ readonly failures: number;
375
+ readonly successes: number;
376
+ readonly lastFailure?: Date;
377
+ readonly lastSuccess?: Date;
378
+ readonly lastStateChange: Date;
379
+ readonly totalRequests: number;
380
+ readonly totalFailures: number;
381
+ readonly totalSuccesses: number;
382
+ }
383
+
384
+ /**
385
+ * Circuit breaker error thrown when circuit is open
386
+ */
387
+ export class CircuitOpenError extends Error {
388
+ readonly name = 'CircuitOpenError';
389
+ readonly resetTime: Date;
390
+
391
+ constructor(resetTime: Date) {
392
+ super(`Circuit is open. Will attempt reset at ${resetTime.toISOString()}`);
393
+ this.resetTime = resetTime;
394
+ }
395
+ }
396
+
397
+ /**
398
+ * Circuit breaker for preventing cascading failures
399
+ *
400
+ * @example
401
+ * ```typescript
402
+ * const breaker = new CircuitBreaker({ failureThreshold: 3 });
403
+ *
404
+ * try {
405
+ * const result = await breaker.execute(async () => {
406
+ * return await riskyOperation();
407
+ * });
408
+ * } catch (error) {
409
+ * if (error instanceof CircuitOpenError) {
410
+ * console.log('Circuit is open, try again at', error.resetTime);
411
+ * }
412
+ * }
413
+ * ```
414
+ */
415
+ export class CircuitBreaker {
416
+ private readonly _config: CircuitBreakerConfig;
417
+ private readonly _logger: Logger;
418
+ private _state: CircuitState = 'closed';
419
+ private _failures = 0;
420
+ private _successes = 0;
421
+ private _lastFailure?: Date;
422
+ private _lastSuccess?: Date;
423
+ private _lastStateChange = new Date();
424
+ private _totalRequests = 0;
425
+ private _totalFailures = 0;
426
+ private _totalSuccesses = 0;
427
+ private _resetTimer?: ReturnType<typeof setTimeout>;
428
+
429
+ constructor(config: Partial<CircuitBreakerConfig> = {}, logger: Logger = new NoopLogger()) {
430
+ this._config = { ...DEFAULT_CIRCUIT_BREAKER_CONFIG, ...config };
431
+ this._logger = logger;
432
+ }
433
+
434
+ /**
435
+ * Current circuit state
436
+ */
437
+ get state(): CircuitState {
438
+ return this._state;
439
+ }
440
+
441
+ /**
442
+ * Get circuit breaker statistics
443
+ */
444
+ get stats(): CircuitBreakerStats {
445
+ return {
446
+ state: this._state,
447
+ failures: this._failures,
448
+ successes: this._successes,
449
+ lastFailure: this._lastFailure,
450
+ lastSuccess: this._lastSuccess,
451
+ lastStateChange: this._lastStateChange,
452
+ totalRequests: this._totalRequests,
453
+ totalFailures: this._totalFailures,
454
+ totalSuccesses: this._totalSuccesses,
455
+ };
456
+ }
457
+
458
+ /**
459
+ * Execute an operation through the circuit breaker
460
+ *
461
+ * @param operation - Operation to execute
462
+ * @returns Operation result
463
+ * @throws {CircuitOpenError} If circuit is open
464
+ */
465
+ async execute<T>(operation: () => Promise<T>): Promise<T> {
466
+ this._totalRequests++;
467
+
468
+ // Check if circuit is open
469
+ if (this._state === 'open') {
470
+ const resetTime = new Date(this._lastStateChange.getTime() + this._config.resetTimeoutMs);
471
+ const now = new Date();
472
+
473
+ if (now < resetTime) {
474
+ throw new CircuitOpenError(resetTime);
475
+ }
476
+
477
+ // Transition to half-open
478
+ this._transitionTo('half-open');
479
+ }
480
+
481
+ try {
482
+ // Execute with timeout
483
+ const result = await executeWithTimeout(operation, this._config.operationTimeoutMs);
484
+ this._recordSuccess();
485
+ return result;
486
+ } catch (error) {
487
+ this._recordFailure();
488
+ throw error;
489
+ }
490
+ }
491
+
492
+ /**
493
+ * Manually reset the circuit breaker
494
+ */
495
+ reset(): void {
496
+ this._failures = 0;
497
+ this._successes = 0;
498
+ this._transitionTo('closed');
499
+ this._clearResetTimer();
500
+ this._logger.info('Circuit breaker manually reset');
501
+ }
502
+
503
+ /**
504
+ * Force the circuit to open
505
+ */
506
+ forceOpen(): void {
507
+ this._transitionTo('open');
508
+ this._logger.warn('Circuit breaker forced open');
509
+ }
510
+
511
+ /**
512
+ * Dispose of the circuit breaker
513
+ */
514
+ dispose(): void {
515
+ this._clearResetTimer();
516
+ }
517
+
518
+ private _recordSuccess(): void {
519
+ this._successes++;
520
+ this._totalSuccesses++;
521
+ this._lastSuccess = new Date();
522
+ this._failures = 0; // Reset failure count on success
523
+
524
+ if (this._state === 'half-open') {
525
+ if (this._successes >= this._config.successThreshold) {
526
+ this._transitionTo('closed');
527
+ }
528
+ }
529
+ }
530
+
531
+ private _recordFailure(): void {
532
+ this._failures++;
533
+ this._totalFailures++;
534
+ this._lastFailure = new Date();
535
+ this._successes = 0; // Reset success count on failure
536
+
537
+ if (this._state === 'closed') {
538
+ if (this._failures >= this._config.failureThreshold) {
539
+ this._transitionTo('open');
540
+ this._scheduleReset();
541
+ }
542
+ } else if (this._state === 'half-open') {
543
+ // Any failure in half-open state opens the circuit
544
+ this._transitionTo('open');
545
+ this._scheduleReset();
546
+ }
547
+ }
548
+
549
+ private _transitionTo(newState: CircuitState): void {
550
+ const previousState = this._state;
551
+ this._state = newState;
552
+ this._lastStateChange = new Date();
553
+ this._logger.info(`Circuit breaker: ${previousState} -> ${newState}`);
554
+ }
555
+
556
+ private _scheduleReset(): void {
557
+ this._clearResetTimer();
558
+ this._resetTimer = setTimeout(() => {
559
+ if (this._state === 'open') {
560
+ this._transitionTo('half-open');
561
+ }
562
+ }, this._config.resetTimeoutMs);
563
+ }
564
+
565
+ private _clearResetTimer(): void {
566
+ if (this._resetTimer) {
567
+ clearTimeout(this._resetTimer);
568
+ this._resetTimer = undefined;
569
+ }
570
+ }
571
+ }
572
+
573
+ // ============================================================================
574
+ // Retry with Circuit Breaker
575
+ // ============================================================================
576
+
577
+ /**
578
+ * Combined retry and circuit breaker options
579
+ */
580
+ export interface RetryWithCircuitBreakerOptions {
581
+ readonly retry?: RetryOptions;
582
+ readonly circuitBreaker?: Partial<CircuitBreakerConfig>;
583
+ }
584
+
585
+ /**
586
+ * Execute an operation with both retry logic and circuit breaker protection
587
+ *
588
+ * @param operation - Operation to execute
589
+ * @param options - Combined options
590
+ * @param signal - Optional abort signal
591
+ * @param logger - Optional logger
592
+ * @returns Retry result
593
+ */
594
+ export async function retryWithCircuitBreaker<T>(
595
+ operation: (context: RetryContext) => Promise<T>,
596
+ circuitBreaker: CircuitBreaker,
597
+ options: RetryOptions = {},
598
+ signal?: AbortSignal,
599
+ logger: Logger = new NoopLogger()
600
+ ): Promise<RetryResult<T>> {
601
+ return retry(
602
+ async (context) => {
603
+ return circuitBreaker.execute(() => operation(context));
604
+ },
605
+ options,
606
+ (error, context) => {
607
+ // Don't retry circuit open errors
608
+ if (error instanceof CircuitOpenError) {
609
+ return false;
610
+ }
611
+ return defaultRetryPredicate(error, context);
612
+ },
613
+ signal,
614
+ logger
615
+ );
616
+ }