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,405 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Integration tests for Langchain exporter
|
|
3
|
+
* @author nich (x.com/nichxbt | github.com/nirholas)
|
|
4
|
+
* @copyright Copyright (c) 2024-2026 nich (nirholas)
|
|
5
|
+
* @license MIT
|
|
6
|
+
* @see https://github.com/nirholas/github-to-mcp
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, it, expect, beforeAll } from 'vitest';
|
|
10
|
+
import { LangchainExporter, exportToLangchain } from '../../packages/core/src/langchain-exporter';
|
|
11
|
+
import { convertOpenApiToMcp } from '@github-to-mcp/openapi-parser';
|
|
12
|
+
import * as fs from 'fs/promises';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
|
|
15
|
+
/** Langchain tests - nich (x.com/nichxbt | github.com/nirholas) */
|
|
16
|
+
const _TEST_META = { author: 'nich', v: 1 } as const;
|
|
17
|
+
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// Test Fixtures
|
|
20
|
+
// ============================================================================
|
|
21
|
+
|
|
22
|
+
const FIXTURES_DIR = path.join(__dirname, '../fixtures');
|
|
23
|
+
|
|
24
|
+
async function loadFixture(relativePath: string): Promise<string> {
|
|
25
|
+
const fullPath = path.join(FIXTURES_DIR, relativePath);
|
|
26
|
+
return fs.readFile(fullPath, 'utf-8');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Sample extracted tools for testing
|
|
30
|
+
const SAMPLE_TOOLS = [
|
|
31
|
+
{
|
|
32
|
+
name: 'get_user',
|
|
33
|
+
description: 'Retrieve a user by their ID',
|
|
34
|
+
inputSchema: {
|
|
35
|
+
type: 'object',
|
|
36
|
+
properties: {
|
|
37
|
+
user_id: {
|
|
38
|
+
type: 'string',
|
|
39
|
+
description: 'The unique user identifier',
|
|
40
|
+
},
|
|
41
|
+
include_profile: {
|
|
42
|
+
type: 'boolean',
|
|
43
|
+
description: 'Whether to include profile details',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
required: ['user_id'],
|
|
47
|
+
},
|
|
48
|
+
source: { type: 'openapi' as const, file: 'api.yaml' },
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'create_user',
|
|
52
|
+
description: 'Create a new user account',
|
|
53
|
+
inputSchema: {
|
|
54
|
+
type: 'object',
|
|
55
|
+
properties: {
|
|
56
|
+
email: {
|
|
57
|
+
type: 'string',
|
|
58
|
+
format: 'email',
|
|
59
|
+
description: 'User email address',
|
|
60
|
+
},
|
|
61
|
+
name: {
|
|
62
|
+
type: 'string',
|
|
63
|
+
description: 'User display name',
|
|
64
|
+
},
|
|
65
|
+
age: {
|
|
66
|
+
type: 'integer',
|
|
67
|
+
minimum: 0,
|
|
68
|
+
maximum: 150,
|
|
69
|
+
description: 'User age',
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
required: ['email', 'name'],
|
|
73
|
+
},
|
|
74
|
+
source: { type: 'openapi' as const, file: 'api.yaml' },
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: 'list_users',
|
|
78
|
+
description: 'List all users with pagination',
|
|
79
|
+
inputSchema: {
|
|
80
|
+
type: 'object',
|
|
81
|
+
properties: {
|
|
82
|
+
limit: {
|
|
83
|
+
type: 'integer',
|
|
84
|
+
default: 20,
|
|
85
|
+
description: 'Maximum items to return',
|
|
86
|
+
},
|
|
87
|
+
offset: {
|
|
88
|
+
type: 'integer',
|
|
89
|
+
default: 0,
|
|
90
|
+
description: 'Items to skip',
|
|
91
|
+
},
|
|
92
|
+
filter: {
|
|
93
|
+
type: 'object',
|
|
94
|
+
properties: {
|
|
95
|
+
status: { type: 'string', enum: ['active', 'inactive', 'pending'] },
|
|
96
|
+
},
|
|
97
|
+
description: 'Filter criteria',
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
required: [],
|
|
101
|
+
},
|
|
102
|
+
source: { type: 'openapi' as const, file: 'api.yaml' },
|
|
103
|
+
},
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
// ============================================================================
|
|
107
|
+
// Exporter Class Tests
|
|
108
|
+
// ============================================================================
|
|
109
|
+
|
|
110
|
+
describe('LangchainExporter', () => {
|
|
111
|
+
describe('TypeScript Export', () => {
|
|
112
|
+
it('should generate valid TypeScript code', () => {
|
|
113
|
+
const exporter = new LangchainExporter();
|
|
114
|
+
const result = exporter.exportTypeScript(SAMPLE_TOOLS);
|
|
115
|
+
|
|
116
|
+
// Should contain imports
|
|
117
|
+
expect(result).toContain("import { DynamicStructuredTool }");
|
|
118
|
+
expect(result).toContain("import { z } from 'zod'");
|
|
119
|
+
|
|
120
|
+
// Should contain tool definitions
|
|
121
|
+
expect(result).toContain('getUserTool');
|
|
122
|
+
expect(result).toContain('createUserTool');
|
|
123
|
+
expect(result).toContain('listUsersTool');
|
|
124
|
+
|
|
125
|
+
// Should have proper structure
|
|
126
|
+
expect(result).toContain('new DynamicStructuredTool');
|
|
127
|
+
expect(result).toContain('schema:');
|
|
128
|
+
expect(result).toContain('func:');
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should generate Zod schemas with correct types', () => {
|
|
132
|
+
const exporter = new LangchainExporter({ includeValidation: true });
|
|
133
|
+
const result = exporter.exportTypeScript(SAMPLE_TOOLS);
|
|
134
|
+
|
|
135
|
+
// Check string types
|
|
136
|
+
expect(result).toContain('z.string()');
|
|
137
|
+
|
|
138
|
+
// Check email format
|
|
139
|
+
expect(result).toContain('z.string().email()');
|
|
140
|
+
|
|
141
|
+
// Check integer type
|
|
142
|
+
expect(result).toContain('z.number().int()');
|
|
143
|
+
|
|
144
|
+
// Check boolean type
|
|
145
|
+
expect(result).toContain('z.boolean()');
|
|
146
|
+
|
|
147
|
+
// Check optional
|
|
148
|
+
expect(result).toContain('.optional()');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should handle enums correctly', () => {
|
|
152
|
+
const exporter = new LangchainExporter();
|
|
153
|
+
const result = exporter.exportTypeScript(SAMPLE_TOOLS);
|
|
154
|
+
|
|
155
|
+
// Should have enum definition for status
|
|
156
|
+
expect(result).toContain("z.enum([");
|
|
157
|
+
expect(result).toContain("'active'");
|
|
158
|
+
expect(result).toContain("'inactive'");
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('should generate toolkit class when format is toolkit', () => {
|
|
162
|
+
const exporter = new LangchainExporter({ format: 'toolkit', toolkitName: 'userTools' });
|
|
163
|
+
const result = exporter.exportTypeScript(SAMPLE_TOOLS);
|
|
164
|
+
|
|
165
|
+
expect(result).toContain('class UserToolsToolkit');
|
|
166
|
+
expect(result).toContain('getTools()');
|
|
167
|
+
expect(result).toContain('getTool(name: string)');
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('should use custom options', () => {
|
|
171
|
+
const exporter = new LangchainExporter({
|
|
172
|
+
toolkitName: 'myApi',
|
|
173
|
+
baseUrl: 'https://api.custom.com',
|
|
174
|
+
apiKeyEnvVar: 'MY_API_KEY',
|
|
175
|
+
});
|
|
176
|
+
const result = exporter.exportTypeScript(SAMPLE_TOOLS);
|
|
177
|
+
|
|
178
|
+
expect(result).toContain('https://api.custom.com');
|
|
179
|
+
expect(result).toContain('MY_API_KEY');
|
|
180
|
+
expect(result).toContain('export const myApi');
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
describe('Python Export', () => {
|
|
185
|
+
it('should generate valid Python code', () => {
|
|
186
|
+
const exporter = new LangchainExporter();
|
|
187
|
+
const result = exporter.exportPython(SAMPLE_TOOLS);
|
|
188
|
+
|
|
189
|
+
// Should contain imports
|
|
190
|
+
expect(result).toContain('from langchain.tools import StructuredTool');
|
|
191
|
+
expect(result).toContain('from pydantic import BaseModel, Field');
|
|
192
|
+
expect(result).toContain('import httpx');
|
|
193
|
+
|
|
194
|
+
// Should contain tool definitions
|
|
195
|
+
expect(result).toContain('get_user_tool');
|
|
196
|
+
expect(result).toContain('create_user_tool');
|
|
197
|
+
expect(result).toContain('list_users_tool');
|
|
198
|
+
|
|
199
|
+
// Should have proper structure
|
|
200
|
+
expect(result).toContain('StructuredTool.from_function');
|
|
201
|
+
expect(result).toContain('async def');
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should generate Pydantic models with correct types', () => {
|
|
205
|
+
const exporter = new LangchainExporter({ includeValidation: true });
|
|
206
|
+
const result = exporter.exportPython(SAMPLE_TOOLS);
|
|
207
|
+
|
|
208
|
+
// Check Python types
|
|
209
|
+
expect(result).toContain(': str');
|
|
210
|
+
expect(result).toContain(': int');
|
|
211
|
+
expect(result).toContain(': bool');
|
|
212
|
+
|
|
213
|
+
// Check optional types
|
|
214
|
+
expect(result).toContain('| None');
|
|
215
|
+
|
|
216
|
+
// Check BaseModel classes
|
|
217
|
+
expect(result).toContain('class GetUserInput(BaseModel)');
|
|
218
|
+
expect(result).toContain('class CreateUserInput(BaseModel)');
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('should use Field for descriptions', () => {
|
|
222
|
+
const exporter = new LangchainExporter({ includeValidation: true });
|
|
223
|
+
const result = exporter.exportPython(SAMPLE_TOOLS);
|
|
224
|
+
|
|
225
|
+
expect(result).toContain('Field(');
|
|
226
|
+
expect(result).toContain('description=');
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('should generate toolkit class when format is toolkit', () => {
|
|
230
|
+
const exporter = new LangchainExporter({ format: 'toolkit', toolkitName: 'userTools' });
|
|
231
|
+
const result = exporter.exportPython(SAMPLE_TOOLS);
|
|
232
|
+
|
|
233
|
+
expect(result).toContain('class UserToolsToolkit');
|
|
234
|
+
expect(result).toContain('def get_tools(self)');
|
|
235
|
+
expect(result).toContain('def get_tool(self, name: str)');
|
|
236
|
+
});
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
describe('Combined Export', () => {
|
|
240
|
+
it('should return both TypeScript and Python exports', () => {
|
|
241
|
+
const exporter = new LangchainExporter();
|
|
242
|
+
const result = exporter.export(SAMPLE_TOOLS);
|
|
243
|
+
|
|
244
|
+
expect(result.typescript).toBeDefined();
|
|
245
|
+
expect(result.python).toBeDefined();
|
|
246
|
+
expect(result.metadata).toBeDefined();
|
|
247
|
+
expect(result.metadata.toolCount).toBe(3);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('should include correct metadata', () => {
|
|
251
|
+
const exporter = new LangchainExporter({ toolkitName: 'customKit' });
|
|
252
|
+
const result = exporter.export(SAMPLE_TOOLS);
|
|
253
|
+
|
|
254
|
+
expect(result.metadata.toolkitName).toBe('customKit');
|
|
255
|
+
expect(result.metadata.toolCount).toBe(SAMPLE_TOOLS.length);
|
|
256
|
+
expect(result.metadata.generatedAt).toBeDefined();
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// ============================================================================
|
|
262
|
+
// Factory Function Tests
|
|
263
|
+
// ============================================================================
|
|
264
|
+
|
|
265
|
+
describe('exportToLangchain factory', () => {
|
|
266
|
+
it('should export tools with default options', () => {
|
|
267
|
+
const result = exportToLangchain(SAMPLE_TOOLS);
|
|
268
|
+
|
|
269
|
+
expect(result.typescript).toContain('DynamicStructuredTool');
|
|
270
|
+
expect(result.python).toContain('StructuredTool');
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('should respect custom options', () => {
|
|
274
|
+
const result = exportToLangchain(SAMPLE_TOOLS, {
|
|
275
|
+
toolkitName: 'apiTools',
|
|
276
|
+
baseUrl: 'https://custom-api.com',
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
expect(result.typescript).toContain('https://custom-api.com');
|
|
280
|
+
expect(result.typescript).toContain('export const apiTools');
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
// ============================================================================
|
|
285
|
+
// Integration with OpenAPI Parser
|
|
286
|
+
// ============================================================================
|
|
287
|
+
|
|
288
|
+
describe('Langchain Export from OpenAPI', () => {
|
|
289
|
+
let petstoreSpec: string;
|
|
290
|
+
|
|
291
|
+
beforeAll(async () => {
|
|
292
|
+
petstoreSpec = await loadFixture('openapi/petstore.yaml');
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
it('should export OpenAPI-extracted tools to Langchain format', async () => {
|
|
296
|
+
const mcpResult = await convertOpenApiToMcp(petstoreSpec);
|
|
297
|
+
const langchainResult = exportToLangchain(mcpResult.tools as any);
|
|
298
|
+
|
|
299
|
+
expect(langchainResult.typescript).toContain('listPetsTool');
|
|
300
|
+
expect(langchainResult.typescript).toContain('createPetTool');
|
|
301
|
+
expect(langchainResult.python).toContain('list_pets_tool');
|
|
302
|
+
expect(langchainResult.python).toContain('create_pet_tool');
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it('should preserve tool descriptions from OpenAPI', async () => {
|
|
306
|
+
const mcpResult = await convertOpenApiToMcp(petstoreSpec);
|
|
307
|
+
const langchainResult = exportToLangchain(mcpResult.tools as any);
|
|
308
|
+
|
|
309
|
+
// Descriptions should be included
|
|
310
|
+
expect(langchainResult.typescript).toContain('description:');
|
|
311
|
+
expect(langchainResult.python).toContain('description=');
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// ============================================================================
|
|
316
|
+
// Edge Cases
|
|
317
|
+
// ============================================================================
|
|
318
|
+
|
|
319
|
+
describe('Edge Cases', () => {
|
|
320
|
+
it('should handle empty tool list', () => {
|
|
321
|
+
const exporter = new LangchainExporter();
|
|
322
|
+
const result = exporter.export([]);
|
|
323
|
+
|
|
324
|
+
expect(result.metadata.toolCount).toBe(0);
|
|
325
|
+
expect(result.typescript).toBeDefined();
|
|
326
|
+
expect(result.python).toBeDefined();
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it('should handle tools without descriptions', () => {
|
|
330
|
+
const toolsWithoutDesc = [
|
|
331
|
+
{
|
|
332
|
+
name: 'simple_tool',
|
|
333
|
+
description: '',
|
|
334
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
335
|
+
source: { type: 'code' as const, file: 'test.ts' },
|
|
336
|
+
},
|
|
337
|
+
];
|
|
338
|
+
|
|
339
|
+
const exporter = new LangchainExporter();
|
|
340
|
+
const result = exporter.export(toolsWithoutDesc);
|
|
341
|
+
|
|
342
|
+
expect(result.typescript).toContain('simple_tool');
|
|
343
|
+
expect(result.python).toContain('simple_tool');
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('should handle tools with complex nested schemas', () => {
|
|
347
|
+
const complexTool = [
|
|
348
|
+
{
|
|
349
|
+
name: 'complex_tool',
|
|
350
|
+
description: 'A tool with nested schema',
|
|
351
|
+
inputSchema: {
|
|
352
|
+
type: 'object',
|
|
353
|
+
properties: {
|
|
354
|
+
config: {
|
|
355
|
+
type: 'object',
|
|
356
|
+
properties: {
|
|
357
|
+
nested: {
|
|
358
|
+
type: 'object',
|
|
359
|
+
properties: {
|
|
360
|
+
deep: { type: 'string' },
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
items: {
|
|
366
|
+
type: 'array',
|
|
367
|
+
items: {
|
|
368
|
+
type: 'object',
|
|
369
|
+
properties: {
|
|
370
|
+
id: { type: 'string' },
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
required: [],
|
|
376
|
+
},
|
|
377
|
+
source: { type: 'code' as const, file: 'test.ts' },
|
|
378
|
+
},
|
|
379
|
+
];
|
|
380
|
+
|
|
381
|
+
const exporter = new LangchainExporter();
|
|
382
|
+
const result = exporter.export(complexTool);
|
|
383
|
+
|
|
384
|
+
expect(result.typescript).toContain('z.object');
|
|
385
|
+
expect(result.typescript).toContain('z.array');
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
it('should escape special characters in descriptions', () => {
|
|
389
|
+
const toolWithSpecialChars = [
|
|
390
|
+
{
|
|
391
|
+
name: 'special_tool',
|
|
392
|
+
description: "Tool with 'quotes' and \"double quotes\" and `backticks`",
|
|
393
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
394
|
+
source: { type: 'code' as const, file: 'test.ts' },
|
|
395
|
+
},
|
|
396
|
+
];
|
|
397
|
+
|
|
398
|
+
const exporter = new LangchainExporter();
|
|
399
|
+
const result = exporter.export(toolWithSpecialChars);
|
|
400
|
+
|
|
401
|
+
// Should not break the code
|
|
402
|
+
expect(result.typescript).toBeDefined();
|
|
403
|
+
expect(result.python).toBeDefined();
|
|
404
|
+
});
|
|
405
|
+
});
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Integration tests for github-to-mcp conversion
|
|
3
|
+
* @author nich (x.com/nichxbt | github.com/nirholas)
|
|
4
|
+
* @copyright Copyright (c) 2024-2026 nich (nirholas)
|
|
5
|
+
* @license MIT
|
|
6
|
+
* @see https://github.com/nirholas/github-to-mcp
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { describe, it, expect, beforeAll, vi } from 'vitest';
|
|
10
|
+
import { convertOpenApiToMcp } from '@github-to-mcp/openapi-parser';
|
|
11
|
+
import * as fs from 'fs/promises';
|
|
12
|
+
import * as path from 'path';
|
|
13
|
+
|
|
14
|
+
/** Integration tests - nich (x.com/nichxbt | github.com/nirholas) */
|
|
15
|
+
const _TEST_META = { author: 'nich', v: 1, project: 'github-to-mcp' } as const;
|
|
16
|
+
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// Test Fixtures
|
|
19
|
+
// ============================================================================
|
|
20
|
+
|
|
21
|
+
const FIXTURES_DIR = path.join(__dirname, '../fixtures');
|
|
22
|
+
|
|
23
|
+
async function loadFixture(relativePath: string): Promise<string> {
|
|
24
|
+
const fullPath = path.join(FIXTURES_DIR, relativePath);
|
|
25
|
+
return fs.readFile(fullPath, 'utf-8');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// OpenAPI Conversion Tests
|
|
30
|
+
// ============================================================================
|
|
31
|
+
|
|
32
|
+
describe('OpenAPI to MCP Conversion', () => {
|
|
33
|
+
let petstoreSpec: string;
|
|
34
|
+
|
|
35
|
+
beforeAll(async () => {
|
|
36
|
+
petstoreSpec = await loadFixture('openapi/petstore.yaml');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe('Basic Conversion', () => {
|
|
40
|
+
it('should convert Petstore OpenAPI spec to MCP tools', async () => {
|
|
41
|
+
const result = await convertOpenApiToMcp(petstoreSpec);
|
|
42
|
+
|
|
43
|
+
expect(result).toBeDefined();
|
|
44
|
+
expect(result.tools).toBeDefined();
|
|
45
|
+
expect(Array.isArray(result.tools)).toBe(true);
|
|
46
|
+
expect(result.tools.length).toBeGreaterThan(0);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should extract all CRUD operations from Petstore', async () => {
|
|
50
|
+
const result = await convertOpenApiToMcp(petstoreSpec);
|
|
51
|
+
|
|
52
|
+
// Should have listPets, createPet, getPet, updatePet, deletePet
|
|
53
|
+
const toolNames = result.tools.map((t: any) => t.name);
|
|
54
|
+
|
|
55
|
+
expect(toolNames).toContain('listPets');
|
|
56
|
+
expect(toolNames).toContain('createPet');
|
|
57
|
+
expect(toolNames).toContain('getPet');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should generate proper input schemas', async () => {
|
|
61
|
+
const result = await convertOpenApiToMcp(petstoreSpec);
|
|
62
|
+
|
|
63
|
+
const listPetsTool = result.tools.find((t: any) => t.name === 'listPets');
|
|
64
|
+
expect(listPetsTool).toBeDefined();
|
|
65
|
+
expect(listPetsTool.inputSchema).toBeDefined();
|
|
66
|
+
expect(listPetsTool.inputSchema.type).toBe('object');
|
|
67
|
+
expect(listPetsTool.inputSchema.properties).toBeDefined();
|
|
68
|
+
|
|
69
|
+
// Check for limit and offset parameters
|
|
70
|
+
expect(listPetsTool.inputSchema.properties.limit).toBeDefined();
|
|
71
|
+
expect(listPetsTool.inputSchema.properties.offset).toBeDefined();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should preserve descriptions from OpenAPI spec', async () => {
|
|
75
|
+
const result = await convertOpenApiToMcp(petstoreSpec);
|
|
76
|
+
|
|
77
|
+
const listPetsTool = result.tools.find((t: any) => t.name === 'listPets');
|
|
78
|
+
expect(listPetsTool.description).toContain('pet');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should handle path parameters correctly', async () => {
|
|
82
|
+
const result = await convertOpenApiToMcp(petstoreSpec);
|
|
83
|
+
|
|
84
|
+
const getPetTool = result.tools.find((t: any) => t.name === 'getPet');
|
|
85
|
+
expect(getPetTool).toBeDefined();
|
|
86
|
+
expect(getPetTool.inputSchema.properties.petId).toBeDefined();
|
|
87
|
+
expect(getPetTool.inputSchema.required).toContain('petId');
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe('Schema Type Conversion', () => {
|
|
92
|
+
it('should convert integer types correctly', async () => {
|
|
93
|
+
const result = await convertOpenApiToMcp(petstoreSpec);
|
|
94
|
+
|
|
95
|
+
const listPetsTool = result.tools.find((t: any) => t.name === 'listPets');
|
|
96
|
+
const limitProp = listPetsTool.inputSchema.properties.limit;
|
|
97
|
+
|
|
98
|
+
expect(limitProp.type).toBe('integer');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should handle required fields', async () => {
|
|
102
|
+
const result = await convertOpenApiToMcp(petstoreSpec);
|
|
103
|
+
|
|
104
|
+
const createPetTool = result.tools.find((t: any) => t.name === 'createPet');
|
|
105
|
+
expect(createPetTool.inputSchema.required).toBeDefined();
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// ============================================================================
|
|
111
|
+
// Generated Code Validation Tests
|
|
112
|
+
// ============================================================================
|
|
113
|
+
|
|
114
|
+
describe('Generated Code Validation', () => {
|
|
115
|
+
let petstoreSpec: string;
|
|
116
|
+
|
|
117
|
+
beforeAll(async () => {
|
|
118
|
+
petstoreSpec = await loadFixture('openapi/petstore.yaml');
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should generate tools with valid structure', async () => {
|
|
122
|
+
const result = await convertOpenApiToMcp(petstoreSpec);
|
|
123
|
+
|
|
124
|
+
for (const tool of result.tools) {
|
|
125
|
+
// Every tool must have name, description, and inputSchema
|
|
126
|
+
expect(tool.name).toBeDefined();
|
|
127
|
+
expect(typeof tool.name).toBe('string');
|
|
128
|
+
expect(tool.name.length).toBeGreaterThan(0);
|
|
129
|
+
|
|
130
|
+
expect(tool.description).toBeDefined();
|
|
131
|
+
expect(typeof tool.description).toBe('string');
|
|
132
|
+
|
|
133
|
+
expect(tool.inputSchema).toBeDefined();
|
|
134
|
+
expect(tool.inputSchema.type).toBe('object');
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should not have duplicate tool names', async () => {
|
|
139
|
+
const result = await convertOpenApiToMcp(petstoreSpec);
|
|
140
|
+
|
|
141
|
+
const names = result.tools.map((t: any) => t.name);
|
|
142
|
+
const uniqueNames = new Set(names);
|
|
143
|
+
|
|
144
|
+
expect(names.length).toBe(uniqueNames.size);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should generate snake_case or camelCase tool names', async () => {
|
|
148
|
+
const result = await convertOpenApiToMcp(petstoreSpec);
|
|
149
|
+
|
|
150
|
+
const validNamePattern = /^[a-zA-Z][a-zA-Z0-9_]*$/;
|
|
151
|
+
|
|
152
|
+
for (const tool of result.tools) {
|
|
153
|
+
expect(tool.name).toMatch(validNamePattern);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// ============================================================================
|
|
159
|
+
// Error Handling Tests
|
|
160
|
+
// ============================================================================
|
|
161
|
+
|
|
162
|
+
describe('Error Handling', () => {
|
|
163
|
+
it('should handle invalid YAML gracefully', async () => {
|
|
164
|
+
const invalidYaml = 'this is not: valid: yaml: [';
|
|
165
|
+
|
|
166
|
+
await expect(convertOpenApiToMcp(invalidYaml)).rejects.toThrow();
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('should handle empty spec', async () => {
|
|
170
|
+
const emptySpec = '';
|
|
171
|
+
|
|
172
|
+
await expect(convertOpenApiToMcp(emptySpec)).rejects.toThrow();
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should handle spec without paths', async () => {
|
|
176
|
+
const noPathsSpec = `
|
|
177
|
+
openapi: 3.0.3
|
|
178
|
+
info:
|
|
179
|
+
title: Empty API
|
|
180
|
+
version: 1.0.0
|
|
181
|
+
`;
|
|
182
|
+
|
|
183
|
+
const result = await convertOpenApiToMcp(noPathsSpec);
|
|
184
|
+
expect(result.tools.length).toBe(0);
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// ============================================================================
|
|
189
|
+
// Performance Tests
|
|
190
|
+
// ============================================================================
|
|
191
|
+
|
|
192
|
+
describe('Performance', () => {
|
|
193
|
+
let petstoreSpec: string;
|
|
194
|
+
|
|
195
|
+
beforeAll(async () => {
|
|
196
|
+
petstoreSpec = await loadFixture('openapi/petstore.yaml');
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('should convert spec within reasonable time', async () => {
|
|
200
|
+
const start = Date.now();
|
|
201
|
+
await convertOpenApiToMcp(petstoreSpec);
|
|
202
|
+
const duration = Date.now() - start;
|
|
203
|
+
|
|
204
|
+
// Should complete within 1 second for a small spec
|
|
205
|
+
expect(duration).toBeLessThan(1000);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('should handle multiple conversions efficiently', async () => {
|
|
209
|
+
const start = Date.now();
|
|
210
|
+
|
|
211
|
+
// Run 10 conversions
|
|
212
|
+
await Promise.all(
|
|
213
|
+
Array(10).fill(null).map(() => convertOpenApiToMcp(petstoreSpec))
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
const duration = Date.now() - start;
|
|
217
|
+
|
|
218
|
+
// 10 conversions should complete within 3 seconds
|
|
219
|
+
expect(duration).toBeLessThan(3000);
|
|
220
|
+
});
|
|
221
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"declaration": true,
|
|
13
|
+
"declarationMap": true,
|
|
14
|
+
"sourceMap": true,
|
|
15
|
+
"outDir": "./dist"
|
|
16
|
+
},
|
|
17
|
+
"exclude": ["node_modules", "dist"]
|
|
18
|
+
}
|
package/vitest.config.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
|
2
|
+
|
|
3
|
+
export default defineConfig({
|
|
4
|
+
test: {
|
|
5
|
+
globals: true,
|
|
6
|
+
coverage: {
|
|
7
|
+
provider: 'v8',
|
|
8
|
+
reporter: ['text', 'json', 'html'],
|
|
9
|
+
include: [
|
|
10
|
+
'packages/*/src/**/*.ts',
|
|
11
|
+
],
|
|
12
|
+
exclude: [
|
|
13
|
+
'**/node_modules/**',
|
|
14
|
+
'**/dist/**',
|
|
15
|
+
'**/__tests__/**',
|
|
16
|
+
'**/cli.ts',
|
|
17
|
+
],
|
|
18
|
+
thresholds: {
|
|
19
|
+
global: {
|
|
20
|
+
branches: 70,
|
|
21
|
+
functions: 70,
|
|
22
|
+
lines: 70,
|
|
23
|
+
statements: 70,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
include: ['packages/*/src/**/*.test.ts', 'tests/**/*.test.ts'],
|
|
28
|
+
exclude: ['**/node_modules/**', '**/dist/**'],
|
|
29
|
+
testTimeout: 30000,
|
|
30
|
+
hookTimeout: 30000,
|
|
31
|
+
},
|
|
32
|
+
});
|