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.
- package/.env.example +8 -0
- package/.github/CODEOWNERS +6 -0
- package/.husky/pre-commit +1 -0
- package/.nvmrc +1 -0
- package/.prettierignore +5 -0
- package/.prettierrc +7 -0
- package/.vscode/settings.json +4 -0
- package/ARCHITECTURE.md +1429 -0
- package/CHANGELOG.md +167 -0
- package/CONTRIBUTING.md +327 -0
- package/LICENSE +201 -0
- package/README.md +1028 -0
- package/SECURITY.md +248 -0
- package/VISUAL_GUIDE.md +437 -0
- package/apps/vscode/IMPLEMENTATION.md +480 -0
- package/apps/vscode/README.md +248 -0
- package/apps/vscode/package.json +381 -0
- package/apps/vscode/resources/icon.png +0 -0
- package/apps/vscode/resources/icon.svg +5 -0
- package/apps/vscode/src/commands/browseRegistry.ts +211 -0
- package/apps/vscode/src/commands/configureClaudeDesktop.ts +332 -0
- package/apps/vscode/src/commands/convert.ts +82 -0
- package/apps/vscode/src/commands/convertCurrentRepo.ts +109 -0
- package/apps/vscode/src/commands/convertFromUrl.ts +138 -0
- package/apps/vscode/src/commands/index.ts +121 -0
- package/apps/vscode/src/commands/validate.ts +197 -0
- package/apps/vscode/src/extension.ts +464 -0
- package/apps/vscode/src/global.d.ts +36 -0
- package/apps/vscode/src/test/extension.test.ts +73 -0
- package/apps/vscode/src/utils/file-generator.ts +529 -0
- package/apps/vscode/src/utils/github-api.ts +335 -0
- package/apps/vscode/src/utils/index.ts +29 -0
- package/apps/vscode/src/utils/mcp-config.ts +334 -0
- package/apps/vscode/src/utils/storage.ts +87 -0
- package/apps/vscode/src/views/McpServersTreeView.ts +160 -0
- package/apps/vscode/src/views/OutputChannelView.ts +195 -0
- package/apps/vscode/src/views/StatusBarItem.ts +251 -0
- package/apps/vscode/src/views/ToolsExplorerView.ts +314 -0
- package/apps/vscode/src/views/historyProvider.ts +75 -0
- package/apps/vscode/src/views/index.ts +12 -0
- package/apps/vscode/src/views/resultsPanel.ts +330 -0
- package/apps/vscode/src/webviews/ConversionPanel.ts +350 -0
- package/apps/vscode/src/webviews/ToolDetailsPanel.ts +448 -0
- package/apps/vscode/src/webviews/index.ts +9 -0
- package/apps/vscode/src/webviews/webview-ui/styles.ts +492 -0
- package/apps/vscode/tsconfig.json +20 -0
- package/apps/web/PLAYGROUND_GUIDE.md +499 -0
- package/apps/web/README.md +505 -0
- package/apps/web/app/api/convert/route.ts +100 -0
- package/apps/web/app/api/convert/stream/route.ts +198 -0
- package/apps/web/app/api/deploy/route.ts +157 -0
- package/apps/web/app/api/edge/route.ts +308 -0
- package/apps/web/app/api/export-docker/route.ts +284 -0
- package/apps/web/app/api/generate-openapi/route.ts +119 -0
- package/apps/web/app/api/mcp/[serverId]/route.ts +263 -0
- package/apps/web/app/api/playground/connect/route.ts +143 -0
- package/apps/web/app/api/playground/disconnect/route.ts +78 -0
- package/apps/web/app/api/playground/execute/route.ts +135 -0
- package/apps/web/app/api/playground/sessions/route.ts +103 -0
- package/apps/web/app/api/playground/tools/route.ts +117 -0
- package/apps/web/app/api/playground/v2/connect/route.ts +96 -0
- package/apps/web/app/api/playground/v2/disconnect/route.ts +88 -0
- package/apps/web/app/api/playground/v2/health/route.ts +80 -0
- package/apps/web/app/api/playground/v2/prompts/route.ts +160 -0
- package/apps/web/app/api/playground/v2/resources/route.ts +159 -0
- package/apps/web/app/api/playground/v2/sessions/route.ts +184 -0
- package/apps/web/app/api/playground/v2/tools/route.ts +167 -0
- package/apps/web/app/api/stream/route.ts +232 -0
- package/apps/web/app/batch/BatchConvertClient.tsx +190 -0
- package/apps/web/app/batch/page.tsx +37 -0
- package/apps/web/app/convert/page.tsx +269 -0
- package/apps/web/app/dashboard/page.tsx +380 -0
- package/apps/web/app/globals.css +622 -0
- package/apps/web/app/layout.tsx +120 -0
- package/apps/web/app/manifest.ts +31 -0
- package/apps/web/app/opengraph-image.tsx +112 -0
- package/apps/web/app/page.old.tsx +924 -0
- package/apps/web/app/page.tsx +77 -0
- package/apps/web/app/playground/page.tsx +306 -0
- package/apps/web/app/playground/v2/error.tsx +163 -0
- package/apps/web/app/playground/v2/layout.tsx +58 -0
- package/apps/web/app/playground/v2/loading.tsx +152 -0
- package/apps/web/app/playground/v2/page.tsx +644 -0
- package/apps/web/app/playground/v2/providers.tsx +214 -0
- package/apps/web/app/playground/v2/use-shortcuts.ts +209 -0
- package/apps/web/app/playground/v2/use-url-state.ts +296 -0
- package/apps/web/app/providers.tsx +22 -0
- package/apps/web/app/sitemap.ts +32 -0
- package/apps/web/app/twitter-image.tsx +112 -0
- package/apps/web/components/BranchSelector.tsx +401 -0
- package/apps/web/components/ClaudeConfigExport.tsx +226 -0
- package/apps/web/components/Features.tsx +84 -0
- package/apps/web/components/Footer.tsx +119 -0
- package/apps/web/components/GenerationProgress.tsx +248 -0
- package/apps/web/components/GithubUrlInput.tsx +483 -0
- package/apps/web/components/Header.tsx +175 -0
- package/apps/web/components/Hero.tsx +117 -0
- package/apps/web/components/HowItWorks.tsx +119 -0
- package/apps/web/components/InstallBanner.tsx +158 -0
- package/apps/web/components/Logo.tsx +116 -0
- package/apps/web/components/ParticleBackground.tsx +105 -0
- package/apps/web/components/Playground.tsx +472 -0
- package/apps/web/components/PlaygroundToolTester.tsx +410 -0
- package/apps/web/components/ProductCards.tsx +179 -0
- package/apps/web/components/SplitView.tsx +194 -0
- package/apps/web/components/ToolFilter.tsx +260 -0
- package/apps/web/components/ToolList.tsx +325 -0
- package/apps/web/components/batch/BatchConvert.tsx +785 -0
- package/apps/web/components/batch/index.ts +7 -0
- package/apps/web/components/convert/ConfigTabs.tsx +230 -0
- package/apps/web/components/convert/ConversionResult.tsx +482 -0
- package/apps/web/components/convert/InlinePlayground.tsx +259 -0
- package/apps/web/components/convert/LoadingSteps.tsx +311 -0
- package/apps/web/components/convert/OneClickInstall.tsx +224 -0
- package/apps/web/components/convert/ToolCard.tsx +189 -0
- package/apps/web/components/convert/TryInPlayground.tsx +242 -0
- package/apps/web/components/convert/index.ts +12 -0
- package/apps/web/components/deploy/DeployButton.tsx +369 -0
- package/apps/web/components/deploy/index.ts +7 -0
- package/apps/web/components/docker/DockerExport.tsx +690 -0
- package/apps/web/components/docker/index.ts +7 -0
- package/apps/web/components/install/OneClickInstall.tsx +676 -0
- package/apps/web/components/install/index.ts +7 -0
- package/apps/web/components/playground/CapabilityTabs.tsx +150 -0
- package/apps/web/components/playground/ConnectionStatusV2.tsx +322 -0
- package/apps/web/components/playground/EmptyStates.tsx +305 -0
- package/apps/web/components/playground/ExecutionLog.tsx +260 -0
- package/apps/web/components/playground/ExecutionLogV2.tsx +378 -0
- package/apps/web/components/playground/JsonViewer.tsx +388 -0
- package/apps/web/components/playground/PlaygroundLayout.tsx +244 -0
- package/apps/web/components/playground/PromptsPanel.tsx +385 -0
- package/apps/web/components/playground/ResourcesPanel.tsx +378 -0
- package/apps/web/components/playground/SchemaForm.tsx +477 -0
- package/apps/web/components/playground/ServerStatus.tsx +151 -0
- package/apps/web/components/playground/ShareButton.tsx +239 -0
- package/apps/web/components/playground/ToolsPanel.tsx +309 -0
- package/apps/web/components/playground/TransportConfigurator.tsx +563 -0
- package/apps/web/components/playground/index.ts +74 -0
- package/apps/web/components/playground/types.ts +202 -0
- package/apps/web/components/streaming/StreamingProgress.tsx +441 -0
- package/apps/web/components/streaming/index.ts +7 -0
- package/apps/web/components/ui/badge.tsx +42 -0
- package/apps/web/components/ui/button.tsx +88 -0
- package/apps/web/components/ui/card.tsx +75 -0
- package/apps/web/components/ui/code-block.tsx +122 -0
- package/apps/web/components/ui/index.ts +12 -0
- package/apps/web/components/ui/input.tsx +55 -0
- package/apps/web/components/ui/tabs.tsx +61 -0
- package/apps/web/hooks/index.ts +85 -0
- package/apps/web/hooks/types.ts +1173 -0
- package/apps/web/hooks/use-conversion.ts +133 -0
- package/apps/web/hooks/use-execution-history.ts +376 -0
- package/apps/web/hooks/use-generation-progress.ts +147 -0
- package/apps/web/hooks/use-local-storage.ts +88 -0
- package/apps/web/hooks/use-mcp-client.ts +623 -0
- package/apps/web/hooks/use-mcp-connection.ts +500 -0
- package/apps/web/hooks/use-mcp-execution.ts +282 -0
- package/apps/web/hooks/use-mcp-prompts.ts +441 -0
- package/apps/web/hooks/use-mcp-resources.ts +430 -0
- package/apps/web/hooks/use-mcp-tools.ts +540 -0
- package/apps/web/hooks/use-playground-store.ts +299 -0
- package/apps/web/hooks/use-playground.ts +184 -0
- package/apps/web/hooks/use-streaming-conversion.ts +227 -0
- package/apps/web/hooks/useBatchConversion.ts +271 -0
- package/apps/web/hooks/useDockerConfig.ts +161 -0
- package/apps/web/hooks/usePlatformDetection.ts +80 -0
- package/apps/web/hooks/useStreaming.ts +199 -0
- package/apps/web/lib/api/errors.ts +386 -0
- package/apps/web/lib/api/index.ts +137 -0
- package/apps/web/lib/api/logger.ts +187 -0
- package/apps/web/lib/api/middleware.ts +364 -0
- package/apps/web/lib/api/openapi.ts +977 -0
- package/apps/web/lib/api/session-manager.ts +594 -0
- package/apps/web/lib/api/types.ts +433 -0
- package/apps/web/lib/api/validation.ts +523 -0
- package/apps/web/lib/constants.ts +114 -0
- package/apps/web/lib/mcp/client.ts +1137 -0
- package/apps/web/lib/mcp/events.ts +651 -0
- package/apps/web/lib/mcp/index.ts +347 -0
- package/apps/web/lib/mcp/logger.ts +428 -0
- package/apps/web/lib/mcp/metrics.ts +703 -0
- package/apps/web/lib/mcp/retry.ts +616 -0
- package/apps/web/lib/mcp/session-manager.ts +779 -0
- package/apps/web/lib/mcp/transports.ts +988 -0
- package/apps/web/lib/mcp/types.ts +594 -0
- package/apps/web/lib/mcp-client-enhanced.ts +871 -0
- package/apps/web/lib/mcp-client.ts +778 -0
- package/apps/web/lib/mcp-errors.ts +489 -0
- package/apps/web/lib/mcp-sandbox.ts +593 -0
- package/apps/web/lib/mcp-testing.ts +428 -0
- package/apps/web/lib/mcp-types.ts +448 -0
- package/apps/web/lib/playground-store.tsx +1147 -0
- package/apps/web/lib/utils.ts +439 -0
- package/apps/web/next-env.d.ts +5 -0
- package/apps/web/next.config.js +23 -0
- package/apps/web/package.json +55 -0
- package/apps/web/postcss.config.js +6 -0
- package/apps/web/public/.well-known/ai-plugin.json +17 -0
- package/apps/web/public/logo.svg +6 -0
- package/apps/web/public/robots.txt +22 -0
- package/apps/web/public/schema.json +27 -0
- package/apps/web/tailwind.config.js +26 -0
- package/apps/web/tailwind.config.ts +123 -0
- package/apps/web/tsconfig.json +20 -0
- package/apps/web/types/deploy.ts +139 -0
- package/apps/web/types/index.ts +247 -0
- package/apps/web/vercel.json +39 -0
- package/eslint.config.mjs +23 -0
- package/llms.txt +102 -0
- package/mkdocs/docs/api/core.md +318 -0
- package/mkdocs/docs/api/index.md +128 -0
- package/mkdocs/docs/api/mcp-server.md +301 -0
- package/mkdocs/docs/api/openapi-parser.md +254 -0
- package/mkdocs/docs/assets/logo.svg +7 -0
- package/mkdocs/docs/changelog.md +118 -0
- package/mkdocs/docs/cli/generate.md +148 -0
- package/mkdocs/docs/cli/index.md +52 -0
- package/mkdocs/docs/cli/inspect.md +164 -0
- package/mkdocs/docs/cli/serve.md +136 -0
- package/mkdocs/docs/concepts/classification.md +254 -0
- package/mkdocs/docs/concepts/how-it-works.md +299 -0
- package/mkdocs/docs/concepts/index.md +77 -0
- package/mkdocs/docs/concepts/mcp-protocol.md +362 -0
- package/mkdocs/docs/concepts/tool-types.md +382 -0
- package/mkdocs/docs/contributing/architecture.md +262 -0
- package/mkdocs/docs/contributing/development.md +245 -0
- package/mkdocs/docs/contributing/index.md +73 -0
- package/mkdocs/docs/contributing/testing.md +320 -0
- package/mkdocs/docs/getting-started/configuration.md +235 -0
- package/mkdocs/docs/getting-started/index.md +54 -0
- package/mkdocs/docs/getting-started/installation.md +145 -0
- package/mkdocs/docs/getting-started/quickstart.md +160 -0
- package/mkdocs/docs/guides/batch.md +375 -0
- package/mkdocs/docs/guides/claude-desktop.md +227 -0
- package/mkdocs/docs/guides/cursor.md +188 -0
- package/mkdocs/docs/guides/custom-tools.md +367 -0
- package/mkdocs/docs/guides/index.md +78 -0
- package/mkdocs/docs/guides/private-repos.md +221 -0
- package/mkdocs/docs/guides/vscode.md +247 -0
- package/mkdocs/docs/index.md +175 -0
- package/mkdocs/docs/reference/config.md +223 -0
- package/mkdocs/docs/reference/env.md +192 -0
- package/mkdocs/docs/reference/index.md +102 -0
- package/mkdocs/docs/reference/tools.md +309 -0
- package/mkdocs/docs/stylesheets/extra.css +231 -0
- package/mkdocs/mkdocs.yml +204 -0
- package/mkdocs/overrides/.gitkeep +1 -0
- package/mkdocs/overrides/main.html +7 -0
- package/mkdocs/python-deps.txt +7 -0
- package/mkdocs/vercel.json +11 -0
- package/package.json +63 -0
- package/packages/core/package.json +61 -0
- package/packages/core/src/__tests__/bitbucket-client.test.ts +366 -0
- package/packages/core/src/__tests__/cli.test.ts +235 -0
- package/packages/core/src/__tests__/code-extractor.test.ts +378 -0
- package/packages/core/src/__tests__/docker-generator.test.ts +255 -0
- package/packages/core/src/__tests__/github-client.test.ts +390 -0
- package/packages/core/src/__tests__/gitlab-client.test.ts +319 -0
- package/packages/core/src/__tests__/go-extractor.test.ts +351 -0
- package/packages/core/src/__tests__/graphql-extractor.test.ts +330 -0
- package/packages/core/src/__tests__/java-extractor.test.ts +497 -0
- package/packages/core/src/__tests__/plugins.test.ts +467 -0
- package/packages/core/src/__tests__/readme-extractor.test.ts +258 -0
- package/packages/core/src/__tests__/redis-cache.test.ts +307 -0
- package/packages/core/src/__tests__/rust-extractor.test.ts +252 -0
- package/packages/core/src/__tests__/streaming.test.ts +251 -0
- package/packages/core/src/additional-extractors.ts +333 -0
- package/packages/core/src/cache/cache-interface.ts +179 -0
- package/packages/core/src/cache/index.ts +210 -0
- package/packages/core/src/cache/redis-cache.ts +291 -0
- package/packages/core/src/cache/upstash-cache.ts +379 -0
- package/packages/core/src/cache.ts +251 -0
- package/packages/core/src/cli.ts +822 -0
- package/packages/core/src/code-extractor.ts +696 -0
- package/packages/core/src/docker-generator.ts +470 -0
- package/packages/core/src/edge-compatible.ts +491 -0
- package/packages/core/src/extractors/go-extractor.ts +791 -0
- package/packages/core/src/extractors/index.ts +9 -0
- package/packages/core/src/extractors/java-extractor.ts +937 -0
- package/packages/core/src/extractors/rust-extractor.ts +744 -0
- package/packages/core/src/github-client.ts +319 -0
- package/packages/core/src/go-generator.ts +356 -0
- package/packages/core/src/graphql-extractor.ts +358 -0
- package/packages/core/src/index.ts +797 -0
- package/packages/core/src/langchain-exporter.ts +617 -0
- package/packages/core/src/language-parsers.ts +1114 -0
- package/packages/core/src/mcp-introspector.ts +279 -0
- package/packages/core/src/monorepo-detector.ts +378 -0
- package/packages/core/src/plugins/index.ts +370 -0
- package/packages/core/src/plugins/registry.ts +404 -0
- package/packages/core/src/plugins/types.ts +215 -0
- package/packages/core/src/providers/base-provider.ts +246 -0
- package/packages/core/src/providers/bitbucket-client.ts +464 -0
- package/packages/core/src/providers/gitlab-client.ts +388 -0
- package/packages/core/src/providers/index.ts +176 -0
- package/packages/core/src/python-generator.ts +260 -0
- package/packages/core/src/queue/index.ts +100 -0
- package/packages/core/src/queue/memory-queue.ts +445 -0
- package/packages/core/src/queue/redis-queue.ts +578 -0
- package/packages/core/src/queue/types.ts +251 -0
- package/packages/core/src/readme-extractor.ts +409 -0
- package/packages/core/src/schema-generator.ts +638 -0
- package/packages/core/src/streaming.ts +999 -0
- package/packages/core/src/types.ts +289 -0
- package/packages/core/tsconfig.json +9 -0
- package/packages/core/tsup.config.ts +25 -0
- package/packages/mcp-server/README.md +297 -0
- package/packages/mcp-server/package.json +55 -0
- package/packages/mcp-server/src/__tests__/mcp-server.test.ts +177 -0
- package/packages/mcp-server/src/__tests__/tools.test.ts +217 -0
- package/packages/mcp-server/src/index.ts +1206 -0
- package/packages/mcp-server/src/prompts/index.ts +601 -0
- package/packages/mcp-server/src/tools/export-docker.ts +362 -0
- package/packages/mcp-server/src/tools/generate-openapi.ts +162 -0
- package/packages/mcp-server/src/tools/monitor-mcp-server.ts +448 -0
- package/packages/mcp-server/src/tools/stream-convert.ts +398 -0
- package/packages/mcp-server/src/tools/test-mcp-tool.ts +531 -0
- package/packages/mcp-server/tsconfig.json +12 -0
- package/packages/mcp-server/tsup.config.ts +14 -0
- package/packages/openapi-parser/package-lock.json +3028 -0
- package/packages/openapi-parser/package.json +41 -0
- package/packages/openapi-parser/src/analyzer.ts +700 -0
- package/packages/openapi-parser/src/asyncapi-parser.ts +475 -0
- package/packages/openapi-parser/src/cli.ts +302 -0
- package/packages/openapi-parser/src/generator.ts +570 -0
- package/packages/openapi-parser/src/generators/express-analyzer.ts +649 -0
- package/packages/openapi-parser/src/generators/fastapi-analyzer.ts +960 -0
- package/packages/openapi-parser/src/generators/index.ts +200 -0
- package/packages/openapi-parser/src/generators/nextjs-analyzer.ts +768 -0
- package/packages/openapi-parser/src/generators/openapi-builder.ts +527 -0
- package/packages/openapi-parser/src/generators/types.ts +298 -0
- package/packages/openapi-parser/src/graphql-parser.ts +462 -0
- package/packages/openapi-parser/src/grpc-parser.ts +649 -0
- package/packages/openapi-parser/src/har-parser.ts +723 -0
- package/packages/openapi-parser/src/index.ts +635 -0
- package/packages/openapi-parser/src/insomnia-parser.ts +614 -0
- package/packages/openapi-parser/src/parser.ts +231 -0
- package/packages/openapi-parser/src/postman-parser.ts +611 -0
- package/packages/openapi-parser/src/ref-resolver.ts +313 -0
- package/packages/openapi-parser/src/transformer.ts +459 -0
- package/packages/openapi-parser/tests/generators/express.test.ts +209 -0
- package/packages/openapi-parser/tests/generators/fastapi.test.ts +236 -0
- package/packages/openapi-parser/tests/generators/nextjs.test.ts +273 -0
- package/packages/openapi-parser/tests/parsers.test.ts +847 -0
- package/packages/openapi-parser/tsconfig.json +9 -0
- package/packages/openapi-parser/tsup.config.ts +11 -0
- package/packages/registry/package.json +59 -0
- package/packages/registry/src/cli.ts +456 -0
- package/packages/registry/src/index.ts +44 -0
- package/packages/registry/src/popular/github.json +47 -0
- package/packages/registry/src/popular/index.ts +55 -0
- package/packages/registry/src/popular/linear.json +42 -0
- package/packages/registry/src/popular/notion.json +42 -0
- package/packages/registry/src/popular/openai.json +40 -0
- package/packages/registry/src/popular/resend.json +38 -0
- package/packages/registry/src/popular/slack.json +42 -0
- package/packages/registry/src/popular/stripe.json +163 -0
- package/packages/registry/src/popular/supabase.json +42 -0
- package/packages/registry/src/popular/twilio.json +40 -0
- package/packages/registry/src/popular/vercel.json +40 -0
- package/packages/registry/src/registry.ts +492 -0
- package/packages/registry/src/storage.ts +334 -0
- package/packages/registry/src/types.ts +275 -0
- package/packages/registry/src/updater.ts +208 -0
- package/packages/registry/tsconfig.json +10 -0
- package/packages/registry/tsup.config.ts +11 -0
- package/pnpm-workspace.yaml +3 -0
- package/scripts/build-docs.sh +16 -0
- package/server.json +9 -0
- package/templates/Dockerfile.python.template +60 -0
- package/templates/Dockerfile.typescript.template +60 -0
- package/templates/docker-compose.template.yml +68 -0
- package/tests/fixtures/express-app/index.js +34 -0
- package/tests/fixtures/express-app/routes/posts.js +43 -0
- package/tests/fixtures/express-app/routes/users.js +58 -0
- package/tests/fixtures/fastapi-app/main.py +125 -0
- package/tests/fixtures/fastapi-app/routes/admin.py +42 -0
- package/tests/fixtures/graphql/simple-schema.graphql +65 -0
- package/tests/fixtures/mocks/github-api-responses.json +63 -0
- package/tests/fixtures/nextjs-app/app/api/posts/route.ts +55 -0
- package/tests/fixtures/nextjs-app/app/api/users/[id]/route.ts +63 -0
- package/tests/fixtures/nextjs-app/app/api/users/route.ts +44 -0
- package/tests/fixtures/nextjs-app/pages/api/health.ts +28 -0
- package/tests/fixtures/openapi/petstore.yaml +179 -0
- package/tests/integration/langchain-export.test.ts +405 -0
- package/tests/integration/openapi-conversion.test.ts +221 -0
- package/tsconfig.json +18 -0
- package/vitest.config.ts +32 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streaming Convert API - Real-time progress updates via Server-Sent Events
|
|
3
|
+
* @copyright 2024-2026 nirholas
|
|
4
|
+
* @license MIT
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { NextRequest } from 'next/server';
|
|
8
|
+
|
|
9
|
+
export const runtime = 'nodejs';
|
|
10
|
+
export const dynamic = 'force-dynamic';
|
|
11
|
+
|
|
12
|
+
// Progress steps for the streaming response
|
|
13
|
+
const PROGRESS_STEPS = [
|
|
14
|
+
{ id: 'validate', label: 'Validating GitHub URL', description: 'Checking repository accessibility' },
|
|
15
|
+
{ id: 'fetch', label: 'Fetching repository', description: 'Downloading repository metadata' },
|
|
16
|
+
{ id: 'classify', label: 'Classifying repository', description: 'Detecting repo type and structure' },
|
|
17
|
+
{ id: 'readme', label: 'Analyzing README', description: 'Extracting documentation and examples' },
|
|
18
|
+
{ id: 'openapi', label: 'Scanning for OpenAPI specs', description: 'Looking for API definitions' },
|
|
19
|
+
{ id: 'code', label: 'Analyzing code', description: 'Extracting functions and patterns' },
|
|
20
|
+
{ id: 'generate-ts', label: 'Generating TypeScript server', description: 'Creating MCP server code' },
|
|
21
|
+
{ id: 'generate-py', label: 'Generating Python server', description: 'Creating Python alternative' },
|
|
22
|
+
{ id: 'configs', label: 'Creating configurations', description: 'Building platform configs' },
|
|
23
|
+
{ id: 'complete', label: 'Conversion complete', description: 'MCP server ready' },
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
export async function GET(request: NextRequest) {
|
|
27
|
+
const url = request.nextUrl.searchParams.get('url');
|
|
28
|
+
|
|
29
|
+
if (!url) {
|
|
30
|
+
return new Response(JSON.stringify({ error: 'GitHub URL is required' }), {
|
|
31
|
+
status: 400,
|
|
32
|
+
headers: { 'Content-Type': 'application/json' },
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Validate GitHub URL
|
|
37
|
+
const githubPattern = /^https?:\/\/(www\.)?github\.com\/[\w-]+\/[\w.-]+/;
|
|
38
|
+
if (!githubPattern.test(url)) {
|
|
39
|
+
return new Response(JSON.stringify({ error: 'Invalid GitHub URL format' }), {
|
|
40
|
+
status: 400,
|
|
41
|
+
headers: { 'Content-Type': 'application/json' },
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const encoder = new TextEncoder();
|
|
46
|
+
|
|
47
|
+
const stream = new ReadableStream({
|
|
48
|
+
async start(controller) {
|
|
49
|
+
const sendEvent = (event: string, data: unknown) => {
|
|
50
|
+
controller.enqueue(encoder.encode(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`));
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
// Step 1: Validate URL
|
|
55
|
+
sendEvent('progress', {
|
|
56
|
+
step: 'validate',
|
|
57
|
+
status: 'in-progress',
|
|
58
|
+
message: PROGRESS_STEPS[0].label,
|
|
59
|
+
description: PROGRESS_STEPS[0].description,
|
|
60
|
+
progress: 5,
|
|
61
|
+
});
|
|
62
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
63
|
+
sendEvent('progress', { step: 'validate', status: 'complete', progress: 10 });
|
|
64
|
+
|
|
65
|
+
// Step 2: Fetch repository
|
|
66
|
+
sendEvent('progress', {
|
|
67
|
+
step: 'fetch',
|
|
68
|
+
status: 'in-progress',
|
|
69
|
+
message: PROGRESS_STEPS[1].label,
|
|
70
|
+
description: PROGRESS_STEPS[1].description,
|
|
71
|
+
progress: 15,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Import the generator dynamically
|
|
75
|
+
const { generateFromGithub } = await import('@nirholas/github-to-mcp');
|
|
76
|
+
|
|
77
|
+
// Create a wrapper that will be used for streaming updates
|
|
78
|
+
let currentProgress = 15;
|
|
79
|
+
|
|
80
|
+
// We'll call the actual generation, but simulate progress steps
|
|
81
|
+
const progressUpdates = [
|
|
82
|
+
{ step: 'fetch', delay: 500, progress: 20 },
|
|
83
|
+
{ step: 'classify', delay: 800, progress: 30 },
|
|
84
|
+
{ step: 'readme', delay: 600, progress: 40 },
|
|
85
|
+
{ step: 'openapi', delay: 1000, progress: 55 },
|
|
86
|
+
{ step: 'code', delay: 1200, progress: 70 },
|
|
87
|
+
{ step: 'generate-ts', delay: 800, progress: 80 },
|
|
88
|
+
{ step: 'generate-py', delay: 600, progress: 90 },
|
|
89
|
+
{ step: 'configs', delay: 400, progress: 95 },
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
// Start the actual generation in the background
|
|
93
|
+
const generationPromise = generateFromGithub(url, {
|
|
94
|
+
sources: ['readme', 'openapi', 'code'],
|
|
95
|
+
githubToken: process.env.GITHUB_TOKEN,
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Send progress updates while generation is happening
|
|
99
|
+
for (const update of progressUpdates) {
|
|
100
|
+
sendEvent('progress', {
|
|
101
|
+
step: update.step,
|
|
102
|
+
status: 'in-progress',
|
|
103
|
+
message: PROGRESS_STEPS.find(s => s.id === update.step)?.label || update.step,
|
|
104
|
+
description: PROGRESS_STEPS.find(s => s.id === update.step)?.description || '',
|
|
105
|
+
progress: update.progress,
|
|
106
|
+
});
|
|
107
|
+
await new Promise(resolve => setTimeout(resolve, update.delay));
|
|
108
|
+
sendEvent('progress', { step: update.step, status: 'complete', progress: update.progress + 5 });
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Wait for actual generation to complete
|
|
112
|
+
const result = await generationPromise;
|
|
113
|
+
|
|
114
|
+
// Generate the MCP server code
|
|
115
|
+
const code = result.generate();
|
|
116
|
+
const pythonCode = result.generatePython ? result.generatePython() : '';
|
|
117
|
+
|
|
118
|
+
// Generate config snippets
|
|
119
|
+
const repoName = result.name;
|
|
120
|
+
|
|
121
|
+
const claudeConfig = JSON.stringify({
|
|
122
|
+
mcpServers: {
|
|
123
|
+
[repoName]: {
|
|
124
|
+
command: 'npx',
|
|
125
|
+
args: ['tsx', `${repoName}-mcp/index.ts`],
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
}, null, 2);
|
|
129
|
+
|
|
130
|
+
const cursorConfig = JSON.stringify({
|
|
131
|
+
mcpServers: {
|
|
132
|
+
[repoName]: {
|
|
133
|
+
command: 'npx',
|
|
134
|
+
args: ['tsx', `${repoName}-mcp/index.ts`],
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
}, null, 2);
|
|
138
|
+
|
|
139
|
+
const claudePythonConfig = JSON.stringify({
|
|
140
|
+
mcpServers: {
|
|
141
|
+
[repoName]: {
|
|
142
|
+
command: 'python',
|
|
143
|
+
args: ['-m', `${repoName.replace(/-/g, '_')}_mcp`],
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
}, null, 2);
|
|
147
|
+
|
|
148
|
+
// Send completion
|
|
149
|
+
sendEvent('progress', {
|
|
150
|
+
step: 'complete',
|
|
151
|
+
status: 'complete',
|
|
152
|
+
message: PROGRESS_STEPS[9].label,
|
|
153
|
+
description: `Successfully extracted ${result.tools.length} tools`,
|
|
154
|
+
progress: 100,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Send the final result
|
|
158
|
+
sendEvent('result', {
|
|
159
|
+
name: result.name,
|
|
160
|
+
tools: result.tools.map((t) => ({
|
|
161
|
+
name: t.name,
|
|
162
|
+
description: t.description,
|
|
163
|
+
inputSchema: t.inputSchema,
|
|
164
|
+
source: t.source,
|
|
165
|
+
})),
|
|
166
|
+
sources: result.sources,
|
|
167
|
+
classification: result.classification,
|
|
168
|
+
code,
|
|
169
|
+
pythonCode,
|
|
170
|
+
claudeConfig,
|
|
171
|
+
cursorConfig,
|
|
172
|
+
claudePythonConfig,
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
sendEvent('done', { success: true });
|
|
176
|
+
|
|
177
|
+
} catch (error) {
|
|
178
|
+
const message = error instanceof Error ? error.message : 'Conversion failed';
|
|
179
|
+
|
|
180
|
+
sendEvent('error', {
|
|
181
|
+
error: message,
|
|
182
|
+
code: message.includes('rate limit') ? 'RATE_LIMIT' : 'CONVERSION_ERROR',
|
|
183
|
+
});
|
|
184
|
+
} finally {
|
|
185
|
+
controller.close();
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
return new Response(stream, {
|
|
191
|
+
headers: {
|
|
192
|
+
'Content-Type': 'text/event-stream',
|
|
193
|
+
'Cache-Control': 'no-cache, no-transform',
|
|
194
|
+
'Connection': 'keep-alive',
|
|
195
|
+
'X-Accel-Buffering': 'no',
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deploy API - Create cloud-hosted MCP servers
|
|
3
|
+
* @copyright 2024-2026 nirholas
|
|
4
|
+
* @license MIT
|
|
5
|
+
*
|
|
6
|
+
* POST /api/deploy - Deploy a new MCP server
|
|
7
|
+
* GET /api/deploy - List user's deployed servers
|
|
8
|
+
* DELETE /api/deploy?id=xxx - Delete a deployed server
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
12
|
+
import { nanoid } from 'nanoid';
|
|
13
|
+
import type {
|
|
14
|
+
DeployRequest,
|
|
15
|
+
DeployResponse,
|
|
16
|
+
DeployedServer,
|
|
17
|
+
ServerListResponse
|
|
18
|
+
} from '@/types/deploy';
|
|
19
|
+
|
|
20
|
+
// In production, this would be a database (Vercel KV, Planetscale, etc.)
|
|
21
|
+
// For now, we use in-memory storage with localStorage sync on client
|
|
22
|
+
const STORAGE_KEY = 'github-to-mcp-deployed-servers';
|
|
23
|
+
|
|
24
|
+
// Generate a secure API key
|
|
25
|
+
function generateApiKey(): string {
|
|
26
|
+
return `mcp_${nanoid(32)}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Hash API key for storage (simple hash for demo, use bcrypt in production)
|
|
30
|
+
function hashApiKey(key: string): string {
|
|
31
|
+
// In production, use proper hashing
|
|
32
|
+
return Buffer.from(key).toString('base64');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Generate server endpoint URL
|
|
36
|
+
function generateEndpoint(serverId: string): string {
|
|
37
|
+
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'https://github-to-mcp.vercel.app';
|
|
38
|
+
return `${baseUrl}/api/mcp/${serverId}`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* POST /api/deploy - Deploy a new MCP server
|
|
43
|
+
*/
|
|
44
|
+
export async function POST(request: NextRequest): Promise<NextResponse<DeployResponse>> {
|
|
45
|
+
try {
|
|
46
|
+
const body = await request.json() as DeployRequest;
|
|
47
|
+
|
|
48
|
+
// Validate request
|
|
49
|
+
if (!body.name || !body.code || !body.tools?.length) {
|
|
50
|
+
return NextResponse.json({
|
|
51
|
+
success: false,
|
|
52
|
+
error: 'Missing required fields: name, code, and tools are required',
|
|
53
|
+
}, { status: 400 });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Generate IDs and keys
|
|
57
|
+
const serverId = nanoid(12);
|
|
58
|
+
const apiKey = generateApiKey();
|
|
59
|
+
const endpoint = generateEndpoint(serverId);
|
|
60
|
+
|
|
61
|
+
// Create deployed server record
|
|
62
|
+
const server: DeployedServer = {
|
|
63
|
+
id: serverId,
|
|
64
|
+
name: body.name,
|
|
65
|
+
description: body.description || `MCP server for ${body.name}`,
|
|
66
|
+
|
|
67
|
+
tools: body.tools.map(t => ({
|
|
68
|
+
name: t.name,
|
|
69
|
+
description: t.description,
|
|
70
|
+
inputSchema: t.inputSchema,
|
|
71
|
+
enabled: true,
|
|
72
|
+
callCount: 0,
|
|
73
|
+
})),
|
|
74
|
+
code: body.code,
|
|
75
|
+
language: 'typescript',
|
|
76
|
+
|
|
77
|
+
endpoint,
|
|
78
|
+
status: 'active',
|
|
79
|
+
region: 'us-east-1',
|
|
80
|
+
createdAt: new Date().toISOString(),
|
|
81
|
+
updatedAt: new Date().toISOString(),
|
|
82
|
+
|
|
83
|
+
sourceRepo: body.sourceRepo,
|
|
84
|
+
|
|
85
|
+
apiKeyHash: hashApiKey(apiKey),
|
|
86
|
+
rateLimit: {
|
|
87
|
+
requestsPerMinute: body.rateLimit?.requestsPerMinute || 60,
|
|
88
|
+
requestsPerDay: body.rateLimit?.requestsPerDay || 10000,
|
|
89
|
+
enabled: true,
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
usage: {
|
|
93
|
+
totalCalls: 0,
|
|
94
|
+
totalCallsToday: 0,
|
|
95
|
+
totalCallsThisMonth: 0,
|
|
96
|
+
successRate: 100,
|
|
97
|
+
avgLatencyMs: 0,
|
|
98
|
+
callsByTool: {},
|
|
99
|
+
callsByDay: [],
|
|
100
|
+
errors: [],
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// In production: Save to database
|
|
105
|
+
// For demo: Return the server data (client will store in localStorage)
|
|
106
|
+
|
|
107
|
+
return NextResponse.json({
|
|
108
|
+
success: true,
|
|
109
|
+
server,
|
|
110
|
+
endpoint,
|
|
111
|
+
apiKey, // Only returned on creation!
|
|
112
|
+
});
|
|
113
|
+
} catch (error) {
|
|
114
|
+
console.error('Deploy error:', error);
|
|
115
|
+
return NextResponse.json({
|
|
116
|
+
success: false,
|
|
117
|
+
error: error instanceof Error ? error.message : 'Deployment failed',
|
|
118
|
+
}, { status: 500 });
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* GET /api/deploy - List deployed servers
|
|
124
|
+
* In production, this would fetch from database based on authenticated user
|
|
125
|
+
*/
|
|
126
|
+
export async function GET(request: NextRequest): Promise<NextResponse<ServerListResponse>> {
|
|
127
|
+
// In production: Fetch from database with auth
|
|
128
|
+
// For demo: Client manages storage, this is a placeholder
|
|
129
|
+
|
|
130
|
+
return NextResponse.json({
|
|
131
|
+
servers: [],
|
|
132
|
+
total: 0,
|
|
133
|
+
hasMore: false,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* DELETE /api/deploy?id=xxx - Delete a deployed server
|
|
139
|
+
*/
|
|
140
|
+
export async function DELETE(request: NextRequest): Promise<NextResponse> {
|
|
141
|
+
const { searchParams } = new URL(request.url);
|
|
142
|
+
const serverId = searchParams.get('id');
|
|
143
|
+
|
|
144
|
+
if (!serverId) {
|
|
145
|
+
return NextResponse.json({
|
|
146
|
+
success: false,
|
|
147
|
+
error: 'Server ID is required',
|
|
148
|
+
}, { status: 400 });
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// In production: Delete from database with auth verification
|
|
152
|
+
|
|
153
|
+
return NextResponse.json({
|
|
154
|
+
success: true,
|
|
155
|
+
message: `Server ${serverId} deleted`,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Edge API Route for github-to-mcp
|
|
3
|
+
*
|
|
4
|
+
* This route runs on Vercel Edge Runtime for fast, globally distributed processing.
|
|
5
|
+
* It provides a lightweight version of the MCP generation that works in edge environments.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
9
|
+
|
|
10
|
+
// Tell Next.js to use edge runtime
|
|
11
|
+
export const runtime = 'edge';
|
|
12
|
+
|
|
13
|
+
// Edge-compatible types
|
|
14
|
+
interface EdgeResult {
|
|
15
|
+
repo: string;
|
|
16
|
+
name: string;
|
|
17
|
+
tools: Array<{
|
|
18
|
+
name: string;
|
|
19
|
+
description: string;
|
|
20
|
+
inputSchema: object;
|
|
21
|
+
source: { type: string; file: string };
|
|
22
|
+
confidence?: number;
|
|
23
|
+
}>;
|
|
24
|
+
classification: {
|
|
25
|
+
type: string;
|
|
26
|
+
confidence: number;
|
|
27
|
+
indicators: string[];
|
|
28
|
+
};
|
|
29
|
+
metadata: {
|
|
30
|
+
stars: number;
|
|
31
|
+
language: string;
|
|
32
|
+
license?: string;
|
|
33
|
+
description?: string;
|
|
34
|
+
};
|
|
35
|
+
typescript?: string;
|
|
36
|
+
python?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Parse GitHub URL
|
|
41
|
+
*/
|
|
42
|
+
function parseGithubUrl(url: string): { owner: string; repo: string; branch?: string } {
|
|
43
|
+
const treeMatch = url.match(/github\.com\/([^\/]+)\/([^\/]+)\/tree\/([^\/]+)/);
|
|
44
|
+
if (treeMatch) {
|
|
45
|
+
return {
|
|
46
|
+
owner: treeMatch[1],
|
|
47
|
+
repo: treeMatch[2].replace('.git', ''),
|
|
48
|
+
branch: treeMatch[3]
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const simpleMatch = url.match(/github\.com\/([^\/]+)\/([^\/]+)/);
|
|
53
|
+
if (simpleMatch) {
|
|
54
|
+
return {
|
|
55
|
+
owner: simpleMatch[1],
|
|
56
|
+
repo: simpleMatch[2].replace('.git', ''),
|
|
57
|
+
branch: 'main'
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
throw new Error(`Invalid GitHub URL: ${url}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Fetch repository metadata from GitHub API
|
|
66
|
+
*/
|
|
67
|
+
async function fetchRepoMetadata(owner: string, repo: string, token?: string) {
|
|
68
|
+
const headers: Record<string, string> = {
|
|
69
|
+
'Accept': 'application/vnd.github.v3+json',
|
|
70
|
+
'User-Agent': 'github-to-mcp-edge'
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
if (token) {
|
|
74
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const response = await fetch(`https://api.github.com/repos/${owner}/${repo}`, { headers });
|
|
78
|
+
|
|
79
|
+
if (!response.ok) {
|
|
80
|
+
throw new Error(`GitHub API error: ${response.status}`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const data = await response.json();
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
stars: data.stargazers_count,
|
|
87
|
+
language: data.language || 'unknown',
|
|
88
|
+
license: data.license?.spdx_id,
|
|
89
|
+
description: data.description,
|
|
90
|
+
defaultBranch: data.default_branch
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Fetch README content
|
|
96
|
+
*/
|
|
97
|
+
async function fetchReadme(owner: string, repo: string, branch?: string, token?: string): Promise<string | null> {
|
|
98
|
+
const headers: Record<string, string> = {
|
|
99
|
+
'Accept': 'application/vnd.github.v3+json',
|
|
100
|
+
'User-Agent': 'github-to-mcp-edge'
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
if (token) {
|
|
104
|
+
headers['Authorization'] = `Bearer ${token}`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const readmeFiles = ['README.md', 'README.MD', 'readme.md'];
|
|
108
|
+
|
|
109
|
+
for (const filename of readmeFiles) {
|
|
110
|
+
try {
|
|
111
|
+
const url = `https://api.github.com/repos/${owner}/${repo}/contents/${filename}${branch ? `?ref=${branch}` : ''}`;
|
|
112
|
+
const response = await fetch(url, { headers });
|
|
113
|
+
|
|
114
|
+
if (response.ok) {
|
|
115
|
+
const data = await response.json();
|
|
116
|
+
if (data.type === 'file' && data.content) {
|
|
117
|
+
return atob(data.content.replace(/\n/g, ''));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
} catch {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Classify repository type
|
|
130
|
+
*/
|
|
131
|
+
function classifyRepo(readme: string | null, language: string) {
|
|
132
|
+
let type = 'unknown';
|
|
133
|
+
let confidence = 0.3;
|
|
134
|
+
const indicators: string[] = [];
|
|
135
|
+
|
|
136
|
+
const readmeLower = readme?.toLowerCase() || '';
|
|
137
|
+
|
|
138
|
+
if (readmeLower.includes('mcp') || readmeLower.includes('model context protocol')) {
|
|
139
|
+
type = 'mcp-server';
|
|
140
|
+
confidence = 0.9;
|
|
141
|
+
indicators.push('Contains MCP references');
|
|
142
|
+
} else if (readmeLower.includes('api') || readmeLower.includes('sdk')) {
|
|
143
|
+
type = 'api-sdk';
|
|
144
|
+
confidence = 0.7;
|
|
145
|
+
indicators.push('Contains API/SDK references');
|
|
146
|
+
} else if (readmeLower.includes('cli') || readmeLower.includes('command line')) {
|
|
147
|
+
type = 'cli-tool';
|
|
148
|
+
confidence = 0.7;
|
|
149
|
+
indicators.push('Contains CLI references');
|
|
150
|
+
} else if (readmeLower.includes('library') || readmeLower.includes('package')) {
|
|
151
|
+
type = 'library';
|
|
152
|
+
confidence = 0.6;
|
|
153
|
+
indicators.push('Contains library references');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
indicators.push(`Language: ${language}`);
|
|
157
|
+
|
|
158
|
+
return { type, confidence, indicators };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Extract tools from README
|
|
163
|
+
*/
|
|
164
|
+
function extractToolsFromReadme(readme: string): EdgeResult['tools'] {
|
|
165
|
+
const tools: EdgeResult['tools'] = [];
|
|
166
|
+
|
|
167
|
+
// Extract API endpoints
|
|
168
|
+
const endpointRegex = /(?:GET|POST|PUT|DELETE|PATCH)\s+[`']?([\/\w\-\{\}:]+)[`']?/gi;
|
|
169
|
+
let match;
|
|
170
|
+
|
|
171
|
+
while ((match = endpointRegex.exec(readme)) !== null) {
|
|
172
|
+
const endpoint = match[1];
|
|
173
|
+
const method = match[0].split(' ')[0].toUpperCase();
|
|
174
|
+
const name = endpoint
|
|
175
|
+
.replace(/[{}]/g, '')
|
|
176
|
+
.split('/')
|
|
177
|
+
.filter(p => p && !p.startsWith(':'))
|
|
178
|
+
.map(p => p.charAt(0).toUpperCase() + p.slice(1))
|
|
179
|
+
.join('');
|
|
180
|
+
|
|
181
|
+
tools.push({
|
|
182
|
+
name: method.toLowerCase() + name,
|
|
183
|
+
description: `${method} ${endpoint}`,
|
|
184
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
185
|
+
source: { type: 'readme', file: 'README.md' },
|
|
186
|
+
confidence: 0.6
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return tools;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Generate TypeScript code
|
|
195
|
+
*/
|
|
196
|
+
function generateTypeScript(tools: EdgeResult['tools'], repoName: string, owner: string): string {
|
|
197
|
+
const safeName = repoName.replace(/[^a-zA-Z0-9]/g, '_');
|
|
198
|
+
|
|
199
|
+
const toolDefs = tools.map(t => ` {
|
|
200
|
+
name: "${t.name}",
|
|
201
|
+
description: "${t.description.replace(/"/g, '\\"')}",
|
|
202
|
+
inputSchema: ${JSON.stringify(t.inputSchema)}
|
|
203
|
+
}`).join(',\n');
|
|
204
|
+
|
|
205
|
+
const handlers = tools.map((t, i) =>
|
|
206
|
+
`${i === 0 ? '' : ' else '}if (name === "${t.name}") {
|
|
207
|
+
return { content: [{ type: "text", text: "Not implemented: ${t.name}" }] };
|
|
208
|
+
}`
|
|
209
|
+
).join('\n ');
|
|
210
|
+
|
|
211
|
+
return `/**
|
|
212
|
+
* Auto-generated MCP Server for ${repoName}
|
|
213
|
+
* Generated by @nirholas/github-to-mcp (Edge)
|
|
214
|
+
* Repository: https://github.com/${owner}/${repoName}
|
|
215
|
+
*/
|
|
216
|
+
|
|
217
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
218
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
219
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
220
|
+
|
|
221
|
+
const server = new Server(
|
|
222
|
+
{ name: "${safeName}-mcp", version: "1.0.0" },
|
|
223
|
+
{ capabilities: { tools: {} } }
|
|
224
|
+
);
|
|
225
|
+
|
|
226
|
+
const tools = [
|
|
227
|
+
${toolDefs}
|
|
228
|
+
];
|
|
229
|
+
|
|
230
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
|
|
231
|
+
|
|
232
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
233
|
+
const { name, arguments: args } = request.params;
|
|
234
|
+
${handlers}
|
|
235
|
+
throw new Error(\`Unknown tool: \${name}\`);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const transport = new StdioServerTransport();
|
|
239
|
+
server.connect(transport);
|
|
240
|
+
`;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* POST handler for edge generation
|
|
245
|
+
*/
|
|
246
|
+
export async function POST(request: NextRequest) {
|
|
247
|
+
try {
|
|
248
|
+
const body = await request.json();
|
|
249
|
+
const { url, language = 'typescript' } = body;
|
|
250
|
+
|
|
251
|
+
if (!url) {
|
|
252
|
+
return NextResponse.json(
|
|
253
|
+
{ error: 'Missing required field: url' },
|
|
254
|
+
{ status: 400 }
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Get GitHub token from environment or request
|
|
259
|
+
const token = process.env.GITHUB_TOKEN || body.token;
|
|
260
|
+
|
|
261
|
+
// Parse URL
|
|
262
|
+
const { owner, repo, branch } = parseGithubUrl(url);
|
|
263
|
+
|
|
264
|
+
// Fetch data in parallel
|
|
265
|
+
const [metadata, readme] = await Promise.all([
|
|
266
|
+
fetchRepoMetadata(owner, repo, token),
|
|
267
|
+
fetchReadme(owner, repo, branch, token)
|
|
268
|
+
]);
|
|
269
|
+
|
|
270
|
+
// Classify and extract
|
|
271
|
+
const classification = classifyRepo(readme, metadata.language);
|
|
272
|
+
const tools = readme ? extractToolsFromReadme(readme) : [];
|
|
273
|
+
|
|
274
|
+
// Build result
|
|
275
|
+
const result: EdgeResult = {
|
|
276
|
+
repo: `${owner}/${repo}`,
|
|
277
|
+
name: repo,
|
|
278
|
+
tools,
|
|
279
|
+
classification,
|
|
280
|
+
metadata
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
// Generate code
|
|
284
|
+
if (language === 'typescript' || language === 'both') {
|
|
285
|
+
result.typescript = generateTypeScript(tools, repo, owner);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
return NextResponse.json(result);
|
|
289
|
+
|
|
290
|
+
} catch (error) {
|
|
291
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
292
|
+
return NextResponse.json(
|
|
293
|
+
{ error: message },
|
|
294
|
+
{ status: 500 }
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* GET handler for health check
|
|
301
|
+
*/
|
|
302
|
+
export async function GET() {
|
|
303
|
+
return NextResponse.json({
|
|
304
|
+
status: 'ok',
|
|
305
|
+
runtime: 'edge',
|
|
306
|
+
timestamp: new Date().toISOString()
|
|
307
|
+
});
|
|
308
|
+
}
|