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,999 @@
1
+ /**
2
+ * @fileoverview Streaming generation for GitHub to MCP conversion
3
+ * @copyright Copyright (c) 2024-2026 nirholas
4
+ * @license MIT
5
+ */
6
+
7
+ import { GithubToMcpGenerator } from './index';
8
+ import {
9
+ GithubToMcpOptions,
10
+ ExtractedTool,
11
+ SourceBreakdown,
12
+ RepoClassification,
13
+ GenerationResult,
14
+ SourceType
15
+ } from './types';
16
+
17
+ /**
18
+ * Event types emitted during streaming generation
19
+ */
20
+ export type StreamEventType =
21
+ | 'start'
22
+ | 'metadata'
23
+ | 'classifying'
24
+ | 'classified'
25
+ | 'extracting'
26
+ | 'tool-found'
27
+ | 'source-complete'
28
+ | 'generating'
29
+ | 'complete'
30
+ | 'error'
31
+ | 'progress';
32
+
33
+ /**
34
+ * Base interface for all stream events
35
+ */
36
+ export interface BaseStreamEvent {
37
+ type: StreamEventType;
38
+ timestamp: number;
39
+ }
40
+
41
+ /**
42
+ * Emitted when generation starts
43
+ */
44
+ export interface StartEvent extends BaseStreamEvent {
45
+ type: 'start';
46
+ url: string;
47
+ owner: string;
48
+ repo: string;
49
+ }
50
+
51
+ /**
52
+ * Emitted when repository metadata is fetched
53
+ */
54
+ export interface MetadataEvent extends BaseStreamEvent {
55
+ type: 'metadata';
56
+ metadata: {
57
+ stars: number;
58
+ language: string;
59
+ license?: string;
60
+ description?: string;
61
+ };
62
+ }
63
+
64
+ /**
65
+ * Emitted when classification begins
66
+ */
67
+ export interface ClassifyingEvent extends BaseStreamEvent {
68
+ type: 'classifying';
69
+ message: string;
70
+ }
71
+
72
+ /**
73
+ * Emitted when classification completes
74
+ */
75
+ export interface ClassifiedEvent extends BaseStreamEvent {
76
+ type: 'classified';
77
+ classification: RepoClassification;
78
+ }
79
+
80
+ /**
81
+ * Emitted when extraction from a source begins
82
+ */
83
+ export interface ExtractingEvent extends BaseStreamEvent {
84
+ type: 'extracting';
85
+ source: SourceType;
86
+ message: string;
87
+ }
88
+
89
+ /**
90
+ * Emitted when a tool is found
91
+ */
92
+ export interface ToolFoundEvent extends BaseStreamEvent {
93
+ type: 'tool-found';
94
+ tool: ExtractedTool;
95
+ source: SourceType;
96
+ totalFound: number;
97
+ }
98
+
99
+ /**
100
+ * Emitted when extraction from a source completes
101
+ */
102
+ export interface SourceCompleteEvent extends BaseStreamEvent {
103
+ type: 'source-complete';
104
+ source: SourceType;
105
+ toolCount: number;
106
+ files: string[];
107
+ }
108
+
109
+ /**
110
+ * Emitted when code generation begins
111
+ */
112
+ export interface GeneratingEvent extends BaseStreamEvent {
113
+ type: 'generating';
114
+ language: 'typescript' | 'python';
115
+ toolCount: number;
116
+ }
117
+
118
+ /**
119
+ * Emitted when generation completes successfully
120
+ */
121
+ export interface CompleteEvent extends BaseStreamEvent {
122
+ type: 'complete';
123
+ result: GenerationResult;
124
+ totalTools: number;
125
+ sources: SourceBreakdown[];
126
+ duration: number;
127
+ }
128
+
129
+ /**
130
+ * Emitted when an error occurs
131
+ */
132
+ export interface ErrorEvent extends BaseStreamEvent {
133
+ type: 'error';
134
+ error: Error;
135
+ phase: string;
136
+ recoverable: boolean;
137
+ }
138
+
139
+ /**
140
+ * Progress update event
141
+ */
142
+ export interface ProgressEvent extends BaseStreamEvent {
143
+ type: 'progress';
144
+ phase: string;
145
+ progress: number; // 0-100
146
+ message: string;
147
+ }
148
+
149
+ /**
150
+ * Union of all stream event types
151
+ */
152
+ export type StreamEvent =
153
+ | StartEvent
154
+ | MetadataEvent
155
+ | ClassifyingEvent
156
+ | ClassifiedEvent
157
+ | ExtractingEvent
158
+ | ToolFoundEvent
159
+ | SourceCompleteEvent
160
+ | GeneratingEvent
161
+ | CompleteEvent
162
+ | ErrorEvent
163
+ | ProgressEvent;
164
+
165
+ /**
166
+ * Options for streaming generation
167
+ */
168
+ export interface StreamOptions extends GithubToMcpOptions {
169
+ /** Emit progress events with percentage */
170
+ emitProgress?: boolean;
171
+ /** Minimum interval between tool-found events in ms (debouncing) */
172
+ toolEventDebounce?: number;
173
+ /** Abort signal for cancellation */
174
+ abortSignal?: AbortSignal;
175
+ }
176
+
177
+ /**
178
+ * Create a timestamp for events
179
+ */
180
+ function timestamp(): number {
181
+ return Date.now();
182
+ }
183
+
184
+ /**
185
+ * Streaming generator class that wraps the main generator
186
+ * and yields events as extraction progresses
187
+ */
188
+ export class StreamingGenerator {
189
+ private options: StreamOptions;
190
+ private toolCount: number = 0;
191
+ private startTime: number = 0;
192
+
193
+ constructor(options: StreamOptions = {}) {
194
+ this.options = options;
195
+ }
196
+
197
+ /**
198
+ * Stream generation events as an async generator
199
+ */
200
+ async *generate(githubUrl: string): AsyncGenerator<StreamEvent, void, unknown> {
201
+ this.startTime = Date.now();
202
+ this.toolCount = 0;
203
+
204
+ // Import dynamically to avoid circular dependencies
205
+ const { GithubClient } = await import('./github-client');
206
+ const { ReadmeExtractor } = await import('./readme-extractor');
207
+ const { CodeExtractor } = await import('./code-extractor');
208
+ const { GraphQLExtractor } = await import('./graphql-extractor');
209
+ const { McpIntrospector } = await import('./mcp-introspector');
210
+ const { PythonGenerator } = await import('./python-generator');
211
+ const { convertOpenApiToMcp } = await import('@github-to-mcp/openapi-parser');
212
+
213
+ const github = new GithubClient(this.options.githubToken);
214
+ const readmeExtractor = new ReadmeExtractor();
215
+ const codeExtractor = new CodeExtractor();
216
+ const graphqlExtractor = new GraphQLExtractor();
217
+ const mcpIntrospector = new McpIntrospector();
218
+ const pythonGenerator = new PythonGenerator();
219
+
220
+ try {
221
+ // Check for abort signal
222
+ if (this.options.abortSignal?.aborted) {
223
+ throw new Error('Generation aborted');
224
+ }
225
+
226
+ // Parse GitHub URL
227
+ const repoMeta = github.parseGithubUrl(githubUrl);
228
+
229
+ // Emit start event
230
+ yield {
231
+ type: 'start',
232
+ timestamp: timestamp(),
233
+ url: githubUrl,
234
+ owner: repoMeta.owner,
235
+ repo: repoMeta.repo
236
+ };
237
+
238
+ // Emit progress
239
+ if (this.options.emitProgress) {
240
+ yield {
241
+ type: 'progress',
242
+ timestamp: timestamp(),
243
+ phase: 'fetching',
244
+ progress: 5,
245
+ message: 'Fetching repository metadata...'
246
+ };
247
+ }
248
+
249
+ // Get repository metadata
250
+ const metadata = await github.getRepoMetadata(repoMeta.owner, repoMeta.repo);
251
+
252
+ yield {
253
+ type: 'metadata',
254
+ timestamp: timestamp(),
255
+ metadata: {
256
+ stars: metadata.stars,
257
+ language: metadata.language,
258
+ license: metadata.license,
259
+ description: metadata.description
260
+ }
261
+ };
262
+
263
+ // Check for abort
264
+ if (this.options.abortSignal?.aborted) {
265
+ throw new Error('Generation aborted');
266
+ }
267
+
268
+ // Get README
269
+ const readme = await github.getReadme(repoMeta.owner, repoMeta.repo);
270
+
271
+ // Emit classifying event
272
+ yield {
273
+ type: 'classifying',
274
+ timestamp: timestamp(),
275
+ message: 'Analyzing repository type...'
276
+ };
277
+
278
+ if (this.options.emitProgress) {
279
+ yield {
280
+ type: 'progress',
281
+ timestamp: timestamp(),
282
+ phase: 'classifying',
283
+ progress: 15,
284
+ message: 'Classifying repository...'
285
+ };
286
+ }
287
+
288
+ // Classify repository
289
+ const classification = await this.classifyRepo(github, repoMeta.owner, repoMeta.repo, readme, metadata);
290
+
291
+ yield {
292
+ type: 'classified',
293
+ timestamp: timestamp(),
294
+ classification
295
+ };
296
+
297
+ // Prepare for extraction
298
+ const tools: ExtractedTool[] = [];
299
+ const sources: SourceBreakdown[] = [];
300
+ const enabledSources = this.options.sources || ['readme', 'openapi', 'code'];
301
+
302
+ let progressBase = 20;
303
+ const progressPerSource = 60 / (enabledSources.length + 2); // +2 for graphql and universal
304
+
305
+ // 1. Extract from OpenAPI specs
306
+ if (enabledSources.includes('openapi')) {
307
+ if (this.options.abortSignal?.aborted) throw new Error('Generation aborted');
308
+
309
+ yield {
310
+ type: 'extracting',
311
+ timestamp: timestamp(),
312
+ source: 'openapi',
313
+ message: 'Searching for OpenAPI/Swagger specifications...'
314
+ };
315
+
316
+ const openapiTools = await this.extractFromOpenApi(github, repoMeta.owner, repoMeta.repo, convertOpenApiToMcp);
317
+
318
+ for (const tool of openapiTools) {
319
+ this.toolCount++;
320
+ tools.push(tool);
321
+ yield {
322
+ type: 'tool-found',
323
+ timestamp: timestamp(),
324
+ tool,
325
+ source: 'openapi',
326
+ totalFound: this.toolCount
327
+ };
328
+ }
329
+
330
+ if (openapiTools.length > 0) {
331
+ sources.push({
332
+ type: 'openapi',
333
+ count: openapiTools.length,
334
+ files: [...new Set(openapiTools.map(t => t.source.file))]
335
+ });
336
+ }
337
+
338
+ yield {
339
+ type: 'source-complete',
340
+ timestamp: timestamp(),
341
+ source: 'openapi',
342
+ toolCount: openapiTools.length,
343
+ files: openapiTools.length > 0 ? [...new Set(openapiTools.map(t => t.source.file))] : []
344
+ };
345
+
346
+ progressBase += progressPerSource;
347
+ if (this.options.emitProgress) {
348
+ yield {
349
+ type: 'progress',
350
+ timestamp: timestamp(),
351
+ phase: 'extracting',
352
+ progress: Math.round(progressBase),
353
+ message: `Extracted ${openapiTools.length} tools from OpenAPI specs`
354
+ };
355
+ }
356
+ }
357
+
358
+ // 2. Extract from README
359
+ if (enabledSources.includes('readme')) {
360
+ if (this.options.abortSignal?.aborted) throw new Error('Generation aborted');
361
+
362
+ yield {
363
+ type: 'extracting',
364
+ timestamp: timestamp(),
365
+ source: 'readme',
366
+ message: 'Extracting tools from README documentation...'
367
+ };
368
+
369
+ const readmeTools = await this.extractFromReadme(readmeExtractor, readme, repoMeta.repo);
370
+
371
+ for (const tool of readmeTools) {
372
+ this.toolCount++;
373
+ tools.push(tool);
374
+ yield {
375
+ type: 'tool-found',
376
+ timestamp: timestamp(),
377
+ tool,
378
+ source: 'readme',
379
+ totalFound: this.toolCount
380
+ };
381
+ }
382
+
383
+ if (readmeTools.length > 0) {
384
+ sources.push({
385
+ type: 'readme',
386
+ count: readmeTools.length,
387
+ files: ['README.md']
388
+ });
389
+ }
390
+
391
+ yield {
392
+ type: 'source-complete',
393
+ timestamp: timestamp(),
394
+ source: 'readme',
395
+ toolCount: readmeTools.length,
396
+ files: readmeTools.length > 0 ? ['README.md'] : []
397
+ };
398
+
399
+ progressBase += progressPerSource;
400
+ if (this.options.emitProgress) {
401
+ yield {
402
+ type: 'progress',
403
+ timestamp: timestamp(),
404
+ phase: 'extracting',
405
+ progress: Math.round(progressBase),
406
+ message: `Extracted ${readmeTools.length} tools from README`
407
+ };
408
+ }
409
+ }
410
+
411
+ // 3. Extract from code
412
+ if (enabledSources.includes('code')) {
413
+ if (this.options.abortSignal?.aborted) throw new Error('Generation aborted');
414
+
415
+ yield {
416
+ type: 'extracting',
417
+ timestamp: timestamp(),
418
+ source: 'code',
419
+ message: 'Analyzing source code for extractable tools...'
420
+ };
421
+
422
+ const codeTools = await this.extractFromCode(github, codeExtractor, repoMeta.owner, repoMeta.repo);
423
+
424
+ for (const tool of codeTools) {
425
+ this.toolCount++;
426
+ tools.push(tool);
427
+ yield {
428
+ type: 'tool-found',
429
+ timestamp: timestamp(),
430
+ tool,
431
+ source: 'code',
432
+ totalFound: this.toolCount
433
+ };
434
+ }
435
+
436
+ if (codeTools.length > 0) {
437
+ sources.push({
438
+ type: 'code',
439
+ count: codeTools.length,
440
+ files: [...new Set(codeTools.map(t => t.source.file))]
441
+ });
442
+ }
443
+
444
+ yield {
445
+ type: 'source-complete',
446
+ timestamp: timestamp(),
447
+ source: 'code',
448
+ toolCount: codeTools.length,
449
+ files: codeTools.length > 0 ? [...new Set(codeTools.map(t => t.source.file))] : []
450
+ };
451
+
452
+ progressBase += progressPerSource;
453
+ if (this.options.emitProgress) {
454
+ yield {
455
+ type: 'progress',
456
+ timestamp: timestamp(),
457
+ phase: 'extracting',
458
+ progress: Math.round(progressBase),
459
+ message: `Extracted ${codeTools.length} tools from source code`
460
+ };
461
+ }
462
+ }
463
+
464
+ // 4. Extract from GraphQL schemas
465
+ if (this.options.abortSignal?.aborted) throw new Error('Generation aborted');
466
+
467
+ yield {
468
+ type: 'extracting',
469
+ timestamp: timestamp(),
470
+ source: 'graphql',
471
+ message: 'Searching for GraphQL schemas...'
472
+ };
473
+
474
+ const graphqlTools = await this.extractFromGraphQL(github, graphqlExtractor, repoMeta.owner, repoMeta.repo);
475
+
476
+ for (const tool of graphqlTools) {
477
+ this.toolCount++;
478
+ tools.push(tool);
479
+ yield {
480
+ type: 'tool-found',
481
+ timestamp: timestamp(),
482
+ tool,
483
+ source: 'graphql',
484
+ totalFound: this.toolCount
485
+ };
486
+ }
487
+
488
+ if (graphqlTools.length > 0) {
489
+ sources.push({
490
+ type: 'graphql',
491
+ count: graphqlTools.length,
492
+ files: [...new Set(graphqlTools.map(t => t.source.file))]
493
+ });
494
+ }
495
+
496
+ yield {
497
+ type: 'source-complete',
498
+ timestamp: timestamp(),
499
+ source: 'graphql',
500
+ toolCount: graphqlTools.length,
501
+ files: graphqlTools.length > 0 ? [...new Set(graphqlTools.map(t => t.source.file))] : []
502
+ };
503
+
504
+ progressBase += progressPerSource;
505
+
506
+ // 5. Introspect existing MCP servers
507
+ if (classification.type === 'mcp-server') {
508
+ if (this.options.abortSignal?.aborted) throw new Error('Generation aborted');
509
+
510
+ yield {
511
+ type: 'extracting',
512
+ timestamp: timestamp(),
513
+ source: 'mcp-introspect',
514
+ message: 'Introspecting existing MCP server tools...'
515
+ };
516
+
517
+ const mcpTools = await this.introspectMcpServer(github, mcpIntrospector, repoMeta.owner, repoMeta.repo);
518
+
519
+ for (const tool of mcpTools) {
520
+ this.toolCount++;
521
+ tools.push(tool);
522
+ yield {
523
+ type: 'tool-found',
524
+ timestamp: timestamp(),
525
+ tool,
526
+ source: 'mcp-introspect',
527
+ totalFound: this.toolCount
528
+ };
529
+ }
530
+
531
+ if (mcpTools.length > 0) {
532
+ sources.push({
533
+ type: 'mcp-introspect',
534
+ count: mcpTools.length,
535
+ files: [...new Set(mcpTools.map(t => t.source.file))]
536
+ });
537
+ }
538
+
539
+ yield {
540
+ type: 'source-complete',
541
+ timestamp: timestamp(),
542
+ source: 'mcp-introspect',
543
+ toolCount: mcpTools.length,
544
+ files: mcpTools.length > 0 ? [...new Set(mcpTools.map(t => t.source.file))] : []
545
+ };
546
+ }
547
+
548
+ // 6. Add universal fallback tools
549
+ yield {
550
+ type: 'extracting',
551
+ timestamp: timestamp(),
552
+ source: 'universal',
553
+ message: 'Adding universal repository tools...'
554
+ };
555
+
556
+ const universalTools = this.generateUniversalTools(repoMeta.owner, repoMeta.repo);
557
+
558
+ for (const tool of universalTools) {
559
+ this.toolCount++;
560
+ tools.push(tool);
561
+ yield {
562
+ type: 'tool-found',
563
+ timestamp: timestamp(),
564
+ tool,
565
+ source: 'universal',
566
+ totalFound: this.toolCount
567
+ };
568
+ }
569
+
570
+ sources.push({
571
+ type: 'universal',
572
+ count: universalTools.length,
573
+ files: []
574
+ });
575
+
576
+ yield {
577
+ type: 'source-complete',
578
+ timestamp: timestamp(),
579
+ source: 'universal',
580
+ toolCount: universalTools.length,
581
+ files: []
582
+ };
583
+
584
+ if (this.options.emitProgress) {
585
+ yield {
586
+ type: 'progress',
587
+ timestamp: timestamp(),
588
+ phase: 'extracting',
589
+ progress: 80,
590
+ message: `Extraction complete. Found ${this.toolCount} total tools.`
591
+ };
592
+ }
593
+
594
+ // Deduplicate tools
595
+ const uniqueTools = this.deduplicateTools(tools);
596
+
597
+ // Generate code
598
+ const outputLanguage = this.options.outputLanguage || 'typescript';
599
+
600
+ yield {
601
+ type: 'generating',
602
+ timestamp: timestamp(),
603
+ language: outputLanguage,
604
+ toolCount: uniqueTools.length
605
+ };
606
+
607
+ if (this.options.emitProgress) {
608
+ yield {
609
+ type: 'progress',
610
+ timestamp: timestamp(),
611
+ phase: 'generating',
612
+ progress: 90,
613
+ message: `Generating ${outputLanguage} MCP server...`
614
+ };
615
+ }
616
+
617
+ // Build result using the main generator for code generation
618
+ const generator = new GithubToMcpGenerator(this.options);
619
+
620
+ const result: GenerationResult = {
621
+ repo: githubUrl,
622
+ name: repoMeta.repo,
623
+ tools: uniqueTools,
624
+ sources,
625
+ classification,
626
+ metadata,
627
+ generate: () => generator['generateCode'](uniqueTools, repoMeta.repo, repoMeta.owner, outputLanguage),
628
+ generatePython: () => pythonGenerator.generateServer(uniqueTools, repoMeta.repo, repoMeta.owner),
629
+ save: async (outputDir: string) => generator['saveToFiles'](uniqueTools, repoMeta.repo, repoMeta.owner, outputDir),
630
+ download: () => generator['downloadZip'](uniqueTools, repoMeta.repo)
631
+ };
632
+
633
+ const duration = Date.now() - this.startTime;
634
+
635
+ if (this.options.emitProgress) {
636
+ yield {
637
+ type: 'progress',
638
+ timestamp: timestamp(),
639
+ phase: 'complete',
640
+ progress: 100,
641
+ message: `Generation complete in ${duration}ms`
642
+ };
643
+ }
644
+
645
+ // Emit complete event
646
+ yield {
647
+ type: 'complete',
648
+ timestamp: timestamp(),
649
+ result,
650
+ totalTools: uniqueTools.length,
651
+ sources,
652
+ duration
653
+ };
654
+
655
+ } catch (error) {
656
+ const err = error instanceof Error ? error : new Error(String(error));
657
+ yield {
658
+ type: 'error',
659
+ timestamp: timestamp(),
660
+ error: err,
661
+ phase: 'generation',
662
+ recoverable: false
663
+ };
664
+ }
665
+ }
666
+
667
+ /**
668
+ * Classify repository type
669
+ */
670
+ private async classifyRepo(
671
+ github: any,
672
+ owner: string,
673
+ repo: string,
674
+ readme: string | null,
675
+ metadata: any
676
+ ): Promise<RepoClassification> {
677
+ const indicators: string[] = [];
678
+ let type: RepoClassification['type'] = 'unknown';
679
+ let confidence = 0.3;
680
+
681
+ const readmeLower = (readme || '').toLowerCase();
682
+
683
+ if (readmeLower.includes('mcp') || readmeLower.includes('model context protocol')) {
684
+ type = 'mcp-server';
685
+ confidence = 0.9;
686
+ indicators.push('MCP keywords in README');
687
+ } else if (readmeLower.includes('api') || readmeLower.includes('sdk') || readmeLower.includes('openapi')) {
688
+ type = 'api-sdk';
689
+ confidence = 0.7;
690
+ indicators.push('API/SDK keywords in README');
691
+ } else if (readmeLower.includes('cli') || readmeLower.includes('command line')) {
692
+ type = 'cli-tool';
693
+ confidence = 0.7;
694
+ indicators.push('CLI keywords in README');
695
+ } else if (metadata.language) {
696
+ type = 'library';
697
+ confidence = 0.5;
698
+ indicators.push(`${metadata.language} repository`);
699
+ }
700
+
701
+ return { type, confidence, indicators };
702
+ }
703
+
704
+ /**
705
+ * Extract tools from OpenAPI specs
706
+ */
707
+ private async extractFromOpenApi(
708
+ github: any,
709
+ owner: string,
710
+ repo: string,
711
+ convertOpenApiToMcp: any
712
+ ): Promise<ExtractedTool[]> {
713
+ const tools: ExtractedTool[] = [];
714
+
715
+ try {
716
+ const specPatterns = [
717
+ 'openapi.json', 'openapi.yaml', 'openapi.yml',
718
+ 'swagger.json', 'swagger.yaml', 'swagger.yml',
719
+ 'api-spec.json', 'api-spec.yaml',
720
+ 'api/openapi.json', 'api/openapi.yaml',
721
+ 'docs/openapi.json', 'docs/openapi.yaml',
722
+ 'spec/openapi.json', 'spec/openapi.yaml'
723
+ ];
724
+
725
+ for (const pattern of specPatterns) {
726
+ try {
727
+ const content = await github.getFile(owner, repo, pattern);
728
+ if (content) {
729
+ const spec = pattern.endsWith('.json')
730
+ ? JSON.parse(content)
731
+ : (await import('yaml')).parse(content);
732
+
733
+ const mcpTools = await convertOpenApiToMcp(spec);
734
+ tools.push(...mcpTools.map((t: any) => ({
735
+ ...t,
736
+ source: { type: 'openapi' as const, file: pattern }
737
+ })));
738
+ break;
739
+ }
740
+ } catch {
741
+ // File not found, continue
742
+ }
743
+ }
744
+ } catch (error) {
745
+ // OpenAPI extraction failed, return empty
746
+ }
747
+
748
+ return tools;
749
+ }
750
+
751
+ /**
752
+ * Extract tools from README
753
+ */
754
+ private async extractFromReadme(
755
+ readmeExtractor: any,
756
+ readme: string | null,
757
+ repoName: string
758
+ ): Promise<ExtractedTool[]> {
759
+ if (!readme) return [];
760
+
761
+ try {
762
+ return await readmeExtractor.extract(readme, repoName);
763
+ } catch {
764
+ return [];
765
+ }
766
+ }
767
+
768
+ /**
769
+ * Extract tools from code
770
+ */
771
+ private async extractFromCode(
772
+ github: any,
773
+ codeExtractor: any,
774
+ owner: string,
775
+ repo: string
776
+ ): Promise<ExtractedTool[]> {
777
+ const tools: ExtractedTool[] = [];
778
+
779
+ try {
780
+ const codeFiles = await github.searchCode(owner, repo, 'extension:ts extension:py extension:js');
781
+
782
+ for (const file of codeFiles.slice(0, 20)) {
783
+ try {
784
+ const content = await github.getFile(owner, repo, file.path);
785
+ if (content) {
786
+ const fileTools = await codeExtractor.extract(content, file.path);
787
+ tools.push(...fileTools);
788
+ }
789
+ } catch {
790
+ // File extraction failed, continue
791
+ }
792
+ }
793
+ } catch {
794
+ // Code extraction failed
795
+ }
796
+
797
+ return tools;
798
+ }
799
+
800
+ /**
801
+ * Extract tools from GraphQL schemas
802
+ */
803
+ private async extractFromGraphQL(
804
+ github: any,
805
+ graphqlExtractor: any,
806
+ owner: string,
807
+ repo: string
808
+ ): Promise<ExtractedTool[]> {
809
+ const tools: ExtractedTool[] = [];
810
+
811
+ try {
812
+ const schemaPatterns = [
813
+ 'schema.graphql', 'schema.gql',
814
+ 'graphql/schema.graphql', 'graphql/schema.gql',
815
+ 'src/schema.graphql', 'src/schema.gql'
816
+ ];
817
+
818
+ for (const pattern of schemaPatterns) {
819
+ try {
820
+ const content = await github.getFile(owner, repo, pattern);
821
+ if (content) {
822
+ const graphqlTools = await graphqlExtractor.extract(content, pattern);
823
+ tools.push(...graphqlTools);
824
+ break;
825
+ }
826
+ } catch {
827
+ // File not found, continue
828
+ }
829
+ }
830
+ } catch {
831
+ // GraphQL extraction failed
832
+ }
833
+
834
+ return tools;
835
+ }
836
+
837
+ /**
838
+ * Introspect existing MCP server
839
+ */
840
+ private async introspectMcpServer(
841
+ github: any,
842
+ mcpIntrospector: any,
843
+ owner: string,
844
+ repo: string
845
+ ): Promise<ExtractedTool[]> {
846
+ const tools: ExtractedTool[] = [];
847
+
848
+ try {
849
+ const serverPatterns = [
850
+ 'src/index.ts', 'src/server.ts', 'src/main.ts',
851
+ 'index.ts', 'server.ts', 'main.ts',
852
+ 'src/index.js', 'src/server.js'
853
+ ];
854
+
855
+ for (const pattern of serverPatterns) {
856
+ try {
857
+ const content = await github.getFile(owner, repo, pattern);
858
+ if (content && (content.includes('server.tool') || content.includes('@mcp'))) {
859
+ const mcpTools = await mcpIntrospector.extract(content, pattern);
860
+ tools.push(...mcpTools);
861
+ }
862
+ } catch {
863
+ // File not found, continue
864
+ }
865
+ }
866
+ } catch {
867
+ // MCP introspection failed
868
+ }
869
+
870
+ return tools;
871
+ }
872
+
873
+ /**
874
+ * Generate universal tools for any repository
875
+ */
876
+ private generateUniversalTools(owner: string, repo: string): ExtractedTool[] {
877
+ return [
878
+ {
879
+ name: 'get_readme',
880
+ description: `Get the README file from ${owner}/${repo}`,
881
+ inputSchema: {
882
+ type: 'object',
883
+ properties: {},
884
+ required: []
885
+ },
886
+ source: { type: 'universal', file: '' }
887
+ },
888
+ {
889
+ name: 'list_files',
890
+ description: `List files in ${owner}/${repo}`,
891
+ inputSchema: {
892
+ type: 'object',
893
+ properties: {
894
+ path: {
895
+ type: 'string',
896
+ description: 'Directory path to list (default: root)',
897
+ default: ''
898
+ }
899
+ },
900
+ required: []
901
+ },
902
+ source: { type: 'universal', file: '' }
903
+ },
904
+ {
905
+ name: 'read_file',
906
+ description: `Read a file from ${owner}/${repo}`,
907
+ inputSchema: {
908
+ type: 'object',
909
+ properties: {
910
+ path: {
911
+ type: 'string',
912
+ description: 'Path to the file to read'
913
+ }
914
+ },
915
+ required: ['path']
916
+ },
917
+ source: { type: 'universal', file: '' }
918
+ },
919
+ {
920
+ name: 'search_code',
921
+ description: `Search for code patterns in ${owner}/${repo}`,
922
+ inputSchema: {
923
+ type: 'object',
924
+ properties: {
925
+ query: {
926
+ type: 'string',
927
+ description: 'Search query'
928
+ },
929
+ extension: {
930
+ type: 'string',
931
+ description: 'File extension to filter (e.g., "ts", "py")'
932
+ }
933
+ },
934
+ required: ['query']
935
+ },
936
+ source: { type: 'universal', file: '' }
937
+ }
938
+ ];
939
+ }
940
+
941
+ /**
942
+ * Deduplicate tools by name
943
+ */
944
+ private deduplicateTools(tools: ExtractedTool[]): ExtractedTool[] {
945
+ const seen = new Map<string, ExtractedTool>();
946
+
947
+ for (const tool of tools) {
948
+ const existing = seen.get(tool.name);
949
+ if (!existing || (tool.confidence || 0) > (existing.confidence || 0)) {
950
+ seen.set(tool.name, tool);
951
+ }
952
+ }
953
+
954
+ return Array.from(seen.values());
955
+ }
956
+ }
957
+
958
+ /**
959
+ * Convenience function for streaming generation
960
+ */
961
+ export async function* streamGenerate(
962
+ url: string,
963
+ options: StreamOptions = {}
964
+ ): AsyncGenerator<StreamEvent, void, unknown> {
965
+ const generator = new StreamingGenerator(options);
966
+ yield* generator.generate(url);
967
+ }
968
+
969
+ /**
970
+ * Collect all events from a streaming generation into an array
971
+ */
972
+ export async function collectStreamEvents(
973
+ url: string,
974
+ options: StreamOptions = {}
975
+ ): Promise<StreamEvent[]> {
976
+ const events: StreamEvent[] = [];
977
+ for await (const event of streamGenerate(url, options)) {
978
+ events.push(event);
979
+ }
980
+ return events;
981
+ }
982
+
983
+ /**
984
+ * Get just the final result from streaming generation
985
+ */
986
+ export async function streamToResult(
987
+ url: string,
988
+ options: StreamOptions = {}
989
+ ): Promise<GenerationResult | null> {
990
+ for await (const event of streamGenerate(url, options)) {
991
+ if (event.type === 'complete') {
992
+ return event.result;
993
+ }
994
+ if (event.type === 'error') {
995
+ throw event.error;
996
+ }
997
+ }
998
+ return null;
999
+ }