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,797 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Module exports and initialization
|
|
3
|
+
* @copyright Copyright (c) 2024-2026 nirholas
|
|
4
|
+
* @license MIT
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Main Generator
|
|
9
|
+
* Orchestrates the entire GitHub to MCP conversion process
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { GithubClient } from './github-client';
|
|
13
|
+
import { ReadmeExtractor } from './readme-extractor';
|
|
14
|
+
import { CodeExtractor } from './code-extractor';
|
|
15
|
+
import { GraphQLExtractor } from './graphql-extractor';
|
|
16
|
+
import { McpIntrospector } from './mcp-introspector';
|
|
17
|
+
import { PythonGenerator } from './python-generator';
|
|
18
|
+
import { GoGenerator } from './go-generator';
|
|
19
|
+
import { convertOpenApiToMcp } from '@github-to-mcp/openapi-parser';
|
|
20
|
+
import {
|
|
21
|
+
GithubToMcpOptions,
|
|
22
|
+
GenerationResult,
|
|
23
|
+
ExtractedTool,
|
|
24
|
+
SourceBreakdown,
|
|
25
|
+
RepoClassification,
|
|
26
|
+
RepoType,
|
|
27
|
+
OutputLanguage
|
|
28
|
+
} from './types';
|
|
29
|
+
import * as fs from 'fs/promises';
|
|
30
|
+
import * as path from 'path';
|
|
31
|
+
|
|
32
|
+
export class GithubToMcpGenerator {
|
|
33
|
+
private github: GithubClient;
|
|
34
|
+
private readmeExtractor: ReadmeExtractor;
|
|
35
|
+
private codeExtractor: CodeExtractor;
|
|
36
|
+
private graphqlExtractor: GraphQLExtractor;
|
|
37
|
+
private mcpIntrospector: McpIntrospector;
|
|
38
|
+
private pythonGenerator: PythonGenerator;
|
|
39
|
+
private goGenerator: GoGenerator;
|
|
40
|
+
|
|
41
|
+
constructor(private options: GithubToMcpOptions = {}) {
|
|
42
|
+
this.github = new GithubClient(options.githubToken);
|
|
43
|
+
this.readmeExtractor = new ReadmeExtractor();
|
|
44
|
+
this.codeExtractor = new CodeExtractor();
|
|
45
|
+
this.graphqlExtractor = new GraphQLExtractor();
|
|
46
|
+
this.mcpIntrospector = new McpIntrospector();
|
|
47
|
+
this.pythonGenerator = new PythonGenerator();
|
|
48
|
+
this.goGenerator = new GoGenerator();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Generate MCP tools from GitHub repository
|
|
53
|
+
*/
|
|
54
|
+
async generate(githubUrl: string): Promise<GenerationResult> {
|
|
55
|
+
// Parse GitHub URL
|
|
56
|
+
const repoMeta = this.github.parseGithubUrl(githubUrl);
|
|
57
|
+
|
|
58
|
+
// Get repository metadata
|
|
59
|
+
const metadata = await this.github.getRepoMetadata(repoMeta.owner, repoMeta.repo);
|
|
60
|
+
|
|
61
|
+
// Get README for classification
|
|
62
|
+
const readme = await this.github.getReadme(repoMeta.owner, repoMeta.repo);
|
|
63
|
+
|
|
64
|
+
// Classify the repository
|
|
65
|
+
const classification = await this.classifyRepo(repoMeta.owner, repoMeta.repo, readme, metadata);
|
|
66
|
+
|
|
67
|
+
// Extract tools from all sources
|
|
68
|
+
const tools: ExtractedTool[] = [];
|
|
69
|
+
const sources: SourceBreakdown[] = [];
|
|
70
|
+
|
|
71
|
+
const enabledSources = this.options.sources || ['readme', 'openapi', 'code'];
|
|
72
|
+
|
|
73
|
+
// 1. Extract from OpenAPI specs
|
|
74
|
+
if (enabledSources.includes('openapi')) {
|
|
75
|
+
const openapiTools = await this.extractFromOpenApi(repoMeta.owner, repoMeta.repo);
|
|
76
|
+
tools.push(...openapiTools);
|
|
77
|
+
|
|
78
|
+
if (openapiTools.length > 0) {
|
|
79
|
+
sources.push({
|
|
80
|
+
type: 'openapi',
|
|
81
|
+
count: openapiTools.length,
|
|
82
|
+
files: openapiTools.map(t => t.source.file)
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// 2. Extract from README
|
|
88
|
+
if (enabledSources.includes('readme')) {
|
|
89
|
+
const readmeTools = await this.extractFromReadme(repoMeta.owner, repoMeta.repo);
|
|
90
|
+
tools.push(...readmeTools);
|
|
91
|
+
|
|
92
|
+
if (readmeTools.length > 0) {
|
|
93
|
+
sources.push({
|
|
94
|
+
type: 'readme',
|
|
95
|
+
count: readmeTools.length,
|
|
96
|
+
files: ['README.md']
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 3. Extract from code
|
|
102
|
+
if (enabledSources.includes('code')) {
|
|
103
|
+
const codeTools = await this.extractFromCode(repoMeta.owner, repoMeta.repo);
|
|
104
|
+
tools.push(...codeTools);
|
|
105
|
+
|
|
106
|
+
if (codeTools.length > 0) {
|
|
107
|
+
sources.push({
|
|
108
|
+
type: 'code',
|
|
109
|
+
count: codeTools.length,
|
|
110
|
+
files: [...new Set(codeTools.map(t => t.source.file))]
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 4. Extract from GraphQL schemas
|
|
116
|
+
const graphqlTools = await this.extractFromGraphQL(repoMeta.owner, repoMeta.repo);
|
|
117
|
+
tools.push(...graphqlTools);
|
|
118
|
+
if (graphqlTools.length > 0) {
|
|
119
|
+
sources.push({
|
|
120
|
+
type: 'graphql',
|
|
121
|
+
count: graphqlTools.length,
|
|
122
|
+
files: graphqlTools.map(t => t.source.file).filter((f, i, a) => a.indexOf(f) === i)
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// 5. Introspect existing MCP servers
|
|
127
|
+
if (classification.type === 'mcp-server') {
|
|
128
|
+
const mcpTools = await this.introspectMcpServer(repoMeta.owner, repoMeta.repo);
|
|
129
|
+
tools.push(...mcpTools);
|
|
130
|
+
if (mcpTools.length > 0) {
|
|
131
|
+
sources.push({
|
|
132
|
+
type: 'mcp-introspect',
|
|
133
|
+
count: mcpTools.length,
|
|
134
|
+
files: mcpTools.map(t => t.source.file).filter((f, i, a) => a.indexOf(f) === i)
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 6. Add universal fallback tools (always included)
|
|
140
|
+
const universalTools = this.generateUniversalTools(repoMeta.owner, repoMeta.repo);
|
|
141
|
+
tools.push(...universalTools);
|
|
142
|
+
sources.push({
|
|
143
|
+
type: 'universal',
|
|
144
|
+
count: universalTools.length,
|
|
145
|
+
files: []
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Deduplicate tools
|
|
149
|
+
const uniqueTools = this.deduplicateTools(tools);
|
|
150
|
+
|
|
151
|
+
// Determine output language
|
|
152
|
+
const outputLanguage = this.options.outputLanguage || 'typescript';
|
|
153
|
+
|
|
154
|
+
// Build result
|
|
155
|
+
const result: GenerationResult = {
|
|
156
|
+
repo: githubUrl,
|
|
157
|
+
name: repoMeta.repo,
|
|
158
|
+
tools: uniqueTools,
|
|
159
|
+
sources,
|
|
160
|
+
classification,
|
|
161
|
+
metadata,
|
|
162
|
+
generate: () => this.generateCode(uniqueTools, repoMeta.repo, repoMeta.owner, outputLanguage),
|
|
163
|
+
generatePython: () => this.pythonGenerator.generateServer(uniqueTools, repoMeta.repo, repoMeta.owner),
|
|
164
|
+
save: async (outputDir: string) => this.saveToFiles(uniqueTools, repoMeta.repo, repoMeta.owner, outputDir),
|
|
165
|
+
download: () => this.downloadZip(uniqueTools, repoMeta.repo)
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
return result;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Classify the repository type
|
|
173
|
+
*/
|
|
174
|
+
private async classifyRepo(
|
|
175
|
+
owner: string,
|
|
176
|
+
repo: string,
|
|
177
|
+
readme: string | null,
|
|
178
|
+
metadata: any
|
|
179
|
+
): Promise<RepoClassification> {
|
|
180
|
+
const indicators: string[] = [];
|
|
181
|
+
let type: RepoType = 'unknown';
|
|
182
|
+
let confidence = 0.3;
|
|
183
|
+
|
|
184
|
+
const readmeLower = (readme || '').toLowerCase();
|
|
185
|
+
|
|
186
|
+
// Check for MCP server indicators
|
|
187
|
+
if (
|
|
188
|
+
readmeLower.includes('mcp') ||
|
|
189
|
+
readmeLower.includes('model context protocol') ||
|
|
190
|
+
readmeLower.includes('@modelcontextprotocol')
|
|
191
|
+
) {
|
|
192
|
+
type = 'mcp-server';
|
|
193
|
+
confidence = 0.9;
|
|
194
|
+
indicators.push('MCP keywords in README');
|
|
195
|
+
}
|
|
196
|
+
// Check for API/SDK indicators
|
|
197
|
+
else if (
|
|
198
|
+
readmeLower.includes('api') ||
|
|
199
|
+
readmeLower.includes('sdk') ||
|
|
200
|
+
readmeLower.includes('client library') ||
|
|
201
|
+
readmeLower.includes('openapi') ||
|
|
202
|
+
readmeLower.includes('swagger')
|
|
203
|
+
) {
|
|
204
|
+
type = 'api-sdk';
|
|
205
|
+
confidence = 0.8;
|
|
206
|
+
indicators.push('API/SDK keywords in README');
|
|
207
|
+
}
|
|
208
|
+
// Check for CLI indicators
|
|
209
|
+
else if (
|
|
210
|
+
readmeLower.includes('cli') ||
|
|
211
|
+
readmeLower.includes('command line') ||
|
|
212
|
+
readmeLower.includes('usage:') ||
|
|
213
|
+
readmeLower.includes('npx ') ||
|
|
214
|
+
readmeLower.includes('$ ')
|
|
215
|
+
) {
|
|
216
|
+
type = 'cli-tool';
|
|
217
|
+
confidence = 0.7;
|
|
218
|
+
indicators.push('CLI patterns in README');
|
|
219
|
+
}
|
|
220
|
+
// Check for library indicators
|
|
221
|
+
else if (
|
|
222
|
+
readmeLower.includes('npm install') ||
|
|
223
|
+
readmeLower.includes('yarn add') ||
|
|
224
|
+
readmeLower.includes('pip install') ||
|
|
225
|
+
readmeLower.includes('import ') ||
|
|
226
|
+
readmeLower.includes('require(')
|
|
227
|
+
) {
|
|
228
|
+
type = 'library';
|
|
229
|
+
confidence = 0.6;
|
|
230
|
+
indicators.push('Package installation patterns');
|
|
231
|
+
}
|
|
232
|
+
// Check for documentation
|
|
233
|
+
else if (
|
|
234
|
+
readmeLower.includes('documentation') ||
|
|
235
|
+
readmeLower.includes('tutorial') ||
|
|
236
|
+
readmeLower.includes('guide') ||
|
|
237
|
+
readmeLower.includes('learn ')
|
|
238
|
+
) {
|
|
239
|
+
type = 'documentation';
|
|
240
|
+
confidence = 0.5;
|
|
241
|
+
indicators.push('Documentation keywords');
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Boost confidence based on language
|
|
245
|
+
if (metadata.language) {
|
|
246
|
+
indicators.push(`Primary language: ${metadata.language}`);
|
|
247
|
+
if (['TypeScript', 'JavaScript', 'Python'].includes(metadata.language)) {
|
|
248
|
+
confidence = Math.min(1, confidence + 0.1);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Boost confidence based on stars
|
|
253
|
+
if (metadata.stars > 1000) {
|
|
254
|
+
indicators.push(`Popular repo (${metadata.stars} stars)`);
|
|
255
|
+
confidence = Math.min(1, confidence + 0.05);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return { type, confidence, indicators };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Generate universal fallback tools that work for any repo
|
|
263
|
+
*/
|
|
264
|
+
private generateUniversalTools(owner: string, repo: string): ExtractedTool[] {
|
|
265
|
+
return [
|
|
266
|
+
{
|
|
267
|
+
name: 'get_readme',
|
|
268
|
+
description: `Get the README content from ${owner}/${repo}`,
|
|
269
|
+
inputSchema: {
|
|
270
|
+
type: 'object',
|
|
271
|
+
properties: {},
|
|
272
|
+
required: []
|
|
273
|
+
},
|
|
274
|
+
implementation: `async function get_readme() {
|
|
275
|
+
const response = await fetch('https://api.github.com/repos/${owner}/${repo}/readme', {
|
|
276
|
+
headers: { 'Accept': 'application/vnd.github.raw' }
|
|
277
|
+
});
|
|
278
|
+
if (!response.ok) {
|
|
279
|
+
if (response.status === 404) {
|
|
280
|
+
return { content: [{ type: 'text', text: 'No README found in this repository.' }] };
|
|
281
|
+
}
|
|
282
|
+
throw new Error(\`Failed to fetch README (HTTP \${response.status})\`);
|
|
283
|
+
}
|
|
284
|
+
return { content: [{ type: 'text', text: await response.text() }] };
|
|
285
|
+
}`,
|
|
286
|
+
source: { type: 'universal', file: 'generated' }
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
name: 'list_files',
|
|
290
|
+
description: `List files and directories in ${owner}/${repo}`,
|
|
291
|
+
inputSchema: {
|
|
292
|
+
type: 'object',
|
|
293
|
+
properties: {
|
|
294
|
+
path: {
|
|
295
|
+
type: 'string',
|
|
296
|
+
description: 'Directory path (empty for root)',
|
|
297
|
+
default: ''
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
required: []
|
|
301
|
+
},
|
|
302
|
+
implementation: `async function list_files(args: { path?: string }) {
|
|
303
|
+
const path = args.path || '';
|
|
304
|
+
const response = await fetch(\`https://api.github.com/repos/${owner}/${repo}/contents/\${path}\`);
|
|
305
|
+
if (!response.ok) {
|
|
306
|
+
if (response.status === 404) {
|
|
307
|
+
return { content: [{ type: 'text', text: \`Directory not found: \${path || '/'}\` }] };
|
|
308
|
+
}
|
|
309
|
+
throw new Error(\`Failed to list files (HTTP \${response.status})\`);
|
|
310
|
+
}
|
|
311
|
+
const data = await response.json();
|
|
312
|
+
const files = Array.isArray(data) ? data.map((f: any) => ({ name: f.name, type: f.type, path: f.path })) : [data];
|
|
313
|
+
return { content: [{ type: 'text', text: JSON.stringify(files, null, 2) }] };
|
|
314
|
+
}`,
|
|
315
|
+
source: { type: 'universal', file: 'generated' }
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
name: 'read_file',
|
|
319
|
+
description: `Read a file from ${owner}/${repo}`,
|
|
320
|
+
inputSchema: {
|
|
321
|
+
type: 'object',
|
|
322
|
+
properties: {
|
|
323
|
+
path: {
|
|
324
|
+
type: 'string',
|
|
325
|
+
description: 'File path to read'
|
|
326
|
+
}
|
|
327
|
+
},
|
|
328
|
+
required: ['path']
|
|
329
|
+
},
|
|
330
|
+
implementation: `async function read_file(args: { path: string }) {
|
|
331
|
+
const response = await fetch(\`https://api.github.com/repos/${owner}/${repo}/contents/\${args.path}\`, {
|
|
332
|
+
headers: { 'Accept': 'application/vnd.github.raw' }
|
|
333
|
+
});
|
|
334
|
+
if (!response.ok) {
|
|
335
|
+
if (response.status === 404) {
|
|
336
|
+
return { content: [{ type: 'text', text: \`File not found: \${args.path}. Use list_files to see available files.\` }] };
|
|
337
|
+
}
|
|
338
|
+
throw new Error(\`Failed to read file (HTTP \${response.status}): \${args.path}\`);
|
|
339
|
+
}
|
|
340
|
+
return { content: [{ type: 'text', text: await response.text() }] };
|
|
341
|
+
}`,
|
|
342
|
+
source: { type: 'universal', file: 'generated' }
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
name: 'search_code',
|
|
346
|
+
description: `Search for code in ${owner}/${repo}`,
|
|
347
|
+
inputSchema: {
|
|
348
|
+
type: 'object',
|
|
349
|
+
properties: {
|
|
350
|
+
query: {
|
|
351
|
+
type: 'string',
|
|
352
|
+
description: 'Search query'
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
required: ['query']
|
|
356
|
+
},
|
|
357
|
+
implementation: `async function search_code(args: { query: string }) {
|
|
358
|
+
const response = await fetch(\`https://api.github.com/search/code?q=\${encodeURIComponent(args.query)}+repo:${owner}/${repo}\`);
|
|
359
|
+
if (!response.ok) {
|
|
360
|
+
if (response.status === 403) {
|
|
361
|
+
return { content: [{ type: 'text', text: 'GitHub API rate limit exceeded. Try again later or use a GitHub token.' }] };
|
|
362
|
+
}
|
|
363
|
+
if (response.status === 422) {
|
|
364
|
+
return { content: [{ type: 'text', text: 'Search query invalid. Try a simpler search term.' }] };
|
|
365
|
+
}
|
|
366
|
+
throw new Error(\`Search failed (HTTP \${response.status})\`);
|
|
367
|
+
}
|
|
368
|
+
const data = await response.json();
|
|
369
|
+
if (!data.items || data.items.length === 0) {
|
|
370
|
+
return { content: [{ type: 'text', text: \`No results found for: \${args.query}\` }] };
|
|
371
|
+
}
|
|
372
|
+
const results = data.items.slice(0, 10).map((item: any) => ({
|
|
373
|
+
file: item.path,
|
|
374
|
+
url: item.html_url
|
|
375
|
+
}));
|
|
376
|
+
return { content: [{ type: 'text', text: JSON.stringify(results, null, 2) }] };
|
|
377
|
+
}`,
|
|
378
|
+
source: { type: 'universal', file: 'generated' }
|
|
379
|
+
}
|
|
380
|
+
];
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Extract tools from OpenAPI specs
|
|
385
|
+
*/
|
|
386
|
+
private async extractFromOpenApi(owner: string, repo: string): Promise<ExtractedTool[]> {
|
|
387
|
+
const tools: ExtractedTool[] = [];
|
|
388
|
+
|
|
389
|
+
const specs = await this.github.findApiSpecs(owner, repo);
|
|
390
|
+
|
|
391
|
+
for (const spec of specs) {
|
|
392
|
+
try {
|
|
393
|
+
// Use OpenAPI converter
|
|
394
|
+
const converted = await convertOpenApiToMcp(spec.spec);
|
|
395
|
+
|
|
396
|
+
// Convert to our format
|
|
397
|
+
for (const tool of converted.tools) {
|
|
398
|
+
tools.push({
|
|
399
|
+
name: tool.name,
|
|
400
|
+
description: tool.description,
|
|
401
|
+
inputSchema: tool.inputSchema,
|
|
402
|
+
source: {
|
|
403
|
+
type: 'openapi',
|
|
404
|
+
file: spec.path
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
} catch (error) {
|
|
409
|
+
console.error(`Failed to convert OpenAPI spec: ${spec.path}`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return tools;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Extract tools from README
|
|
418
|
+
*/
|
|
419
|
+
private async extractFromReadme(owner: string, repo: string): Promise<ExtractedTool[]> {
|
|
420
|
+
const readme = await this.github.getReadme(owner, repo);
|
|
421
|
+
|
|
422
|
+
if (!readme) {
|
|
423
|
+
return [];
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return this.readmeExtractor.extract(readme);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Extract tools from code
|
|
431
|
+
*/
|
|
432
|
+
private async extractFromCode(owner: string, repo: string): Promise<ExtractedTool[]> {
|
|
433
|
+
const tools: ExtractedTool[] = [];
|
|
434
|
+
|
|
435
|
+
// Search for SDK files (TypeScript, JavaScript, and Python)
|
|
436
|
+
const sdkFiles = await this.github.searchFiles(
|
|
437
|
+
owner,
|
|
438
|
+
repo,
|
|
439
|
+
/\.(ts|js|py)$/,
|
|
440
|
+
2 // Max depth
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
for (const file of sdkFiles) {
|
|
444
|
+
// Skip test files, config files, etc.
|
|
445
|
+
if (this.shouldSkipFile(file.path)) {
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
const extracted = await this.codeExtractor.extract(file.content, file.path);
|
|
450
|
+
tools.push(...extracted);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
return tools;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Check if file should be skipped
|
|
458
|
+
*/
|
|
459
|
+
private shouldSkipFile(filepath: string): boolean {
|
|
460
|
+
const skipPatterns = [
|
|
461
|
+
/test/i,
|
|
462
|
+
/spec/i,
|
|
463
|
+
/\.config\./,
|
|
464
|
+
/\.setup\./,
|
|
465
|
+
/node_modules/,
|
|
466
|
+
/dist/,
|
|
467
|
+
/build/
|
|
468
|
+
];
|
|
469
|
+
|
|
470
|
+
return skipPatterns.some(pattern => pattern.test(filepath));
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Extract tools from GraphQL schemas
|
|
475
|
+
*/
|
|
476
|
+
private async extractFromGraphQL(owner: string, repo: string): Promise<ExtractedTool[]> {
|
|
477
|
+
const tools: ExtractedTool[] = [];
|
|
478
|
+
|
|
479
|
+
try {
|
|
480
|
+
// Search for GraphQL schema files
|
|
481
|
+
const graphqlFiles = await this.github.searchFiles(
|
|
482
|
+
owner,
|
|
483
|
+
repo,
|
|
484
|
+
/\.(graphql|gql)$/,
|
|
485
|
+
3 // Max depth
|
|
486
|
+
);
|
|
487
|
+
|
|
488
|
+
for (const file of graphqlFiles) {
|
|
489
|
+
if (file.path.includes('node_modules')) continue;
|
|
490
|
+
|
|
491
|
+
try {
|
|
492
|
+
const schema = this.graphqlExtractor.parseSchema(file.content);
|
|
493
|
+
|
|
494
|
+
// Determine GraphQL endpoint (guess based on common patterns)
|
|
495
|
+
const endpoint = `https://api.github.com/repos/${owner}/${repo}/graphql`;
|
|
496
|
+
|
|
497
|
+
const schemaTools = this.graphqlExtractor.schemaToTools(schema, endpoint, owner, repo);
|
|
498
|
+
tools.push(...schemaTools);
|
|
499
|
+
} catch (error) {
|
|
500
|
+
console.error(`Failed to parse GraphQL schema: ${file.path}`);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
} catch (error) {
|
|
504
|
+
// No GraphQL files found
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
return tools;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Introspect existing MCP server to extract tool definitions
|
|
512
|
+
*/
|
|
513
|
+
private async introspectMcpServer(owner: string, repo: string): Promise<ExtractedTool[]> {
|
|
514
|
+
const tools: ExtractedTool[] = [];
|
|
515
|
+
|
|
516
|
+
try {
|
|
517
|
+
// Search for likely MCP server files
|
|
518
|
+
const serverFiles = await this.github.searchFiles(
|
|
519
|
+
owner,
|
|
520
|
+
repo,
|
|
521
|
+
/\.(ts|js|py)$/,
|
|
522
|
+
3
|
|
523
|
+
);
|
|
524
|
+
|
|
525
|
+
for (const file of serverFiles) {
|
|
526
|
+
// Check if this file looks like an MCP server
|
|
527
|
+
if (!this.mcpIntrospector.isLikelyMcpServer(file.content)) {
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
let extracted: ExtractedTool[] = [];
|
|
532
|
+
|
|
533
|
+
if (file.path.endsWith('.py')) {
|
|
534
|
+
extracted = this.mcpIntrospector.extractFromPython(file.content, file.path);
|
|
535
|
+
} else {
|
|
536
|
+
extracted = this.mcpIntrospector.extractFromTypeScript(file.content, file.path);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
tools.push(...extracted);
|
|
540
|
+
}
|
|
541
|
+
} catch (error) {
|
|
542
|
+
console.error('Failed to introspect MCP server:', error);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
return tools;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Deduplicate tools by name
|
|
550
|
+
*/
|
|
551
|
+
private deduplicateTools(tools: ExtractedTool[]): ExtractedTool[] {
|
|
552
|
+
const seen = new Map<string, ExtractedTool>();
|
|
553
|
+
|
|
554
|
+
for (const tool of tools) {
|
|
555
|
+
if (!seen.has(tool.name)) {
|
|
556
|
+
seen.set(tool.name, tool);
|
|
557
|
+
} else {
|
|
558
|
+
// Prefer MCP introspect > OpenAPI > GraphQL > Code > README > universal > others
|
|
559
|
+
const existing = seen.get(tool.name)!;
|
|
560
|
+
const priority: Record<string, number> = {
|
|
561
|
+
'mcp-introspect': 8,
|
|
562
|
+
openapi: 7,
|
|
563
|
+
graphql: 6,
|
|
564
|
+
code: 5,
|
|
565
|
+
tests: 4,
|
|
566
|
+
docs: 3,
|
|
567
|
+
examples: 2,
|
|
568
|
+
readme: 1,
|
|
569
|
+
universal: 0
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
if ((priority[tool.source.type] || 0) > (priority[existing.source.type] || 0)) {
|
|
573
|
+
seen.set(tool.name, tool);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
return Array.from(seen.values());
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/**
|
|
582
|
+
* Generate TypeScript MCP server code
|
|
583
|
+
*/
|
|
584
|
+
private generateCode(tools: ExtractedTool[], repoName: string, owner?: string, language: OutputLanguage = 'typescript'): string {
|
|
585
|
+
// If Python output requested, use Python generator
|
|
586
|
+
if (language === 'python') {
|
|
587
|
+
return this.pythonGenerator.generateServer(tools, repoName, owner || 'unknown');
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
const toolDefinitions = tools.map(t => ({
|
|
591
|
+
name: t.name,
|
|
592
|
+
description: t.description,
|
|
593
|
+
inputSchema: t.inputSchema
|
|
594
|
+
}));
|
|
595
|
+
|
|
596
|
+
const toolCases = tools.map(t => `
|
|
597
|
+
case '${t.name}':
|
|
598
|
+
return await ${t.name}(args);`
|
|
599
|
+
).join('\n');
|
|
600
|
+
|
|
601
|
+
const implementations = tools.map(t => t.implementation || '').join('\n\n');
|
|
602
|
+
|
|
603
|
+
return `/**
|
|
604
|
+
* Auto-generated MCP server for ${repoName}
|
|
605
|
+
* Generated by @nirholas/github-to-mcp
|
|
606
|
+
*/
|
|
607
|
+
|
|
608
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
609
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
610
|
+
import {
|
|
611
|
+
CallToolRequestSchema,
|
|
612
|
+
ListToolsRequestSchema
|
|
613
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
614
|
+
|
|
615
|
+
const server = new Server({
|
|
616
|
+
name: '${repoName}-mcp',
|
|
617
|
+
version: '1.0.0'
|
|
618
|
+
}, {
|
|
619
|
+
capabilities: {
|
|
620
|
+
tools: {}
|
|
621
|
+
}
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
// Tool definitions
|
|
625
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
626
|
+
tools: ${JSON.stringify(toolDefinitions, null, 2)}
|
|
627
|
+
}));
|
|
628
|
+
|
|
629
|
+
// Tool implementations
|
|
630
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
631
|
+
const { name, arguments: args } = request.params;
|
|
632
|
+
|
|
633
|
+
switch (name) {${toolCases}
|
|
634
|
+
default:
|
|
635
|
+
throw new Error(\`Unknown tool: \${name}\`);
|
|
636
|
+
}
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
// Tool functions
|
|
640
|
+
${implementations}
|
|
641
|
+
|
|
642
|
+
// Start server
|
|
643
|
+
async function main() {
|
|
644
|
+
const transport = new StdioServerTransport();
|
|
645
|
+
await server.connect(transport);
|
|
646
|
+
console.error('${repoName} MCP server running on stdio');
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
main().catch(console.error);
|
|
650
|
+
`;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* Save generated code to files
|
|
655
|
+
*/
|
|
656
|
+
private async saveToFiles(tools: ExtractedTool[], repoName: string, owner: string, outputDir: string): Promise<void> {
|
|
657
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
658
|
+
|
|
659
|
+
// Generate main server file
|
|
660
|
+
const serverCode = this.generateCode(tools, repoName, owner);
|
|
661
|
+
await fs.writeFile(path.join(outputDir, 'index.ts'), serverCode);
|
|
662
|
+
|
|
663
|
+
// Generate package.json
|
|
664
|
+
const packageJson = {
|
|
665
|
+
name: `${repoName}-mcp`,
|
|
666
|
+
version: '1.0.0',
|
|
667
|
+
type: 'module',
|
|
668
|
+
dependencies: {
|
|
669
|
+
'@modelcontextprotocol/sdk': '^1.0.0'
|
|
670
|
+
}
|
|
671
|
+
};
|
|
672
|
+
await fs.writeFile(
|
|
673
|
+
path.join(outputDir, 'package.json'),
|
|
674
|
+
JSON.stringify(packageJson, null, 2)
|
|
675
|
+
);
|
|
676
|
+
|
|
677
|
+
// Generate README
|
|
678
|
+
const readme = this.generateReadme(tools, repoName);
|
|
679
|
+
await fs.writeFile(path.join(outputDir, 'README.md'), readme);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
/**
|
|
683
|
+
* Generate README for the MCP server
|
|
684
|
+
*/
|
|
685
|
+
private generateReadme(tools: ExtractedTool[], repoName: string): string {
|
|
686
|
+
const toolsList = tools.map(t => `- \`${t.name}\`: ${t.description}`).join('\n');
|
|
687
|
+
|
|
688
|
+
return `# ${repoName} MCP Server
|
|
689
|
+
|
|
690
|
+
Auto-generated MCP server with ${tools.length} tools.
|
|
691
|
+
|
|
692
|
+
## Tools
|
|
693
|
+
|
|
694
|
+
${toolsList}
|
|
695
|
+
|
|
696
|
+
## Installation
|
|
697
|
+
|
|
698
|
+
\`\`\`bash
|
|
699
|
+
npm install
|
|
700
|
+
\`\`\`
|
|
701
|
+
|
|
702
|
+
## Usage
|
|
703
|
+
|
|
704
|
+
\`\`\`bash
|
|
705
|
+
node index.ts
|
|
706
|
+
\`\`\`
|
|
707
|
+
`;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* Download as ZIP (browser only)
|
|
712
|
+
*/
|
|
713
|
+
private downloadZip(tools: ExtractedTool[], repoName: string): void {
|
|
714
|
+
// This would require a ZIP library in browser context
|
|
715
|
+
console.log('Download functionality requires browser environment');
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* Convenience function for single repo
|
|
721
|
+
*/
|
|
722
|
+
export async function generateFromGithub(
|
|
723
|
+
url: string,
|
|
724
|
+
options?: GithubToMcpOptions
|
|
725
|
+
): Promise<GenerationResult> {
|
|
726
|
+
const generator = new GithubToMcpGenerator(options);
|
|
727
|
+
return generator.generate(url);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* Batch processing
|
|
732
|
+
*/
|
|
733
|
+
export async function generateFromGithubBatch(
|
|
734
|
+
urls: string[],
|
|
735
|
+
options?: GithubToMcpOptions
|
|
736
|
+
): Promise<GenerationResult[]> {
|
|
737
|
+
const generator = new GithubToMcpGenerator(options);
|
|
738
|
+
return Promise.all(urls.map(url => generator.generate(url)));
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// Export all types
|
|
742
|
+
export * from './types';
|
|
743
|
+
|
|
744
|
+
// Export streaming module
|
|
745
|
+
export {
|
|
746
|
+
StreamingGenerator,
|
|
747
|
+
streamGenerate,
|
|
748
|
+
collectStreamEvents,
|
|
749
|
+
streamToResult,
|
|
750
|
+
type StreamEvent,
|
|
751
|
+
type StreamOptions,
|
|
752
|
+
type StreamEventType,
|
|
753
|
+
type StartEvent,
|
|
754
|
+
type MetadataEvent,
|
|
755
|
+
type ClassifyingEvent,
|
|
756
|
+
type ClassifiedEvent,
|
|
757
|
+
type ExtractingEvent,
|
|
758
|
+
type ToolFoundEvent,
|
|
759
|
+
type SourceCompleteEvent,
|
|
760
|
+
type GeneratingEvent,
|
|
761
|
+
type CompleteEvent,
|
|
762
|
+
type ErrorEvent,
|
|
763
|
+
type ProgressEvent
|
|
764
|
+
} from './streaming';
|
|
765
|
+
|
|
766
|
+
// Export plugin system
|
|
767
|
+
export {
|
|
768
|
+
PluginManager,
|
|
769
|
+
PluginRegistry,
|
|
770
|
+
defaultPluginManager,
|
|
771
|
+
defaultRegistry,
|
|
772
|
+
registerPlugin,
|
|
773
|
+
unregisterPlugin,
|
|
774
|
+
listPlugins,
|
|
775
|
+
loadPlugin,
|
|
776
|
+
loadPluginFromFile,
|
|
777
|
+
type ExtractorPlugin,
|
|
778
|
+
type PluginRepoContext,
|
|
779
|
+
type PluginExtractionResult,
|
|
780
|
+
type PluginDetectionResult,
|
|
781
|
+
type PluginManagerConfig,
|
|
782
|
+
type PluginLoadResult,
|
|
783
|
+
type PluginEvent,
|
|
784
|
+
type PluginEventHandler,
|
|
785
|
+
type PluginMetadata,
|
|
786
|
+
type PluginConfigSchema,
|
|
787
|
+
type PluginHooks
|
|
788
|
+
} from './plugins';
|
|
789
|
+
|
|
790
|
+
// Export language-specific extractors
|
|
791
|
+
export { RustExtractor } from './extractors/rust-extractor';
|
|
792
|
+
export { GoExtractor } from './extractors/go-extractor';
|
|
793
|
+
export { JavaExtractor } from './extractors/java-extractor';
|
|
794
|
+
|
|
795
|
+
// Export language-specific generators
|
|
796
|
+
export { PythonGenerator } from './python-generator';
|
|
797
|
+
export { GoGenerator } from './go-generator';
|