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,269 @@
1
+ /**
2
+ * Convert Page - GitHub to MCP Conversion Interface
3
+ * @copyright 2024-2026 nirholas
4
+ * @license MIT
5
+ */
6
+
7
+ 'use client';
8
+
9
+ import { useEffect, Suspense, useState } from 'react';
10
+ import { useSearchParams, useRouter } from 'next/navigation';
11
+ import { motion, AnimatePresence } from 'framer-motion';
12
+ import { ArrowLeft, Github, Zap } from 'lucide-react';
13
+ import Link from 'next/link';
14
+
15
+ import Header from '@/components/Header';
16
+ import Footer from '@/components/Footer';
17
+ import ParticleBackground from '@/components/ParticleBackground';
18
+ import GithubUrlInput from '@/components/GithubUrlInput';
19
+ import ConversionResult from '@/components/convert/ConversionResult';
20
+ import LoadingSteps from '@/components/convert/LoadingSteps';
21
+ import GenerationProgress from '@/components/GenerationProgress';
22
+ import { useConversion } from '@/hooks/use-conversion';
23
+ import { useStreamingConversion } from '@/hooks/use-streaming-conversion';
24
+ import { useGenerationProgress } from '@/hooks/use-generation-progress';
25
+ import type { GitRef } from '@/components/BranchSelector';
26
+
27
+ function ConvertContent() {
28
+ const searchParams = useSearchParams();
29
+ const router = useRouter();
30
+ const urlParam = searchParams.get('url');
31
+ const [useStreaming, setUseStreaming] = useState(true);
32
+
33
+ // Regular conversion hook (fallback)
34
+ const regularConversion = useConversion();
35
+
36
+ // Streaming conversion hook (enhanced experience)
37
+ const streamingConversion = useStreamingConversion();
38
+
39
+ // Use streaming by default, fallback to regular if needed
40
+ const {
41
+ status,
42
+ result,
43
+ error,
44
+ convert: convertFn,
45
+ reset,
46
+ } = useStreaming ? streamingConversion : regularConversion;
47
+
48
+ // Get history from regular conversion hook (not available in streaming)
49
+ const { history } = regularConversion;
50
+
51
+ // Streaming-specific state
52
+ const { steps, currentStep, progress } = streamingConversion;
53
+
54
+ // Auto-convert if URL is provided in query params
55
+ useEffect(() => {
56
+ if (urlParam && status === 'idle') {
57
+ convertFn(urlParam);
58
+ }
59
+ }, [urlParam, status, convertFn]);
60
+
61
+ const handleSubmit = (url: string, ref?: GitRef | null) => {
62
+ // Build URL with optional ref parameter
63
+ let convertUrl = url;
64
+ if (ref && !ref.isDefault) {
65
+ // Append ref to URL for the conversion
66
+ const urlObj = new URL(url.startsWith('http') ? url : `https://${url}`);
67
+ // GitHub URL format: /owner/repo/tree/branch for browsing
68
+ // But for API, we'll pass as query param
69
+ convertUrl = `${url}${url.includes('?') ? '&' : '?'}ref=${encodeURIComponent(ref.sha || ref.name)}`;
70
+ }
71
+ router.push(`/convert?url=${encodeURIComponent(url)}${ref && !ref.isDefault ? `&ref=${encodeURIComponent(ref.sha || ref.name)}` : ''}`);
72
+ convertFn(convertUrl);
73
+ };
74
+
75
+ const handleReset = () => {
76
+ reset();
77
+ router.push('/convert');
78
+ };
79
+
80
+ return (
81
+ <main id="main-content" className="relative min-h-screen">
82
+ <ParticleBackground />
83
+ <Header />
84
+
85
+ <div className="container mx-auto px-4 pt-24 pb-16">
86
+ {/* Back link */}
87
+ <motion.div
88
+ initial={{ opacity: 0, x: -20 }}
89
+ animate={{ opacity: 1, x: 0 }}
90
+ className="mb-8"
91
+ >
92
+ <Link
93
+ href="/"
94
+ className="inline-flex items-center gap-2 text-sm text-neutral-400 hover:text-white transition-colors"
95
+ >
96
+ <ArrowLeft className="w-4 h-4" />
97
+ Back to Home
98
+ </Link>
99
+ </motion.div>
100
+
101
+ {/* Page header */}
102
+ <motion.div
103
+ initial={{ opacity: 0, y: 20 }}
104
+ animate={{ opacity: 1, y: 0 }}
105
+ className="text-center mb-12"
106
+ >
107
+ <div className="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-white/5 border border-neutral-800 mb-6">
108
+ <Github className="w-4 h-4 text-white" />
109
+ <span className="text-sm font-medium text-neutral-400">
110
+ GitHub to <span className="text-white font-semibold">MCP Server</span>
111
+ </span>
112
+ {useStreaming && (
113
+ <span className="ml-2 px-2 py-0.5 text-xs bg-green-500/20 text-green-400 rounded-full flex items-center gap-1">
114
+ <Zap className="w-3 h-3" />
115
+ Live
116
+ </span>
117
+ )}
118
+ </div>
119
+
120
+ <h1 className="text-4xl md:text-5xl font-bold text-white mb-4">
121
+ Convert Repository
122
+ </h1>
123
+ <p className="text-lg text-neutral-400 max-w-2xl mx-auto">
124
+ Enter a GitHub repository URL to generate a ready-to-use MCP server
125
+ </p>
126
+ </motion.div>
127
+
128
+ {/* Input section - always visible */}
129
+ <motion.div
130
+ initial={{ opacity: 0, y: 20 }}
131
+ animate={{ opacity: 1, y: 0 }}
132
+ transition={{ delay: 0.1 }}
133
+ className="max-w-2xl mx-auto mb-12"
134
+ >
135
+ <GithubUrlInput
136
+ onSubmit={handleSubmit}
137
+ disabled={status === 'loading'}
138
+ initialValue={urlParam || ''}
139
+ showBranchSelector={true}
140
+ />
141
+ </motion.div>
142
+
143
+ {/* Content area */}
144
+ <AnimatePresence mode="wait">
145
+ {status === 'loading' && (
146
+ <motion.div
147
+ key="loading"
148
+ initial={{ opacity: 0, y: 20 }}
149
+ animate={{ opacity: 1, y: 0 }}
150
+ exit={{ opacity: 0, y: -20 }}
151
+ >
152
+ <LoadingSteps
153
+ steps={useStreaming ? steps : undefined}
154
+ currentStep={useStreaming ? currentStep : undefined}
155
+ progress={useStreaming ? progress : undefined}
156
+ isStreaming={useStreaming}
157
+ />
158
+ </motion.div>
159
+ )}
160
+
161
+ {status === 'error' && error && (
162
+ <motion.div
163
+ key="error"
164
+ initial={{ opacity: 0, y: 20 }}
165
+ animate={{ opacity: 1, y: 0 }}
166
+ exit={{ opacity: 0, y: -20 }}
167
+ className="max-w-2xl mx-auto"
168
+ >
169
+ <div className="rounded-xl border border-red-500/30 bg-red-500/10 p-6">
170
+ <div className="flex items-start gap-4">
171
+ <div className="w-10 h-10 rounded-lg bg-red-500/20 flex items-center justify-center flex-shrink-0">
172
+ <span className="text-red-400 text-xl">!</span>
173
+ </div>
174
+ <div className="flex-1">
175
+ <h3 className="text-lg font-semibold text-red-400 mb-2">
176
+ Conversion Failed
177
+ </h3>
178
+ <p className="text-neutral-300 mb-4">{error.error}</p>
179
+ {error.details && (
180
+ <p className="text-sm text-neutral-500 mb-4">{error.details}</p>
181
+ )}
182
+ {error.retryAfter && (
183
+ <p className="text-sm text-neutral-500">
184
+ Please try again in {error.retryAfter} seconds
185
+ </p>
186
+ )}
187
+ <button
188
+ onClick={handleReset}
189
+ className="mt-4 px-4 py-2 bg-white/10 border border-neutral-700 rounded-lg text-white hover:bg-white/20 transition-colors"
190
+ >
191
+ Try Again
192
+ </button>
193
+ </div>
194
+ </div>
195
+ </div>
196
+ </motion.div>
197
+ )}
198
+
199
+ {status === 'success' && result && (
200
+ <motion.div
201
+ key="success"
202
+ initial={{ opacity: 0, y: 20 }}
203
+ animate={{ opacity: 1, y: 0 }}
204
+ exit={{ opacity: 0, y: -20 }}
205
+ >
206
+ <ConversionResult result={result} onReset={handleReset} />
207
+ </motion.div>
208
+ )}
209
+
210
+ {status === 'idle' && !urlParam && (
211
+ <motion.div
212
+ key="idle"
213
+ initial={{ opacity: 0, y: 20 }}
214
+ animate={{ opacity: 1, y: 0 }}
215
+ exit={{ opacity: 0, y: -20 }}
216
+ >
217
+ {/* Recent history */}
218
+ {history.length > 0 && (
219
+ <div className="max-w-3xl mx-auto">
220
+ <h2 className="text-xl font-semibold text-white mb-6">Recent Conversions</h2>
221
+ <div className="grid gap-4">
222
+ {history.slice(0, 5).map((item) => (
223
+ <button
224
+ key={item.id}
225
+ onClick={() => handleSubmit(item.url)}
226
+ className="group flex items-center justify-between p-4 rounded-xl border border-neutral-800 bg-neutral-900/50 hover:border-neutral-600 hover:bg-neutral-900/80 transition-all text-left"
227
+ >
228
+ <div className="flex items-center gap-4">
229
+ <div className="w-10 h-10 rounded-lg bg-white/5 border border-neutral-800 flex items-center justify-center">
230
+ <Github className="w-5 h-5 text-white" />
231
+ </div>
232
+ <div>
233
+ <div className="font-medium text-white group-hover:text-white transition-colors">
234
+ {item.name}
235
+ </div>
236
+ <div className="text-sm text-neutral-500">
237
+ {item.toolCount} tools • {item.classification}
238
+ </div>
239
+ </div>
240
+ </div>
241
+ <div className="text-xs text-neutral-600">
242
+ {new Date(item.convertedAt).toLocaleDateString()}
243
+ </div>
244
+ </button>
245
+ ))}
246
+ </div>
247
+ </div>
248
+ )}
249
+ </motion.div>
250
+ )}
251
+ </AnimatePresence>
252
+ </div>
253
+
254
+ <Footer />
255
+ </main>
256
+ );
257
+ }
258
+
259
+ export default function ConvertPage() {
260
+ return (
261
+ <Suspense fallback={
262
+ <div className="min-h-screen bg-black flex items-center justify-center">
263
+ <div className="animate-spin w-8 h-8 border-2 border-white border-t-transparent rounded-full" />
264
+ </div>
265
+ }>
266
+ <ConvertContent />
267
+ </Suspense>
268
+ );
269
+ }
@@ -0,0 +1,380 @@
1
+ /**
2
+ * Dashboard Page - Manage deployed MCP servers
3
+ * @copyright 2024-2026 nirholas
4
+ * @license MIT
5
+ */
6
+
7
+ 'use client';
8
+
9
+ import { useState, useEffect, useCallback, useMemo } from 'react';
10
+ import { motion, AnimatePresence } from 'framer-motion';
11
+ import {
12
+ Cloud,
13
+ Server,
14
+ Activity,
15
+ BarChart3,
16
+ Clock,
17
+ Zap,
18
+ Settings,
19
+ Trash2,
20
+ Copy,
21
+ Check,
22
+ ExternalLink,
23
+ AlertCircle,
24
+ RefreshCw,
25
+ Play,
26
+ Pause,
27
+ ChevronRight,
28
+ TrendingUp,
29
+ Globe,
30
+ Shield,
31
+ } from 'lucide-react';
32
+ import Header from '@/components/Header';
33
+ import Footer from '@/components/Footer';
34
+ import ParticleBackground from '@/components/ParticleBackground';
35
+ import { Button } from '@/components/ui/button';
36
+ import { copyToClipboard } from '@/lib/utils';
37
+ import type { DeployedServer } from '@/types/deploy';
38
+ import Link from 'next/link';
39
+
40
+ export default function DashboardPage() {
41
+ const [servers, setServers] = useState<DeployedServer[]>([]);
42
+ const [selectedServer, setSelectedServer] = useState<DeployedServer | null>(null);
43
+ const [loading, setLoading] = useState(true);
44
+ const [copied, setCopied] = useState<string | null>(null);
45
+
46
+ // Load servers from localStorage
47
+ useEffect(() => {
48
+ const stored = localStorage.getItem('deployed-servers');
49
+ if (stored) {
50
+ try {
51
+ const parsed = JSON.parse(stored);
52
+ setServers(parsed);
53
+ if (parsed.length > 0) {
54
+ setSelectedServer(parsed[0]);
55
+ }
56
+ } catch (e) {
57
+ console.error('Failed to parse stored servers:', e);
58
+ }
59
+ }
60
+ setLoading(false);
61
+ }, []);
62
+
63
+ const handleCopy = useCallback(async (text: string, id: string) => {
64
+ const success = await copyToClipboard(text);
65
+ if (success) {
66
+ setCopied(id);
67
+ setTimeout(() => setCopied(null), 2000);
68
+ }
69
+ }, []);
70
+
71
+ const handleDelete = useCallback((serverId: string) => {
72
+ if (!confirm('Are you sure you want to delete this server?')) return;
73
+
74
+ const updated = servers.filter(s => s.id !== serverId);
75
+ setServers(updated);
76
+ localStorage.setItem('deployed-servers', JSON.stringify(updated));
77
+
78
+ if (selectedServer?.id === serverId) {
79
+ setSelectedServer(updated[0] || null);
80
+ }
81
+ }, [servers, selectedServer]);
82
+
83
+ const handleToggleStatus = useCallback((serverId: string) => {
84
+ const updated = servers.map(s => {
85
+ if (s.id === serverId) {
86
+ return { ...s, status: s.status === 'active' ? 'paused' as const : 'active' as const };
87
+ }
88
+ return s;
89
+ });
90
+ setServers(updated);
91
+ localStorage.setItem('deployed-servers', JSON.stringify(updated));
92
+
93
+ if (selectedServer?.id === serverId) {
94
+ setSelectedServer(updated.find(s => s.id === serverId) || null);
95
+ }
96
+ }, [servers, selectedServer]);
97
+
98
+ // Calculate overall stats
99
+ const stats = useMemo(() => {
100
+ return {
101
+ totalServers: servers.length,
102
+ activeServers: servers.filter(s => s.status === 'active').length,
103
+ totalTools: servers.reduce((sum, s) => sum + s.tools.length, 0),
104
+ totalCalls: servers.reduce((sum, s) => sum + s.usage.totalCalls, 0),
105
+ };
106
+ }, [servers]);
107
+
108
+ if (loading) {
109
+ return (
110
+ <main className="relative min-h-screen">
111
+ <ParticleBackground />
112
+ <Header />
113
+ <div className="container mx-auto px-4 pt-24 pb-16 flex items-center justify-center min-h-[60vh]">
114
+ <div className="flex flex-col items-center gap-4">
115
+ <RefreshCw className="w-8 h-8 text-white animate-spin" />
116
+ <div className="text-neutral-400">Loading dashboard...</div>
117
+ </div>
118
+ </div>
119
+ <Footer />
120
+ </main>
121
+ );
122
+ }
123
+
124
+ return (
125
+ <main className="relative min-h-screen">
126
+ <ParticleBackground />
127
+ <Header />
128
+
129
+ <div className="container mx-auto px-4 pt-24 pb-16">
130
+ {/* Page Header */}
131
+ <motion.div
132
+ initial={{ opacity: 0, y: 20 }}
133
+ animate={{ opacity: 1, y: 0 }}
134
+ className="mb-8"
135
+ >
136
+ <div className="flex items-center gap-3 mb-2">
137
+ <div className="w-10 h-10 rounded-xl bg-gradient-to-br from-blue-500 to-purple-600 flex items-center justify-center">
138
+ <Cloud className="w-5 h-5 text-white" />
139
+ </div>
140
+ <div>
141
+ <h1 className="text-3xl font-bold text-white">Dashboard</h1>
142
+ <p className="text-neutral-400">Manage your deployed MCP servers</p>
143
+ </div>
144
+ </div>
145
+ </motion.div>
146
+
147
+ {/* Stats Grid */}
148
+ <motion.div
149
+ initial={{ opacity: 0, y: 20 }}
150
+ animate={{ opacity: 1, y: 0 }}
151
+ transition={{ delay: 0.1 }}
152
+ className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8"
153
+ >
154
+ {[
155
+ { label: 'Deployed Servers', value: stats.totalServers, icon: Server, color: 'blue' },
156
+ { label: 'Active', value: stats.activeServers, icon: Zap, color: 'green' },
157
+ { label: 'Total Tools', value: stats.totalTools, icon: Settings, color: 'purple' },
158
+ { label: 'API Calls', value: stats.totalCalls.toLocaleString(), icon: Activity, color: 'orange' },
159
+ ].map(({ label, value, icon: Icon, color }) => (
160
+ <div
161
+ key={label}
162
+ className="p-4 rounded-xl border border-neutral-800 bg-neutral-900/50 backdrop-blur-sm"
163
+ >
164
+ <div className="flex items-center gap-2 mb-2">
165
+ <Icon className={`w-4 h-4 text-${color}-400`} />
166
+ <span className="text-xs text-neutral-500">{label}</span>
167
+ </div>
168
+ <div className="text-2xl font-bold text-white">{value}</div>
169
+ </div>
170
+ ))}
171
+ </motion.div>
172
+
173
+ {servers.length === 0 ? (
174
+ /* Empty State */
175
+ <motion.div
176
+ initial={{ opacity: 0, y: 20 }}
177
+ animate={{ opacity: 1, y: 0 }}
178
+ transition={{ delay: 0.2 }}
179
+ className="text-center py-16"
180
+ >
181
+ <div className="w-20 h-20 mx-auto rounded-full bg-neutral-800 flex items-center justify-center mb-6">
182
+ <Cloud className="w-10 h-10 text-neutral-600" />
183
+ </div>
184
+ <h2 className="text-xl font-bold text-white mb-2">No deployed servers yet</h2>
185
+ <p className="text-neutral-400 mb-6 max-w-md mx-auto">
186
+ Convert a GitHub repository and deploy it to the cloud to see it here.
187
+ </p>
188
+ <Link href="/convert">
189
+ <Button className="bg-white text-black hover:bg-neutral-200">
190
+ Convert a Repository
191
+ <ChevronRight className="w-4 h-4 ml-1" />
192
+ </Button>
193
+ </Link>
194
+ </motion.div>
195
+ ) : (
196
+ /* Server List & Details */
197
+ <div className="grid md:grid-cols-3 gap-6">
198
+ {/* Server List */}
199
+ <motion.div
200
+ initial={{ opacity: 0, x: -20 }}
201
+ animate={{ opacity: 1, x: 0 }}
202
+ transition={{ delay: 0.2 }}
203
+ className="md:col-span-1 space-y-3"
204
+ >
205
+ <h2 className="text-sm font-medium text-neutral-400 mb-4">Your Servers</h2>
206
+ {servers.map((server) => (
207
+ <button
208
+ key={server.id}
209
+ onClick={() => setSelectedServer(server)}
210
+ className={`w-full p-4 rounded-xl border text-left transition-all ${
211
+ selectedServer?.id === server.id
212
+ ? 'border-blue-500 bg-blue-500/10'
213
+ : 'border-neutral-800 bg-neutral-900/50 hover:border-neutral-700'
214
+ }`}
215
+ >
216
+ <div className="flex items-start justify-between mb-2">
217
+ <div className="font-medium text-white truncate pr-2">{server.name}</div>
218
+ <span
219
+ className={`px-2 py-0.5 text-xs rounded-full ${
220
+ server.status === 'active'
221
+ ? 'bg-green-500/20 text-green-400'
222
+ : 'bg-neutral-500/20 text-neutral-400'
223
+ }`}
224
+ >
225
+ {server.status}
226
+ </span>
227
+ </div>
228
+ <div className="text-xs text-neutral-500 flex items-center gap-3">
229
+ <span>{server.tools.length} tools</span>
230
+ <span>•</span>
231
+ <span>{server.usage.totalCalls} calls</span>
232
+ </div>
233
+ </button>
234
+ ))}
235
+ </motion.div>
236
+
237
+ {/* Server Details */}
238
+ <motion.div
239
+ initial={{ opacity: 0, x: 20 }}
240
+ animate={{ opacity: 1, x: 0 }}
241
+ transition={{ delay: 0.3 }}
242
+ className="md:col-span-2"
243
+ >
244
+ {selectedServer && (
245
+ <div className="rounded-xl border border-neutral-800 bg-neutral-900/50 backdrop-blur-sm overflow-hidden">
246
+ {/* Server Header */}
247
+ <div className="p-6 border-b border-neutral-800">
248
+ <div className="flex items-start justify-between">
249
+ <div>
250
+ <h2 className="text-xl font-bold text-white mb-1">{selectedServer.name}</h2>
251
+ <p className="text-sm text-neutral-400">{selectedServer.description}</p>
252
+ </div>
253
+ <div className="flex items-center gap-2">
254
+ <button
255
+ onClick={() => handleToggleStatus(selectedServer.id)}
256
+ className="p-2 text-neutral-400 hover:text-white rounded-lg hover:bg-white/5 transition-colors"
257
+ title={selectedServer.status === 'active' ? 'Pause server' : 'Resume server'}
258
+ >
259
+ {selectedServer.status === 'active' ? <Pause className="w-4 h-4" /> : <Play className="w-4 h-4" />}
260
+ </button>
261
+ <button
262
+ onClick={() => handleDelete(selectedServer.id)}
263
+ className="p-2 text-neutral-400 hover:text-red-400 rounded-lg hover:bg-red-500/10 transition-colors"
264
+ title="Delete server"
265
+ >
266
+ <Trash2 className="w-4 h-4" />
267
+ </button>
268
+ </div>
269
+ </div>
270
+ </div>
271
+
272
+ {/* Endpoint */}
273
+ <div className="p-6 border-b border-neutral-800">
274
+ <div className="text-xs text-neutral-500 mb-2">Endpoint URL</div>
275
+ <div className="flex items-center gap-2 p-3 bg-black/30 rounded-lg">
276
+ <Globe className="w-4 h-4 text-blue-400 flex-shrink-0" />
277
+ <code className="flex-1 text-sm text-green-400 font-mono truncate">
278
+ {selectedServer.endpoint}
279
+ </code>
280
+ <button
281
+ onClick={() => handleCopy(selectedServer.endpoint, `endpoint-${selectedServer.id}`)}
282
+ className="p-1.5 text-neutral-400 hover:text-white rounded hover:bg-white/5"
283
+ >
284
+ {copied === `endpoint-${selectedServer.id}` ? (
285
+ <Check className="w-4 h-4 text-green-400" />
286
+ ) : (
287
+ <Copy className="w-4 h-4" />
288
+ )}
289
+ </button>
290
+ </div>
291
+ </div>
292
+
293
+ {/* Usage Stats */}
294
+ <div className="p-6 border-b border-neutral-800">
295
+ <h3 className="text-sm font-medium text-neutral-400 mb-4 flex items-center gap-2">
296
+ <BarChart3 className="w-4 h-4" />
297
+ Usage Statistics
298
+ </h3>
299
+ <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
300
+ {[
301
+ { label: 'Total Calls', value: selectedServer.usage.totalCalls, trend: '+12%' },
302
+ { label: 'Today', value: selectedServer.usage.totalCallsToday },
303
+ { label: 'Success Rate', value: `${selectedServer.usage.successRate}%`, good: true },
304
+ { label: 'Avg Latency', value: `${selectedServer.usage.avgLatencyMs}ms` },
305
+ ].map(({ label, value, trend, good }) => (
306
+ <div key={label} className="p-3 bg-black/30 rounded-lg">
307
+ <div className="text-xs text-neutral-500 mb-1">{label}</div>
308
+ <div className="flex items-center gap-2">
309
+ <div className="text-lg font-bold text-white">{value}</div>
310
+ {trend && (
311
+ <span className="text-xs text-green-400 flex items-center">
312
+ <TrendingUp className="w-3 h-3 mr-0.5" />
313
+ {trend}
314
+ </span>
315
+ )}
316
+ </div>
317
+ </div>
318
+ ))}
319
+ </div>
320
+ </div>
321
+
322
+ {/* Tools */}
323
+ <div className="p-6">
324
+ <h3 className="text-sm font-medium text-neutral-400 mb-4 flex items-center gap-2">
325
+ <Settings className="w-4 h-4" />
326
+ Deployed Tools ({selectedServer.tools.length})
327
+ </h3>
328
+ <div className="space-y-2">
329
+ {selectedServer.tools.map((tool) => (
330
+ <div
331
+ key={tool.name}
332
+ className="flex items-center justify-between p-3 bg-black/30 rounded-lg"
333
+ >
334
+ <div className="flex items-center gap-3">
335
+ <div className={`w-2 h-2 rounded-full ${tool.enabled ? 'bg-green-400' : 'bg-neutral-500'}`} />
336
+ <div>
337
+ <div className="text-sm font-medium text-white">{tool.name}</div>
338
+ <div className="text-xs text-neutral-500 truncate max-w-[300px]">
339
+ {tool.description}
340
+ </div>
341
+ </div>
342
+ </div>
343
+ <div className="text-xs text-neutral-400">
344
+ {tool.callCount} calls
345
+ </div>
346
+ </div>
347
+ ))}
348
+ </div>
349
+ </div>
350
+
351
+ {/* Metadata */}
352
+ <div className="px-6 pb-6">
353
+ <div className="flex items-center gap-4 text-xs text-neutral-500">
354
+ <span className="flex items-center gap-1">
355
+ <Clock className="w-3 h-3" />
356
+ Created {new Date(selectedServer.createdAt).toLocaleDateString()}
357
+ </span>
358
+ <span className="flex items-center gap-1">
359
+ <Globe className="w-3 h-3" />
360
+ {selectedServer.region}
361
+ </span>
362
+ {selectedServer.sourceRepo && (
363
+ <span className="flex items-center gap-1">
364
+ <ExternalLink className="w-3 h-3" />
365
+ {selectedServer.sourceRepo}
366
+ </span>
367
+ )}
368
+ </div>
369
+ </div>
370
+ </div>
371
+ )}
372
+ </motion.div>
373
+ </div>
374
+ )}
375
+ </div>
376
+
377
+ <Footer />
378
+ </main>
379
+ );
380
+ }