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,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview API client implementation
|
|
3
|
+
* @copyright Copyright (c) 2024-2026 nirholas
|
|
4
|
+
* @license MIT
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* GitHub Repository Client
|
|
9
|
+
* Fetch files and metadata from GitHub repositories
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { Octokit } from '@octokit/rest';
|
|
13
|
+
import { RepoMetadata, FileContent, ApiSpec } from './types';
|
|
14
|
+
|
|
15
|
+
export class GithubClient {
|
|
16
|
+
private octokit: Octokit;
|
|
17
|
+
|
|
18
|
+
constructor(token?: string) {
|
|
19
|
+
this.octokit = new Octokit({
|
|
20
|
+
auth: token
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Parse GitHub URL to extract metadata
|
|
26
|
+
*/
|
|
27
|
+
parseGithubUrl(url: string): RepoMetadata {
|
|
28
|
+
// Handle URLs with /tree/branch pattern
|
|
29
|
+
// Format: github.com/owner/repo/tree/branch[/path]
|
|
30
|
+
const treeMatch = url.match(/github\.com\/([^\/]+)\/([^\/]+)\/tree\/(.+)/);
|
|
31
|
+
if (treeMatch) {
|
|
32
|
+
const owner = treeMatch[1];
|
|
33
|
+
const repo = treeMatch[2].replace('.git', '');
|
|
34
|
+
const rest = treeMatch[3];
|
|
35
|
+
|
|
36
|
+
// Split the rest into parts
|
|
37
|
+
const parts = rest.split('/');
|
|
38
|
+
|
|
39
|
+
// Heuristic: if the URL looks like it has a file path (contains common extensions or known dirs)
|
|
40
|
+
// try to identify where branch ends and path begins
|
|
41
|
+
// Common approach: first segment is branch unless it contains file-like patterns
|
|
42
|
+
|
|
43
|
+
// Check if this looks like a branch with slashes (feature/xxx pattern)
|
|
44
|
+
// by looking for common file extensions or src/lib/etc paths
|
|
45
|
+
const fileExtensions = /\.(ts|js|py|md|json|yaml|yml|tsx|jsx|html|css|go|rs|java|rb|php)$/i;
|
|
46
|
+
const commonDirs = ['src', 'lib', 'packages', 'apps', 'test', 'tests', 'docs', 'examples'];
|
|
47
|
+
|
|
48
|
+
let branch = parts[0];
|
|
49
|
+
let pathParts: string[] = [];
|
|
50
|
+
|
|
51
|
+
// If only one part, it's just the branch
|
|
52
|
+
if (parts.length === 1) {
|
|
53
|
+
return { owner, repo, branch, path: undefined };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Check if second part looks like a directory/file rather than continuation of branch
|
|
57
|
+
// This handles: tree/main/src/file.ts (branch=main, path=src/file.ts)
|
|
58
|
+
// vs: tree/feature/new-feature (branch=feature/new-feature)
|
|
59
|
+
if (commonDirs.includes(parts[1]) || fileExtensions.test(parts[parts.length - 1])) {
|
|
60
|
+
// Likely first part is branch, rest is path
|
|
61
|
+
branch = parts[0];
|
|
62
|
+
pathParts = parts.slice(1);
|
|
63
|
+
} else {
|
|
64
|
+
// Could be a branch with slashes - if last part has extension, work backwards
|
|
65
|
+
if (fileExtensions.test(parts[parts.length - 1])) {
|
|
66
|
+
// Find where path starts by looking for common dirs
|
|
67
|
+
let pathStart = parts.length;
|
|
68
|
+
for (let i = 1; i < parts.length; i++) {
|
|
69
|
+
if (commonDirs.includes(parts[i])) {
|
|
70
|
+
pathStart = i;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
branch = parts.slice(0, pathStart).join('/');
|
|
75
|
+
pathParts = parts.slice(pathStart);
|
|
76
|
+
} else {
|
|
77
|
+
// No file extension - assume it's all branch name
|
|
78
|
+
branch = rest;
|
|
79
|
+
pathParts = [];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
owner,
|
|
85
|
+
repo,
|
|
86
|
+
branch,
|
|
87
|
+
path: pathParts.length > 0 ? pathParts.join('/') : undefined
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const patterns = [
|
|
92
|
+
/github\.com\/([^\/]+)\/([^\/]+)$/,
|
|
93
|
+
/github\.com\/([^\/]+)\/([^\/]+)/
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
for (const pattern of patterns) {
|
|
97
|
+
const match = url.match(pattern);
|
|
98
|
+
if (match) {
|
|
99
|
+
return {
|
|
100
|
+
owner: match[1],
|
|
101
|
+
repo: match[2].replace('.git', ''),
|
|
102
|
+
branch: match[3] || 'main',
|
|
103
|
+
path: match[4]
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
throw new Error(`Invalid GitHub URL: ${url}`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get repository metadata
|
|
113
|
+
*/
|
|
114
|
+
async getRepoMetadata(owner: string, repo: string) {
|
|
115
|
+
const { data } = await this.octokit.repos.get({
|
|
116
|
+
owner,
|
|
117
|
+
repo
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
stars: data.stargazers_count,
|
|
122
|
+
language: data.language || 'unknown',
|
|
123
|
+
license: data.license?.spdx_id ?? undefined,
|
|
124
|
+
description: data.description ?? undefined,
|
|
125
|
+
defaultBranch: data.default_branch
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Get file content from repository
|
|
131
|
+
*/
|
|
132
|
+
async getFileContent(
|
|
133
|
+
owner: string,
|
|
134
|
+
repo: string,
|
|
135
|
+
path: string,
|
|
136
|
+
branch?: string
|
|
137
|
+
): Promise<FileContent | null> {
|
|
138
|
+
try {
|
|
139
|
+
const { data } = await this.octokit.repos.getContent({
|
|
140
|
+
owner,
|
|
141
|
+
repo,
|
|
142
|
+
path,
|
|
143
|
+
ref: branch
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
if (Array.isArray(data)) {
|
|
147
|
+
return null; // Directory
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (data.type === 'file' && data.content) {
|
|
151
|
+
const content = Buffer.from(data.content, 'base64').toString('utf-8');
|
|
152
|
+
return {
|
|
153
|
+
path: data.path,
|
|
154
|
+
content,
|
|
155
|
+
type: 'file',
|
|
156
|
+
sha: data.sha
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return null;
|
|
161
|
+
} catch (error) {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* List directory contents
|
|
168
|
+
*/
|
|
169
|
+
async listDirectory(
|
|
170
|
+
owner: string,
|
|
171
|
+
repo: string,
|
|
172
|
+
path: string = '',
|
|
173
|
+
branch?: string
|
|
174
|
+
): Promise<FileContent[]> {
|
|
175
|
+
try {
|
|
176
|
+
const { data } = await this.octokit.repos.getContent({
|
|
177
|
+
owner,
|
|
178
|
+
repo,
|
|
179
|
+
path,
|
|
180
|
+
ref: branch
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
if (!Array.isArray(data)) {
|
|
184
|
+
return [];
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return data.map(item => ({
|
|
188
|
+
path: item.path,
|
|
189
|
+
content: '',
|
|
190
|
+
type: item.type as 'file' | 'dir',
|
|
191
|
+
sha: item.sha
|
|
192
|
+
}));
|
|
193
|
+
} catch (error) {
|
|
194
|
+
return [];
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Search for API specification files
|
|
200
|
+
*/
|
|
201
|
+
async findApiSpecs(
|
|
202
|
+
owner: string,
|
|
203
|
+
repo: string,
|
|
204
|
+
branch?: string
|
|
205
|
+
): Promise<ApiSpec[]> {
|
|
206
|
+
const specs: ApiSpec[] = [];
|
|
207
|
+
|
|
208
|
+
// Common locations for API specs
|
|
209
|
+
const locations = [
|
|
210
|
+
'openapi.json',
|
|
211
|
+
'openapi.yaml',
|
|
212
|
+
'openapi.yml',
|
|
213
|
+
'swagger.json',
|
|
214
|
+
'swagger.yaml',
|
|
215
|
+
'swagger.yml',
|
|
216
|
+
'api/openapi.json',
|
|
217
|
+
'api/swagger.json',
|
|
218
|
+
'spec/openapi.json',
|
|
219
|
+
'spec/swagger.json',
|
|
220
|
+
'docs/openapi.json',
|
|
221
|
+
'docs/swagger.json',
|
|
222
|
+
'.well-known/openapi.json'
|
|
223
|
+
];
|
|
224
|
+
|
|
225
|
+
for (const location of locations) {
|
|
226
|
+
const file = await this.getFileContent(owner, repo, location, branch);
|
|
227
|
+
|
|
228
|
+
if (file) {
|
|
229
|
+
try {
|
|
230
|
+
const spec = JSON.parse(file.content);
|
|
231
|
+
|
|
232
|
+
// Determine type and version
|
|
233
|
+
let type: 'openapi' | 'swagger' = 'openapi';
|
|
234
|
+
let version = '3.0.0';
|
|
235
|
+
|
|
236
|
+
if (spec.swagger) {
|
|
237
|
+
type = 'swagger';
|
|
238
|
+
version = spec.swagger;
|
|
239
|
+
} else if (spec.openapi) {
|
|
240
|
+
type = 'openapi';
|
|
241
|
+
version = spec.openapi;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
specs.push({
|
|
245
|
+
type,
|
|
246
|
+
version,
|
|
247
|
+
spec,
|
|
248
|
+
path: location
|
|
249
|
+
});
|
|
250
|
+
} catch (error) {
|
|
251
|
+
// Not JSON, try YAML
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return specs;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Get README content
|
|
262
|
+
*/
|
|
263
|
+
async getReadme(owner: string, repo: string, branch?: string): Promise<string | null> {
|
|
264
|
+
const readmeFiles = ['README.md', 'README.MD', 'readme.md', 'Readme.md'];
|
|
265
|
+
|
|
266
|
+
for (const filename of readmeFiles) {
|
|
267
|
+
const file = await this.getFileContent(owner, repo, filename, branch);
|
|
268
|
+
if (file) {
|
|
269
|
+
return file.content;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Search repository for files by pattern
|
|
278
|
+
*/
|
|
279
|
+
async searchFiles(
|
|
280
|
+
owner: string,
|
|
281
|
+
repo: string,
|
|
282
|
+
pattern: RegExp,
|
|
283
|
+
maxDepth: number = 3
|
|
284
|
+
): Promise<FileContent[]> {
|
|
285
|
+
const results: FileContent[] = [];
|
|
286
|
+
|
|
287
|
+
const searchDir = async (path: string, depth: number) => {
|
|
288
|
+
if (depth > maxDepth) return;
|
|
289
|
+
|
|
290
|
+
const contents = await this.listDirectory(owner, repo, path);
|
|
291
|
+
|
|
292
|
+
for (const item of contents) {
|
|
293
|
+
if (item.type === 'file' && pattern.test(item.path)) {
|
|
294
|
+
const file = await this.getFileContent(owner, repo, item.path);
|
|
295
|
+
if (file) {
|
|
296
|
+
results.push(file);
|
|
297
|
+
}
|
|
298
|
+
} else if (item.type === 'dir') {
|
|
299
|
+
await searchDir(item.path, depth + 1);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
await searchDir('', 0);
|
|
305
|
+
return results;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Rate limit info
|
|
310
|
+
*/
|
|
311
|
+
async getRateLimit() {
|
|
312
|
+
const { data } = await this.octokit.rateLimit.get();
|
|
313
|
+
return {
|
|
314
|
+
remaining: data.rate.remaining,
|
|
315
|
+
limit: data.rate.limit,
|
|
316
|
+
reset: new Date(data.rate.reset * 1000)
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
}
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Go MCP server code generator
|
|
3
|
+
* @copyright Copyright (c) 2024-2026 nirholas
|
|
4
|
+
* @license MIT
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ExtractedTool } from './types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Generate Go MCP server code from tools
|
|
11
|
+
*/
|
|
12
|
+
export class GoGenerator {
|
|
13
|
+
/**
|
|
14
|
+
* Generate complete Go MCP server code
|
|
15
|
+
*/
|
|
16
|
+
generateServer(tools: ExtractedTool[], repoName: string, owner: string): string {
|
|
17
|
+
const toolDefinitions = this.generateToolDefinitions(tools);
|
|
18
|
+
const toolHandlers = this.generateToolHandlers(tools, owner, repoName);
|
|
19
|
+
const moduleName = this.sanitizeModuleName(repoName);
|
|
20
|
+
|
|
21
|
+
return `// Auto-generated MCP server for ${repoName}
|
|
22
|
+
// Generated by @nirholas/github-to-mcp
|
|
23
|
+
|
|
24
|
+
package main
|
|
25
|
+
|
|
26
|
+
import (
|
|
27
|
+
"context"
|
|
28
|
+
"encoding/json"
|
|
29
|
+
"fmt"
|
|
30
|
+
"io"
|
|
31
|
+
"net/http"
|
|
32
|
+
"os"
|
|
33
|
+
|
|
34
|
+
"github.com/mark3labs/mcp-go/mcp"
|
|
35
|
+
"github.com/mark3labs/mcp-go/server"
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
func main() {
|
|
39
|
+
// Create server instance
|
|
40
|
+
s := server.NewMCPServer(
|
|
41
|
+
"${moduleName}-mcp",
|
|
42
|
+
"1.0.0",
|
|
43
|
+
server.WithResourceCapabilities(true, true),
|
|
44
|
+
server.WithPromptCapabilities(true),
|
|
45
|
+
server.WithToolCapabilities(true),
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
// Register tools
|
|
49
|
+
registerTools(s)
|
|
50
|
+
|
|
51
|
+
// Start stdio server
|
|
52
|
+
if err := server.ServeStdio(s); err != nil {
|
|
53
|
+
fmt.Fprintf(os.Stderr, "Server error: %v\\n", err)
|
|
54
|
+
os.Exit(1)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
func registerTools(s *server.MCPServer) {
|
|
59
|
+
${toolDefinitions}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Tool handler implementations
|
|
63
|
+
${toolHandlers}
|
|
64
|
+
|
|
65
|
+
// Helper function to make HTTP requests
|
|
66
|
+
func httpGet(url string, headers map[string]string) ([]byte, error) {
|
|
67
|
+
req, err := http.NewRequest("GET", url, nil)
|
|
68
|
+
if err != nil {
|
|
69
|
+
return nil, err
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
for key, value := range headers {
|
|
73
|
+
req.Header.Set(key, value)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
client := &http.Client{}
|
|
77
|
+
resp, err := client.Do(req)
|
|
78
|
+
if err != nil {
|
|
79
|
+
return nil, err
|
|
80
|
+
}
|
|
81
|
+
defer resp.Body.Close()
|
|
82
|
+
|
|
83
|
+
if resp.StatusCode >= 400 {
|
|
84
|
+
return nil, fmt.Errorf("HTTP error: %d", resp.StatusCode)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return io.ReadAll(resp.Body)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Helper function to format JSON response
|
|
91
|
+
func formatJSON(data interface{}) string {
|
|
92
|
+
bytes, err := json.MarshalIndent(data, "", " ")
|
|
93
|
+
if err != nil {
|
|
94
|
+
return fmt.Sprintf("%v", data)
|
|
95
|
+
}
|
|
96
|
+
return string(bytes)
|
|
97
|
+
}
|
|
98
|
+
`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Generate Go tool definitions
|
|
103
|
+
*/
|
|
104
|
+
private generateToolDefinitions(tools: ExtractedTool[]): string {
|
|
105
|
+
return tools.map(tool => {
|
|
106
|
+
const schemaJSON = JSON.stringify({
|
|
107
|
+
type: 'object',
|
|
108
|
+
properties: tool.inputSchema.properties || {},
|
|
109
|
+
required: tool.inputSchema.required || [],
|
|
110
|
+
}, null, 2).replace(/"/g, '`');
|
|
111
|
+
|
|
112
|
+
return ` // Register ${tool.name}
|
|
113
|
+
s.AddTool(
|
|
114
|
+
mcp.NewTool("${tool.name}",
|
|
115
|
+
mcp.WithDescription("${this.escapeString(tool.description)}"),
|
|
116
|
+
mcp.WithString("inputSchema",
|
|
117
|
+
mcp.Description("Input schema for the tool"),
|
|
118
|
+
),
|
|
119
|
+
),
|
|
120
|
+
handle${this.toPascalCase(tool.name)},
|
|
121
|
+
)`;
|
|
122
|
+
}).join('\n\n');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Generate tool handler functions
|
|
127
|
+
*/
|
|
128
|
+
private generateToolHandlers(tools: ExtractedTool[], owner: string, repo: string): string {
|
|
129
|
+
return tools.map(tool => {
|
|
130
|
+
const funcName = `handle${this.toPascalCase(tool.name)}`;
|
|
131
|
+
const impl = this.generateGoImplementation(tool, owner, repo);
|
|
132
|
+
|
|
133
|
+
return `func ${funcName}(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
134
|
+
arguments := request.Params.Arguments
|
|
135
|
+
${impl}
|
|
136
|
+
}`;
|
|
137
|
+
}).join('\n\n');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Generate Go implementation for a tool
|
|
142
|
+
*/
|
|
143
|
+
private generateGoImplementation(tool: ExtractedTool, owner: string, repo: string): string {
|
|
144
|
+
// Check if it's a universal tool
|
|
145
|
+
if (tool.source.type === 'universal') {
|
|
146
|
+
return this.generateUniversalToolGo(tool.name, owner, repo);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Check if it's a GraphQL tool
|
|
150
|
+
if (tool.source.type === 'graphql') {
|
|
151
|
+
return this.generateGraphQLToolGo(tool);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Default implementation
|
|
155
|
+
return ` // TODO: Implement ${tool.name}
|
|
156
|
+
return mcp.NewToolResultText(fmt.Sprintf("Tool ${tool.name} called with args: %v", arguments)), nil`;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Generate Go code for universal tools
|
|
161
|
+
*/
|
|
162
|
+
private generateUniversalToolGo(name: string, owner: string, repo: string): string {
|
|
163
|
+
switch (name) {
|
|
164
|
+
case 'get_readme':
|
|
165
|
+
return ` url := "https://api.github.com/repos/${owner}/${repo}/readme"
|
|
166
|
+
headers := map[string]string{"Accept": "application/vnd.github.raw"}
|
|
167
|
+
|
|
168
|
+
body, err := httpGet(url, headers)
|
|
169
|
+
if err != nil {
|
|
170
|
+
return mcp.NewToolResultError(-1, fmt.Sprintf("Failed to fetch README: %v", err)), nil
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return mcp.NewToolResultText(string(body)), nil`;
|
|
174
|
+
|
|
175
|
+
case 'list_files':
|
|
176
|
+
return ` path, _ := arguments["path"].(string)
|
|
177
|
+
url := fmt.Sprintf("https://api.github.com/repos/${owner}/${repo}/contents/%s", path)
|
|
178
|
+
|
|
179
|
+
body, err := httpGet(url, nil)
|
|
180
|
+
if err != nil {
|
|
181
|
+
return mcp.NewToolResultError(-1, fmt.Sprintf("Failed to list files: %v", err)), nil
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
var files []map[string]interface{}
|
|
185
|
+
if err := json.Unmarshal(body, &files); err != nil {
|
|
186
|
+
// Single file response
|
|
187
|
+
var file map[string]interface{}
|
|
188
|
+
if err := json.Unmarshal(body, &file); err != nil {
|
|
189
|
+
return mcp.NewToolResultError(-1, fmt.Sprintf("Failed to parse response: %v", err)), nil
|
|
190
|
+
}
|
|
191
|
+
files = []map[string]interface{}{file}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
result := make([]map[string]string, 0, len(files))
|
|
195
|
+
for _, f := range files {
|
|
196
|
+
result = append(result, map[string]string{
|
|
197
|
+
"name": f["name"].(string),
|
|
198
|
+
"type": f["type"].(string),
|
|
199
|
+
"path": f["path"].(string),
|
|
200
|
+
})
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return mcp.NewToolResultText(formatJSON(result)), nil`;
|
|
204
|
+
|
|
205
|
+
case 'read_file':
|
|
206
|
+
return ` path, _ := arguments["path"].(string)
|
|
207
|
+
url := fmt.Sprintf("https://api.github.com/repos/${owner}/${repo}/contents/%s", path)
|
|
208
|
+
headers := map[string]string{"Accept": "application/vnd.github.raw"}
|
|
209
|
+
|
|
210
|
+
body, err := httpGet(url, headers)
|
|
211
|
+
if err != nil {
|
|
212
|
+
return mcp.NewToolResultError(-1, fmt.Sprintf("Failed to read file: %v", err)), nil
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return mcp.NewToolResultText(string(body)), nil`;
|
|
216
|
+
|
|
217
|
+
case 'search_code':
|
|
218
|
+
return ` query, _ := arguments["query"].(string)
|
|
219
|
+
url := fmt.Sprintf("https://api.github.com/search/code?q=%s+repo:${owner}/${repo}", query)
|
|
220
|
+
|
|
221
|
+
body, err := httpGet(url, nil)
|
|
222
|
+
if err != nil {
|
|
223
|
+
return mcp.NewToolResultError(-1, fmt.Sprintf("Failed to search code: %v", err)), nil
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
var data struct {
|
|
227
|
+
Items []struct {
|
|
228
|
+
Path string \`json:"path"\`
|
|
229
|
+
HtmlURL string \`json:"html_url"\`
|
|
230
|
+
} \`json:"items"\`
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if err := json.Unmarshal(body, &data); err != nil {
|
|
234
|
+
return mcp.NewToolResultError(-1, fmt.Sprintf("Failed to parse response: %v", err)), nil
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if len(data.Items) == 0 {
|
|
238
|
+
return mcp.NewToolResultText(fmt.Sprintf("No results found for: %s", query)), nil
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
results := make([]map[string]string, 0, 10)
|
|
242
|
+
for i, item := range data.Items {
|
|
243
|
+
if i >= 10 {
|
|
244
|
+
break
|
|
245
|
+
}
|
|
246
|
+
results = append(results, map[string]string{
|
|
247
|
+
"file": item.Path,
|
|
248
|
+
"url": item.HtmlURL,
|
|
249
|
+
})
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return mcp.NewToolResultText(formatJSON(results)), nil`;
|
|
253
|
+
|
|
254
|
+
default:
|
|
255
|
+
return ` return mcp.NewToolResultText(fmt.Sprintf("Tool ${name} not implemented")), nil`;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Generate Go code for GraphQL tools
|
|
261
|
+
*/
|
|
262
|
+
private generateGraphQLToolGo(tool: ExtractedTool): string {
|
|
263
|
+
return ` // GraphQL query execution
|
|
264
|
+
query := \`${tool.implementation?.match(/query = \`([^`]+)\`/)?.[1] || 'query { __typename }'}\`
|
|
265
|
+
|
|
266
|
+
// TODO: Implement GraphQL request
|
|
267
|
+
return mcp.NewToolResultText(fmt.Sprintf("GraphQL tool %s: %v", "${tool.name}", query)), nil`;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Generate go.mod content
|
|
272
|
+
*/
|
|
273
|
+
generateGoMod(repoName: string): string {
|
|
274
|
+
const moduleName = this.sanitizeModuleName(repoName);
|
|
275
|
+
return `module ${moduleName}-mcp
|
|
276
|
+
|
|
277
|
+
go 1.21
|
|
278
|
+
|
|
279
|
+
require github.com/mark3labs/mcp-go v0.6.0
|
|
280
|
+
`;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Generate README content
|
|
285
|
+
*/
|
|
286
|
+
generateReadme(repoName: string, owner: string): string {
|
|
287
|
+
const moduleName = this.sanitizeModuleName(repoName);
|
|
288
|
+
return `# ${repoName} MCP Server (Go)
|
|
289
|
+
|
|
290
|
+
Auto-generated MCP server for interacting with the ${owner}/${repoName} GitHub repository.
|
|
291
|
+
|
|
292
|
+
## Installation
|
|
293
|
+
|
|
294
|
+
\`\`\`bash
|
|
295
|
+
go build -o ${moduleName}-mcp .
|
|
296
|
+
\`\`\`
|
|
297
|
+
|
|
298
|
+
## Usage
|
|
299
|
+
|
|
300
|
+
### With Claude Desktop
|
|
301
|
+
|
|
302
|
+
Add to your \`claude_desktop_config.json\`:
|
|
303
|
+
|
|
304
|
+
\`\`\`json
|
|
305
|
+
{
|
|
306
|
+
"mcpServers": {
|
|
307
|
+
"${moduleName}": {
|
|
308
|
+
"command": "/path/to/${moduleName}-mcp"
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
\`\`\`
|
|
313
|
+
|
|
314
|
+
### Standalone
|
|
315
|
+
|
|
316
|
+
\`\`\`bash
|
|
317
|
+
./${moduleName}-mcp
|
|
318
|
+
\`\`\`
|
|
319
|
+
|
|
320
|
+
## Dependencies
|
|
321
|
+
|
|
322
|
+
- [mcp-go](https://github.com/mark3labs/mcp-go) - Go SDK for Model Context Protocol
|
|
323
|
+
|
|
324
|
+
## License
|
|
325
|
+
|
|
326
|
+
MIT
|
|
327
|
+
`;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Convert tool name to PascalCase for Go function names
|
|
332
|
+
*/
|
|
333
|
+
private toPascalCase(name: string): string {
|
|
334
|
+
return name
|
|
335
|
+
.split(/[-_]/)
|
|
336
|
+
.map(part => part.charAt(0).toUpperCase() + part.slice(1))
|
|
337
|
+
.join('');
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Sanitize module name for Go
|
|
342
|
+
*/
|
|
343
|
+
private sanitizeModuleName(name: string): string {
|
|
344
|
+
return name.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/--+/g, '-');
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Escape string for Go
|
|
349
|
+
*/
|
|
350
|
+
private escapeString(str: string): string {
|
|
351
|
+
return str
|
|
352
|
+
.replace(/\\/g, '\\\\')
|
|
353
|
+
.replace(/"/g, '\\"')
|
|
354
|
+
.replace(/\n/g, '\\n');
|
|
355
|
+
}
|
|
356
|
+
}
|