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,696 @@
1
+ /**
2
+ * @fileoverview code-extractor module implementation
3
+ * @copyright Copyright (c) 2024-2026 nirholas
4
+ * @license MIT
5
+ */
6
+
7
+ /**
8
+ * Code Extractor
9
+ * Extract tools from SDK source code
10
+ */
11
+
12
+ import { ExtractedTool, SdkMethod } from './types';
13
+ import { GoExtractor } from './extractors/go-extractor';
14
+ import { JavaExtractor } from './extractors/java-extractor';
15
+ import { RustExtractor } from './extractors/rust-extractor';
16
+
17
+ export class CodeExtractor {
18
+ private goExtractor: GoExtractor;
19
+ private javaExtractor: JavaExtractor;
20
+ private rustExtractor: RustExtractor;
21
+
22
+ constructor() {
23
+ this.goExtractor = new GoExtractor();
24
+ this.javaExtractor = new JavaExtractor();
25
+ this.rustExtractor = new RustExtractor();
26
+ }
27
+
28
+ /**
29
+ * Extract tools from code files
30
+ */
31
+ async extract(code: string, filename: string): Promise<ExtractedTool[]> {
32
+ const tools: ExtractedTool[] = [];
33
+
34
+ // Detect language
35
+ const lang = this.detectLanguage(filename);
36
+
37
+ if (lang === 'typescript' || lang === 'javascript') {
38
+ const methods = this.extractMethods(code, filename);
39
+ tools.push(...methods.map(m => this.methodToTool(m)));
40
+ } else if (lang === 'python') {
41
+ const pythonTools = this.extractPythonMcpTools(code, filename);
42
+ tools.push(...pythonTools);
43
+ } else if (lang === 'go') {
44
+ const goTools = await this.goExtractor.extract(code, filename);
45
+ tools.push(...goTools);
46
+ } else if (lang === 'java' || lang === 'kotlin') {
47
+ const javaTools = await this.javaExtractor.extract(code, filename);
48
+ tools.push(...javaTools);
49
+ } else if (lang === 'rust') {
50
+ const rustTools = await this.rustExtractor.extract(code, filename);
51
+ tools.push(...rustTools);
52
+ }
53
+
54
+ return tools;
55
+ }
56
+
57
+ /**
58
+ * Extract MCP tools from Python code using @mcp.tool decorators
59
+ */
60
+ private extractPythonMcpTools(code: string, filename: string): ExtractedTool[] {
61
+ const tools: ExtractedTool[] = [];
62
+ const lines = code.split('\n');
63
+
64
+ // Pattern for @mcp.tool decorator with various formats
65
+ const decoratorPatterns = [
66
+ // @mcp.tool(name="ToolName", description="...")
67
+ /@(?:mcp|server|app)\.tool\s*\(\s*name\s*=\s*["']([^"']+)["']\s*,\s*description\s*=\s*["']([^"']+)["']/g,
68
+ // @mcp.tool(description="...", name="ToolName")
69
+ /@(?:mcp|server|app)\.tool\s*\(\s*description\s*=\s*["']([^"']+)["']\s*,\s*name\s*=\s*["']([^"']+)["']/g,
70
+ // @server.tool("ToolName")
71
+ /@(?:mcp|server|app)\.tool\s*\(\s*["']([^"']+)["']\s*(?:,\s*description\s*=\s*["']([^"']+)["'])?\s*\)/g,
72
+ ];
73
+
74
+ for (let i = 0; i < lines.length; i++) {
75
+ const line = lines[i];
76
+
77
+ for (const pattern of decoratorPatterns) {
78
+ pattern.lastIndex = 0;
79
+ const match = pattern.exec(line);
80
+ if (match) {
81
+ // Extract function signature on next lines
82
+ const funcInfo = this.extractPythonFunction(lines, i + 1);
83
+
84
+ // Handle different match groups based on pattern
85
+ let name: string;
86
+ let description: string | undefined;
87
+
88
+ if (match[1] && match[2]) {
89
+ // Check which pattern matched
90
+ if (line.includes('name=') && line.indexOf('name=') < line.indexOf('description=')) {
91
+ name = match[1];
92
+ description = match[2];
93
+ } else if (line.includes('description=') && line.indexOf('description=') < line.indexOf('name=')) {
94
+ description = match[1];
95
+ name = match[2];
96
+ } else {
97
+ name = match[1];
98
+ description = match[2];
99
+ }
100
+ } else {
101
+ name = match[1];
102
+ description = match[2];
103
+ }
104
+
105
+ tools.push({
106
+ name,
107
+ description: description || funcInfo.docstring || `${name} tool`,
108
+ inputSchema: {
109
+ type: 'object',
110
+ properties: this.pythonParamsToSchema(funcInfo.params),
111
+ required: funcInfo.required
112
+ },
113
+ source: {
114
+ type: 'code',
115
+ file: filename,
116
+ line: i + 1
117
+ }
118
+ });
119
+ }
120
+ }
121
+ }
122
+
123
+ // Also look for Tool class instantiations
124
+ const toolClassPattern = /Tool\s*\(\s*name\s*=\s*["']([^"']+)["']\s*,\s*description\s*=\s*["']([^"']+)["']/g;
125
+ let match;
126
+ while ((match = toolClassPattern.exec(code)) !== null) {
127
+ const lineNum = code.substring(0, match.index).split('\n').length;
128
+ tools.push({
129
+ name: match[1],
130
+ description: match[2],
131
+ inputSchema: { type: 'object', properties: {}, required: [] },
132
+ source: { type: 'code', file: filename, line: lineNum }
133
+ });
134
+ }
135
+
136
+ return tools;
137
+ }
138
+
139
+ /**
140
+ * Extract Python function info from lines after decorator
141
+ */
142
+ private extractPythonFunction(lines: string[], startLine: number): {
143
+ name: string;
144
+ params: Array<{ name: string; type: string; default?: string }>;
145
+ required: string[];
146
+ docstring?: string;
147
+ } {
148
+ const result = {
149
+ name: '',
150
+ params: [] as Array<{ name: string; type: string; default?: string }>,
151
+ required: [] as string[],
152
+ docstring: undefined as string | undefined
153
+ };
154
+
155
+ // Find async def or def line and collect full function signature (may span multiple lines)
156
+ let funcSignature = '';
157
+ let funcStartLine = -1;
158
+ let parenDepth = 0;
159
+ let foundDef = false;
160
+
161
+ for (let i = startLine; i < Math.min(startLine + 20, lines.length); i++) {
162
+ const line = lines[i];
163
+
164
+ if (!foundDef) {
165
+ const defMatch = line.match(/(?:async\s+)?def\s+(\w+)\s*\(/);
166
+ if (defMatch) {
167
+ foundDef = true;
168
+ funcStartLine = i;
169
+ result.name = defMatch[1];
170
+ funcSignature = line;
171
+ // Count parentheses
172
+ for (const char of line) {
173
+ if (char === '(') parenDepth++;
174
+ if (char === ')') parenDepth--;
175
+ }
176
+ if (parenDepth === 0) break;
177
+ continue;
178
+ }
179
+ } else {
180
+ funcSignature += ' ' + line.trim();
181
+ for (const char of line) {
182
+ if (char === '(') parenDepth++;
183
+ if (char === ')') parenDepth--;
184
+ }
185
+ if (parenDepth === 0) break;
186
+ }
187
+ }
188
+
189
+ // Extract params from the full signature
190
+ if (funcSignature) {
191
+ const paramsMatch = funcSignature.match(/\(([^)]*)\)/);
192
+ if (paramsMatch) {
193
+ const paramsStr = paramsMatch[1];
194
+
195
+ // Parse parameters using bracket-aware splitting (skip 'self' and context params)
196
+ const params = this.splitPythonParams(paramsStr).filter(p =>
197
+ p && !p.startsWith('self') && !p.includes('Context') && !p.includes('ctx')
198
+ );
199
+
200
+ for (const param of params) {
201
+ // Parse: name: type = default or name = default or just name
202
+ const paramMatch = param.match(/(\w+)(?:\s*:\s*([^=]+))?(?:\s*=\s*(.+))?/);
203
+ if (paramMatch) {
204
+ const [, name, type, defaultVal] = paramMatch;
205
+ result.params.push({
206
+ name,
207
+ type: type?.trim() || 'string',
208
+ default: defaultVal?.trim()
209
+ });
210
+
211
+ if (!defaultVal) {
212
+ result.required.push(name);
213
+ }
214
+ }
215
+ }
216
+ }
217
+
218
+ // Look for docstring after function definition
219
+ const docstringStartLine = funcStartLine >= 0 ? funcStartLine + 1 : startLine + 1;
220
+ for (let j = docstringStartLine; j < Math.min(docstringStartLine + 10, lines.length); j++) {
221
+ const docLine = lines[j].trim();
222
+ if (docLine.startsWith('"""') || docLine.startsWith("'''")) {
223
+ // Single line docstring
224
+ const docMatch = docLine.match(/['"]{3}(.+?)['"]{3}/);
225
+ if (docMatch) {
226
+ result.docstring = docMatch[1].trim();
227
+ } else {
228
+ // Multi-line docstring - get first line
229
+ result.docstring = docLine.replace(/^['"]{3}/, '').trim();
230
+ }
231
+ break;
232
+ }
233
+ }
234
+ }
235
+
236
+ return result;
237
+ }
238
+
239
+ /**
240
+ * Convert Python params to JSON schema properties
241
+ */
242
+ private pythonParamsToSchema(params: Array<{ name: string; type: string; default?: string }>): Record<string, any> {
243
+ const properties: Record<string, any> = {};
244
+
245
+ for (const param of params) {
246
+ properties[param.name] = {
247
+ type: this.pythonTypeToJsonSchema(param.type),
248
+ description: `${param.name} parameter`
249
+ };
250
+
251
+ if (param.default !== undefined) {
252
+ properties[param.name].default = this.parsePythonDefault(param.default);
253
+ }
254
+ }
255
+
256
+ return properties;
257
+ }
258
+
259
+ /**
260
+ * Convert Python type to JSON schema type
261
+ * Handles complex typing patterns including:
262
+ * - Container types: List, Dict, Set, Tuple, Sequence, Mapping
263
+ * - Union types: Union[X, Y], X | Y (Python 3.10+)
264
+ * - Optional: Optional[X] (equivalent to Union[X, None])
265
+ * - Literal types: Literal["a", "b"]
266
+ * - Any, None types
267
+ * - Nested generics: List[Dict[str, int]]
268
+ */
269
+ private pythonTypeToJsonSchema(pythonType: string): string {
270
+ const type = pythonType.toLowerCase().trim();
271
+
272
+ // Handle empty or whitespace-only types
273
+ if (!type) return 'string';
274
+
275
+ // Check container types first (they may contain other type names like 'str')
276
+ // List-like types
277
+ if (type.startsWith('list[') || type === 'list' ||
278
+ type.startsWith('sequence[') || type === 'sequence' ||
279
+ type.startsWith('set[') || type === 'set' ||
280
+ type.startsWith('frozenset[') || type === 'frozenset' ||
281
+ type.startsWith('tuple[') || type === 'tuple' ||
282
+ type.startsWith('iterable[') || type === 'iterable' ||
283
+ type.includes('[]')) {
284
+ return 'array';
285
+ }
286
+
287
+ // Dict-like types
288
+ if (type.startsWith('dict[') || type === 'dict' ||
289
+ type.startsWith('mapping[') || type === 'mapping' ||
290
+ type.startsWith('mutablemapping[') || type === 'mutablemapping' ||
291
+ type.startsWith('typeddict') || type === 'typeddict' ||
292
+ type.startsWith('record[')) {
293
+ return 'object';
294
+ }
295
+
296
+ // Handle Optional[X] - extract inner type
297
+ if (type.startsWith('optional[')) {
298
+ const inner = type.match(/optional\[(.+)\]$/i);
299
+ if (inner) return this.pythonTypeToJsonSchema(inner[1]);
300
+ return 'string';
301
+ }
302
+
303
+ // Handle Union[X, Y, ...] - return type of first non-None type
304
+ if (type.startsWith('union[')) {
305
+ const inner = type.match(/union\[(.+)\]$/i);
306
+ if (inner) {
307
+ const types = this.splitGenericArgs(inner[1]);
308
+ const nonNoneType = types.find(t => t.trim().toLowerCase() !== 'none');
309
+ if (nonNoneType) return this.pythonTypeToJsonSchema(nonNoneType);
310
+ }
311
+ return 'string';
312
+ }
313
+
314
+ // Handle Python 3.10+ union syntax: X | Y
315
+ if (type.includes(' | ')) {
316
+ const types = type.split('|').map(t => t.trim());
317
+ const nonNoneType = types.find(t => t !== 'none');
318
+ if (nonNoneType) return this.pythonTypeToJsonSchema(nonNoneType);
319
+ return 'string';
320
+ }
321
+
322
+ // Handle Literal["a", "b"] - these are strings with enum constraint
323
+ if (type.startsWith('literal[')) {
324
+ // Check what's inside the literal
325
+ const inner = type.match(/literal\[(.+)\]/i);
326
+ if (inner) {
327
+ const firstValue = inner[1].split(',')[0].trim();
328
+ // Check for quoted strings
329
+ if (firstValue.startsWith('"') || firstValue.startsWith("'")) return 'string';
330
+ // Check for numeric values (including negative numbers and floats)
331
+ if (/^-?\d+(\.\d+)?$/.test(firstValue)) return 'number';
332
+ // Check for boolean values (case-insensitive since we lowercased)
333
+ if (firstValue === 'true' || firstValue === 'false') return 'boolean';
334
+ }
335
+ return 'string';
336
+ }
337
+
338
+ // Handle Callable - return 'string' as we can't represent functions in JSON Schema
339
+ if (type.startsWith('callable[') || type === 'callable') {
340
+ return 'string';
341
+ }
342
+
343
+ // Handle None/NoneType
344
+ if (type === 'none' || type === 'nonetype') {
345
+ return 'null';
346
+ }
347
+
348
+ // Handle Any
349
+ if (type === 'any') {
350
+ return 'object';
351
+ }
352
+
353
+ // Check primitive types - use exact match or startsWith for type annotations with whitespace
354
+ // String types
355
+ if (type === 'str' || type === 'string' || type === 'text' ||
356
+ type === 'bytes' || type === 'bytearray') {
357
+ return 'string';
358
+ }
359
+
360
+ // Integer types (map to 'number' for JSON Schema compatibility)
361
+ if (type === 'int' || type === 'integer') {
362
+ return 'number';
363
+ }
364
+
365
+ // Float/decimal types
366
+ if (type === 'float' || type === 'double' || type === 'decimal' ||
367
+ type === 'number' || type === 'complex') {
368
+ return 'number';
369
+ }
370
+
371
+ // Boolean type
372
+ if (type === 'bool' || type === 'boolean') {
373
+ return 'boolean';
374
+ }
375
+
376
+ // Object types
377
+ if (type === 'object' || type === 'jsonobject') {
378
+ return 'object';
379
+ }
380
+
381
+ // Path types - treat as strings
382
+ if (type === 'path' || type === 'pathlike' || type.startsWith('path[')) {
383
+ return 'string';
384
+ }
385
+
386
+ // UUID - treat as string
387
+ if (type === 'uuid') {
388
+ return 'string';
389
+ }
390
+
391
+ // Date/time types - treat as strings (ISO format)
392
+ if (type === 'datetime' || type === 'date' || type === 'time' ||
393
+ type === 'timedelta' || type === 'timestamp') {
394
+ return 'string';
395
+ }
396
+
397
+ // Default to string for unknown types
398
+ return 'string';
399
+ }
400
+
401
+ /**
402
+ * Split generic type arguments, handling nested brackets
403
+ * e.g., "str, Dict[str, int], bool" -> ["str", "Dict[str, int]", "bool"]
404
+ */
405
+ private splitGenericArgs(args: string): string[] {
406
+ const result: string[] = [];
407
+ let current = '';
408
+ let depth = 0;
409
+
410
+ for (const char of args) {
411
+ if (char === '[') {
412
+ depth++;
413
+ current += char;
414
+ } else if (char === ']') {
415
+ depth--;
416
+ current += char;
417
+ } else if (char === ',' && depth === 0) {
418
+ result.push(current.trim());
419
+ current = '';
420
+ } else {
421
+ current += char;
422
+ }
423
+ }
424
+
425
+ if (current.trim()) {
426
+ result.push(current.trim());
427
+ }
428
+
429
+ return result;
430
+ }
431
+
432
+ /**
433
+ * Split Python function parameters, handling nested brackets and quotes
434
+ * This correctly handles types like List[str], Dict[str, int], Literal["a", "b"]
435
+ * e.g., "name: str, items: List[int], status: Literal['a', 'b']"
436
+ * -> ["name: str", "items: List[int]", "status: Literal['a', 'b']"]
437
+ */
438
+ private splitPythonParams(paramsStr: string): string[] {
439
+ const result: string[] = [];
440
+ let current = '';
441
+ let bracketDepth = 0;
442
+ let inSingleQuote = false;
443
+ let inDoubleQuote = false;
444
+
445
+ for (let i = 0; i < paramsStr.length; i++) {
446
+ const char = paramsStr[i];
447
+ const prevChar = i > 0 ? paramsStr[i - 1] : '';
448
+
449
+ // Track quotes (but not escaped ones)
450
+ if (char === "'" && prevChar !== '\\' && !inDoubleQuote) {
451
+ inSingleQuote = !inSingleQuote;
452
+ } else if (char === '"' && prevChar !== '\\' && !inSingleQuote) {
453
+ inDoubleQuote = !inDoubleQuote;
454
+ }
455
+
456
+ // Track bracket depth (only when not in quotes)
457
+ if (!inSingleQuote && !inDoubleQuote) {
458
+ if (char === '[' || char === '(' || char === '{') {
459
+ bracketDepth++;
460
+ } else if (char === ']' || char === ')' || char === '}') {
461
+ bracketDepth--;
462
+ }
463
+ }
464
+
465
+ // Split on comma only at top level (depth 0, not in quotes)
466
+ if (char === ',' && bracketDepth === 0 && !inSingleQuote && !inDoubleQuote) {
467
+ const trimmed = current.trim();
468
+ if (trimmed) {
469
+ result.push(trimmed);
470
+ }
471
+ current = '';
472
+ } else {
473
+ current += char;
474
+ }
475
+ }
476
+
477
+ // Don't forget the last param
478
+ const trimmed = current.trim();
479
+ if (trimmed) {
480
+ result.push(trimmed);
481
+ }
482
+
483
+ return result;
484
+ }
485
+
486
+ /**
487
+ * Parse Python default value
488
+ */
489
+ private parsePythonDefault(value: string): any {
490
+ if (value === 'None' || value === 'null') return null;
491
+ if (value === 'True') return true;
492
+ if (value === 'False') return false;
493
+ if (/^["']/.test(value)) return value.slice(1, -1);
494
+ if (/^\d+$/.test(value)) return parseInt(value);
495
+ if (/^\d+\.\d+$/.test(value)) return parseFloat(value);
496
+ return value;
497
+ }
498
+
499
+ /**
500
+ * Detect programming language
501
+ */
502
+ private detectLanguage(filename: string): string {
503
+ if (filename.endsWith('.ts') || filename.endsWith('.tsx')) return 'typescript';
504
+ if (filename.endsWith('.js') || filename.endsWith('.jsx') || filename.endsWith('.mjs')) return 'javascript';
505
+ if (filename.endsWith('.py') || filename.endsWith('.pyi')) return 'python';
506
+ if (filename.endsWith('.go')) return 'go';
507
+ if (filename.endsWith('.java')) return 'java';
508
+ if (filename.endsWith('.kt') || filename.endsWith('.kts')) return 'kotlin';
509
+ if (filename.endsWith('.rs')) return 'rust';
510
+ if (filename.endsWith('.proto')) return 'protobuf';
511
+ return 'unknown';
512
+ }
513
+
514
+ /**
515
+ * Extract methods from TypeScript/JavaScript
516
+ */
517
+ private extractMethods(code: string, filename: string): SdkMethod[] {
518
+ const methods: SdkMethod[] = [];
519
+
520
+ // Match class methods
521
+ const methodPattern = /(?:async\s+)?(\w+)\s*\(([^)]*)\)\s*:\s*([^{]+)\s*\{/g;
522
+
523
+ let match;
524
+ let lineNumber = 1;
525
+
526
+ while ((match = methodPattern.exec(code)) !== null) {
527
+ const [fullMatch, name, paramsStr, returnType] = match;
528
+
529
+ // Skip constructors and private methods
530
+ if (name === 'constructor' || name.startsWith('_')) {
531
+ continue;
532
+ }
533
+
534
+ // Parse parameters
535
+ const parameters = this.parseParameters(paramsStr);
536
+
537
+ // Get description from JSDoc
538
+ const description = this.extractJsDoc(code, match.index);
539
+
540
+ // Calculate line number
541
+ const codeBeforeMatch = code.substring(0, match.index);
542
+ lineNumber = (codeBeforeMatch.match(/\n/g) || []).length + 1;
543
+
544
+ methods.push({
545
+ name,
546
+ parameters,
547
+ returnType: returnType.trim(),
548
+ description,
549
+ file: filename,
550
+ line: lineNumber
551
+ });
552
+ }
553
+
554
+ return methods;
555
+ }
556
+
557
+ /**
558
+ * Parse function parameters
559
+ */
560
+ private parseParameters(paramsStr: string): Array<{
561
+ name: string;
562
+ type: string;
563
+ required: boolean;
564
+ description?: string;
565
+ }> {
566
+ if (!paramsStr.trim()) {
567
+ return [];
568
+ }
569
+
570
+ const params = paramsStr.split(',').map(p => p.trim());
571
+
572
+ return params.map(param => {
573
+ // Parse: "name: type" or "name?: type" or "name: type = default"
574
+ const match = param.match(/(\w+)(\??):\s*([^=]+)(?:\s*=\s*(.+))?/);
575
+
576
+ if (!match) {
577
+ return {
578
+ name: param,
579
+ type: 'any',
580
+ required: true
581
+ };
582
+ }
583
+
584
+ const [, name, optional, type, defaultValue] = match;
585
+
586
+ return {
587
+ name,
588
+ type: type.trim(),
589
+ required: !optional && !defaultValue,
590
+ description: undefined
591
+ };
592
+ });
593
+ }
594
+
595
+ /**
596
+ * Extract JSDoc comment before code
597
+ */
598
+ private extractJsDoc(code: string, index: number): string | undefined {
599
+ const codeBeforeMethod = code.substring(0, index);
600
+ const jsdocMatch = codeBeforeMethod.match(/\/\*\*\s*([\s\S]*?)\s*\*\/\s*$/);
601
+
602
+ if (jsdocMatch) {
603
+ const jsdoc = jsdocMatch[1];
604
+
605
+ // Extract description (first line before @tags)
606
+ const lines = jsdoc.split('\n').map(l => l.replace(/^\s*\*\s?/, ''));
607
+ const descriptionLines = [];
608
+
609
+ for (const line of lines) {
610
+ if (line.startsWith('@')) break;
611
+ descriptionLines.push(line);
612
+ }
613
+
614
+ return descriptionLines.join(' ').trim();
615
+ }
616
+
617
+ return undefined;
618
+ }
619
+
620
+ /**
621
+ * Convert SDK method to MCP tool
622
+ */
623
+ private methodToTool(method: SdkMethod): ExtractedTool {
624
+ // Build input schema
625
+ const properties: Record<string, any> = {};
626
+ const required: string[] = [];
627
+
628
+ for (const param of method.parameters) {
629
+ properties[param.name] = {
630
+ type: this.typeScriptToJsonSchema(param.type),
631
+ description: param.description || `${param.name} parameter`
632
+ };
633
+
634
+ if (param.required) {
635
+ required.push(param.name);
636
+ }
637
+ }
638
+
639
+ // Generate implementation
640
+ const implementation = this.generateImplementation(method);
641
+
642
+ return {
643
+ name: this.toToolName(method.name),
644
+ description: method.description || `Call ${method.name}`,
645
+ inputSchema: {
646
+ type: 'object',
647
+ properties,
648
+ required
649
+ },
650
+ implementation,
651
+ source: {
652
+ type: 'code',
653
+ file: method.file,
654
+ line: method.line
655
+ }
656
+ };
657
+ }
658
+
659
+ /**
660
+ * Convert TypeScript type to JSON Schema type
661
+ */
662
+ private typeScriptToJsonSchema(tsType: string): string {
663
+ const type = tsType.toLowerCase();
664
+
665
+ if (type.includes('string')) return 'string';
666
+ if (type.includes('number')) return 'number';
667
+ if (type.includes('boolean')) return 'boolean';
668
+ if (type.includes('array') || type.includes('[]')) return 'array';
669
+ if (type.includes('object') || type.includes('{}')) return 'object';
670
+
671
+ return 'string'; // Default
672
+ }
673
+
674
+ /**
675
+ * Convert method name to tool name
676
+ */
677
+ private toToolName(methodName: string): string {
678
+ return methodName.replace(/([A-Z])/g, '_$1').toLowerCase();
679
+ }
680
+
681
+ /**
682
+ * Generate implementation code
683
+ */
684
+ private generateImplementation(method: SdkMethod): string {
685
+ const paramNames = method.parameters.map(p => p.name);
686
+
687
+ return `async function ${method.name}(args: any) {
688
+ const { ${paramNames.join(', ')} } = args;
689
+
690
+ // Call SDK method
691
+ const result = await sdk.${method.name}(${paramNames.join(', ')});
692
+
693
+ return result;
694
+ }`;
695
+ }
696
+ }