#
tokens: 49511/50000 162/252 files (page 1/10)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 1 of 10. Use http://codebase.md/jakedismo/master-mcp-server?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .env.example
├── .eslintignore
├── .eslintrc.cjs
├── .eslintrc.js
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .prettierrc.json
├── CHANGELOG.md
├── config
│   ├── default.json
│   ├── development.json
│   ├── production.json
│   └── schema.json
├── config.json
├── CONTRIBUTING.md
├── debug-stdio.cjs
├── debug-stdio.js
├── deploy
│   ├── cloudflare
│   │   ├── .gitkeep
│   │   ├── README.md
│   │   └── wrangler.toml
│   ├── docker
│   │   ├── .gitkeep
│   │   ├── docker-compose.yml
│   │   ├── Dockerfile
│   │   └── entrypoint.sh
│   ├── koyeb
│   │   ├── .gitkeep
│   │   └── koyeb.yaml
│   └── README.md
├── docker-compose.yml
├── Dockerfile
├── docs
│   ├── .DS_Store
│   ├── .vitepress
│   │   ├── cache
│   │   │   └── deps
│   │   │       ├── _metadata.json
│   │   │       ├── chunk-HVR2FF6M.js
│   │   │       ├── chunk-HVR2FF6M.js.map
│   │   │       ├── chunk-P2XGSYO7.js
│   │   │       ├── chunk-P2XGSYO7.js.map
│   │   │       ├── package.json
│   │   │       ├── vitepress___@vue_devtools-api.js
│   │   │       ├── vitepress___@vue_devtools-api.js.map
│   │   │       ├── vitepress___@vueuse_core.js
│   │   │       ├── vitepress___@vueuse_core.js.map
│   │   │       ├── vitepress___@vueuse_integrations_useFocusTrap.js
│   │   │       ├── vitepress___@vueuse_integrations_useFocusTrap.js.map
│   │   │       ├── vitepress___mark__js_src_vanilla__js.js
│   │   │       ├── vitepress___mark__js_src_vanilla__js.js.map
│   │   │       ├── vitepress___minisearch.js
│   │   │       ├── vitepress___minisearch.js.map
│   │   │       ├── vue.js
│   │   │       └── vue.js.map
│   │   ├── config.ts
│   │   ├── dist
│   │   │   ├── 404.html
│   │   │   ├── advanced
│   │   │   │   ├── extensibility.html
│   │   │   │   ├── index.html
│   │   │   │   ├── monitoring.html
│   │   │   │   ├── performance.html
│   │   │   │   └── security.html
│   │   │   ├── api
│   │   │   │   ├── index.html
│   │   │   │   └── README.html
│   │   │   ├── assets
│   │   │   │   ├── advanced_extensibility.md.TrXUn5w5.js
│   │   │   │   ├── advanced_extensibility.md.TrXUn5w5.lean.js
│   │   │   │   ├── advanced_index.md.CPcpUlw_.js
│   │   │   │   ├── advanced_index.md.CPcpUlw_.lean.js
│   │   │   │   ├── advanced_monitoring.md.DTybdNg-.js
│   │   │   │   ├── advanced_monitoring.md.DTybdNg-.lean.js
│   │   │   │   ├── advanced_performance.md.DKmzK0ia.js
│   │   │   │   ├── advanced_performance.md.DKmzK0ia.lean.js
│   │   │   │   ├── advanced_security.md.B-oBD7IB.js
│   │   │   │   ├── advanced_security.md.B-oBD7IB.lean.js
│   │   │   │   ├── api_index.md.Dl1JB08_.js
│   │   │   │   ├── api_index.md.Dl1JB08_.lean.js
│   │   │   │   ├── chunks
│   │   │   │   │   └── framework.CHl2ywxc.js
│   │   │   │   ├── configuration_environment-variables.md.Ddy3P_Wz.js
│   │   │   │   ├── configuration_environment-variables.md.Ddy3P_Wz.lean.js
│   │   │   │   ├── configuration_environment.md.DxcTQ623.js
│   │   │   │   ├── configuration_environment.md.DxcTQ623.lean.js
│   │   │   │   ├── configuration_overview.md.DIkVDv7V.js
│   │   │   │   ├── configuration_overview.md.DIkVDv7V.lean.js
│   │   │   │   ├── configuration_performance.md.DbJdmLrW.js
│   │   │   │   ├── configuration_performance.md.DbJdmLrW.lean.js
│   │   │   │   ├── configuration_reference.md.27IKWqtk.js
│   │   │   │   ├── configuration_reference.md.27IKWqtk.lean.js
│   │   │   │   ├── configuration_security.md.-OOlkzN4.js
│   │   │   │   ├── configuration_security.md.-OOlkzN4.lean.js
│   │   │   │   ├── contributing_dev-setup.md.Ceqh4w-R.js
│   │   │   │   ├── contributing_dev-setup.md.Ceqh4w-R.lean.js
│   │   │   │   ├── contributing_guidelines.md.ZEAX2yVh.js
│   │   │   │   ├── contributing_guidelines.md.ZEAX2yVh.lean.js
│   │   │   │   ├── contributing_index.md.DYq9R6wr.js
│   │   │   │   ├── contributing_index.md.DYq9R6wr.lean.js
│   │   │   │   ├── contributing_maintenance.md.k2bR0IaR.js
│   │   │   │   ├── contributing_maintenance.md.k2bR0IaR.lean.js
│   │   │   │   ├── deployment_cicd.md.Ci2T0UYC.js
│   │   │   │   ├── deployment_cicd.md.Ci2T0UYC.lean.js
│   │   │   │   ├── deployment_cloudflare-workers.md.D2WHsfep.js
│   │   │   │   ├── deployment_cloudflare-workers.md.D2WHsfep.lean.js
│   │   │   │   ├── deployment_docker.md.B8bQDQTo.js
│   │   │   │   ├── deployment_docker.md.B8bQDQTo.lean.js
│   │   │   │   ├── deployment_index.md.ClYeOkpy.js
│   │   │   │   ├── deployment_index.md.ClYeOkpy.lean.js
│   │   │   │   ├── deployment_koyeb.md.B_wJhvF7.js
│   │   │   │   ├── deployment_koyeb.md.B_wJhvF7.lean.js
│   │   │   │   ├── examples_advanced-routing.md.B3CqhLZ7.js
│   │   │   │   ├── examples_advanced-routing.md.B3CqhLZ7.lean.js
│   │   │   │   ├── examples_basic-node.md.CaDZzGlO.js
│   │   │   │   ├── examples_basic-node.md.CaDZzGlO.lean.js
│   │   │   │   ├── examples_cloudflare-worker.md.DwVSz-c7.js
│   │   │   │   ├── examples_cloudflare-worker.md.DwVSz-c7.lean.js
│   │   │   │   ├── examples_index.md.CBF_BLkl.js
│   │   │   │   ├── examples_index.md.CBF_BLkl.lean.js
│   │   │   │   ├── examples_oauth-delegation.md.1hZxoqDl.js
│   │   │   │   ├── examples_oauth-delegation.md.1hZxoqDl.lean.js
│   │   │   │   ├── examples_overview.md.CZN0JbZ7.js
│   │   │   │   ├── examples_overview.md.CZN0JbZ7.lean.js
│   │   │   │   ├── examples_testing.md.Dek4GpNs.js
│   │   │   │   ├── examples_testing.md.Dek4GpNs.lean.js
│   │   │   │   ├── getting-started_concepts.md.D7ON9iGB.js
│   │   │   │   ├── getting-started_concepts.md.D7ON9iGB.lean.js
│   │   │   │   ├── getting-started_installation.md.BKnVqAGg.js
│   │   │   │   ├── getting-started_installation.md.BKnVqAGg.lean.js
│   │   │   │   ├── getting-started_overview.md.DvJDFL2N.js
│   │   │   │   ├── getting-started_overview.md.DvJDFL2N.lean.js
│   │   │   │   ├── getting-started_quickstart-node.md.GOO4aGas.js
│   │   │   │   ├── getting-started_quickstart-node.md.GOO4aGas.lean.js
│   │   │   │   ├── getting-started_quickstart-workers.md.Cpofh8Mj.js
│   │   │   │   ├── getting-started_quickstart-workers.md.Cpofh8Mj.lean.js
│   │   │   │   ├── getting-started.md.DG9ndneo.js
│   │   │   │   ├── getting-started.md.DG9ndneo.lean.js
│   │   │   │   ├── guides_configuration-management.md.B-jwYMbA.js
│   │   │   │   ├── guides_configuration-management.md.B-jwYMbA.lean.js
│   │   │   │   ├── guides_configuration.md.Ci3zYDFA.js
│   │   │   │   ├── guides_configuration.md.Ci3zYDFA.lean.js
│   │   │   │   ├── guides_index.md.CIlq2fmx.js
│   │   │   │   ├── guides_index.md.CIlq2fmx.lean.js
│   │   │   │   ├── guides_module-loading.md.BkJvuRnQ.js
│   │   │   │   ├── guides_module-loading.md.BkJvuRnQ.lean.js
│   │   │   │   ├── guides_oauth-delegation.md.DEOZ-_G0.js
│   │   │   │   ├── guides_oauth-delegation.md.DEOZ-_G0.lean.js
│   │   │   │   ├── guides_request-routing.md.Bdzf0VLg.js
│   │   │   │   ├── guides_request-routing.md.Bdzf0VLg.lean.js
│   │   │   │   ├── guides_testing.md.kYfHqJLu.js
│   │   │   │   ├── guides_testing.md.kYfHqJLu.lean.js
│   │   │   │   ├── inter-italic-cyrillic-ext.r48I6akx.woff2
│   │   │   │   ├── inter-italic-cyrillic.By2_1cv3.woff2
│   │   │   │   ├── inter-italic-greek-ext.1u6EdAuj.woff2
│   │   │   │   ├── inter-italic-greek.DJ8dCoTZ.woff2
│   │   │   │   ├── inter-italic-latin-ext.CN1xVJS-.woff2
│   │   │   │   ├── inter-italic-latin.C2AdPX0b.woff2
│   │   │   │   ├── inter-italic-vietnamese.BSbpV94h.woff2
│   │   │   │   ├── inter-roman-cyrillic-ext.BBPuwvHQ.woff2
│   │   │   │   ├── inter-roman-cyrillic.C5lxZ8CY.woff2
│   │   │   │   ├── inter-roman-greek-ext.CqjqNYQ-.woff2
│   │   │   │   ├── inter-roman-greek.BBVDIX6e.woff2
│   │   │   │   ├── inter-roman-latin-ext.4ZJIpNVo.woff2
│   │   │   │   ├── inter-roman-latin.Di8DUHzh.woff2
│   │   │   │   ├── inter-roman-vietnamese.BjW4sHH5.woff2
│   │   │   │   ├── README.md.BO5r5M9u.js
│   │   │   │   ├── README.md.BO5r5M9u.lean.js
│   │   │   │   ├── style.BQrfSMzK.css
│   │   │   │   ├── troubleshooting_common-issues.md.CScvzWM1.js
│   │   │   │   ├── troubleshooting_common-issues.md.CScvzWM1.lean.js
│   │   │   │   ├── troubleshooting_deployment.md.DUhpqnLE.js
│   │   │   │   ├── troubleshooting_deployment.md.DUhpqnLE.lean.js
│   │   │   │   ├── troubleshooting_errors.md.BSCsEmGc.js
│   │   │   │   ├── troubleshooting_errors.md.BSCsEmGc.lean.js
│   │   │   │   ├── troubleshooting_oauth.md.Cw60Eka3.js
│   │   │   │   ├── troubleshooting_oauth.md.Cw60Eka3.lean.js
│   │   │   │   ├── troubleshooting_performance.md.DxY6LJcT.js
│   │   │   │   ├── troubleshooting_performance.md.DxY6LJcT.lean.js
│   │   │   │   ├── troubleshooting_routing.md.BHN-MDhs.js
│   │   │   │   ├── troubleshooting_routing.md.BHN-MDhs.lean.js
│   │   │   │   ├── troubleshooting_security-best-practices.md.Yiu8E-zt.js
│   │   │   │   ├── troubleshooting_security-best-practices.md.Yiu8E-zt.lean.js
│   │   │   │   ├── tutorials_beginner-getting-started.md.BXObgobW.js
│   │   │   │   ├── tutorials_beginner-getting-started.md.BXObgobW.lean.js
│   │   │   │   ├── tutorials_cloudflare-workers-tutorial.md.MPHsc0aT.js
│   │   │   │   ├── tutorials_cloudflare-workers-tutorial.md.MPHsc0aT.lean.js
│   │   │   │   ├── tutorials_load-balancing-and-resilience.md.Dv9r9jyW.js
│   │   │   │   ├── tutorials_load-balancing-and-resilience.md.Dv9r9jyW.lean.js
│   │   │   │   ├── tutorials_oauth-delegation-github.md.Nq4glqCe.js
│   │   │   │   └── tutorials_oauth-delegation-github.md.Nq4glqCe.lean.js
│   │   │   ├── configuration
│   │   │   │   ├── environment-variables.html
│   │   │   │   ├── environment.html
│   │   │   │   ├── examples.html
│   │   │   │   ├── overview.html
│   │   │   │   ├── performance.html
│   │   │   │   ├── reference.html
│   │   │   │   └── security.html
│   │   │   ├── contributing
│   │   │   │   ├── dev-setup.html
│   │   │   │   ├── guidelines.html
│   │   │   │   ├── index.html
│   │   │   │   └── maintenance.html
│   │   │   ├── deployment
│   │   │   │   ├── cicd.html
│   │   │   │   ├── cloudflare-workers.html
│   │   │   │   ├── docker.html
│   │   │   │   ├── index.html
│   │   │   │   └── koyeb.html
│   │   │   ├── diagrams
│   │   │   │   └── architecture.svg
│   │   │   ├── examples
│   │   │   │   ├── advanced-routing.html
│   │   │   │   ├── basic-node.html
│   │   │   │   ├── cloudflare-worker.html
│   │   │   │   ├── index.html
│   │   │   │   ├── oauth-delegation.html
│   │   │   │   ├── overview.html
│   │   │   │   └── testing.html
│   │   │   ├── getting-started
│   │   │   │   ├── concepts.html
│   │   │   │   ├── installation.html
│   │   │   │   ├── overview.html
│   │   │   │   ├── quick-start.html
│   │   │   │   ├── quickstart-node.html
│   │   │   │   └── quickstart-workers.html
│   │   │   ├── getting-started.html
│   │   │   ├── guides
│   │   │   │   ├── authentication.html
│   │   │   │   ├── client-integration.html
│   │   │   │   ├── configuration-management.html
│   │   │   │   ├── configuration.html
│   │   │   │   ├── index.html
│   │   │   │   ├── module-loading.html
│   │   │   │   ├── oauth-delegation.html
│   │   │   │   ├── request-routing.html
│   │   │   │   ├── server-management.html
│   │   │   │   ├── server-sharing.html
│   │   │   │   └── testing.html
│   │   │   ├── hashmap.json
│   │   │   ├── index.html
│   │   │   ├── logo.svg
│   │   │   ├── README.html
│   │   │   ├── reports
│   │   │   │   └── mcp-compliance-audit.html
│   │   │   ├── troubleshooting
│   │   │   │   ├── common-issues.html
│   │   │   │   ├── deployment.html
│   │   │   │   ├── errors.html
│   │   │   │   ├── index.html
│   │   │   │   ├── oauth.html
│   │   │   │   ├── performance.html
│   │   │   │   ├── routing.html
│   │   │   │   └── security-best-practices.html
│   │   │   ├── tutorials
│   │   │   │   ├── beginner-getting-started.html
│   │   │   │   ├── cloudflare-workers-tutorial.html
│   │   │   │   ├── load-balancing-and-resilience.html
│   │   │   │   └── oauth-delegation-github.html
│   │   │   └── vp-icons.css
│   │   └── theme
│   │       ├── components
│   │       │   ├── ApiPlayground.vue
│   │       │   ├── AuthFlowDemo.vue
│   │       │   ├── CodeTabs.vue
│   │       │   └── ConfigGenerator.vue
│   │       ├── index.ts
│   │       └── style.css
│   ├── advanced
│   │   ├── extensibility.md
│   │   ├── index.md
│   │   ├── monitoring.md
│   │   ├── performance.md
│   │   └── security.md
│   ├── api
│   │   ├── functions
│   │   │   └── createServer.md
│   │   ├── index.md
│   │   ├── interfaces
│   │   │   └── RunningServer.md
│   │   └── README.md
│   ├── architecture
│   │   └── images
│   │       └── mcp_master_architecture.svg
│   ├── configuration
│   │   ├── environment-variables.md
│   │   ├── environment.md
│   │   ├── examples.md
│   │   ├── overview.md
│   │   ├── performance.md
│   │   ├── reference.md
│   │   └── security.md
│   ├── contributing
│   │   ├── dev-setup.md
│   │   ├── guidelines.md
│   │   ├── index.md
│   │   └── maintenance.md
│   ├── deployment
│   │   ├── cicd.md
│   │   ├── cloudflare-workers.md
│   │   ├── docker.md
│   │   ├── docs-site.md
│   │   ├── index.md
│   │   └── koyeb.md
│   ├── examples
│   │   ├── advanced-routing.md
│   │   ├── basic-node.md
│   │   ├── cloudflare-worker.md
│   │   ├── index.md
│   │   ├── oauth-delegation.md
│   │   ├── overview.md
│   │   └── testing.md
│   ├── getting-started
│   │   ├── concepts.md
│   │   ├── installation.md
│   │   ├── overview.md
│   │   ├── quick-start.md
│   │   ├── quickstart-node.md
│   │   └── quickstart-workers.md
│   ├── getting-started.md
│   ├── guides
│   │   ├── authentication.md
│   │   ├── client-integration.md
│   │   ├── configuration-management.md
│   │   ├── configuration.md
│   │   ├── index.md
│   │   ├── module-loading.md
│   │   ├── oauth-delegation.md
│   │   ├── request-routing.md
│   │   ├── server-management.md
│   │   ├── server-sharing.md
│   │   └── testing.md
│   ├── index.html
│   ├── public
│   │   ├── diagrams
│   │   │   └── architecture.svg
│   │   ├── github-social.png
│   │   │   └── image.png
│   │   ├── logo.png
│   │   └── logo.svg
│   ├── README.md
│   ├── stdio-servers.md
│   ├── testing
│   │   └── phase-9-testing-architecture.md
│   ├── troubleshooting
│   │   ├── common-issues.md
│   │   ├── deployment.md
│   │   ├── errors.md
│   │   ├── index.md
│   │   ├── oauth.md
│   │   ├── performance.md
│   │   ├── routing.md
│   │   └── security-best-practices.md
│   └── tutorials
│       ├── beginner-getting-started.md
│       ├── cloudflare-workers-tutorial.md
│       ├── load-balancing-and-resilience.md
│       └── oauth-delegation-github.md
├── examples
│   ├── advanced-routing
│   │   ├── config.yaml
│   │   └── README.md
│   ├── basic-node
│   │   ├── config.yaml
│   │   ├── README.md
│   │   └── server.ts
│   ├── cloudflare-worker
│   │   ├── README.md
│   │   └── worker.ts
│   ├── custom-auth
│   │   ├── config.yaml
│   │   ├── index.ts
│   │   └── README.md
│   ├── multi-server
│   │   ├── config.yaml
│   │   └── README.md
│   ├── oauth-delegation
│   │   └── README.md
│   ├── oauth-node
│   │   ├── config.yaml
│   │   └── README.md
│   ├── performance
│   │   ├── config.yaml
│   │   └── README.md
│   ├── sample-configs
│   │   ├── basic.yaml
│   │   └── simple-setup.yaml
│   ├── security-hardening
│   │   └── README.md
│   ├── stdio-mcp-server.cjs
│   ├── test-mcp-server.js
│   └── test-stdio-server.js
├── LICENSE
├── master-mcp-definition.md
├── package-lock.json
├── package.json
├── README.md
├── reports
│   └── claude_report_20250815_222153.html
├── scripts
│   └── generate-config-docs.ts
├── src
│   ├── auth
│   │   ├── multi-auth-manager.ts
│   │   ├── oauth-providers.ts
│   │   └── token-manager.ts
│   ├── config
│   │   ├── config-loader.ts
│   │   ├── environment-manager.ts
│   │   ├── schema-validator.ts
│   │   └── secret-manager.ts
│   ├── index.ts
│   ├── mcp-server.ts
│   ├── modules
│   │   ├── capability-aggregator.ts
│   │   ├── module-loader.ts
│   │   ├── request-router.ts
│   │   ├── stdio-capability-discovery.ts
│   │   └── stdio-manager.ts
│   ├── oauth
│   │   ├── callback-handler.ts
│   │   ├── flow-controller.ts
│   │   ├── flow-validator.ts
│   │   ├── pkce-manager.ts
│   │   ├── state-manager.ts
│   │   └── web-interface.ts
│   ├── routing
│   │   ├── circuit-breaker.ts
│   │   ├── load-balancer.ts
│   │   ├── retry-handler.ts
│   │   └── route-registry.ts
│   ├── runtime
│   │   ├── node.ts
│   │   └── worker.ts
│   ├── server
│   │   ├── config-manager.ts
│   │   ├── dependency-container.ts
│   │   ├── master-server.ts
│   │   └── protocol-handler.ts
│   ├── types
│   │   ├── auth.ts
│   │   ├── config.ts
│   │   ├── jose-shim.d.ts
│   │   ├── mcp.ts
│   │   └── server.ts
│   └── utils
│       ├── cache.ts
│       ├── crypto.ts
│       ├── dev.ts
│       ├── errors.ts
│       ├── http.ts
│       ├── logger.ts
│       ├── monitoring.ts
│       ├── string.ts
│       ├── time.ts
│       ├── validation.ts
│       └── validators.ts
├── static
│   └── oauth
│       ├── consent.html
│       ├── error.html
│       ├── script.js
│       ├── style.css
│       └── success.html
├── tests
│   ├── _setup
│   │   ├── miniflare.setup.ts
│   │   └── vitest.setup.ts
│   ├── _utils
│   │   ├── log-capture.ts
│   │   ├── mock-fetch.ts
│   │   └── test-server.ts
│   ├── .gitkeep
│   ├── e2e
│   │   ├── flow-controller.express.test.ts
│   │   └── flow-controller.worker.test.ts
│   ├── factories
│   │   ├── configFactory.ts
│   │   ├── mcpFactory.ts
│   │   └── oauthFactory.ts
│   ├── fixtures
│   │   ├── capabilities.json
│   │   └── stdio-server.js
│   ├── integration
│   │   ├── modules.capability-aggregator.test.ts
│   │   ├── modules.module-loader-health.test.ts
│   │   ├── oauth.callback-handler.test.ts
│   │   └── request-router.test.ts
│   ├── mocks
│   │   ├── mcp
│   │   │   └── fake-backend.ts
│   │   └── oauth
│   │       └── mock-oidc-provider.ts
│   ├── perf
│   │   ├── artillery
│   │   │   └── auth-routing.yaml
│   │   └── perf.auth-and-routing.test.ts
│   ├── security
│   │   └── security.oauth-and-input.test.ts
│   ├── servers
│   │   ├── test-auth-simple.js
│   │   ├── test-debug.js
│   │   ├── test-master-mcp.js
│   │   ├── test-mcp-client.js
│   │   ├── test-streaming-both-complete.js
│   │   ├── test-streaming-both-full.js
│   │   ├── test-streaming-both-simple.js
│   │   ├── test-streaming-both.js
│   │   └── test-streaming.js
│   ├── setup
│   │   └── test-setup.ts
│   ├── unit
│   │   ├── auth.multi-auth-manager.test.ts
│   │   ├── auth.token-manager.test.ts
│   │   ├── config.environment-manager.test.ts
│   │   ├── config.schema-validator.test.ts
│   │   ├── config.secret-manager.test.ts
│   │   ├── modules
│   │   │   ├── stdio-capability-discovery.test.ts
│   │   │   └── stdio-manager.test.ts
│   │   ├── modules.route-registry.test.ts
│   │   ├── oauth.pkce-state.test.ts
│   │   ├── routing
│   │   │   └── circuit-breaker.test.ts
│   │   ├── routing.core.test.ts
│   │   ├── stdio-capability-discovery.test.ts
│   │   ├── utils.crypto.test.ts
│   │   ├── utils.logger.test.ts
│   │   └── utils.monitoring.test.ts
│   └── utils
│       ├── fake-express.ts
│       ├── mock-http.ts
│       ├── oauth-mocks.ts
│       └── token-storages.ts
├── tsconfig.base.json
├── tsconfig.json
├── tsconfig.node.json
├── tsconfig.worker.json
├── typedoc.json
├── vitest.config.ts
└── vitest.worker.config.ts
```

# Files

--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------

```javascript
1 | 
```

--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------

```
1 | 
```

--------------------------------------------------------------------------------
/deploy/cloudflare/.gitkeep:
--------------------------------------------------------------------------------

```
1 | 
2 | 
```

--------------------------------------------------------------------------------
/deploy/docker/.gitkeep:
--------------------------------------------------------------------------------

```
1 | 
2 | 
```

--------------------------------------------------------------------------------
/deploy/koyeb/.gitkeep:
--------------------------------------------------------------------------------

```
1 | 
2 | 
```

--------------------------------------------------------------------------------
/tests/.gitkeep:
--------------------------------------------------------------------------------

```
1 | 
2 | 
```

--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------

```
1 | dist
2 | node_modules
3 | coverage
4 | 
5 | 
```

--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------

```
1 | dist
2 | node_modules
3 | coverage
4 | 
5 | 
```

--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "singleQuote": true,
3 |   "semi": false,
4 |   "trailingComma": "es5",
5 |   "printWidth": 100
6 | }
7 | 
8 | 
```

--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------

```
 1 | # Runtime
 2 | NODE_ENV=development
 3 | LOG_LEVEL=info
 4 | LOG_FORMAT=json
 5 | 
 6 | # Hosting
 7 | # If running behind a PaaS that sets PORT, the config loader will detect it.
 8 | PORT=3000
 9 | MASTER_HOSTING_PLATFORM=node
10 | MASTER_HOSTING_PORT=3000
11 | MASTER_BASE_URL=http://localhost:3000
12 | 
13 | # Security
14 | # REQUIRED in production; if missing in dev, an ephemeral key is generated
15 | TOKEN_ENC_KEY=replace-with-32+char-hex-or-random
16 | 
17 | # OAuth defaults (example values; override per provider)
18 | MASTER_OAUTH_AUTHORIZATION_ENDPOINT=https://example.com/auth
19 | MASTER_OAUTH_TOKEN_ENDPOINT=https://example.com/token
20 | MASTER_OAUTH_CLIENT_ID=placeholder
21 | MASTER_OAUTH_REDIRECT_URI=http://localhost:3000/oauth/callback
22 | MASTER_OAUTH_SCOPES=openid
23 | 
24 | 
```

--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------

```
 1 | /* eslint-env node */
 2 | module.exports = {
 3 |   root: true,
 4 |   parser: '@typescript-eslint/parser',
 5 |   parserOptions: {
 6 |     project: ['./tsconfig.node.json'],
 7 |     tsconfigRootDir: __dirname,
 8 |     sourceType: 'module',
 9 |     ecmaVersion: 2022
10 |   },
11 |   env: {
12 |     node: true,
13 |     es2022: true
14 |   },
15 |   plugins: ['@typescript-eslint'],
16 |   extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
17 |   rules: {
18 |     'no-console': 'off',
19 |     '@typescript-eslint/no-explicit-any': 'off',
20 |     '@typescript-eslint/no-unused-vars': 'off'
21 |   },
22 |   overrides: [
23 |     {
24 |       files: ['**/*.ts', '**/*.tsx'],
25 |       parser: '@typescript-eslint/parser',
26 |       parserOptions: {
27 |         project: ['./tsconfig.node.json'],
28 |         tsconfigRootDir: __dirname,
29 |         sourceType: 'module',
30 |         ecmaVersion: 2022,
31 |       },
32 |     },
33 |     {
34 |       files: ['src/runtime/worker.ts'],
35 |       parserOptions: {
36 |         project: ['./tsconfig.worker.json'],
37 |       },
38 |     },
39 |   ],
40 |   ignorePatterns: ['dist/**', 'node_modules/**']
41 | }
42 | 
```

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
  1 | # Master MCP Server - Comprehensive .gitignore
  2 | 
  3 | # Node.js & npm
  4 | node_modules/
  5 | npm-debug.log*
  6 | yarn-debug.log*
  7 | yarn-error.log*
  8 | lerna-debug.log*
  9 | .pnpm-debug.log*
 10 | 
 11 | # Package manager lock files (keep package-lock.json for reproducible builds)
 12 | yarn.lock
 13 | pnpm-lock.yaml
 14 | 
 15 | # Runtime data
 16 | pids/
 17 | *.pid
 18 | *.seed
 19 | *.pid.lock
 20 | 
 21 | # Coverage directory used by tools like istanbul
 22 | coverage/
 23 | *.lcov
 24 | .nyc_output/
 25 | .coverage/
 26 | 
 27 | # Compiled output
 28 | dist/
 29 | build/
 30 | lib/
 31 | out/
 32 | *.tsbuildinfo
 33 | 
 34 | # TypeScript cache
 35 | *.tsbuildinfo
 36 | 
 37 | # ESLint cache
 38 | .eslintcache
 39 | 
 40 | # Prettier cache
 41 | .prettiercache
 42 | 
 43 | # Optional npm cache directory
 44 | .npm
 45 | 
 46 | # Optional eslint cache
 47 | .eslintcache
 48 | 
 49 | # Microbundle cache
 50 | .rpt2_cache/
 51 | .rts2_cache_cjs/
 52 | .rts2_cache_es/
 53 | .rts2_cache_umd/
 54 | 
 55 | # Optional REPL history
 56 | .node_repl_history
 57 | 
 58 | # Output of 'npm pack'
 59 | *.tgz
 60 | 
 61 | # Yarn Integrity file
 62 | .yarn-integrity
 63 | 
 64 | # Environment variables
 65 | .env
 66 | .env.local
 67 | .env.development.local
 68 | .env.test.local
 69 | .env.production.local
 70 | .env.*.local
 71 | .env.production
 72 | 
 73 | # Secrets and sensitive configuration
 74 | config/secrets.json
 75 | config/production-secrets.json
 76 | .secrets/
 77 | secrets/
 78 | 
 79 | # IDE and Editor files
 80 | .vscode/
 81 | .idea/
 82 | *.swp
 83 | *.swo
 84 | *~
 85 | .DS_Store
 86 | Thumbs.db
 87 | 
 88 | # OS generated files
 89 | .DS_Store
 90 | .DS_Store?
 91 | ._*
 92 | .Spotlight-V100
 93 | .Trashes
 94 | ehthumbs.db
 95 | Thumbs.db
 96 | 
 97 | # Logs
 98 | logs/
 99 | *.log
100 | npm-debug.log*
101 | yarn-debug.log*
102 | yarn-error.log*
103 | lerna-debug.log*
104 | 
105 | # Runtime and process files
106 | .pm2/
107 | .pid
108 | 
109 | # Database
110 | *.db
111 | *.sqlite
112 | *.sqlite3
113 | 
114 | # Cache directories
115 | .cache/
116 | .parcel-cache/
117 | .next/
118 | .nuxt/
119 | .vuepress/dist
120 | 
121 | # Temporary directories
122 | tmp/
123 | temp/
124 | .tmp/
125 | .temp/
126 | 
127 | # Test artifacts
128 | test-results/
129 | junit.xml
130 | coverage-final.json
131 | 
132 | # Documentation build artifacts
133 | docs/.vitepress/dist/
134 | docs/.vitepress/cache/
135 | .typedoc/
136 | 
137 | # Deployment artifacts
138 | deploy/secrets/
139 | deploy/keys/
140 | deploy/*.key
141 | deploy/*.pem
142 | 
143 | # Docker
144 | .dockerignore
145 | docker-compose.override.yml
146 | 
147 | # Cloudflare Workers
148 | .dev.vars
149 | .wrangler/
150 | worker-configuration.d.ts
151 | 
152 | # Koyeb
153 | .koyeb/
154 | 
155 | # SSL certificates and keys
156 | *.pem
157 | *.key
158 | *.crt
159 | *.ca-bundle
160 | *.p12
161 | *.pfx
162 | 
163 | # API keys and tokens
164 | .api-keys
165 | *.token
166 | auth.json
167 | 
168 | # Ouroboros and Swarm Agent Files
169 | ouroboros-results/
170 | ouroboros-logs/
171 | ouroboros-cache/
172 | ouroboros-data/
173 | swarm-cache/
174 | swarm-logs/
175 | agent-logs/
176 | agent-results/
177 | agent-cache/
178 | .ouroboros/
179 | .swarm/
180 | 
181 | # Session and memory files
182 | SESSION-MEMORY.md
183 | session-*.md
184 | .session/
185 | memory/
186 | 
187 | # MCP specific
188 | mcp-logs/
189 | mcp-cache/
190 | server-data/
191 | server-logs/
192 | backend-servers/
193 | loaded-servers/
194 | .mcp/
195 | 
196 | # OAuth and authentication
197 | oauth-tokens/
198 | oauth-cache/
199 | .oauth/
200 | tokens/
201 | session-store/
202 | 
203 | # Performance and monitoring
204 | metrics/
205 | traces/
206 | .monitoring/
207 | perf-data/
208 | 
209 | # Local development
210 | .dev/
211 | dev-data/
212 | local-config/
213 | local-secrets/
214 | 
215 | # Husky hooks (if needed, can be uncommented)
216 | .husky/
217 | 
218 | # Backup files
219 | *.backup
220 | *.bak
221 | *~
222 | 
223 | # Temporary files
224 | *.tmp
225 | *.temp
226 | 
227 | # Archive files
228 | *.zip
229 | *.tar.gz
230 | *.rar
231 | *.7z
232 | 
233 | # Binary files (unless specifically needed)
234 | *.exe
235 | *.dll
236 | *.so
237 | *.dylib
238 | 
239 | # Cloud provider specific
240 | .aws/
241 | .gcp/
242 | .azure/
243 | 
244 | # Terraform
245 | *.tfstate
246 | *.tfstate.*
247 | .terraform/
248 | .terraform.lock.hcl
249 | 
250 | # Kubernetes
251 | *.kubeconfig
252 | 
253 | # Monitoring and observability
254 | jaeger-data/
255 | prometheus-data/
256 | grafana-data/
257 | 
258 | # Load testing
259 | artillery-output/
260 | k6-results/
261 | 
262 | # Keep important files (negative patterns)
263 | !.gitkeep
264 | !.env.example
265 | !.env.template
266 | !config/default.json
267 | !config/schema.json
268 | !examples/**/*.yaml
269 | !examples/**/*.json
270 | !docs/**/*
271 | !deploy/docker/Dockerfile
272 | !deploy/cloudflare/wrangler.toml
273 | !deploy/koyeb/koyeb.yaml
274 | 
275 | 
276 | # MCP / local tooling
277 | .crush/
278 | .kiro/
279 | .claude/
280 | .ouroboros/
281 | ouroboros-results/
282 | 
283 | # Keep uv.lock tracked (do not ignore)
284 | 
285 | # IDEs and Ouroboros
286 | AGENTS.md
287 | CLAUDE.md
288 | CRUSH.md
289 | GEMINI.md
290 | QWEN.md
291 | IMPLEMENTATION_PLAN.md
292 | SESSION-MEMORY.md
293 | task-definition.md
294 | 
295 | # Documentation application
296 | .vitepress
297 | 
298 | # Random
299 | .DS_Store
```

--------------------------------------------------------------------------------
/examples/advanced-routing/README.md:
--------------------------------------------------------------------------------

```markdown
1 | # Advanced Routing Example
2 | 
3 | Demonstrates retry policy, circuit breaker, and load balancing configuration.
4 | 
5 | Run
6 | - `CONFIG_PATH=examples/advanced-routing/config.yaml npm start`
7 | 
8 | 
```

--------------------------------------------------------------------------------
/examples/performance/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Example: Performance Tuning
 2 | 
 3 | Demonstrates routing configuration tuned for high-throughput and resilience.
 4 | 
 5 | ## Run
 6 | 
 7 | ```
 8 | MASTER_CONFIG_PATH=examples/performance/config.yaml npm run dev
 9 | ```
10 | 
11 | 
```

--------------------------------------------------------------------------------
/examples/multi-server/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Example: Multi-Server with Resilience
 2 | 
 3 | Demonstrates multiple instances of the same service id with load balancing, retries, and circuit breaker.
 4 | 
 5 | ## Run
 6 | 
 7 | ```
 8 | MASTER_CONFIG_PATH=examples/multi-server/config.yaml npm run dev
 9 | ```
10 | 
11 | 
```

--------------------------------------------------------------------------------
/examples/custom-auth/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Example: Custom Authentication Strategy
 2 | 
 3 | Shows how to attach a custom `MultiAuthManager` that tweaks headers per backend.
 4 | 
 5 | ## Run
 6 | 
 7 | ```
 8 | MASTER_CONFIG_PATH=examples/custom-auth/config.yaml \
 9 | node --loader ts-node/esm examples/custom-auth/index.ts
10 | ```
11 | 
12 | 
```

--------------------------------------------------------------------------------
/examples/cloudflare-worker/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Cloudflare Worker Example
 2 | 
 3 | Runs the Master MCP Worker handler with Wrangler.
 4 | 
 5 | Steps
 6 | 1. Build worker bundle: `npm run build:worker`
 7 | 2. Dev: `npx wrangler dev examples/cloudflare-worker/worker.ts`
 8 | 3. Deploy: configure and run from `/deploy/cloudflare`.
 9 | 
10 | 
```

--------------------------------------------------------------------------------
/docs/api/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | **master-mcp-server**
 2 | 
 3 | ***
 4 | 
 5 | # master-mcp-server
 6 | 
 7 | ## Interfaces
 8 | 
 9 | - [RunningServer](interfaces/RunningServer.md)
10 | 
11 | ## Functions
12 | 
13 | - [createServer](functions/createServer.md)
14 | 
15 | ## References
16 | 
17 | ### default
18 | 
19 | Renames and re-exports [createServer](functions/createServer.md)
20 | 
```

--------------------------------------------------------------------------------
/examples/basic-node/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Example: Basic Master MCP Server (Node)
 2 | 
 3 | This example runs the Node runtime with a single local backend.
 4 | 
 5 | ## Run
 6 | 
 7 | ```
 8 | MASTER_CONFIG_PATH=examples/basic-node/config.yaml npm run dev
 9 | ```
10 | 
11 | Endpoints:
12 | 
13 | - http://localhost:3000/health
14 | - http://localhost:3000/mcp/tools/list
15 | 
16 | 
```

--------------------------------------------------------------------------------
/examples/oauth-delegation/README.md:
--------------------------------------------------------------------------------

```markdown
1 | # OAuth Delegation Example
2 | 
3 | Enable delegated OAuth for backends and complete flows via the built-in controller.
4 | 
5 | Run
6 | 1. Configure `oauth_delegation.enabled: true` in your config, and set provider entries if desired.
7 | 2. Start the server and visit `/oauth` to initiate flows.
8 | 
9 | 
```

--------------------------------------------------------------------------------
/examples/oauth-node/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Example: OAuth Delegation (GitHub)
 2 | 
 3 | Demonstrates `delegate_oauth` for a GitHub-protected backend.
 4 | 
 5 | ## Run
 6 | 
 7 | Set secrets:
 8 | 
 9 | ```
10 | export GITHUB_CLIENT_SECRET=... # from GitHub OAuth app
11 | ```
12 | 
13 | Start:
14 | 
15 | ```
16 | MASTER_CONFIG_PATH=examples/oauth-node/config.yaml npm run dev
17 | ```
18 | 
19 | Then open:
20 | 
21 | ```
22 | http://localhost:3000/oauth/authorize?server_id=github-tools
23 | ```
24 | 
25 | 
```

--------------------------------------------------------------------------------
/examples/security-hardening/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Example: Security Hardening
 2 | 
 3 | This example outlines recommended environment and config for production.
 4 | 
 5 | ## Environment
 6 | 
 7 | - `NODE_ENV=production`
 8 | - `LOG_FORMAT=json`
 9 | - `LOG_LEVEL=info`
10 | - `TOKEN_ENC_KEY` set via secret store
11 | - `MASTER_BASE_URL=https://your.domain`
12 | 
13 | ## Config Snippet
14 | 
15 | ```yaml
16 | security:
17 |   audit: true
18 | logging:
19 |   level: info
20 | hosting:
21 |   platform: node
22 |   port: 3000
23 | ```
24 | 
25 | Deploy with Docker/Koyeb using read-only config mounts and non-root users (see Dockerfiles).
26 | 
27 | 
```

--------------------------------------------------------------------------------
/deploy/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Deployment Overview
 2 | 
 3 | Artifacts and configs to deploy the Master MCP Server:
 4 | 
 5 | - Docker
 6 |   - `deploy/docker/Dockerfile`: multi-stage build for Node runtime.
 7 |   - `deploy/docker/docker-compose.yml`: local development runner.
 8 | - Cloudflare Workers
 9 |   - `deploy/cloudflare/wrangler.toml`: Workers config (staging/production envs).
10 |   - `deploy/cloudflare/README.md`: usage notes.
11 | - Koyeb
12 |   - `deploy/koyeb/koyeb.yaml`: Koyeb service and autoscaling settings.
13 | 
14 | CI/CD pipelines live in `.github/workflows`. See `docs/architecture/phase10-deployment-architecture.md` for full details.
15 | 
16 | 
```

--------------------------------------------------------------------------------
/deploy/cloudflare/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Cloudflare Workers Deployment
 2 | 
 3 | ## Prerequisites
 4 | - Cloudflare account and `CLOUDFLARE_API_TOKEN` with Workers permissions.
 5 | - `wrangler` installed locally or use GitHub Action for CI deploys.
 6 | 
 7 | ## Local Dev
 8 | ```
 9 | wrangler dev
10 | ```
11 | 
12 | ## Configure Secrets
13 | ```
14 | wrangler secret put TOKEN_ENC_KEY
15 | # Add any OAuth client secrets as needed
16 | ```
17 | 
18 | ## Deploy
19 | ```
20 | wrangler deploy --env staging
21 | wrangler deploy --env production
22 | ```
23 | 
24 | The worker entry is `src/runtime/worker.ts` which exports a `fetch` handler. Ensure your config values align with Workers (e.g., base URLs for OAuth callbacks).
25 | 
26 | 
```

--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Master MCP Server Documentation
 2 | 
 3 | Welcome to the Master MCP Server docs. This documentation covers architecture, configuration, authentication flows, request routing, deployment, and troubleshooting. It also includes end-to-end tutorials and working examples.
 4 | 
 5 | ## Contents
 6 | 
 7 | - Getting Started: `../docs/getting-started.md`
 8 | - Guides:
 9 |   - Authentication: `./guides/authentication.md`
10 |   - Configuration Mgmt: `./guides/configuration-management.md`
11 |   - Module Loading & Aggregation: `./guides/module-loading.md`
12 |   - Request Routing & Resilience: `./guides/request-routing.md`
13 |   - Server Management: `./guides/server-management.md`
14 | - Tutorials:
15 |   - Beginner Setup: `./tutorials/beginner-getting-started.md`
16 |   - OAuth Delegation with GitHub: `./tutorials/oauth-delegation-github.md`
17 |   - Cloudflare Workers: `./tutorials/cloudflare-workers-tutorial.md`
18 |   - Load Balancing & Resilience: `./tutorials/load-balancing-and-resilience.md`
19 | - API Reference: `./api/README.md` (generated via TypeDoc)
20 | - Configuration:
21 |   - Schema & Reference: `./configuration/reference.md`
22 |   - Environment Variables: `./configuration/environment-variables.md`
23 |   - Security: `./configuration/security.md`
24 |   - Performance: `./configuration/performance.md`
25 | - Deployment:
26 |   - Docker: `./deployment/docker.md`
27 |   - Cloudflare Workers: `./deployment/cloudflare-workers.md`
28 |   - Koyeb: `./deployment/koyeb.md`
29 |   - CI/CD: `./deployment/cicd.md`
30 | - Troubleshooting:
31 |   - Common Issues: `./troubleshooting/common-issues.md`
32 |   - Error Reference: `./troubleshooting/errors.md`
33 |   - Performance Troubleshooting: `./troubleshooting/performance.md`
34 |   - Security Best Practices: `./troubleshooting/security-best-practices.md`
35 | 
36 | If you are looking for design notes per phase, see `./architecture/*` and testing strategy in `./testing/phase-9-testing-architecture.md`.
37 | 
38 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Master MCP Server
  2 | 
  3 | Master MCP Server aggregates multiple MCP servers behind a single, secure endpoint. It provides configuration-driven module loading, unified capability discovery, request routing with resilience, and first-class OAuth flows for multi-backend authentication.
  4 | 
  5 | ## Highlights
  6 | 
  7 | - Aggregates multiple MCP servers with tool/resource discovery and namespacing
  8 | - OAuth support: master token pass-through, delegated provider flows, proxy refresh
  9 | - Config-driven setup with JSON/YAML, schema validation, and secret resolution
 10 | - Resilient routing: load-balancing, retries with backoff/jitter, circuit-breakers
 11 | - Cross-platform: Node.js server and Cloudflare Workers runtime
 12 | - Production-ready deployment: Docker, Cloudflare Workers, Koyeb
 13 | - Testing strategy and CI-ready structure
 14 | 
 15 | ## Quick Start (Node.js)
 16 | 
 17 | 1) Install dependencies (requires network):
 18 | 
 19 | ```plaintext
 20 | npm ci
 21 | ```
 22 | 
 23 | 2) Configure environment (copy and edit):
 24 | 
 25 | ```plaintext
 26 | cp .env.example .env
 27 | ```
 28 | 
 29 | 3) Run in dev mode:
 30 | 
 31 | ```plaintext
 32 | npm run dev
 33 | ```
 34 | 
 35 | 4) Health and Metrics:
 36 | 
 37 | - `GET /health` → `{ ok: true }`
 38 | - `GET /metrics` → basic system metrics
 39 | 
 40 | 5) MCP endpoints (HTTP gateway):
 41 | 
 42 | - `POST /mcp/tools/list`
 43 | - `POST /mcp/tools/call` with `{ name, arguments }`
 44 | - `POST /mcp/resources/list`
 45 | - `POST /mcp/resources/read` with `{ uri }`
 46 | 
 47 | See `docs/` for full guides and end-to-end examples.
 48 | 
 49 | ## Documentation
 50 | 
 51 | - Docs index: `docs/index.md`
 52 | - Getting started: `docs/getting-started/overview.md`
 53 | - Guides: `docs/guides/*`
 54 | - API reference: generated into `docs/api/reference/` (see below)
 55 | - Configuration reference: `docs/configuration/*`
 56 | - Deployment: `docs/deployment/*`
 57 | - Troubleshooting: `docs/troubleshooting/*`
 58 | - Contributing: `docs/contributing/*`
 59 | 
 60 | ## Generate API Docs
 61 | 
 62 | We use TypeDoc (Markdown) to generate API docs from TypeScript.
 63 | 
 64 | 1) Install (requires network):
 65 | 
 66 | ```plaintext
 67 | npm i -D typedoc typedoc-plugin-markdown
 68 | ```
 69 | 
 70 | 2) Generate docs:
 71 | 
 72 | ```plaintext
 73 | npm run docs:api
 74 | ```
 75 | 
 76 | Outputs to `docs/api/`.
 77 | 
 78 | ## Examples
 79 | 
 80 | Working examples live in `examples/`:
 81 | 
 82 | - Basic Node: `examples/basic-node`
 83 | - Cloudflare Worker: `examples/cloudflare-worker`
 84 | - Advanced Routing: `examples/advanced-routing`
 85 | - OAuth Delegation: `examples/oauth-delegation`
 86 | - Testing Patterns: see `/tests` and `docs/examples/testing.md`
 87 | 
 88 | Each example has a README with run instructions.
 89 | 
 90 | ## Deployment
 91 | 
 92 | - Docker: `deploy/docker/*` and top-level `Dockerfile` / `docker-compose.yml`
 93 | - Cloudflare Workers: `deploy/cloudflare/*` with `wrangler.toml`
 94 | - Koyeb: `deploy/koyeb/koyeb.yaml`
 95 | - CI/CD examples: see `docs/deployment/cicd.md`
 96 | 
 97 | ## Architecture
 98 | 
 99 | ![MCP Master Architecture](docs/architecture/images/mcp_master_architecture.svg)
100 | 
101 | ## Contributing & Support
102 | 
103 | - See `docs/contributing/*` for development workflow and guidelines
104 | - See `docs/troubleshooting/index.md` for solutions
105 | - Open an issue or discussion for help and ideas
106 | 
107 | ## License
108 | 
109 | See `LICENSE`. This repository currently uses UNLICENSED for private/internal use.
110 | 
```

--------------------------------------------------------------------------------
/docs/advanced/security.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Security Hardening
 3 | ---
 4 | 
 5 | # Security Hardening
 6 | 
 7 | - Rotate secrets regularly (`security.rotation_days`).
 8 | - Use `security.audit` for config change logging.
 9 | - Lock down OAuth redirect URIs and audiences.
10 | - Enforce strict TLS and CSP in hosting platform.
11 | - Validate inputs and sanitize logs (see `utils/security` patterns).
12 | 
13 | 
```

--------------------------------------------------------------------------------
/docs/configuration/security.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Security Configuration & Practices
 2 | 
 3 | ## Secrets in Config
 4 | 
 5 | Use either of the following in your config:
 6 | 
 7 | - `env:VARNAME` → value is read from `process.env.VARNAME`
 8 | - `enc:gcm:<base64>` → value is decrypted using `MASTER_CONFIG_KEY` (or `MASTER_SECRET_KEY`)
 9 | 
10 | `SecretManager` handles both resolving and redacting sensitive values for logs.
11 | 
12 | ## Token Encryption
13 | 
14 | `TokenManager` encrypts stored delegated/proxy tokens with `TOKEN_ENC_KEY`. In production this must be set; otherwise startup fails. In development, a warning is logged and an ephemeral key is generated.
15 | 
16 | ## OAuth Best Practices
17 | 
18 | - Always set `hosting.base_url` correctly for accurate redirect URIs behind proxies.
19 | - Use PKCE (enabled by default) and short-lived state tokens.
20 | - Limit scopes in `servers[].auth_config.scopes` to the minimum required.
21 | 
22 | ## Hardening Tips
23 | 
24 | - Drop container capabilities and run as non-root (see Dockerfiles)
25 | - Use `LOG_FORMAT=json` in production for structured logs
26 | - Ensure secrets are injected via platform secret stores (KMS, Workers Secrets, Koyeb Secrets)
27 | - Enable `security.audit` to log config changes (redacted)
28 | 
29 | 
```

--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Contributing Guide
 2 | 
 3 | Thanks for your interest in contributing to the Master MCP Server. This guide outlines the development workflow and standards.
 4 | 
 5 | ## Development Setup
 6 | 
 7 | 1) Install Node >= 18.17
 8 | 2) Install dependencies:
 9 | 
10 | ```
11 | npm ci
12 | ```
13 | 
14 | 3) Useful scripts:
15 | 
16 | ```
17 | npm run typecheck
18 | npm run build
19 | npm run dev
20 | npm run test
21 | npm run lint && npm run format
22 | ```
23 | 
24 | ## Docs & API Reference
25 | 
26 | - Author guides and tutorials in `docs/`
27 | - Generate API docs (requires network): `npm run docs:api`
28 | - Keep examples in `examples/` runnable and minimal
29 | 
30 | ## Coding Standards
31 | 
32 | - TypeScript strict mode; no `any` without justification
33 | - Prefer small, composable modules and clear interfaces
34 | - Avoid introducing runtime-only dependencies in shared modules (support both Node and Workers)
35 | 
36 | ## Testing
37 | 
38 | - Unit tests under `tests/unit` and integration under `tests/integration`
39 | - Add targeted tests for new modules and critical paths
40 | 
41 | ## Commit Style
42 | 
43 | - Use clear, imperative messages (e.g., "Add OAuth state validation")
44 | - Reference issues where applicable
45 | 
46 | ## Security
47 | 
48 | - Never commit secrets
49 | - Use `SecretManager` patterns for config secrets
50 | 
51 | 
```

--------------------------------------------------------------------------------
/docs/.vitepress/cache/deps/package.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "type": "module"
3 | }
4 | 
```

--------------------------------------------------------------------------------
/config/production.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "logging": { "level": "info" }
3 | }
4 | 
5 | 
```

--------------------------------------------------------------------------------
/config/development.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "logging": { "level": "debug" }
3 | }
4 | 
5 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
1 | {
2 |   "extends": "./tsconfig.node.json"
3 | }
4 | 
5 | 
```

--------------------------------------------------------------------------------
/examples/cloudflare-worker/worker.ts:
--------------------------------------------------------------------------------

```typescript
1 | export { default as default } from '../../src/runtime/worker.js'
2 | 
3 | 
```

--------------------------------------------------------------------------------
/src/utils/validators.ts:
--------------------------------------------------------------------------------

```typescript
1 | export { isNonEmptyString, isRecord } from './validation.js'
2 | export * as Validation from './validation.js'
3 | 
```

--------------------------------------------------------------------------------
/docs/advanced/index.md:
--------------------------------------------------------------------------------

```markdown
1 | ---
2 | title: Advanced Topics
3 | ---
4 | 
5 | # Advanced Topics
6 | 
7 | Deep dives into security, performance, monitoring, and extensibility.
8 | 
9 | 
```

--------------------------------------------------------------------------------
/tests/fixtures/stdio-server.js:
--------------------------------------------------------------------------------

```javascript
1 | process.stdout.write(JSON.stringify({ type: 'notification', message: 'server ready' }) + '\n');
2 | 
3 | setInterval(() => {
4 |   // Keep the process alive
5 | }, 1000)
```

--------------------------------------------------------------------------------
/static/oauth/script.js:
--------------------------------------------------------------------------------

```javascript
1 | // Placeholder for future enhancements like telemetry, animations, etc.
2 | // Intentionally minimal to reduce attack surface.
3 | document.documentElement.classList.add('js')
4 | 
5 | 
```

--------------------------------------------------------------------------------
/tests/fixtures/capabilities.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "tools": [
 3 |     { "name": "echo", "description": "Echo input" }
 4 |   ],
 5 |   "resources": [
 6 |     { "uri": "docs.readme", "name": "Readme", "mimeType": "text/plain" }
 7 |   ]
 8 | }
 9 | 
10 | 
```

--------------------------------------------------------------------------------
/examples/basic-node/server.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { createServer } from '../../src/index.js'
 2 | 
 3 | async function main() {
 4 |   await createServer(true)
 5 | }
 6 | 
 7 | // eslint-disable-next-line @typescript-eslint/no-floating-promises
 8 | main()
 9 | 
10 | 
```

--------------------------------------------------------------------------------
/docs/advanced/extensibility.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Extensibility & Plugins
 3 | ---
 4 | 
 5 | # Extensibility & Plugins
 6 | 
 7 | - Extend `ModuleLoader` to support new sources.
 8 | - Add routing strategies by extending the load balancer.
 9 | - Use typed interfaces in `src/types/*` for compatibility.
10 | 
11 | 
```

--------------------------------------------------------------------------------
/docs/examples/testing.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Testing Patterns
 3 | ---
 4 | 
 5 | # Example: Testing Patterns
 6 | 
 7 | Use `/tests` as the primary reference. This example demonstrates configuring Node vs Workers test environments and using utilities in `_utils`.
 8 | 
 9 | Run
10 | - `npm run test` or target specific suites.
11 | 
12 | 
```

--------------------------------------------------------------------------------
/docs/contributing/index.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Contributing
 3 | ---
 4 | 
 5 | # Contributing
 6 | 
 7 | We welcome contributions across code, documentation, and examples.
 8 | 
 9 | - Read Guidelines for coding and docs conventions
10 | - Use Dev Setup to get your environment ready
11 | - Open PRs with focused changes and include tests/docs
12 | 
13 | 
```

--------------------------------------------------------------------------------
/tsconfig.node.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "extends": "./tsconfig.base.json",
 3 |   "compilerOptions": {
 4 |     "outDir": "dist/node",
 5 |     "module": "NodeNext",
 6 |     "moduleResolution": "NodeNext",
 7 |     "types": ["node"],
 8 |     "lib": ["ES2022"],
 9 |     "jsx": "react-jsx"
10 |   },
11 |   "exclude": ["src/runtime/worker.ts"]
12 | }
13 | 
```

--------------------------------------------------------------------------------
/docs/advanced/performance.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Performance & Scalability
 3 | ---
 4 | 
 5 | # Performance & Scalability
 6 | 
 7 | - Tune retry/backoff to avoid thundering herd.
 8 | - Right-size circuit breaker thresholds per backend latency.
 9 | - Use caching (`utils/cache`) where safe.
10 | - Monitor p95/p99 latencies and error rates.
11 | 
12 | 
```

--------------------------------------------------------------------------------
/docs/advanced/monitoring.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Monitoring & Logging
 3 | ---
 4 | 
 5 | # Monitoring & Logging
 6 | 
 7 | - Use `/metrics` endpoint and `collectSystemMetrics()` for basic telemetry.
 8 | - Integrate logs with your platform (stdout in Docker/Koyeb, Workers logs).
 9 | - Centralize error handling in `utils/errors` and `utils/logger`.
10 | 
11 | 
```

--------------------------------------------------------------------------------
/tests/_setup/miniflare.setup.ts:
--------------------------------------------------------------------------------

```typescript
1 | // Miniflare/Vitest setup for Workers-targeted suites
2 | import { Logger } from '../../src/utils/logger.js'
3 | 
4 | Logger.configure({ level: 'error', json: true })
5 | 
6 | // Miniflare provides global fetch/Request/Response.
7 | // If we need to start auxiliary Node HTTP stubs, do it within tests.
8 | 
9 | 
```

--------------------------------------------------------------------------------
/docs/troubleshooting/deployment.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Deployment
 3 | ---
 4 | 
 5 | # Troubleshooting: Deployment
 6 | 
 7 | - Docker: ensure env files loaded and ports exposed.
 8 | - Workers: align bundling target and avoid Node APIs.
 9 | - Koyeb: ensure service listens on the configured port.
10 | - Secrets: verify platform secret injection and `config_key_env`.
11 | 
12 | 
```

--------------------------------------------------------------------------------
/docs/examples/oauth-delegation.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: OAuth Delegation
 3 | ---
 4 | 
 5 | # Example: OAuth Delegation
 6 | 
 7 | Folder: `/examples/oauth-delegation`
 8 | 
 9 | What it shows
10 | - Enabling `oauth_delegation` and providers
11 | - Using `OAuthFlowController` to complete flows
12 | 
13 | Run
14 | 1. Configure providers and redirect URIs
15 | 2. Start Node server and visit `/oauth` UI
16 | 
17 | 
```

--------------------------------------------------------------------------------
/docs/examples/cloudflare-worker.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Cloudflare Worker
 3 | ---
 4 | 
 5 | # Example: Cloudflare Worker
 6 | 
 7 | Folder: `/examples/cloudflare-worker`
 8 | 
 9 | What it shows
10 | - Worker `fetch` handler delegating to runtime adapter
11 | - Using `wrangler.toml` from `/deploy/cloudflare`
12 | 
13 | Run
14 | 1. `npm run build:worker`
15 | 2. `npx wrangler dev examples/cloudflare-worker/worker.ts`
16 | 
17 | 
```

--------------------------------------------------------------------------------
/src/types/jose-shim.d.ts:
--------------------------------------------------------------------------------

```typescript
 1 | declare module 'jose' {
 2 |   export function createRemoteJWKSet(url: URL): any
 3 |   export function jwtVerify(
 4 |     jwt: string,
 5 |     key: any,
 6 |     options?: { issuer?: string | string[]; audience?: string | string[] }
 7 |   ): Promise<{ payload: any; protectedHeader: any }>
 8 |   export function decodeJwt(jwt: string): any
 9 | }
10 | 
11 | 
```

--------------------------------------------------------------------------------
/tsconfig.worker.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "extends": "./tsconfig.base.json",
 3 |   "compilerOptions": {
 4 |     "outDir": "dist/worker",
 5 |     "module": "ESNext",
 6 |     "moduleResolution": "Bundler",
 7 |     "types": [],
 8 |     "lib": ["ES2022", "WebWorker"]
 9 |   },
10 |   "exclude": [
11 |     "src/runtime/node.ts",
12 |     "src/utils/crypto.ts",
13 |     "src/config/**",
14 |     "src/auth/token-manager.ts"
15 |   ]
16 | }
17 | 
```

--------------------------------------------------------------------------------
/docs/deployment/index.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Deployment Overview
 3 | ---
 4 | 
 5 | # Deployment Overview
 6 | 
 7 | Supported targets
 8 | - Docker (Node runtime)
 9 | - Cloudflare Workers
10 | - Koyeb (Node runtime)
11 | 
12 | Deployment assets live in `/deploy/*`. Platform-specific guides reference these files and environment variable requirements.
13 | 
14 | See architecture: `docs/architecture/phase10-deployment-architecture.md`.
15 | 
16 | 
```

--------------------------------------------------------------------------------
/deploy/docker/entrypoint.sh:
--------------------------------------------------------------------------------

```bash
 1 | #!/bin/sh
 2 | set -e
 3 | 
 4 | # Map PaaS-provided PORT to MASTER_HOSTING_PORT if not explicitly set.
 5 | if [ -n "${PORT}" ] && [ -z "${MASTER_HOSTING_PORT}" ]; then
 6 |   export MASTER_HOSTING_PORT="${PORT}"
 7 | fi
 8 | 
 9 | # Default to json logs in production if not set
10 | if [ "${NODE_ENV}" = "production" ] && [ -z "${LOG_FORMAT}" ]; then
11 |   export LOG_FORMAT=json
12 | fi
13 | 
14 | exec "$@"
15 | 
16 | 
```

--------------------------------------------------------------------------------
/docs/guides/index.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Guides
 3 | ---
 4 | 
 5 | # User Guides
 6 | 
 7 | Structured, task-based guides for common scenarios across auth, routing, configuration, testing, and operations.
 8 | 
 9 | Recommended path by persona
10 | - Developers: Authentication → Module Loading → Request Routing
11 | - DevOps: Configuration → Deployment → Monitoring
12 | - Integrators: OAuth Delegation → Routing policies → Security
13 | 
14 | 
```

--------------------------------------------------------------------------------
/docs/examples/advanced-routing.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Advanced Routing
 3 | ---
 4 | 
 5 | # Example: Advanced Routing
 6 | 
 7 | Folder: `/examples/advanced-routing`
 8 | 
 9 | What it shows
10 | - Configure retry policy with backoff/jitter
11 | - Circuit breaker thresholds and recovery
12 | - Load balancer strategies
13 | 
14 | Run
15 | 1. Use `config.yaml` from the example
16 | 2. Start the server with `CONFIG_PATH=examples/advanced-routing/config.yaml npm start`
17 | 
18 | 
```

--------------------------------------------------------------------------------
/docs/configuration/environment.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Environment Variables
 3 | ---
 4 | 
 5 | # Environment Variables
 6 | 
 7 | Common variables
 8 | - `NODE_ENV`: `development` | `production`
 9 | - `PORT`: overrides `hosting.port`
10 | - OAuth secrets: `MASTER_OAUTH_CLIENT_SECRET`, provider secrets
11 | - Encryption: key name from `security.config_key_env`
12 | 
13 | Use `.env` for local development and set secrets via platform secrets in production.
14 | 
15 | 
```

--------------------------------------------------------------------------------
/examples/basic-node/config.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | hosting:
 2 |   platform: node
 3 |   port: 3000
 4 | 
 5 | master_oauth:
 6 |   authorization_endpoint: https://example.com/oauth/authorize
 7 |   token_endpoint: https://example.com/oauth/token
 8 |   client_id: master-mcp
 9 |   redirect_uri: http://localhost:3000/oauth/callback
10 |   scopes: [openid]
11 | 
12 | servers:
13 |   - id: tools
14 |     type: local
15 |     auth_strategy: bypass_auth
16 |     config:
17 |       port: 3333
18 | 
19 | 
```

--------------------------------------------------------------------------------
/tests/factories/mcpFactory.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type { ToolDefinition, ResourceDefinition } from '../../src/types/mcp.js'
 2 | 
 3 | export function makeTools(...names: string[]): ToolDefinition[] {
 4 |   return names.map((n) => ({ name: n, description: `${n} tool` }))
 5 | }
 6 | 
 7 | export function makeResources(...uris: string[]): ResourceDefinition[] {
 8 |   return uris.map((u) => ({ uri: u, name: u, mimeType: 'text/plain' }))
 9 | }
10 | 
11 | 
```

--------------------------------------------------------------------------------
/static/oauth/success.html:
--------------------------------------------------------------------------------

```html
 1 | <!doctype html>
 2 | <html lang="en">
 3 | <head>
 4 |   <meta charset="utf-8" />
 5 |   <meta name="viewport" content="width=device-width, initial-scale=1" />
 6 |   <title>OAuth Success</title>
 7 |   <link rel="stylesheet" href="/static/oauth/style.css" />
 8 | </head>
 9 | <body>
10 |   <main class="container">
11 |     <h1>Success</h1>
12 |     <p>Authorization completed successfully.</p>
13 |   </main>
14 | </body>
15 | </html>
16 | 
17 | 
```

--------------------------------------------------------------------------------
/typedoc.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "$schema": "https://typedoc.org/schema.json",
 3 |   "entryPoints": [
 4 |     "src"
 5 |   ],
 6 |   "tsconfig": "tsconfig.node.json",
 7 |   "plugin": ["typedoc-plugin-markdown"],
 8 |   "out": "docs/api",
 9 |   "cleanOutputDir": false,
10 |   "categorizeByGroup": false,
11 |   "hideBreadcrumbs": true,
12 |   "excludePrivate": true,
13 |   "excludeProtected": false,
14 |   "excludeInternal": true,
15 |   "readme": "none"
16 | }
17 | 
18 | 
```

--------------------------------------------------------------------------------
/docs/troubleshooting/routing.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Routing & Modules
 3 | ---
 4 | 
 5 | # Troubleshooting: Routing & Modules
 6 | 
 7 | - Missing capabilities: call `discoverAllCapabilities()` after loading servers.
 8 | - Unhealthy backend: check health checks and restart via `restartServer(id)`.
 9 | - Retry storms: reduce `maxRetries` or increase `baseDelayMs`.
10 | - Circuit breaker open: lower `failureThreshold` or increase recovery timeout.
11 | 
12 | 
```

--------------------------------------------------------------------------------
/docs/contributing/dev-setup.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Development Setup
 3 | ---
 4 | 
 5 | # Development Setup
 6 | 
 7 | Prerequisites
 8 | - Node 18.17+
 9 | - npm or pnpm
10 | 
11 | Common commands
12 | - `npm run build` — build Node and Worker bundles
13 | - `npm run dev` — start local server
14 | - `npm run test` — run test suites
15 | - `npm run lint` / `npm run format` — code quality
16 | 
17 | Docs
18 | - `npm run docs:api` — generate API reference
19 | - `npm run docs:dev` — serve docs locally
20 | 
21 | 
```

--------------------------------------------------------------------------------
/examples/sample-configs/basic.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | hosting:
 2 |   platform: node
 3 |   port: 3000
 4 | 
 5 | master_oauth:
 6 |   authorization_endpoint: https://example.com/auth
 7 |   token_endpoint: https://example.com/token
 8 |   client_id: demo-client
 9 |   redirect_uri: http://localhost:3000/callback
10 |   scopes:
11 |     - openid
12 | 
13 | servers:
14 |   - id: example
15 |     type: local
16 |     auth_strategy: master_oauth
17 |     config:
18 |       environment: {}
19 |       args: []
20 |       port: 3333
21 | 
22 | 
```

--------------------------------------------------------------------------------
/static/oauth/error.html:
--------------------------------------------------------------------------------

```html
 1 | <!doctype html>
 2 | <html lang="en">
 3 | <head>
 4 |   <meta charset="utf-8" />
 5 |   <meta name="viewport" content="width=device-width, initial-scale=1" />
 6 |   <title>OAuth Error</title>
 7 |   <link rel="stylesheet" href="/static/oauth/style.css" />
 8 | </head>
 9 | <body>
10 |   <main class="container error">
11 |     <h1>Authorization Error</h1>
12 |     <p>Something went wrong during the OAuth flow.</p>
13 |   </main>
14 | </body>
15 | </html>
16 | 
17 | 
```

--------------------------------------------------------------------------------
/docs/examples/basic-node.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Basic Node Aggregator
 3 | ---
 4 | 
 5 | # Example: Basic Node Aggregator
 6 | 
 7 | Folder: `/examples/basic-node`
 8 | 
 9 | What it shows
10 | - Load two MCP servers from config
11 | - Expose health, metrics, and MCP endpoints
12 | - Validate configuration with schema
13 | 
14 | Run
15 | 1. `npm run build`
16 | 2. `node examples/basic-node/server.ts` (ts-node recommended for dev)
17 | 
18 | Config
19 | - Copy and adapt `examples/sample-configs/basic.yaml`.
20 | 
21 | 
```

--------------------------------------------------------------------------------
/docs/getting-started/quickstart-workers.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Quickstart (Workers)
 3 | ---
 4 | 
 5 | # Quickstart (Cloudflare Workers)
 6 | 
 7 | Run Master MCP in Cloudflare Workers runtime using `src/runtime/worker.ts`.
 8 | 
 9 | Steps
10 | 1. Copy `deploy/cloudflare/wrangler.toml` and adjust env vars.
11 | 2. Build worker bundle: `npm run build:worker`.
12 | 3. Publish with Wrangler: `npx wrangler deploy`.
13 | 
14 | See also: Deployment → Cloudflare Workers and Examples → Cloudflare Worker.
15 | 
16 | 
```

--------------------------------------------------------------------------------
/docs/getting-started/installation.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Installation
 3 | ---
 4 | 
 5 | # Installation
 6 | 
 7 | Prerequisites
 8 | - Node.js >= 18.17
 9 | - npm or pnpm
10 | 
11 | Install
12 | 1. Clone the repository and install deps: `npm install`
13 | 2. Copy `.env.example` to `.env` and adjust values.
14 | 3. Build Node and Worker bundles: `npm run build`
15 | 
16 | Run (Node)
17 | - Dev: `npm run dev` or `npm run dev:watch`
18 | - Prod: `npm run start:prod`
19 | 
20 | Next: Quickstart (Node) or Quickstart (Workers)
21 | 
22 | 
```

--------------------------------------------------------------------------------
/examples/sample-configs/simple-setup.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | hosting:
 2 |   platform: node
 3 |   port: 3000
 4 | 
 5 | master_oauth:
 6 |   authorization_endpoint: https://auth.example.com/authorize
 7 |   token_endpoint: https://auth.example.com/token
 8 |   client_id: master-mcp
 9 |   redirect_uri: http://localhost:3000/oauth/callback
10 |   scopes: [openid, profile]
11 | 
12 | servers:
13 |   - id: local-simple
14 |     type: local
15 |     auth_strategy: bypass_auth
16 |     config:
17 |       port: 4001
18 |       environment: {}
19 | 
20 | 
```

--------------------------------------------------------------------------------
/tests/factories/oauthFactory.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export function makeToken(overrides?: Partial<{ access_token: string; expires_in: number; scope: string | string[] }>) {
 2 |   const scope = overrides?.scope ?? ['openid']
 3 |   return {
 4 |     access_token: overrides?.access_token ?? `at_${Math.random().toString(36).slice(2)}`,
 5 |     token_type: 'bearer',
 6 |     expires_in: overrides?.expires_in ?? 3600,
 7 |     scope: Array.isArray(scope) ? scope.join(' ') : scope,
 8 |   }
 9 | }
10 | 
11 | 
```

--------------------------------------------------------------------------------
/src/runtime/node.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import express from 'express'
 2 | import { createServer } from '../index.js'
 3 | 
 4 | export async function startNode() {
 5 |   const app = express()
 6 |   await createServer()
 7 |   const port = process.env.PORT ? Number(process.env.PORT) : 3000
 8 |   app.get('/health', (_req, res) => res.json({ ok: true }))
 9 |   app.listen(port, () => {
10 |     // eslint-disable-next-line no-console
11 |     console.log(`Master MCP (Node) on ${port}`)
12 |   })
13 | }
14 | 
15 | 
```

--------------------------------------------------------------------------------
/docs/contributing/guidelines.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Coding & Docs Guidelines
 3 | ---
 4 | 
 5 | # Coding & Docs Guidelines
 6 | 
 7 | Code
 8 | - Follow TypeScript strictness and ESLint rules.
 9 | - Prefer TSDoc comments for public APIs with `@example` where useful.
10 | - Keep modules cohesive and avoid unrelated changes.
11 | 
12 | Docs
13 | - Write in Markdown under `/docs`.
14 | - Add pages to VitePress sidebar via `.vitepress/config.ts`.
15 | - For API docs, rely on TypeDoc output under `/docs/api/reference`.
16 | 
17 | 
```

--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Changelog
 2 | 
 3 | All notable changes to this project will be documented in this file.
 4 | 
 5 | ## 0.1.0 – Phase 11 (Final)
 6 | 
 7 | - Complete documentation set (guides, tutorials, configuration, deployment)
 8 | - API reference pipeline via TypeDoc
 9 | - Working examples for Node, OAuth delegation, multi-server, custom auth, performance, security
10 | - Deployment guides for Docker, Cloudflare Workers, and Koyeb
11 | - Troubleshooting and best practices
12 | 
13 | 
```

--------------------------------------------------------------------------------
/docs/contributing/maintenance.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Maintenance Procedures
 3 | ---
 4 | 
 5 | # Maintenance & Updates
 6 | 
 7 | - After adding/changing public APIs: update TSDoc and run `npm run docs:api`.
 8 | - After changing config schema or examples: run `npm run docs:config`.
 9 | - Before releases: run `npm run docs:all` and preview with `npm run docs:preview`.
10 | - Keep `.vitepress/config.ts` nav/sidebars in sync with new pages.
11 | - Update examples under `/examples/*` and link from `/docs/examples`.
12 | 
13 | 
```

--------------------------------------------------------------------------------
/docs/api/functions/createServer.md:
--------------------------------------------------------------------------------

```markdown
 1 | [**master-mcp-server**](../README.md)
 2 | 
 3 | ***
 4 | 
 5 | # Function: createServer()
 6 | 
 7 | > **createServer**(`startHttp`): `Promise`\<[`RunningServer`](../interfaces/RunningServer.md)\>
 8 | 
 9 | Defined in: [index.ts:18](https://github.com/solita-internal/master-mcp-server/blob/cd13e0009f7a1b7f244de882dc738bbf1f90f2c2/src/index.ts#L18)
10 | 
11 | ## Parameters
12 | 
13 | ### startHttp
14 | 
15 | `boolean` = `true`
16 | 
17 | ## Returns
18 | 
19 | `Promise`\<[`RunningServer`](../interfaces/RunningServer.md)\>
20 | 
```

--------------------------------------------------------------------------------
/docs/troubleshooting/oauth.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: OAuth & Tokens
 3 | ---
 4 | 
 5 | # Troubleshooting: OAuth & Tokens
 6 | 
 7 | - Symptom: `invalid_grant` — Check code exchange timing and redirect URI match.
 8 | - Symptom: `invalid_client` — Verify client_id/secret; rotate if leaked.
 9 | - Symptom: missing `Authorization` — Ensure client token is passed to router/handler.
10 | - Symptom: provider callback 404 — Mount `OAuthFlowController` endpoints.
11 | 
12 | Logs
13 | - Increase log level to `debug` to see flow details.
14 | 
15 | 
```

--------------------------------------------------------------------------------
/docs/troubleshooting/security-best-practices.md:
--------------------------------------------------------------------------------

```markdown
1 | # Security Best Practices
2 | 
3 | - Store secrets in environment or platform secret stores; avoid plaintext in config
4 | - Set `TOKEN_ENC_KEY` in production and rotate periodically
5 | - Use minimal OAuth scopes and avoid long-lived tokens when possible
6 | - Prefer `LOG_FORMAT=json` and sanitize logs; `SecretManager.redact` prevents secret leakage in config logs
7 | - Enforce `https` at the edge and set `MASTER_BASE_URL=https://...` to ensure secure redirects
8 | 
9 | 
```

--------------------------------------------------------------------------------
/tests/_setup/vitest.setup.ts:
--------------------------------------------------------------------------------

```typescript
 1 | // Global test setup for Node-targeted suites
 2 | import { Logger } from '../../src/utils/logger.js'
 3 | 
 4 | // Reduce log noise; allow tests to opt into capture
 5 | Logger.configure({ level: 'error', json: true })
 6 | 
 7 | // Node 18 has global fetch; ensure it exists for all tests
 8 | if (typeof fetch !== 'function') {
 9 |   // eslint-disable-next-line @typescript-eslint/no-var-requires
10 |   const nodeFetch = require('node-fetch')
11 |   // @ts-ignore
12 |   globalThis.fetch = nodeFetch
13 | }
14 | 
15 | 
```

--------------------------------------------------------------------------------
/docs/examples/index.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Examples
 3 | ---
 4 | 
 5 | # Examples
 6 | 
 7 | Real-world usage patterns for Node and Workers with routing, OAuth, and configuration.
 8 | 
 9 | - Basic Node Aggregator — minimal end-to-end setup
10 | - Cloudflare Worker — Workers runtime entry
11 | - Advanced Routing — retries, circuit-breaking, load balancing
12 | - OAuth Delegation — per-backend OAuth flows
13 | - Testing Patterns — integrate with the test utilities
14 | 
15 | Each example has a runnable skeleton under `/examples/*` with a README.
16 | 
17 | 
```

--------------------------------------------------------------------------------
/tests/perf/artillery/auth-routing.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | config:
 2 |   target: "http://127.0.0.1:3000"
 3 |   phases:
 4 |     - duration: 30
 5 |       arrivalRate: 10
 6 |     - duration: 60
 7 |       arrivalRate: 25
 8 | scenarios:
 9 |   - name: "Call tool echo"
10 |     flow:
11 |       - post:
12 |           url: "/mcp/tools/call"
13 |           json:
14 |             name: "backend.echo"
15 |             arguments: { msg: "hello" }
16 |       - think: 1
17 |   - name: "Read resource"
18 |     flow:
19 |       - post:
20 |           url: "/mcp/resources/read"
21 |           json:
22 |             uri: "backend.docs.readme"
23 | 
24 | 
```

--------------------------------------------------------------------------------
/docs/guides/oauth-delegation.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: OAuth Delegation
 3 | ---
 4 | 
 5 | # OAuth Delegation Guide
 6 | 
 7 | Enable per-server OAuth by delegating authorization flows.
 8 | 
 9 | - Configure `oauth_delegation.enabled: true` and optional `providers` map.
10 | - Implement callback base URL and provider-specific overrides.
11 | - Use `FlowController` with Express or Workers runtime to complete flows.
12 | 
13 | Security
14 | - Use state and PKCE to prevent CSRF and code interception.
15 | - Restrict allowed redirect URIs.
16 | 
17 | See: `src/oauth/*` and `examples/oauth-delegation/`.
18 | 
19 | 
```

--------------------------------------------------------------------------------
/static/oauth/consent.html:
--------------------------------------------------------------------------------

```html
 1 | <!doctype html>
 2 | <html lang="en">
 3 | <head>
 4 |   <meta charset="utf-8" />
 5 |   <meta name="viewport" content="width=device-width, initial-scale=1" />
 6 |   <title>Connect Account</title>
 7 |   <link rel="stylesheet" href="/static/oauth/style.css" />
 8 |   <script src="/static/oauth/script.js" defer></script>
 9 | </head>
10 | <body>
11 |   <main class="container">
12 |     <h1>Connect Your Account</h1>
13 |     <p>This page is a placeholder template. The server may use dynamic pages for provider redirect.</p>
14 |   </main>
15 | </body>
16 | </html>
17 | 
18 | 
```

--------------------------------------------------------------------------------
/docs/guides/testing.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Testing Strategy
 3 | ---
 4 | 
 5 | # Testing Strategy
 6 | 
 7 | Phase 9 established a comprehensive strategy with unit, integration, e2e, perf, and security tests.
 8 | 
 9 | - Structure: see `/tests` directories by test type.
10 | - Runtimes: run both Node and Workers (Miniflare) where applicable.
11 | - Utilities: `_utils` helpers for HTTP, logging, and test servers.
12 | 
13 | Commands
14 | - `npm run test` — run all tests
15 | - `npm run test:unit|integration|e2e|perf|security`
16 | 
17 | See also: `docs/testing/phase-9-testing-architecture.md`.
18 | 
19 | 
```

--------------------------------------------------------------------------------
/docs/deployment/koyeb.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Deploy on Koyeb
 2 | 
 3 | Use the CI-built image and the service manifest in `deploy/koyeb/koyeb.yaml`.
 4 | 
 5 | ## Steps
 6 | 
 7 | 1) Build and push an image to GHCR or Docker Hub
 8 | 2) In Koyeb, create a new service from container image
 9 | 3) Set environment variables and secrets:
10 |    - `NODE_ENV=production`
11 |    - `TOKEN_ENC_KEY` (secret)
12 |    - `MASTER_BASE_URL` set to your Koyeb app URL
13 | 4) Configure autoscaling (see example manifest)
14 | 
15 | The platform-provided `PORT` is mapped automatically to `MASTER_HOSTING_PORT` by `deploy/docker/entrypoint.sh`.
16 | 
17 | 
```

--------------------------------------------------------------------------------
/docs/getting-started/concepts.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Core Concepts
 3 | ---
 4 | 
 5 | # Core Concepts
 6 | 
 7 | - Master OAuth: centralized OAuth for aggregated servers.
 8 | - Delegated OAuth: per-server OAuth via delegation.
 9 | - Module Loader: fetches and manages external MCP servers.
10 | - Request Router: registers routes and dispatches requests, with retries and circuit breaking.
11 | - Runtime Abstraction: Node vs Workers environment differences.
12 | - Config System: schema validation, secrets, and environment.
13 | 
14 | Architecture references are available under `docs/architecture/phase*-architecture.md`.
15 | 
16 | 
```

--------------------------------------------------------------------------------
/docs/getting-started/quickstart-node.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Quickstart (Node)
 3 | ---
 4 | 
 5 | # Quickstart (Node)
 6 | 
 7 | This minimal example runs Master MCP Server in Node, aggregating two servers.
 8 | 
 9 | Steps
10 | 1. Create a config file (e.g., `config/master.yaml`) based on `examples/sample-configs/basic.yaml`.
11 | 2. Start the server: `npm run start`.
12 | 3. Connect your MCP client to the exposed endpoint.
13 | 
14 | Highlights
15 | - Uses `src/runtime/node.ts` to bootstrap.
16 | - Validates config with `SchemaValidator`.
17 | - Routes requests via `RouteRegistry` and `RequestRouter`.
18 | 
19 | See also: Examples → Basic Node Aggregator.
20 | 
21 | 
```

--------------------------------------------------------------------------------
/docs/configuration/overview.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Configuration Overview
 3 | ---
 4 | 
 5 | # Configuration Overview
 6 | 
 7 | The Master MCP configuration is validated against a JSON Schema (`SchemaValidator`).
 8 | 
 9 | Key Sections
10 | - `master_oauth`: top-level OAuth issuer/client settings
11 | - `hosting`: platform and runtime options
12 | - `logging`, `security`: operational controls
13 | - `routing`: load balancing, retries, circuit breakers
14 | - `servers[]`: aggregated MCP servers with per-entry config
15 | 
16 | Start with examples in `/examples/sample-configs/*.yaml`.
17 | Generate the full reference with `npm run docs:config`.
18 | 
19 | 
```

--------------------------------------------------------------------------------
/docs/guides/configuration.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Configuration
 3 | ---
 4 | 
 5 | # Configuration Guide
 6 | 
 7 | Centralized configuration with schema validation and secrets.
 8 | 
 9 | - Types: `MasterConfig`, `HostingConfig`, `RoutingConfig`, `ServerConfig`, `SecurityConfig`.
10 | - Validation: `SchemaValidator` with built-in default schema.
11 | - Secrets: `SecretManager` decrypts protected values; keys from `SecurityConfig.config_key_env`.
12 | - Environments: `EnvironmentManager` to load/merge env vars.
13 | 
14 | Commands
15 | - Generate reference from schema: `npm run docs:config`
16 | 
17 | See: Configuration → Reference for full schema.
18 | 
19 | 
```

--------------------------------------------------------------------------------
/tsconfig.base.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2022",
 4 |     "module": "ESNext",
 5 |     "rootDir": "src",
 6 |     "strict": true,
 7 |     "noImplicitOverride": true,
 8 |     "noUnusedLocals": true,
 9 |     "noUnusedParameters": true,
10 |     "noFallthroughCasesInSwitch": true,
11 |     "forceConsistentCasingInFileNames": true,
12 |     "skipLibCheck": false,
13 |     "sourceMap": true,
14 |     "declaration": true,
15 |     "declarationMap": true,
16 |     "resolveJsonModule": true,
17 |     "esModuleInterop": true,
18 |     "moduleResolution": "NodeNext",
19 |     "types": []
20 |   },
21 |   "include": ["src/**/*"],
22 |   "exclude": ["node_modules", "dist", "tests"]
23 | }
24 | 
25 | 
```

--------------------------------------------------------------------------------
/docs/.vitepress/theme/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import DefaultTheme from 'vitepress/theme'
 2 | import type { Theme } from 'vitepress'
 3 | import CodeTabs from './components/CodeTabs.vue'
 4 | import ConfigGenerator from './components/ConfigGenerator.vue'
 5 | import AuthFlowDemo from './components/AuthFlowDemo.vue'
 6 | import ApiPlayground from './components/ApiPlayground.vue'
 7 | import './style.css'
 8 | 
 9 | const theme: Theme = {
10 |   ...DefaultTheme,
11 |   enhanceApp({ app }) {
12 |     app.component('CodeTabs', CodeTabs)
13 |     app.component('ConfigGenerator', ConfigGenerator)
14 |     app.component('AuthFlowDemo', AuthFlowDemo)
15 |     app.component('ApiPlayground', ApiPlayground)
16 |   },
17 | }
18 | 
19 | export default theme
20 | 
21 | 
```

--------------------------------------------------------------------------------
/docs/api/index.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: API Overview
 3 | ---
 4 | 
 5 | # API Overview
 6 | 
 7 | The API reference is generated from TypeScript sources using TypeDoc and the `typedoc-plugin-markdown` plugin.
 8 | 
 9 | - Generated docs output: `/api/reference/`
10 | - Generation config: `typedoc.json`
11 | - Command: `npm run docs:api`
12 | 
13 | Key entry points
14 | - `MasterServer` — main orchestration server
15 | - `ModuleLoader`, `RequestRouter`, `CapabilityAggregator` — module and routing
16 | - `MultiAuthManager`, `TokenManager` — authentication core
17 | - `FlowController` and related OAuth utilities — OAuth flows
18 | - `SchemaValidator`, `ConfigLoader` — configuration
19 | 
20 | See `/api/reference/` for the full API.
21 | 
22 | 
```

--------------------------------------------------------------------------------
/docs/deployment/cloudflare-workers.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Deploy on Cloudflare Workers
 2 | 
 3 | Configuration lives in `deploy/cloudflare/wrangler.toml`.
 4 | 
 5 | ## Setup
 6 | 
 7 | ```
 8 | wrangler whoami
 9 | wrangler login
10 | ```
11 | 
12 | Set secrets:
13 | 
14 | ```
15 | wrangler secret put TOKEN_ENC_KEY
16 | # Optional provider secrets as needed
17 | ```
18 | 
19 | Bind KV for token persistence (optional but recommended):
20 | 
21 | ```
22 | wrangler kv:namespace create TOKENS
23 | # Add binding to wrangler.toml and your environments
24 | ```
25 | 
26 | ## Dev and Deploy
27 | 
28 | ```
29 | wrangler dev
30 | wrangler deploy --env staging
31 | wrangler deploy --env production
32 | ```
33 | 
34 | Ensure your config uses `hosting.platform=cloudflare-workers` (auto-detected) and `hosting.base_url` is set for OAuth redirects.
35 | 
36 | 
```

--------------------------------------------------------------------------------
/docs/examples/overview.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Examples Overview
 2 | 
 3 | This directory groups runnable examples demonstrating common scenarios:
 4 | 
 5 | - `examples/basic-node` — Minimal Node runtime with a local backend
 6 | - `examples/oauth-node` — OAuth delegation using GitHub
 7 | - `examples/multi-server` — Multiple instances, load balancing, retries, circuit breaker
 8 | - `examples/custom-auth` — Custom `MultiAuthManager` that tweaks backend headers
 9 | - `examples/performance` — Tuning routing for throughput and resilience
10 | - `examples/security-hardening` — Production environment configuration tips
11 | 
12 | Run each by pointing `MASTER_CONFIG_PATH` and using `npm run dev`, unless a custom launcher is provided.
13 | 
14 | 
```

--------------------------------------------------------------------------------
/docs/troubleshooting/performance.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Performance Troubleshooting
 2 | 
 3 | ## Symptoms
 4 | 
 5 | - Elevated latency on tool calls
 6 | - Increased error rates or timeouts
 7 | 
 8 | ## Checks
 9 | 
10 | - Inspect `/metrics` (Node) and platform dashboards (Workers, Koyeb)
11 | - Verify backends’ `/health` and logs
12 | - Confirm load-balancing strategy is appropriate for your topology
13 | 
14 | ## Tuning
15 | 
16 | - Increase `retry.maxRetries` and `baseDelayMs` judiciously
17 | - Switch to `health` strategy and feed health scores when available
18 | - Tighten circuit breaker thresholds to fail fast on unhealthy instances
19 | 
20 | ## Environment
21 | 
22 | - Run Node with adequate CPU/memory; consider horizontal scaling
23 | - Use KV-backed tokens in Workers to reduce token cache misses
24 | 
25 | 
```

--------------------------------------------------------------------------------
/examples/oauth-node/config.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | hosting:
 2 |   platform: node
 3 |   port: 3000
 4 | 
 5 | master_oauth:
 6 |   authorization_endpoint: https://example.com/oauth/authorize
 7 |   token_endpoint: https://example.com/oauth/token
 8 |   client_id: master-mcp
 9 |   redirect_uri: http://localhost:3000/oauth/callback
10 |   scopes: [openid]
11 | 
12 | servers:
13 |   - id: github-tools
14 |     type: local
15 |     auth_strategy: delegate_oauth
16 |     auth_config:
17 |       provider: github
18 |       authorization_endpoint: https://github.com/login/oauth/authorize
19 |       token_endpoint: https://github.com/login/oauth/access_token
20 |       client_id: ${GITHUB_CLIENT_ID}
21 |       client_secret: env:GITHUB_CLIENT_SECRET
22 |       scopes: [repo, read:user]
23 |     config:
24 |       port: 4100
25 | 
26 | 
```

--------------------------------------------------------------------------------
/deploy/cloudflare/wrangler.toml:
--------------------------------------------------------------------------------

```toml
 1 | name = "master-mcp-server"
 2 | main = "src/runtime/worker.ts"
 3 | compatibility_date = "2024-07-01"
 4 | workers_dev = true
 5 | 
 6 | # Optional: enable Node compat if needed (try to keep off)
 7 | # node_compat = false
 8 | 
 9 | [vars]
10 | # Non-sensitive defaults; override per-env below or via dashboard
11 | MASTER_HOSTING_PLATFORM = "workers"
12 | LOG_LEVEL = "info"
13 | LOG_FORMAT = "json"
14 | 
15 | [env.staging]
16 | name = "master-mcp-server-staging"
17 | 
18 | [env.staging.vars]
19 | LOG_LEVEL = "debug"
20 | 
21 | [env.production]
22 | name = "master-mcp-server-prod"
23 | 
24 | [env.production.vars]
25 | LOG_LEVEL = "info"
26 | 
27 | # Secrets to provision via: wrangler secret put TOKEN_ENC_KEY
28 | # - TOKEN_ENC_KEY
29 | # - Any OAuth client secrets required by configured backends
30 | 
31 | 
```

--------------------------------------------------------------------------------
/examples/advanced-routing/config.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | master_oauth:
 2 |   authorization_endpoint: https://example.com/auth
 3 |   token_endpoint: https://example.com/token
 4 |   client_id: example
 5 |   redirect_uri: http://localhost:3000/oauth/callback
 6 |   scopes: [openid, profile]
 7 | 
 8 | hosting:
 9 |   platform: node
10 |   port: 3000
11 | 
12 | routing:
13 |   loadBalancer:
14 |     strategy: round_robin
15 |   retry:
16 |     maxRetries: 3
17 |     baseDelayMs: 250
18 |     maxDelayMs: 4000
19 |     backoffFactor: 2
20 |     jitter: full
21 |   circuitBreaker:
22 |     failureThreshold: 5
23 |     successThreshold: 2
24 |     recoveryTimeoutMs: 30000
25 | 
26 | servers:
27 |   - id: local-a
28 |     type: local
29 |     auth_strategy: bypass_auth
30 |     config: {}
31 |   - id: local-b
32 |     type: local
33 |     auth_strategy: bypass_auth
34 |     config: {}
35 | 
36 | 
```

--------------------------------------------------------------------------------
/vitest.config.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { defineConfig } from 'vitest/config'
 2 | 
 3 | export default defineConfig({
 4 |   test: {
 5 |     globals: true,
 6 |     include: ['tests/**/*.{test,spec}.ts'],
 7 |     exclude: ['tests/workers/**/*', 'dist', 'node_modules'],
 8 |     setupFiles: ['tests/_setup/vitest.setup.ts'],
 9 |     environment: 'node',
10 |     coverage: {
11 |       reporter: ['text', 'lcov', 'cobertura'],
12 |       provider: 'v8',
13 |       reportsDirectory: './coverage/node',
14 |       all: true,
15 |       include: ['src/**/*.ts'],
16 |       exclude: ['src/runtime/worker.ts', 'src/types/**', 'src/**/index.ts'],
17 |       thresholds: {
18 |         lines: 0.85,
19 |         functions: 0.85,
20 |         branches: 0.8,
21 |         statements: 0.85,
22 |       },
23 |     },
24 |   },
25 | })
26 | 
27 | 
```

--------------------------------------------------------------------------------
/docs/getting-started/overview.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Overview
 3 | ---
 4 | 
 5 | # Overview
 6 | 
 7 | Master MCP Server aggregates multiple MCP servers and exposes a unified endpoint with:
 8 | 
 9 | - Authentication: Master OAuth, delegated OAuth, token management.
10 | - Module loading: Git, NPM, PyPI, Docker, local.
11 | - Request routing: load balancing, retries, circuit breakers.
12 | - Configuration: schema validation, secrets, environment management.
13 | - Runtimes: Node and Cloudflare Workers.
14 | - Testing and Deployment: comprehensive strategy with CI.
15 | 
16 | Who is this for?
17 | - Developers integrating MCP into applications.
18 | - DevOps engineers deploying/managing the server.
19 | - System integrators configuring auth and routing.
20 | 
21 | Continue with Installation and Quickstarts.
22 | 
23 | 
```

--------------------------------------------------------------------------------
/docs/troubleshooting/errors.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Error Reference
 2 | 
 3 | ## Configuration validation failed
 4 | 
 5 | The config did not conform to the schema. The error lists the path and reason. Fix the offending property and reload.
 6 | 
 7 | ## CircuitOpenError
 8 | 
 9 | The circuit breaker is open for the selected upstream instance. Reduce upstream failures or increase `recoveryTimeoutMs`. Calls will resume after a successful half-open trial.
10 | 
11 | ## OAuthError
12 | 
13 | An upstream OAuth provider response was invalid. Check client credentials, scopes, and redirect URIs.
14 | 
15 | ## Token decryption failed
16 | 
17 | Persisted token ciphertext could not be decrypted with `TOKEN_ENC_KEY`. Ensure the key has not changed unexpectedly. Clear token storage if necessary and re-authorize.
18 | 
19 | 
```

--------------------------------------------------------------------------------
/docs/tutorials/cloudflare-workers-tutorial.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Tutorial: Cloudflare Workers
 2 | 
 3 | Run Master MCP Server on Cloudflare Workers with the provided runtime.
 4 | 
 5 | ## 1) Prerequisites
 6 | 
 7 | - Cloudflare account
 8 | - `wrangler` CLI
 9 | 
10 | ## 2) Configure
11 | 
12 | Update `deploy/cloudflare/wrangler.toml` as needed. Secrets:
13 | 
14 | ```
15 | wrangler secret put TOKEN_ENC_KEY
16 | ```
17 | 
18 | If you need persistent token storage, bind a KV namespace named `TOKENS` and pass it via environment bindings.
19 | 
20 | ## 3) Dev
21 | 
22 | ```
23 | wrangler dev
24 | ```
25 | 
26 | ## 4) Deploy
27 | 
28 | ```
29 | wrangler deploy --env staging
30 | wrangler deploy --env production
31 | ```
32 | 
33 | Ensure `hosting.platform` resolves to `cloudflare-workers` (detected automatically) and that `hosting.base_url` is set appropriately if you rely on absolute redirects for OAuth.
34 | 
35 | 
```

--------------------------------------------------------------------------------
/tests/unit/config.secret-manager.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import '../setup/test-setup.js'
 2 | import test from 'node:test'
 3 | import assert from 'node:assert/strict'
 4 | import { SecretManager } from '../../src/config/secret-manager.js'
 5 | 
 6 | test('SecretManager encrypt/decrypt and resolve env placeholders', () => {
 7 |   const sm = new SecretManager({ key: 'k123' })
 8 |   const enc = sm.encrypt('s3cr3t')
 9 |   assert.ok(sm.isEncrypted(enc))
10 |   assert.equal(sm.decrypt(enc), 's3cr3t')
11 | 
12 |   process.env.MY_TOKEN = 'abc'
13 |   const cfg = { a: enc, b: 'env:MY_TOKEN', c: { password: 'x' } }
14 |   const resolved = sm.resolveSecrets(cfg)
15 |   assert.equal(resolved.a, 's3cr3t')
16 |   assert.equal(resolved.b, 'abc')
17 |   const redacted = sm.redact(resolved)
18 |   assert.equal(redacted.c.password, '***')
19 | })
20 | 
21 | 
```

--------------------------------------------------------------------------------
/config.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "hosting": {
 3 |     "platform": "node",
 4 |     "port": 3005,
 5 |     "base_url": "http://localhost:3005"
 6 |   },
 7 |   "master_oauth": {
 8 |     "authorization_endpoint": "https://github.com/login/oauth/authorize",
 9 |     "token_endpoint": "https://github.com/login/oauth/access_token",
10 |     "client_id": "Ov23li2S7w1LYoM4yLJP",
11 |     "client_secret": "9f2cebe77974976e5fe7125eb50edefa81ee5219",
12 |     "redirect_uri": "http://localhost:3005/oauth/callback",
13 |     "scopes": ["read:user", "user:email"]
14 |   },
15 |   "servers": [
16 |     {
17 |       "id": "test-server",
18 |       "type": "local",
19 |       "url": "http://localhost:3006",
20 |       "auth_strategy": "bypass_auth",
21 |       "config": {
22 |         "environment": {},
23 |         "args": []
24 |       }
25 |     }
26 |   ]
27 | }
```

--------------------------------------------------------------------------------
/tests/utils/token-storages.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type { TokenStorage } from '../../src/auth/token-manager.js'
 2 | 
 3 | export class MemoryKVStorage implements TokenStorage {
 4 |   private kv = new Map<string,string>()
 5 |   async set(key: string, value: string) { this.kv.set(key, value) }
 6 |   async get(key: string) { return this.kv.get(key) }
 7 |   async delete(key: string) { this.kv.delete(key) }
 8 |   async *entries() { for (const e of this.kv.entries()) yield e }
 9 | }
10 | 
11 | export class RedisLikeStorage implements TokenStorage {
12 |   private map = new Map<string, string>()
13 |   async set(key: string, value: string) { this.map.set(key, value) }
14 |   async get(key: string) { return this.map.get(key) }
15 |   async delete(key: string) { this.map.delete(key) }
16 |   async *entries() { for (const e of this.map.entries()) yield e }
17 | }
18 | 
19 | 
```

--------------------------------------------------------------------------------
/docs/tutorials/beginner-getting-started.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Tutorial: Beginner Setup
 2 | 
 3 | Goal: Run Master MCP Server with a single local backend and call a tool.
 4 | 
 5 | ## 1) Install and Start
 6 | 
 7 | ```
 8 | npm ci
 9 | cp .env.example .env
10 | npm run dev
11 | ```
12 | 
13 | ## 2) Add a Backend
14 | 
15 | Create `examples/basic-node/config.yaml` (already provided) and run with:
16 | 
17 | ```
18 | MASTER_CONFIG_PATH=examples/basic-node/config.yaml npm run dev
19 | ```
20 | 
21 | ## 3) Verify Health and Capabilities
22 | 
23 | ```
24 | curl http://localhost:3000/health
25 | curl -X POST http://localhost:3000/mcp/tools/list -H 'content-type: application/json' -d '{}'
26 | ```
27 | 
28 | ## 4) Call a Tool
29 | 
30 | ```
31 | curl -X POST http://localhost:3000/mcp/tools/call \
32 |   -H 'content-type: application/json' \
33 |   -d '{"name":"tools.echo","arguments":{"text":"hello"}}'
34 | ```
35 | 
36 | Replace `tools.echo` with a tool exposed by your backend.
37 | 
38 | 
```

--------------------------------------------------------------------------------
/examples/custom-auth/config.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | hosting:
 2 |   platform: node
 3 |   port: 3000
 4 | 
 5 | master_oauth:
 6 |   authorization_endpoint: https://example.com/oauth/authorize
 7 |   token_endpoint: https://example.com/oauth/token
 8 |   client_id: master-mcp
 9 |   redirect_uri: http://localhost:3000/oauth/callback
10 |   scopes: [openid]
11 | 
12 | servers:
13 |   - id: public-tools
14 |     type: local
15 |     auth_strategy: bypass_auth
16 |     config:
17 |       port: 4200
18 | 
19 |   - id: custom-proxy
20 |     type: local
21 |     auth_strategy: proxy_oauth
22 |     auth_config:
23 |       provider: google
24 |       authorization_endpoint: https://accounts.google.com/o/oauth2/v2/auth
25 |       token_endpoint: https://oauth2.googleapis.com/token
26 |       client_id: ${GOOGLE_CLIENT_ID}
27 |       client_secret: env:GOOGLE_CLIENT_SECRET
28 |       scopes: [openid, profile, email]
29 |     config:
30 |       port: 4201
31 | 
32 | 
```

--------------------------------------------------------------------------------
/deploy/koyeb/koyeb.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | version: v1
 2 | 
 3 | services:
 4 |   - name: master-mcp
 5 |     type: web
 6 |     ports:
 7 |       - port: 80
 8 |         protocol: http
 9 |     instance_types:
10 |       - micro
11 |     min_instances: 2
12 |     max_instances: 10
13 |     scaling:
14 |       metric: cpu
15 |       target: 70
16 |       stabilization_window: 60
17 |     health_check:
18 |       path: /health
19 |       interval: 10s
20 |       timeout: 3s
21 |       unhealthy_threshold: 3
22 |       healthy_threshold: 1
23 |     docker:
24 |       image: ghcr.io/OWNER/REPO:latest # replaced by CI/CD
25 |       env:
26 |         - key: NODE_ENV
27 |           value: production
28 |         - key: LOG_FORMAT
29 |           value: json
30 |         - key: LOG_LEVEL
31 |           value: info
32 |         # Koyeb provides PORT; entrypoint maps it to hosting.port
33 |         - key: TOKEN_ENC_KEY
34 |           value: ${TOKEN_ENC_KEY} # set via Koyeb secrets
35 | 
36 | 
```

--------------------------------------------------------------------------------
/vitest.worker.config.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { defineConfig } from 'vitest/config'
 2 | 
 3 | export default defineConfig({
 4 |   test: {
 5 |     globals: true,
 6 |     include: ['tests/workers/**/*.{test,spec}.ts'],
 7 |     setupFiles: ['tests/_setup/miniflare.setup.ts'],
 8 |     environment: 'miniflare',
 9 |     environmentOptions: {
10 |       modules: true,
11 |       script: undefined, // tests import modules directly
12 |       bindings: {},
13 |       kvNamespaces: [],
14 |       durableObjects: {},
15 |     },
16 |     coverage: {
17 |       reporter: ['text', 'lcov'],
18 |       provider: 'v8',
19 |       reportsDirectory: './coverage/workers',
20 |       all: true,
21 |       include: ['src/**/*.ts'],
22 |       exclude: ['src/runtime/node.ts', 'src/types/**'],
23 |       thresholds: {
24 |         lines: 0.8,
25 |         functions: 0.8,
26 |         branches: 0.75,
27 |         statements: 0.8,
28 |       },
29 |     },
30 |   },
31 | })
32 | 
33 | 
```

--------------------------------------------------------------------------------
/tests/unit/modules/stdio-capability-discovery.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { test } from 'node:test'
 2 | import assert from 'node:assert'
 3 | import { StdioCapabilityDiscovery } from '../../../src/modules/stdio-capability-discovery.js'
 4 | import { StdioManager } from '../../../src/modules/stdio-manager.js'
 5 | 
 6 | test('StdioCapabilityDiscovery should instantiate correctly', async () => {
 7 |   const manager = new StdioManager()
 8 |   const discovery = new StdioCapabilityDiscovery(manager)
 9 |   assert.ok(discovery)
10 | })
11 | 
12 | test('StdioCapabilityDiscovery should have required methods', async () => {
13 |   const manager = new StdioManager()
14 |   const discovery = new StdioCapabilityDiscovery(manager)
15 |   assert.strictEqual(typeof discovery.discoverCapabilities, 'function')
16 |   assert.strictEqual(typeof discovery.callTool, 'function')
17 |   assert.strictEqual(typeof discovery.readResource, 'function')
18 | })
```

--------------------------------------------------------------------------------
/docs/configuration/performance.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Performance & Tuning
 2 | 
 3 | Tune routing and runtime to handle your workload.
 4 | 
 5 | ## Routing
 6 | 
 7 | - Prefer `health` strategy to route to instances with better health scores (when provided)
 8 | - Increase `retry.maxRetries` for flaky networks, but cap `maxDelayMs`
 9 | - Use `jitter: full` to avoid thundering herds
10 | - Adjust `circuitBreaker` thresholds based on observed upstream reliability
11 | 
12 | ## Node Runtime
13 | 
14 | - Use `NODE_ENV=production`
15 | - Run behind a reverse proxy (nginx, Cloudflare) for TLS termination
16 | - Set `LOG_LEVEL=info` or `warn`
17 | 
18 | ## Workers Runtime
19 | 
20 | - Bind KV storage for token persistence to avoid in-memory losses across isolates
21 | - Avoid large responses; stream when possible
22 | 
23 | ## Observability
24 | 
25 | - Use `/metrics` to scrape basic system stats in Node
26 | - Add platform logs/metrics (Cloudflare, Koyeb dashboards)
27 | 
28 | 
```

--------------------------------------------------------------------------------
/examples/multi-server/config.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | hosting:
 2 |   platform: node
 3 |   port: 3000
 4 | 
 5 | master_oauth:
 6 |   authorization_endpoint: https://example.com/oauth/authorize
 7 |   token_endpoint: https://example.com/oauth/token
 8 |   client_id: master-mcp
 9 |   redirect_uri: http://localhost:3000/oauth/callback
10 |   scopes: [openid]
11 | 
12 | routing:
13 |   loadBalancer:
14 |     strategy: health
15 |   circuitBreaker:
16 |     failureThreshold: 3
17 |     successThreshold: 2
18 |     recoveryTimeoutMs: 10000
19 |   retry:
20 |     maxRetries: 3
21 |     baseDelayMs: 200
22 |     maxDelayMs: 3000
23 |     backoffFactor: 2
24 |     jitter: full
25 |     retryOn:
26 |       networkErrors: true
27 |       httpStatuses: [408, 429]
28 |       httpStatusClasses: [5]
29 | 
30 | servers:
31 |   - id: compute
32 |     type: local
33 |     auth_strategy: bypass_auth
34 |     config:
35 |       port: 4101
36 |   - id: compute
37 |     type: local
38 |     auth_strategy: bypass_auth
39 |     config:
40 |       port: 4102
41 | 
42 | 
```

--------------------------------------------------------------------------------
/deploy/docker/docker-compose.yml:
--------------------------------------------------------------------------------

```yaml
 1 | version: '3.9'
 2 | 
 3 | services:
 4 |   master-mcp:
 5 |     build:
 6 |       context: ../..
 7 |       dockerfile: deploy/docker/Dockerfile
 8 |       args:
 9 |         - NODE_VERSION=20
10 |     image: master-mcp:dev
11 |     environment:
12 |       - NODE_ENV=development
13 |       - LOG_LEVEL=debug
14 |       - MASTER_HOSTING_PLATFORM=node
15 |       - MASTER_BASE_URL=http://localhost:3000
16 |       # TOKEN_ENC_KEY is recommended even in dev to persist tokens across restarts
17 |       - TOKEN_ENC_KEY=dev-dev-dev-dev-dev-dev-dev-dev
18 |     ports:
19 |       - "3000:3000"
20 |     volumes:
21 |       - ../../config:/app/config:ro
22 |     healthcheck:
23 |       test: ["CMD", "node", "-e", "const http=require('http');http.get('http://127.0.0.1:3000/health',r=>process.exit(r.statusCode===200?0:1)).on('error',()=>process.exit(1))"]
24 |       interval: 5s
25 |       timeout: 3s
26 |       retries: 20
27 |       start_period: 10s
28 | 
29 | 
```

--------------------------------------------------------------------------------
/docs/troubleshooting/common-issues.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Troubleshooting: Common Issues
 2 | 
 3 | ## Config validation failed
 4 | 
 5 | - Error shows `<path>: <reason>` from `SchemaValidator`
 6 | - Verify your file is valid JSON/YAML
 7 | - Check required fields under `master_oauth`, `hosting`, `servers`
 8 | 
 9 | ## Missing TOKEN_ENC_KEY in production
10 | 
11 | - Set `TOKEN_ENC_KEY` to a strong random string
12 | - In development, an ephemeral key is generated with a warning
13 | 
14 | ## OAuth callback mismatch
15 | 
16 | - Ensure `master_oauth.redirect_uri` matches your runtime base URL
17 | - If behind a proxy, set `MASTER_BASE_URL` to the external URL
18 | 
19 | ## 401 Unauthorized to backends
20 | 
21 | - Ensure client token is valid or delegated tokens are stored
22 | - For delegated flows, complete `/oauth/authorize` and `/oauth/callback` first
23 | 
24 | ## Workers runtime odd redirects
25 | 
26 | - Always set `hosting.base_url` in Workers to generate correct absolute URLs
27 | 
28 | 
```

--------------------------------------------------------------------------------
/examples/performance/config.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | hosting:
 2 |   platform: node
 3 |   port: 3000
 4 | 
 5 | master_oauth:
 6 |   authorization_endpoint: https://example.com/oauth/authorize
 7 |   token_endpoint: https://example.com/oauth/token
 8 |   client_id: master-mcp
 9 |   redirect_uri: http://localhost:3000/oauth/callback
10 |   scopes: [openid]
11 | 
12 | logging:
13 |   level: info
14 | 
15 | routing:
16 |   loadBalancer:
17 |     strategy: weighted
18 |   retry:
19 |     maxRetries: 4
20 |     baseDelayMs: 100
21 |     maxDelayMs: 1500
22 |     backoffFactor: 1.8
23 |     jitter: full
24 |     retryOn:
25 |       networkErrors: true
26 |       httpStatuses: [408, 429]
27 |       httpStatusClasses: [5]
28 |   circuitBreaker:
29 |     failureThreshold: 4
30 |     successThreshold: 2
31 |     recoveryTimeoutMs: 8000
32 | 
33 | servers:
34 |   - id: compute
35 |     type: local
36 |     auth_strategy: bypass_auth
37 |     config:
38 |       port: 4301
39 |   - id: compute
40 |     type: local
41 |     auth_strategy: bypass_auth
42 |     config:
43 |       port: 4302
44 | 
45 | 
```

--------------------------------------------------------------------------------
/tests/setup/test-setup.ts:
--------------------------------------------------------------------------------

```typescript
 1 | // Global test setup for Node test runner with ts-node ESM
 2 | // - Configures logger to reduce noise
 3 | // - Provides minimal polyfills and deterministic behavior where helpful
 4 | 
 5 | import { Logger } from '../../src/utils/logger.js'
 6 | 
 7 | // Quiet logs during tests unless DEBUG is set
 8 | Logger.configure({ level: (process.env.DEBUG ? 'debug' : 'error') as any, json: false })
 9 | 
10 | // Ensure process.env defaults for tests
11 | process.env.NODE_ENV = process.env.NODE_ENV || 'test'
12 | 
13 | // Deterministic Math.random for some tests (can be overridden locally)
14 | const seed = 42
15 | let state = seed
16 | const origRandom = Math.random
17 | globalThis.Math.random = () => {
18 |   if (process.env.TEST_NON_DETERMINISTIC === '1') return origRandom()
19 |   state = (1103515245 * state + 12345) % 0x100000000
20 |   return state / 0x100000000
21 | }
22 | 
23 | // Export nothing; imported by tests as side-effect
24 | export {}
25 | 
26 | 
```

--------------------------------------------------------------------------------
/tests/_utils/log-capture.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export class LogCapture {
 2 |   private originalLog = console.log
 3 |   private originalError = console.error
 4 |   private logs: string[] = []
 5 |   private errors: string[] = []
 6 | 
 7 |   start(): void {
 8 |     console.log = (...args: any[]) => {
 9 |       try { this.logs.push(args.map(String).join(' ')) } catch {}
10 |       this.originalLog.apply(console, args as any)
11 |     }
12 |     console.error = (...args: any[]) => {
13 |       try { this.errors.push(args.map(String).join(' ')) } catch {}
14 |       this.originalError.apply(console, args as any)
15 |     }
16 |   }
17 | 
18 |   stop(): void {
19 |     console.log = this.originalLog
20 |     console.error = this.originalError
21 |   }
22 | 
23 |   find(substr: string): boolean {
24 |     return this.logs.concat(this.errors).some((l) => l.includes(substr))
25 |   }
26 | 
27 |   dump(): { logs: string[]; errors: string[] } {
28 |     return { logs: [...this.logs], errors: [...this.errors] }
29 |   }
30 | }
31 | 
32 | 
```

--------------------------------------------------------------------------------
/src/types/auth.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export type AuthHeaders = Record<string, string>
 2 | 
 3 | export interface ClientInfo {
 4 |   client_id?: string
 5 |   redirect_uri?: string
 6 |   scopes?: string[]
 7 |   metadata?: Record<string, unknown>
 8 | }
 9 | 
10 | export interface OAuthDelegation {
11 |   type: 'oauth_delegation'
12 |   auth_endpoint: string
13 |   token_endpoint: string
14 |   client_info: ClientInfo
15 |   required_scopes: string[]
16 |   redirect_after_auth: boolean
17 | }
18 | 
19 | export interface OAuthToken {
20 |   access_token: string
21 |   refresh_token?: string
22 |   expires_at: number // epoch millis
23 |   scope: string[]
24 |   user_info?: unknown
25 | }
26 | 
27 | export interface AuthInfo {
28 |   type: 'bearer'
29 |   token: string
30 | }
31 | 
32 | export interface TokenValidationResult {
33 |   valid: boolean
34 |   expiresAt?: number
35 |   scopes?: string[]
36 |   error?: string
37 | }
38 | 
39 | export interface UserInfo {
40 |   id: string
41 |   name?: string
42 |   email?: string
43 |   avatarUrl?: string
44 |   [key: string]: unknown
45 | }
46 | 
47 | 
```

--------------------------------------------------------------------------------
/static/oauth/style.css:
--------------------------------------------------------------------------------

```css
 1 | /* Minimal, responsive styles for OAuth pages */
 2 | :root { --bg: #0b0d10; --fg: #e8edf2; --muted: #a9b3bd; --accent: #52b788; }
 3 | * { box-sizing: border-box; }
 4 | html, body { height: 100%; }
 5 | body {
 6 |   margin: 0; font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, Noto Sans, "Apple Color Emoji", "Segoe UI Emoji";
 7 |   background: var(--bg); color: var(--fg);
 8 |   display: grid; place-items: center;
 9 | }
10 | .container { width: 100%; max-width: 640px; padding: 24px; }
11 | h1 { font-size: 1.5rem; margin: 0 0 0.5rem; }
12 | p { color: var(--muted); line-height: 1.5; }
13 | .button {
14 |   display: inline-block; background: var(--accent); color: #02120c; font-weight: 600;
15 |   padding: 10px 14px; border-radius: 8px; text-decoration: none; margin-top: 12px;
16 | }
17 | .error h1 { color: #ff8692; }
18 | @media (max-width: 480px) { .container { padding: 16px; } }
19 | 
20 | 
```

--------------------------------------------------------------------------------
/tests/servers/test-debug.js:
--------------------------------------------------------------------------------

```javascript
 1 | import { MultiAuthManager } from '../../src/auth/multi-auth-manager.js'
 2 | import { AuthStrategy } from '../../src/types/config.js'
 3 | 
 4 | const masterCfg = {
 5 |   authorization_endpoint: 'http://localhost/auth',
 6 |   token_endpoint: 'http://localhost/token',
 7 |   client_id: 'master',
 8 |   redirect_uri: 'http://localhost/cb',
 9 |   scopes: ['openid'],
10 | }
11 | 
12 | try {
13 |   console.log('Creating MultiAuthManager...')
14 |   const mam = new MultiAuthManager(masterCfg)
15 |   console.log('MultiAuthManager created successfully')
16 |   
17 |   console.log('Registering server auth...')
18 |   mam.registerServerAuth('srv1', AuthStrategy.MASTER_OAUTH)
19 |   console.log('Server auth registered')
20 |   
21 |   console.log('Preparing auth for backend...')
22 |   const h = await mam.prepareAuthForBackend('srv1', 'CLIENT')
23 |   console.log('Result:', h)
24 |   
25 | } catch (error) {
26 |   console.error('Error:', error)
27 |   console.error('Stack:', error.stack)
28 | }
```

--------------------------------------------------------------------------------
/tests/utils/oauth-mocks.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { createMockServer, MockServer } from './mock-http.js'
 2 | 
 3 | export async function createGitHubMock(): Promise<MockServer> {
 4 |   return createMockServer([
 5 |     { method: 'GET', path: '/user', handler: () => ({ headers: { 'x-oauth-scopes': 'read:user, repo' }, body: { id: 1, login: 'octocat' } }) },
 6 |   ])
 7 | }
 8 | 
 9 | export async function createGoogleMock(): Promise<MockServer> {
10 |   return createMockServer([
11 |     { method: 'GET', path: '/userinfo', handler: () => ({ body: { sub: '123', name: 'Alice', email: '[email protected]', picture: 'http://x' } }) },
12 |   ])
13 | }
14 | 
15 | export async function createCustomOIDCMock(): Promise<MockServer> {
16 |   return createMockServer([
17 |     { method: 'POST', path: '/token', handler: () => ({ body: { access_token: 'AT', expires_in: 3600, scope: 'openid' } }) },
18 |     { method: 'GET', path: '/userinfo', handler: () => ({ body: { sub: 'abc', name: 'Bob' } }) },
19 |   ])
20 | }
21 | 
22 | 
```

--------------------------------------------------------------------------------
/tests/integration/modules.module-loader-health.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import '../setup/test-setup.js'
 2 | import test from 'node:test'
 3 | import assert from 'node:assert/strict'
 4 | import { DefaultModuleLoader } from '../../src/modules/module-loader.js'
 5 | import { createMockServer } from '../utils/mock-http.js'
 6 | 
 7 | test('DefaultModuleLoader performHealthCheck against /health JSON', async () => {
 8 |   const srv = await createMockServer([
 9 |     { method: 'GET', path: '/health', handler: () => ({ body: { ok: true } }) },
10 |   ])
11 |   try {
12 |     const loader = new DefaultModuleLoader()
13 |     const ls: any = { id: 'a', type: 'node', endpoint: srv.url, config: {} as any, status: 'starting', lastHealthCheck: 0 }
14 |     const ok = await loader.performHealthCheck(ls)
15 |     assert.equal(ok, true)
16 |     // performHealthCheck doesn't update status, that's done by the load method
17 |     assert(ls.lastHealthCheck > 0, 'lastHealthCheck should be updated')
18 |   } finally {
19 |     await srv.close()
20 |   }
21 | })
22 | 
23 | 
```

--------------------------------------------------------------------------------
/docs/deployment/docker.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Deploy with Docker
 2 | 
 3 | Two Docker setups are provided:
 4 | 
 5 | 1) Top-level `Dockerfile` (multi-stage) and `docker-compose.yml` for local dev
 6 | 2) `deploy/docker/Dockerfile` optimized for CI-built images and Koyeb
 7 | 
 8 | ## Local Development
 9 | 
10 | ```
11 | docker compose up --build
12 | ```
13 | 
14 | This uses the dev target with hot reload (`nodemon`) and maps your working directory into the container.
15 | 
16 | ## Production Image (CI)
17 | 
18 | Build and push an image:
19 | 
20 | ```
21 | docker build -f deploy/docker/Dockerfile -t ghcr.io/OWNER/REPO:latest .
22 | docker push ghcr.io/OWNER/REPO:latest
23 | ```
24 | 
25 | Run:
26 | 
27 | ```
28 | docker run -p 3000:3000 \
29 |   -e NODE_ENV=production \
30 |   -e TOKEN_ENC_KEY=... \
31 |   -e MASTER_BASE_URL=https://your.domain \
32 |   ghcr.io/OWNER/REPO:latest
33 | ```
34 | 
35 | ## Environment
36 | 
37 | - Set `TOKEN_ENC_KEY` in production
38 | - Set `MASTER_BASE_URL` if serving behind a proxy to ensure correct OAuth redirects
39 | - Inject `MASTER_OAUTH_CLIENT_SECRET` and other provider secrets via env
40 | 
41 | 
```

--------------------------------------------------------------------------------
/src/types/server.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type { ToolDefinition, ResourceDefinition, PromptDefinition } from './mcp.js'
 2 | import type { ServerConfig } from './config.js'
 3 | 
 4 | export type ServerType = 'python' | 'node' | 'typescript' | 'stdio' | 'unknown'
 5 | 
 6 | export interface ServerProcess {
 7 |   pid?: number
 8 |   port?: number
 9 |   url?: string
10 |   stop: () => Promise<void>
11 | }
12 | 
13 | export interface ServerCapabilities {
14 |   tools: ToolDefinition[]
15 |   resources: ResourceDefinition[]
16 |   prompts?: PromptDefinition[]
17 | }
18 | 
19 | export interface LoadedServer {
20 |   id: string
21 |   type: ServerType
22 |   process?: ServerProcess
23 |   endpoint: string
24 |   config: ServerConfig
25 |   capabilities?: ServerCapabilities
26 |   status: 'starting' | 'running' | 'stopped' | 'error'
27 |   lastHealthCheck: number
28 |   // Optional: when a server has multiple deploys/instances
29 |   instances?: ServerInstance[]
30 | }
31 | 
32 | export interface ServerInstance {
33 |   id: string
34 |   url: string
35 |   weight?: number
36 |   healthScore?: number // 0..100, used by health-based LB
37 | }
38 | 
```

--------------------------------------------------------------------------------
/docs/guides/module-loading.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Module Loading & Capability Aggregation
 2 | 
 3 | Master MCP loads backend servers from multiple sources and aggregates their capabilities.
 4 | 
 5 | ## Sources
 6 | 
 7 | - `local`: A locally running server exposing HTTP endpoints
 8 | - `git`, `npm`, `pypi`, `docker`: Stubs for different origins; endpoint resolution is config-driven (e.g., `config.port` or `url`).
 9 | 
10 | Example server block:
11 | 
12 | ```yaml
13 | servers:
14 |   - id: search
15 |     type: local
16 |     auth_strategy: master_oauth
17 |     config:
18 |       port: 4100
19 | ```
20 | 
21 | ## Health Checks
22 | 
23 | `DefaultModuleLoader` pings each server’s `/health` endpoint when loading to set an initial status (`running` or `error`).
24 | 
25 | ## Capability Aggregation
26 | 
27 | `CapabilityAggregator` discovers tools and resources via:
28 | 
29 | - `GET /capabilities` (optional if provided by backend)
30 | - `POST /mcp/tools/list`
31 | - `POST /mcp/resources/list`
32 | 
33 | Capabilities can be prefixed by server id (default) to avoid naming conflicts. Use the aggregated names in requests, e.g., `serverId.toolName`.
34 | 
35 | 
```

--------------------------------------------------------------------------------
/docs/guides/request-routing.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Request Routing & Resilience
 2 | 
 3 | Requests are routed by `RequestRouter`, which uses a `RouteRegistry`, `LoadBalancer`, `RetryHandler`, and `CircuitBreaker` to provide resilient upstream calls.
 4 | 
 5 | ## Endpoints
 6 | 
 7 | - Tools: `POST /mcp/tools/call` with `{ name, arguments }`
 8 | - Resources: `POST /mcp/resources/read` with `{ uri }`
 9 | 
10 | Names and URIs may be prefixed by server id when aggregated.
11 | 
12 | ## Load Balancing
13 | 
14 | Configure strategy under `routing.loadBalancer.strategy`:
15 | 
16 | - `round_robin` (default)
17 | - `weighted`
18 | - `health`
19 | 
20 | ## Retries
21 | 
22 | `routing.retry` controls attempts with backoff and jitter:
23 | 
24 | - `maxRetries`, `baseDelayMs`, `maxDelayMs`, `backoffFactor`, `jitter` (`full` or `none`)
25 | - `retryOn.httpStatuses`, `retryOn.httpStatusClasses`, `retryOn.networkErrors`
26 | 
27 | ## Circuit Breaker
28 | 
29 | `routing.circuitBreaker` manages failure thresholds and recovery:
30 | 
31 | - `failureThreshold`, `successThreshold`, `recoveryTimeoutMs`
32 | 
33 | When open, requests fail fast with a retry-after hint.
34 | 
35 | 
```

--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------

```yaml
 1 | version: "3.9"
 2 | 
 3 | services:
 4 |   master-mcp:
 5 |     build:
 6 |       context: .
 7 |       target: dev
 8 |     image: master-mcp-server:dev
 9 |     container_name: master-mcp-dev
10 |     ports:
11 |       - "3000:3000"
12 |     environment:
13 |       - NODE_ENV=development
14 |       - MASTER_ENV=development
15 |       - MASTER_HOSTING_PLATFORM=node
16 |       - MASTER_HOSTING_PORT=3000
17 |       # Uncomment and set for local secrets
18 |       # - MASTER_OAUTH_CLIENT_SECRET=${MASTER_OAUTH_CLIENT_SECRET}
19 |       # - TOKEN_ENC_KEY=${TOKEN_ENC_KEY}
20 |     env_file:
21 |       - .env
22 |     volumes:
23 |       - ./:/app
24 |       - /app/node_modules
25 |     healthcheck:
26 |       test: ["CMD", "wget", "-qO-", "http://127.0.0.1:3000/health"]
27 |       interval: 10s
28 |       timeout: 3s
29 |       retries: 3
30 |       start_period: 20s
31 |     security_opt:
32 |       - no-new-privileges:true
33 |     cap_drop:
34 |       - ALL
35 |     deploy:
36 |       resources:
37 |         limits:
38 |           cpus: "0.75"
39 |           memory: 768M
40 |         reservations:
41 |           cpus: "0.25"
42 |           memory: 256M
43 | 
44 | 
```

--------------------------------------------------------------------------------
/tests/_utils/mock-fetch.ts:
--------------------------------------------------------------------------------

```typescript
 1 | // Lightweight Node fetch mocking via Undici MockAgent (Node 18)
 2 | // Falls back to no-op if Undici not available.
 3 | 
 4 | type RemoveFn = () => void
 5 | 
 6 | export function withMockFetch(routes: Array<{ method: string; url: RegExp | string; reply: (body?: any) => any }>): RemoveFn {
 7 |   try {
 8 |     // eslint-disable-next-line @typescript-eslint/no-var-requires
 9 |     const undici = require('undici')
10 |     const agent = new undici.MockAgent()
11 |     agent.disableNetConnect()
12 |     const pool = agent.get('http://localhost')
13 |     for (const r of routes) {
14 |       const method = r.method.toUpperCase()
15 |       const matcher = typeof r.url === 'string' ? new RegExp(r.url.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) : r.url
16 |       pool.intercept({ path: matcher, method }).reply(200, (_opts: any) => r.reply(_opts?.body))
17 |     }
18 |     undici.setGlobalDispatcher(agent)
19 |     return () => undici.setGlobalDispatcher(new undici.Agent())
20 |   } catch {
21 |     // No undici; do nothing.
22 |     return () => void 0
23 |   }
24 | }
25 | 
26 | 
```

--------------------------------------------------------------------------------
/tests/unit/config.environment-manager.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import '../setup/test-setup.js'
 2 | import test from 'node:test'
 3 | import assert from 'node:assert/strict'
 4 | import { EnvironmentManager } from '../../src/config/environment-manager.js'
 5 | 
 6 | test('EnvironmentManager parseCliArgs dotted keys', () => {
 7 |   const orig = process.argv
 8 |   process.argv = ['node', 'script', '--hosting.port=4001', '--logging.level=debug', '--config-path=./x.json']
 9 |   try {
10 |     const parsed = EnvironmentManager.parseCliArgs()
11 |     assert.equal((parsed as any).hosting.port, 4001)
12 |     assert.equal((parsed as any).logging.level, 'debug')
13 |     assert.equal((parsed as any).configPath, './x.json')
14 |   } finally {
15 |     process.argv = orig
16 |   }
17 | })
18 | 
19 | test('EnvironmentManager loadEnvOverrides maps vars', () => {
20 |   process.env.MASTER_HOSTING_PORT = '1234'
21 |   process.env.MASTER_OAUTH_SCOPES = 'a,b'
22 |   const ov = EnvironmentManager.loadEnvOverrides()
23 |   // @ts-ignore
24 |   assert.equal(ov.hosting?.port, 1234)
25 |   // @ts-ignore
26 |   assert.deepEqual(ov.master_oauth?.scopes, ['a','b'])
27 | })
28 | 
29 | 
```

--------------------------------------------------------------------------------
/tests/integration/modules.capability-aggregator.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import '../setup/test-setup.js'
 2 | import test from 'node:test'
 3 | import assert from 'node:assert/strict'
 4 | import { CapabilityAggregator } from '../../src/modules/capability-aggregator.js'
 5 | import { createMockServer } from '../utils/mock-http.js'
 6 | 
 7 | test('CapabilityAggregator discovers via /capabilities', async () => {
 8 |   const caps = {
 9 |     tools: [{ name: 't1' }],
10 |     resources: [{ uri: 'r1' }],
11 |   }
12 |   const srv = await createMockServer([
13 |     { method: 'GET', path: '/capabilities', handler: () => ({ body: caps }) },
14 |   ])
15 |   try {
16 |     const servers = new Map<string, any>([[
17 |       's1', { id: 's1', type: 'node', endpoint: srv.url, config: {} as any, status: 'running', lastHealthCheck: 0 }
18 |     ]])
19 |     const ag = new CapabilityAggregator()
20 |     await ag.discoverCapabilities(servers as any)
21 |     const tools = ag.getAllTools(servers as any)
22 |     assert.equal(tools[0].name, 's1.t1')
23 |     const map = ag.getMappingForTool('s1.t1')
24 |     assert.equal(map?.originalName, 't1')
25 |   } finally {
26 |     await srv.close()
27 |   }
28 | })
29 | 
30 | 
```

--------------------------------------------------------------------------------
/docs/api/interfaces/RunningServer.md:
--------------------------------------------------------------------------------

```markdown
 1 | [**master-mcp-server**](../README.md)
 2 | 
 3 | ***
 4 | 
 5 | # Interface: RunningServer
 6 | 
 7 | Defined in: [index.ts:7](https://github.com/solita-internal/master-mcp-server/blob/cd13e0009f7a1b7f244de882dc738bbf1f90f2c2/src/index.ts#L7)
 8 | 
 9 | ## Properties
10 | 
11 | ### container
12 | 
13 | > **container**: `DependencyContainer`
14 | 
15 | Defined in: [index.ts:10](https://github.com/solita-internal/master-mcp-server/blob/cd13e0009f7a1b7f244de882dc738bbf1f90f2c2/src/index.ts#L10)
16 | 
17 | ***
18 | 
19 | ### name
20 | 
21 | > **name**: `string`
22 | 
23 | Defined in: [index.ts:8](https://github.com/solita-internal/master-mcp-server/blob/cd13e0009f7a1b7f244de882dc738bbf1f90f2c2/src/index.ts#L8)
24 | 
25 | ***
26 | 
27 | ### stop()
28 | 
29 | > **stop**: () => `Promise`\<`void`\>
30 | 
31 | Defined in: [index.ts:11](https://github.com/solita-internal/master-mcp-server/blob/cd13e0009f7a1b7f244de882dc738bbf1f90f2c2/src/index.ts#L11)
32 | 
33 | #### Returns
34 | 
35 | `Promise`\<`void`\>
36 | 
37 | ***
38 | 
39 | ### version
40 | 
41 | > **version**: `string`
42 | 
43 | Defined in: [index.ts:9](https://github.com/solita-internal/master-mcp-server/blob/cd13e0009f7a1b7f244de882dc738bbf1f90f2c2/src/index.ts#L9)
44 | 
```

--------------------------------------------------------------------------------
/tests/unit/utils.monitoring.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import '../setup/test-setup.js'
 2 | import test from 'node:test'
 3 | import assert from 'node:assert/strict'
 4 | import { MetricRegistry, HealthCheckRegistry, monitorEventLoopLag } from '../../src/utils/monitoring.js'
 5 | 
 6 | test('MetricRegistry counters/gauges/histograms', () => {
 7 |   const R = new MetricRegistry()
 8 |   R.counter('c').inc()
 9 |   R.gauge('g').set(5)
10 |   R.histogram('h').observe(0.02)
11 |   const snap = R.list()
12 |   assert.equal(snap.counters.c, 1)
13 |   assert.equal(snap.gauges.g, 5)
14 |   assert.ok(Array.isArray(snap.histograms.h.counts))
15 | })
16 | 
17 | test('HealthCheckRegistry aggregates ok/degraded', async () => {
18 |   const H = new HealthCheckRegistry()
19 |   H.register('ok', async () => ({ ok: true }))
20 |   H.register('bad', async () => ({ ok: false, info: 'x' }))
21 |   const res = await H.run()
22 |   assert.equal(res.status, 'degraded')
23 | })
24 | 
25 | test('monitorEventLoopLag provides callback and stopper', async () => {
26 |   let called = 0
27 |   const stop = monitorEventLoopLag(() => { called++ }, 5)
28 |   await new Promise((r) => setTimeout(r, 20))
29 |   stop()
30 |   assert.ok(called >= 1)
31 | })
32 | 
33 | 
```

--------------------------------------------------------------------------------
/tests/unit/stdio-capability-discovery.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { test } from 'node:test'
 2 | import assert from 'node:assert'
 3 | import { StdioCapabilityDiscovery } from '../src/modules/stdio-capability-discovery.js'
 4 | 
 5 | test('StdioCapabilityDiscovery should discover capabilities from a STDIO server', async () => {
 6 |   // This test would require a running STDIO server
 7 |   // For now, we'll just test that the class can be instantiated
 8 |   const discovery = new StdioCapabilityDiscovery()
 9 |   assert.ok(discovery)
10 | })
11 | 
12 | test('StdioCapabilityDiscovery should have discoverCapabilities method', async () => {
13 |   const discovery = new StdioCapabilityDiscovery()
14 |   assert.strictEqual(typeof discovery.discoverCapabilities, 'function')
15 | })
16 | 
17 | test('StdioCapabilityDiscovery should have callTool method', async () => {
18 |   const discovery = new StdioCapabilityDiscovery()
19 |   assert.strictEqual(typeof discovery.callTool, 'function')
20 | })
21 | 
22 | test('StdioCapabilityDiscovery should have readResource method', async () => {
23 |   const discovery = new StdioCapabilityDiscovery()
24 |   assert.strictEqual(typeof discovery.readResource, 'function')
25 | })
```

--------------------------------------------------------------------------------
/tests/unit/modules/stdio-manager.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { test } from 'node:test'
 2 | import assert from 'node:assert'
 3 | import { StdioManager } from '../../../src/modules/stdio-manager.js'
 4 | import path from 'node:path'
 5 | 
 6 | test('StdioManager should handle notifications', async () => {
 7 |   const manager = new StdioManager()
 8 |   const serverId = 'test-server'
 9 |   const serverPath = path.resolve(process.cwd(), 'tests/fixtures/stdio-server.js')
10 | 
11 |   let notificationReceived = null
12 |   const notificationPromise = new Promise(resolve => {
13 |     manager.onNotification(serverId, (message) => {
14 |       notificationReceived = message
15 |       resolve(message)
16 |     })
17 |   })
18 | 
19 |   await manager.startServer(serverId, serverPath)
20 | 
21 |   // Give the server a moment to start and send a notification
22 |   await new Promise(resolve => setTimeout(resolve, 500))
23 | 
24 |   // The test server should send a notification on start
25 |   // Let's wait for it
26 |   await notificationPromise
27 | 
28 |   assert.deepStrictEqual(notificationReceived, { type: 'notification', message: 'server ready' })
29 | 
30 |   const server = manager['processes'].get(serverId)
31 |   server?.kill()
32 | })
```

--------------------------------------------------------------------------------
/tests/unit/modules.route-registry.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import '../setup/test-setup.js'
 2 | import test from 'node:test'
 3 | import assert from 'node:assert/strict'
 4 | import { RouteRegistry } from '../../src/routing/route-registry.js'
 5 | import { CircuitBreaker } from '../../src/routing/circuit-breaker.js'
 6 | import { LoadBalancer } from '../../src/routing/load-balancer.js'
 7 | 
 8 | test('RouteRegistry resolves and caches, bumps health', () => {
 9 |   const servers = new Map([
10 |     ['s1', { id: 's1', type: 'node', endpoint: 'http://localhost:1234', config: {} as any, status: 'running', lastHealthCheck: Date.now(), instances: [
11 |       { id: 'i1', url: 'http://localhost:1', healthScore: 50 },
12 |       { id: 'i2', url: 'http://localhost:2', healthScore: 50 },
13 |     ] }]
14 |   ])
15 |   const reg = new RouteRegistry(servers as any, new CircuitBreaker({ failureThreshold: 5, successThreshold: 1, recoveryTimeoutMs: 10 }), new LoadBalancer())
16 |   const r1 = reg.resolve('s1')!
17 |   assert.ok(r1.instance.id === 'i1' || r1.instance.id === 'i2')
18 |   // mark success and failure adjust health without throwing
19 |   reg.markSuccess('s1', r1.instance.id)
20 |   reg.markFailure('s1', r1.instance.id)
21 | })
22 | 
23 | 
```

--------------------------------------------------------------------------------
/tests/unit/auth.token-manager.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import '../setup/test-setup.js'
 2 | import test from 'node:test'
 3 | import assert from 'node:assert/strict'
 4 | import { TokenManager, InMemoryTokenStorage } from '../../src/auth/token-manager.js'
 5 | 
 6 | test('TokenManager stores, retrieves and cleans up', async () => {
 7 |   const storage = new InMemoryTokenStorage()
 8 |   const tm = new TokenManager({ storage, secret: 'k' })
 9 |   const key = 'user::server'
10 |   await tm.storeToken(key, { access_token: 't', expires_at: Date.now() + 50, scope: [] })
11 |   const tok = await tm.getToken(key)
12 |   assert.equal(tok?.access_token, 't')
13 |   await new Promise((r) => setTimeout(r, 60))
14 |   await tm.cleanupExpiredTokens()
15 |   const tok2 = await tm.getToken(key)
16 |   assert.equal(tok2, null)
17 | })
18 | 
19 | test('TokenManager works with custom KV-like storage', async () => {
20 |   const { MemoryKVStorage } = await import('../utils/token-storages.js')
21 |   const storage = new MemoryKVStorage()
22 |   const tm = new TokenManager({ storage, secret: 'k' })
23 |   await tm.storeToken('k1', { access_token: 'Z', expires_at: Date.now() + 1000, scope: [] })
24 |   const tok = await tm.getToken('k1')
25 |   assert.equal(tok?.access_token, 'Z')
26 | })
27 | 
```

--------------------------------------------------------------------------------
/docs/.vitepress/theme/components/CodeTabs.vue:
--------------------------------------------------------------------------------

```vue
 1 | <template>
 2 |   <div class="mcp-tabs" role="tablist" aria-label="Code Tabs">
 3 |     <div class="mcp-tabs__nav">
 4 |       <button
 5 |         v-for="opt in options"
 6 |         :key="opt.value"
 7 |         class="mcp-tabs__btn"
 8 |         role="tab"
 9 |         :aria-selected="active === opt.value"
10 |         @click="active = opt.value"
11 |       >
12 |         {{ opt.label }}
13 |       </button>
14 |     </div>
15 |     <div class="mcp-tabs__panel" role="tabpanel">
16 |       <slot :name="active" />
17 |     </div>
18 |   </div>
19 |   <div v-if="note" class="mcp-callout" style="margin-top:8px">{{ note }}</div>
20 |   <div v-if="footnote" style="margin-top:6px;color:var(--vp-c-text-2);font-size:.9rem">{{ footnote }}</div>
21 | </template>
22 | 
23 | <script setup lang="ts">
24 | import { ref, watchEffect } from 'vue'
25 | 
26 | interface Option { label: string; value: string }
27 | const props = defineProps<{
28 |   options: Option[]
29 |   modelValue?: string
30 |   note?: string
31 |   footnote?: string
32 | }>()
33 | const active = ref(props.modelValue || (props.options[0]?.value ?? ''))
34 | watchEffect(() => {
35 |   if (!props.options.find(o => o.value === active.value)) {
36 |     active.value = props.options[0]?.value ?? ''
37 |   }
38 | })
39 | </script>
40 | 
41 | 
```

--------------------------------------------------------------------------------
/tests/unit/utils.logger.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import '../setup/test-setup.js'
 2 | import test from 'node:test'
 3 | import assert from 'node:assert/strict'
 4 | import { Logger } from '../../src/utils/logger.js'
 5 | 
 6 | test('Logger emits human log line', () => {
 7 |   const lines: string[] = []
 8 |   const orig = console.log
 9 |   console.log = (s: any) => { lines.push(String(s)) }
10 |   try {
11 |     Logger.configure({ json: false, level: 'debug' })
12 |     Logger.info('hello', { a: 1 })
13 |     assert.ok(lines.length >= 1)
14 |     assert.match(lines[0], /\[INFO\].*hello/)
15 |   } finally {
16 |     console.log = orig
17 |     Logger.configure({ json: false, level: 'error' })
18 |   }
19 | })
20 | 
21 | test('Logger child with base fields', () => {
22 |   const lines: string[] = []
23 |   const orig = console.log
24 |   console.log = (s: any) => { lines.push(String(s)) }
25 |   try {
26 |     Logger.configure({ json: true, level: 'debug', base: { svc: 'x' } })
27 |     const L = Logger.with({ reqId: 'r1' })
28 |     L.debug('dbg', { extra: 2 })
29 |     assert.ok(lines.length)
30 |     const parsed = JSON.parse(lines[0])
31 |     assert.equal(parsed.svc, 'x')
32 |     assert.equal(parsed.reqId, 'r1')
33 |     assert.equal(parsed.msg, 'dbg')
34 |   } finally {
35 |     console.log = orig
36 |   }
37 | })
38 | 
39 | 
```

--------------------------------------------------------------------------------
/docs/getting-started/quick-start.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Quick Start
 3 | ---
 4 | 
 5 | # Quick Start
 6 | 
 7 | Get from zero to a running Master MCP Server in under 10 minutes.
 8 | 
 9 | <CodeTabs
10 |   :options="[
11 |     { label: 'Node.js', value: 'node' },
12 |     { label: 'Docker', value: 'docker' },
13 |     { label: 'Cloudflare Workers', value: 'workers' }
14 |   ]"
15 |   note="Follow one tab end-to-end."
16 | >
17 |   <template #node>
18 | 
19 | ```bash
20 | npm install
21 | cp .env.example .env
22 | npm run build && npm run start
23 | ```
24 | 
25 | Minimal `config/master.yaml`:
26 | 
27 | ```yaml
28 | hosting:
29 |   port: 3000
30 | servers:
31 |   - id: search
32 |     type: local
33 |     auth_strategy: master_oauth
34 |     config:
35 |       port: 4100
36 | ```
37 | 
38 | Verify:
39 | 
40 | ```bash
41 | curl -s http://localhost:3000/health
42 | curl -s http://localhost:3000/mcp/tools/list | jq
43 | ```
44 | 
45 |   </template>
46 |   <template #docker>
47 | 
48 | ```bash
49 | docker compose up --build
50 | ```
51 | 
52 | Production image:
53 | 
54 | ```bash
55 | docker run -p 3000:3000 \
56 |   -e NODE_ENV=production \
57 |   -e TOKEN_ENC_KEY=... \
58 |   ghcr.io/OWNER/REPO:latest
59 | ```
60 | 
61 |   </template>
62 |   <template #workers>
63 | 
64 | ```bash
65 | npm run build:worker
66 | npx wrangler deploy deploy/cloudflare
67 | ```
68 | 
69 |   </template>
70 | </CodeTabs>
71 | 
72 | ## Generate a Config
73 | 
74 | <ConfigGenerator />
75 | 
76 | ## Test Requests
77 | 
78 | <ApiPlayground />
79 | 
80 | 
```

--------------------------------------------------------------------------------
/src/types/mcp.ts:
--------------------------------------------------------------------------------

```typescript
 1 | // Minimal MCP-like types for Phase 1 compilation.
 2 | // Replace with @modelcontextprotocol/sdk imports in later phases.
 3 | 
 4 | export interface ToolDefinition {
 5 |   name: string
 6 |   description?: string
 7 |   inputSchema?: unknown
 8 | }
 9 | 
10 | export interface ResourceDefinition {
11 |   uri: string
12 |   name?: string
13 |   description?: string
14 |   mimeType?: string
15 | }
16 | 
17 | export interface PromptDefinition {
18 |   name: string
19 |   description?: string
20 |   input?: unknown
21 | }
22 | 
23 | export interface ListToolsRequest {
24 |   type: 'list_tools'
25 | }
26 | 
27 | export interface ListToolsResult {
28 |   tools: ToolDefinition[]
29 | }
30 | 
31 | export interface CallToolRequest {
32 |   name: string
33 |   arguments?: Record<string, unknown> | undefined
34 | }
35 | 
36 | export interface CallToolResult {
37 |   content: unknown
38 |   isError?: boolean
39 | }
40 | 
41 | export interface ListResourcesRequest {
42 |   type: 'list_resources'
43 | }
44 | 
45 | export interface ListResourcesResult {
46 |   resources: ResourceDefinition[]
47 | }
48 | 
49 | export interface ReadResourceRequest {
50 |   uri: string
51 | }
52 | 
53 | export interface ReadResourceResult {
54 |   contents: string | Uint8Array
55 |   mimeType?: string
56 | }
57 | 
58 | export interface SubscribeRequest {
59 |   target: string
60 | }
61 | 
62 | export interface SubscribeResult {
63 |   ok: boolean
64 | }
65 | 
66 | 
```

--------------------------------------------------------------------------------
/tests/factories/configFactory.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type { MasterConfig, ServerConfig, AuthStrategy } from '../../src/types/config.js'
 2 | 
 3 | export function makeServerConfig(id: string, endpoint: string, authStrategy: AuthStrategy = 0 as any): ServerConfig {
 4 |   return {
 5 |     id,
 6 |     type: 'local',
 7 |     url: endpoint,
 8 |     auth_strategy: authStrategy || 'bypass_auth',
 9 |     config: { port: new URL(endpoint).port ? Number(new URL(endpoint).port) : undefined },
10 |   }
11 | }
12 | 
13 | export function makeMasterConfig(params: {
14 |   servers: Array<{ id: string; endpoint: string }>
15 |   hosting?: Partial<MasterConfig['hosting']>
16 |   routing?: MasterConfig['routing']
17 |   master_oauth?: Partial<MasterConfig['master_oauth']>
18 | }): MasterConfig {
19 |   const servers: ServerConfig[] = params.servers.map((s) => makeServerConfig(s.id, s.endpoint))
20 |   return {
21 |     master_oauth: {
22 |       authorization_endpoint: 'http://localhost/authorize',
23 |       token_endpoint: 'http://localhost/token',
24 |       client_id: 'local',
25 |       redirect_uri: 'http://localhost/oauth/callback',
26 |       scopes: ['openid'],
27 |       ...(params.master_oauth ?? {}),
28 |     },
29 |     servers,
30 |     hosting: { platform: 'node', port: 0, ...(params.hosting ?? {}) },
31 |     routing: params.routing,
32 |   }
33 | }
34 | 
35 | 
```

--------------------------------------------------------------------------------
/tests/unit/config.schema-validator.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import '../setup/test-setup.js'
 2 | import test from 'node:test'
 3 | import assert from 'node:assert/strict'
 4 | import { SchemaValidator } from '../../src/config/schema-validator.js'
 5 | 
 6 | test('SchemaValidator accepts minimal valid config', async () => {
 7 |   const schema = await SchemaValidator.loadSchema('config/schema.json')
 8 |   const cfg = {
 9 |     master_oauth: {
10 |       authorization_endpoint: 'https://auth.local/authorize',
11 |       token_endpoint: 'https://auth.local/token',
12 |       client_id: 'x',
13 |       redirect_uri: 'http://localhost/cb',
14 |       scopes: ['openid'],
15 |     },
16 |     hosting: { platform: 'node' },
17 |     servers: [],
18 |   }
19 |   assert.doesNotThrow(() => SchemaValidator.assertValid(cfg, schema!))
20 | })
21 | 
22 | test('SchemaValidator rejects invalid platform', async () => {
23 |   const schema = await SchemaValidator.loadSchema('config/schema.json')
24 |   const cfg: any = {
25 |     master_oauth: {
26 |       authorization_endpoint: 'https://auth.local/authorize',
27 |       token_endpoint: 'https://auth.local/token',
28 |       client_id: 'x',
29 |       redirect_uri: 'http://localhost/cb',
30 |       scopes: ['openid'],
31 |     },
32 |     hosting: { platform: 'nope' },
33 |     servers: [],
34 |   }
35 |   assert.throws(() => SchemaValidator.assertValid(cfg, schema!))
36 | })
37 | 
38 | 
```

--------------------------------------------------------------------------------
/config/default.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "master_oauth": {
 3 |     "authorization_endpoint": "https://example.com/oauth/authorize",
 4 |     "token_endpoint": "https://example.com/oauth/token",
 5 |     "client_id": "master-mcp",
 6 |     "client_secret": "env:MASTER_OAUTH_CLIENT_SECRET",
 7 |     "redirect_uri": "http://localhost:3000/callback",
 8 |     "scopes": ["openid", "profile"],
 9 |     "audience": "master-mcp"
10 |   },
11 |   "hosting": {
12 |     "platform": "node",
13 |     "port": 3000
14 |   },
15 |   "logging": {
16 |     "level": "info"
17 |   },
18 |   "routing": {
19 |     "loadBalancer": { "strategy": "round_robin" },
20 |     "circuitBreaker": { "failureThreshold": 5, "successThreshold": 2, "recoveryTimeoutMs": 30000 },
21 |     "retry": { "maxRetries": 2, "baseDelayMs": 250, "maxDelayMs": 4000, "backoffFactor": 2, "jitter": "full" }
22 |   },
23 |   "servers": [
24 |     {
25 |       "id": "test-server",
26 |       "type": "local",
27 |       "url": "http://localhost:3006",
28 |       "auth_strategy": "bypass_auth",
29 |       "config": {
30 |         "environment": {},
31 |         "args": []
32 |       }
33 |     },
34 |     {
35 |       "id": "stdio-server",
36 |       "type": "local",
37 |       "url": "file://./examples/stdio-mcp-server.cjs",
38 |       "auth_strategy": "bypass_auth",
39 |       "config": {
40 |         "environment": {},
41 |         "args": []
42 |       }
43 |     }
44 |   ]
45 | }
46 | 
47 | 
```

--------------------------------------------------------------------------------
/docs/deployment/docs-site.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Deploy the Docs Site
 3 | ---
 4 | 
 5 | # Deploy the Docs Site
 6 | 
 7 | The documentation is built with VitePress and lives under `docs/`.
 8 | 
 9 | ## Build Locally
10 | 
11 | ```bash
12 | npm run docs:build
13 | ```
14 | 
15 | The static site is emitted to `docs/.vitepress/dist`.
16 | 
17 | ## Preview Locally
18 | 
19 | ```bash
20 | npm run docs:preview
21 | ```
22 | 
23 | ## GitHub Pages
24 | 
25 | Setup workflow (example):
26 | 
27 | ```yaml
28 | name: Deploy Docs
29 | on:
30 |   push:
31 |     branches: [ main ]
32 | permissions:
33 |   contents: read
34 |   pages: write
35 |   id-token: write
36 | jobs:
37 |   build:
38 |     runs-on: ubuntu-latest
39 |     steps:
40 |       - uses: actions/checkout@v4
41 |       - uses: actions/setup-node@v4
42 |         with: { node-version: '20' }
43 |       - run: npm ci
44 |       - run: npm run docs:build
45 |       - uses: actions/upload-pages-artifact@v3
46 |         with: { path: docs/.vitepress/dist }
47 |   deploy:
48 |     needs: build
49 |     runs-on: ubuntu-latest
50 |     environment: { name: github-pages, url: ${{ steps.deployment.outputs.page_url }} }
51 |     steps:
52 |       - id: deployment
53 |         uses: actions/deploy-pages@v4
54 | ```
55 | 
56 | ## Cloudflare Pages
57 | 
58 | - Framework preset: None
59 | - Build command: `npm run docs:build`
60 | - Build output directory: `docs/.vitepress/dist`
61 | 
62 | ## Netlify
63 | 
64 | - Build command: `npm run docs:build`
65 | - Publish directory: `docs/.vitepress/dist`
66 | 
67 | 
```

--------------------------------------------------------------------------------
/docs/tutorials/load-balancing-and-resilience.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Tutorial: Load Balancing & Resilience
 2 | 
 3 | Demonstrates multiple backends with load balancing, retries, and circuit breaker tuning.
 4 | 
 5 | ## Configuration
 6 | 
 7 | `examples/multi-server/config.yaml` (provided):
 8 | 
 9 | ```yaml
10 | hosting:
11 |   platform: node
12 |   port: 3000
13 | 
14 | master_oauth:
15 |   authorization_endpoint: https://example.com/oauth/authorize
16 |   token_endpoint: https://example.com/oauth/token
17 |   client_id: master-mcp
18 |   redirect_uri: http://localhost:3000/oauth/callback
19 |   scopes: [openid]
20 | 
21 | routing:
22 |   loadBalancer:
23 |     strategy: health
24 |   circuitBreaker:
25 |     failureThreshold: 3
26 |     successThreshold: 2
27 |     recoveryTimeoutMs: 10000
28 |   retry:
29 |     maxRetries: 3
30 |     baseDelayMs: 200
31 |     maxDelayMs: 3000
32 |     backoffFactor: 2
33 |     jitter: full
34 |     retryOn:
35 |       networkErrors: true
36 |       httpStatuses: [408, 429]
37 |       httpStatusClasses: [5]
38 | 
39 | servers:
40 |   - id: compute
41 |     type: local
42 |     auth_strategy: bypass_auth
43 |     config:
44 |       port: 4101
45 |   - id: compute
46 |     type: local
47 |     auth_strategy: bypass_auth
48 |     config:
49 |       port: 4102
50 | ```
51 | 
52 | Run master with:
53 | 
54 | ```
55 | MASTER_CONFIG_PATH=examples/multi-server/config.yaml npm run dev
56 | ```
57 | 
58 | The router will choose an instance per call, retry on transient errors, and open the circuit if failures breach the threshold.
59 | 
60 | 
```

--------------------------------------------------------------------------------
/docs/deployment/cicd.md:
--------------------------------------------------------------------------------

```markdown
 1 | # CI/CD Pipelines
 2 | 
 3 | Below are example steps you can adapt for your CI provider.
 4 | 
 5 | ## Build & Publish Docker Image (GitHub Actions)
 6 | 
 7 | ```yaml
 8 | name: build-and-push
 9 | on:
10 |   push:
11 |     branches: [ main ]
12 | 
13 | jobs:
14 |   docker:
15 |     runs-on: ubuntu-latest
16 |     permissions:
17 |       contents: read
18 |       packages: write
19 |     steps:
20 |       - uses: actions/checkout@v4
21 |       - uses: docker/setup-buildx-action@v3
22 |       - uses: docker/login-action@v3
23 |         with:
24 |           registry: ghcr.io
25 |           username: ${{ github.actor }}
26 |           password: ${{ secrets.GITHUB_TOKEN }}
27 |       - name: Build
28 |         run: |
29 |           docker build -f deploy/docker/Dockerfile -t ghcr.io/${{ github.repository }}:latest .
30 |       - name: Push
31 |         run: docker push ghcr.io/${{ github.repository }}:latest
32 | ```
33 | 
34 | ## Deploy to Cloudflare Workers (GitHub Actions)
35 | 
36 | ```yaml
37 | name: deploy-workers
38 | on:
39 |   push:
40 |     branches: [ main ]
41 | 
42 | jobs:
43 |   deploy:
44 |     runs-on: ubuntu-latest
45 |     steps:
46 |       - uses: actions/checkout@v4
47 |       - uses: cloudflare/wrangler-action@v3
48 |         with:
49 |           apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
50 |           command: deploy --env production
51 | ```
52 | 
53 | ## Deploy to Koyeb (CLI from CI)
54 | 
55 | Use Koyeb’s GitHub Action or the CLI with an API token to update the service image tag after push to GHCR.
56 | 
57 | 
```

--------------------------------------------------------------------------------
/src/runtime/worker.ts:
--------------------------------------------------------------------------------

```typescript
 1 | // Worker runtime with minimal surface to avoid Node-specific modules
 2 | import { ConfigLoader } from '../config/config-loader.js'
 3 | import { OAuthFlowController } from '../oauth/flow-controller.js'
 4 | import { collectSystemMetrics } from '../utils/monitoring.js'
 5 | 
 6 | export default {
 7 |   async fetch(_req: Request, env?: Record<string, unknown>): Promise<Response> {
 8 |     ;(globalThis as any).__WORKER_ENV = env || (globalThis as any).__WORKER_ENV || {}
 9 |     try {
10 |       const url = new URL(_req.url)
11 |       if (url.pathname === '/health') {
12 |         return new Response(JSON.stringify({ ok: true }), { headers: { 'content-type': 'application/json' } })
13 |       }
14 |       if (url.pathname === '/metrics') {
15 |         return new Response(
16 |           JSON.stringify({ ok: true, system: collectSystemMetrics() }),
17 |           { headers: { 'content-type': 'application/json' } }
18 |         )
19 |       }
20 |       if (url.pathname.startsWith('/oauth')) {
21 |         const cfg = await ConfigLoader.loadFromEnv()
22 |         const ctrl = new OAuthFlowController({ getConfig: () => cfg })
23 |         return await ctrl.handleRequest(_req)
24 |       }
25 |       return new Response(JSON.stringify({ ok: true }), {
26 |         headers: { 'content-type': 'application/json' },
27 |       })
28 |     } finally {
29 |       // keep server warm for now; no-op
30 |     }
31 |   },
32 | }
33 | 
```

--------------------------------------------------------------------------------
/docs/public/diagrams/architecture.svg:
--------------------------------------------------------------------------------

```
 1 | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 280">
 2 |   <defs>
 3 |     <style>
 4 |       .box{fill:#fff;stroke:#0ea5e9;stroke-width:2;rx:10;}
 5 |       .t{font:16px sans-serif;dominant-baseline:middle;text-anchor:middle;}
 6 |     </style>
 7 |     <marker id="arrow" markerWidth="10" markerHeight="10" refX="6" refY="3" orient="auto">
 8 |       <path d="M0,0 L0,6 L6,3 z" fill="#0ea5e9" />
 9 |     </marker>
10 |   </defs>
11 |   <rect x="40" y="40" width="160" height="60" class="box"/>
12 |   <text x="120" y="70" class="t">MCP Client(s)</text>
13 | 
14 |   <rect x="320" y="40" width="180" height="60" class="box"/>
15 |   <text x="410" y="60" class="t">Master MCP Server</text>
16 |   <text x="410" y="80" class="t">Auth • Routing • Config</text>
17 | 
18 |   <rect x="620" y="20" width="140" height="40" class="box"/>
19 |   <text x="690" y="40" class="t">Server A</text>
20 |   <rect x="620" y="80" width="140" height="40" class="box"/>
21 |   <text x="690" y="100" class="t">Server B</text>
22 |   <rect x="620" y="140" width="140" height="40" class="box"/>
23 |   <text x="690" y="160" class="t">Server C</text>
24 | 
25 |   <path d="M200,70 L320,70" stroke="#0ea5e9" stroke-width="2" marker-end="url(#arrow)"/>
26 |   <path d="M500,60 L620,40" stroke="#0ea5e9" stroke-width="2" marker-end="url(#arrow)"/>
27 |   <path d="M500,70 L620,100" stroke="#0ea5e9" stroke-width="2" marker-end="url(#arrow)"/>
28 |   <path d="M500,80 L620,160" stroke="#0ea5e9" stroke-width="2" marker-end="url(#arrow)"/>
29 | </svg>
30 | 
31 | 
```

--------------------------------------------------------------------------------
/docs/configuration/environment-variables.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Environment Variables
 2 | 
 3 | Environment variables can override configuration at load time. Key variables:
 4 | 
 5 | ## Hosting
 6 | 
 7 | - `MASTER_HOSTING_PLATFORM` → `hosting.platform`
 8 | - `MASTER_HOSTING_PORT` → `hosting.port`
 9 | - `MASTER_BASE_URL` → `hosting.base_url`
10 | 
11 | ## Logging
12 | 
13 | - `MASTER_LOG_LEVEL` → `logging.level`
14 | 
15 | ## Master OAuth
16 | 
17 | - `MASTER_OAUTH_ISSUER` → `master_oauth.issuer`
18 | - `MASTER_OAUTH_AUTHORIZATION_ENDPOINT` → `master_oauth.authorization_endpoint`
19 | - `MASTER_OAUTH_TOKEN_ENDPOINT` → `master_oauth.token_endpoint`
20 | - `MASTER_OAUTH_JWKS_URI` → `master_oauth.jwks_uri`
21 | - `MASTER_OAUTH_CLIENT_ID` → `master_oauth.client_id`
22 | - `MASTER_OAUTH_CLIENT_SECRET` → `master_oauth.client_secret` (stored as `env:MASTER_OAUTH_CLIENT_SECRET`)
23 | - `MASTER_OAUTH_REDIRECT_URI` → `master_oauth.redirect_uri`
24 | - `MASTER_OAUTH_SCOPES` → comma-separated list → `master_oauth.scopes[]`
25 | - `MASTER_OAUTH_AUDIENCE` → `master_oauth.audience`
26 | 
27 | ## Servers (bulk)
28 | 
29 | - `MASTER_SERVERS` → JSON array of servers
30 | - `MASTER_SERVERS_YAML` → YAML array of servers
31 | 
32 | ## Config discovery and env
33 | 
34 | - `MASTER_CONFIG_PATH` → explicit path to YAML/JSON config file
35 | - `MASTER_ENV` / `NODE_ENV` → selects env-specific overrides and affects runtime behavior
36 | 
37 | ## Secrets & Tokens
38 | 
39 | - `MASTER_CONFIG_KEY` (or `MASTER_SECRET_KEY`) → decrypts `enc:gcm:` config values
40 | - `TOKEN_ENC_KEY` → encrypts stored delegated/proxy tokens (REQUIRED in production)
41 | 
42 | See `.env.example` for a template.
43 | 
44 | 
```

--------------------------------------------------------------------------------
/docs/guides/server-sharing.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Server Sharing
 3 | ---
 4 | 
 5 | # Server Sharing
 6 | 
 7 | Expose multiple MCP backends through the master server and share a single, consistent endpoint with your team or applications.
 8 | 
 9 | ## Add Backends
10 | 
11 | Backends are defined in your master config under `servers`.
12 | 
13 | ```yaml
14 | servers:
15 |   - id: search
16 |     type: local
17 |     auth_strategy: master_oauth
18 |     config: { port: 4100 }
19 |   - id: github-tools
20 |     type: local
21 |     auth_strategy: delegate_oauth
22 |     auth_config:
23 |       provider: github
24 |       authorization_endpoint: https://github.com/login/oauth/authorize
25 |       token_endpoint: https://github.com/login/oauth/access_token
26 |       client_id: ${GITHUB_CLIENT_ID}
27 |       client_secret: env:GITHUB_CLIENT_SECRET
28 |       scopes: [repo, read:user]
29 |     config: { port: 4010 }
30 | ```
31 | 
32 | Name collisions are avoided by prefixing capabilities with the server id (e.g., `search.query`, `github-tools.repo.read`).
33 | 
34 | ## Auth Strategies per Server
35 | 
36 | Choose one per server: `master_oauth`, `delegate_oauth`, `proxy_oauth`, `bypass_auth`.
37 | 
38 | <AuthFlowDemo />
39 | 
40 | ## Share the Endpoint
41 | 
42 | - Local: `http://localhost:<port>`
43 | - Docker: container port mapped to host
44 | - Workers: public URL from your deployment
45 | 
46 | Distribute the base URL along with any client token requirements.
47 | 
48 | ## Health Monitoring & Logs
49 | 
50 | - `GET /health` and `GET /metrics`
51 | - Container logs (Docker/Koyeb) or platform logs (Workers)
52 | - Use `performHealthChecks()` from code if embedding the master as a library
53 | 
54 | 
```

--------------------------------------------------------------------------------
/docs/tutorials/oauth-delegation-github.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Tutorial: OAuth Delegation (GitHub)
 2 | 
 3 | Goal: Use delegated OAuth for a backend requiring GitHub OAuth.
 4 | 
 5 | ## 1) Create a GitHub OAuth App
 6 | 
 7 | - Homepage URL: `http://localhost:3000`
 8 | - Authorization callback URL: `http://localhost:3000/oauth/callback`
 9 | 
10 | Record `Client ID` and `Client Secret`.
11 | 
12 | ## 2) Configuration
13 | 
14 | `examples/oauth-node/config.yaml` (provided):
15 | 
16 | ```yaml
17 | hosting:
18 |   platform: node
19 |   port: 3000
20 | 
21 | master_oauth:
22 |   authorization_endpoint: https://example.com/oauth/authorize
23 |   token_endpoint: https://example.com/oauth/token
24 |   client_id: master-mcp
25 |   redirect_uri: http://localhost:3000/oauth/callback
26 |   scopes: [openid]
27 | 
28 | servers:
29 |   - id: github-tools
30 |     type: local
31 |     auth_strategy: delegate_oauth
32 |     auth_config:
33 |       provider: github
34 |       authorization_endpoint: https://github.com/login/oauth/authorize
35 |       token_endpoint: https://github.com/login/oauth/access_token
36 |       client_id: ${GITHUB_CLIENT_ID}
37 |       client_secret: env:GITHUB_CLIENT_SECRET
38 |       scopes: [repo, read:user]
39 |     config:
40 |       port: 4100
41 | ```
42 | 
43 | Set environment variable:
44 | 
45 | ```
46 | export GITHUB_CLIENT_SECRET=... # from GitHub app
47 | ```
48 | 
49 | Run with:
50 | 
51 | ```
52 | MASTER_CONFIG_PATH=examples/oauth-node/config.yaml npm run dev
53 | ```
54 | 
55 | ## 3) Start the Flow
56 | 
57 | Navigate to:
58 | 
59 | ```
60 | http://localhost:3000/oauth/authorize?server_id=github-tools
61 | ```
62 | 
63 | Complete the GitHub consent, then you should see a success page. Calls to tools under `github-tools.*` will now include the delegated token.
64 | 
65 | 
```

--------------------------------------------------------------------------------
/tests/unit/utils.crypto.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import '../setup/test-setup.js'
 2 | import test from 'node:test'
 3 | import assert from 'node:assert/strict'
 4 | import { CryptoUtils } from '../../src/utils/crypto.js'
 5 | 
 6 | test('CryptoUtils encrypt/decrypt roundtrip', () => {
 7 |   const key = 'super-secret-key'
 8 |   const text = 'hello world ' + Date.now()
 9 |   const enc = CryptoUtils.encrypt(text, key)
10 |   assert.ok(typeof enc === 'string' && enc.length > 16)
11 |   const dec = CryptoUtils.decrypt(enc, key)
12 |   assert.equal(dec, text)
13 | })
14 | 
15 | test('CryptoUtils hash/verify', () => {
16 |   const h = CryptoUtils.hash('abc')
17 |   assert.ok(h.length === 64)
18 |   assert.ok(CryptoUtils.verify('abc', h))
19 |   assert.equal(CryptoUtils.verify('abcd', h), false)
20 | })
21 | 
22 | test('CryptoUtils pbkdf2 and scrypt hashing', () => {
23 |   const p = 'password'
24 |   const pb = CryptoUtils.pbkdf2Hash(p, 10_000, 8)
25 |   assert.ok(pb.startsWith('pbkdf2$sha256$'))
26 |   assert.ok(CryptoUtils.pbkdf2Verify(p, pb))
27 |   assert.equal(CryptoUtils.pbkdf2Verify('nope', pb), false)
28 | 
29 |   const sc = CryptoUtils.scryptHash(p, { N: 1024, r: 8, p: 1, saltLen: 8, keyLen: 16 })
30 |   assert.ok(sc.startsWith('scrypt$'))
31 |   assert.ok(CryptoUtils.scryptVerify(p, sc))
32 |   assert.equal(CryptoUtils.scryptVerify('nope', sc), false)
33 | })
34 | 
35 | test('CryptoUtils bcryptHash falls back but verifies', async () => {
36 |   const p = 'topsecret'
37 |   const h = await CryptoUtils.bcryptHash(p)
38 |   assert.ok(typeof h === 'string')
39 |   assert.ok(await CryptoUtils.bcryptVerify(p, h))
40 |   assert.equal(await CryptoUtils.bcryptVerify('nope', h), false)
41 | })
42 | 
43 | 
```

--------------------------------------------------------------------------------
/tests/security/security.oauth-and-input.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import '../setup/test-setup.js'
 2 | import test from 'node:test'
 3 | import assert from 'node:assert/strict'
 4 | import { CallbackHandler } from '../../src/oauth/callback-handler.js'
 5 | import { PKCEManager } from '../../src/oauth/pkce-manager.js'
 6 | import { StateManager } from '../../src/oauth/state-manager.js'
 7 | import { TokenManager, InMemoryTokenStorage } from '../../src/auth/token-manager.js'
 8 | 
 9 | test('CallbackHandler rejects missing/invalid state', async () => {
10 |   const cb = new CallbackHandler({
11 |     config: { master_oauth: { authorization_endpoint: 'http://a', token_endpoint: 'http://t', client_id: 'x', redirect_uri: 'http://l', scopes: ['openid'] }, hosting: { platform: 'node' }, servers: [] } as any,
12 |     stateManager: new StateManager(),
13 |     pkceManager: new PKCEManager(),
14 |     baseUrl: 'http://localhost',
15 |   })
16 |   const res = await cb.handleCallback(new URLSearchParams({ state: 'nope', code: 'x' }), { provider: 'custom', authorization_endpoint: 'http://a', token_endpoint: 'http://t', client_id: 'x' })
17 |   assert.ok(res.error)
18 | })
19 | 
20 | test('TokenManager decryption failure is handled and entry removed', async () => {
21 |   const storage = new InMemoryTokenStorage()
22 |   const tm1 = new TokenManager({ storage, secret: 'a' })
23 |   const tm2 = new TokenManager({ storage, secret: 'b' })
24 |   const key = 'k'
25 |   await tm1.storeToken(key, { access_token: 'X', expires_at: Date.now() + 1000, scope: [] })
26 |   const before = await tm2.getToken(key)
27 |   assert.equal(before, null) // decryption failed => deleted
28 | })
29 | 
30 | 
```

--------------------------------------------------------------------------------
/docs/troubleshooting/index.md:
--------------------------------------------------------------------------------

```markdown
 1 | ---
 2 | title: Common Issues
 3 | ---
 4 | 
 5 | # Troubleshooting: Common Issues
 6 | 
 7 | - Invalid configuration: run `npm run docs:config` and compare with schema.
 8 | - OAuth callback fails: verify redirect URIs, state/PKCE, and client secrets.
 9 | - Workers runtime errors: avoid Node-only APIs; use Web Crypto and Fetch.
10 | - Routing loop or failure: check circuit breaker status and retry limits.
11 | - CORS/Networking: ensure your hosting platform permits required egress.
12 | 
13 | ## FAQ
14 | 
15 | <details>
16 | <summary>How do I connect a GUI client like Claude Desktop?</summary>
17 | 
18 | If your version supports remote/HTTP MCP servers, point it at your master base URL and include any required bearer token. Otherwise, run a light stdio→HTTP bridge that forwards MCP requests to the master’s `/mcp/*` endpoints.
19 | 
20 | </details>
21 | 
22 | <details>
23 | <summary>Why do I get 401/403 responses?</summary>
24 | 
25 | The backend server may require a different token than your client token. Configure `delegate_oauth` or `proxy_oauth` on that backend, then complete the OAuth flow via `/oauth/authorize?server_id=<id>`.
26 | 
27 | </details>
28 | 
29 | <details>
30 | <summary>Tools or resources are missing in the client.</summary>
31 | 
32 | Confirm each backend is healthy and exposes capabilities. Check `/capabilities` and `/mcp/tools/list`. Prefix names with the server id (e.g., `serverId.toolName`).
33 | 
34 | </details>
35 | 
36 | <details>
37 | <summary>Requests time out under load.</summary>
38 | 
39 | Tune retries and circuit breaker thresholds in `routing`, and monitor p95/p99 latencies. See Advanced → Performance & Scalability.
40 | 
41 | </details>
42 | 
43 | 
```

--------------------------------------------------------------------------------
/tests/mocks/mcp/fake-backend.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type http from 'node:http'
 2 | import { createTestServer } from '../../_utils/test-server.js'
 3 | 
 4 | export interface FakeBackendOptions {
 5 |   id: string
 6 |   tools?: Array<{ name: string; description?: string }>
 7 |   resources?: Array<{ uri: string; description?: string; mimeType?: string }>
 8 | }
 9 | 
10 | export async function startFakeMcpBackend(opts: FakeBackendOptions): Promise<{ url: string; stop: () => Promise<void> }> {
11 |   const srv = await createTestServer()
12 |   const tools = opts.tools ?? [{ name: 'echo', description: 'Echo input' }]
13 |   const resources = opts.resources ?? []
14 | 
15 |   srv.register('GET', '/health', () => ({ body: { ok: true } }))
16 |   srv.register('GET', '/capabilities', () => ({ body: { tools, resources } }))
17 |   srv.register('POST', '/mcp/tools/list', () => ({ body: { tools } }))
18 |   srv.register('POST', '/mcp/resources/list', () => ({ body: { resources } }))
19 |   srv.register('POST', '/mcp/tools/call', (_req: http.IncomingMessage, raw) => {
20 |     const body = safeParse(raw)
21 |     if (body?.name === 'echo') return { body: { content: body?.arguments ?? {}, isError: false } }
22 |     return { body: { content: { error: 'unknown tool' }, isError: true } }
23 |   })
24 |   srv.register('POST', '/mcp/resources/read', (_req, raw) => {
25 |     const body = safeParse(raw)
26 |     return { body: { contents: `content:${body?.uri ?? ''}`, mimeType: 'text/plain' } }
27 |   })
28 | 
29 |   return { url: srv.url, stop: srv.close }
30 | }
31 | 
32 | function safeParse(raw?: string): any {
33 |   try { return raw ? JSON.parse(raw) : undefined } catch { return undefined }
34 | }
35 | 
36 | 
```

--------------------------------------------------------------------------------
/docs/getting-started.md:
--------------------------------------------------------------------------------

```markdown
 1 | # Getting Started
 2 | 
 3 | This guide walks you through running Master MCP Server locally, configuring backends, and discovering capabilities.
 4 | 
 5 | ## Prerequisites
 6 | 
 7 | - Node.js >= 18.17
 8 | - npm
 9 | - Network access to install dependencies and reach your OAuth providers/backends
10 | 
11 | ## Install
12 | 
13 | ```
14 | npm ci
15 | ```
16 | 
17 | ## Configure
18 | 
19 | 1) Copy env template and edit as needed:
20 | 
21 | ```
22 | cp .env.example .env
23 | ```
24 | 
25 | 2) Put your configuration in `config/` or pass a YAML/JSON path via `MASTER_CONFIG_PATH`. The built-in schema lives in `config/schema.json` and is also embedded as a fallback.
26 | 
27 | Example minimal YAML (single local server):
28 | 
29 | ```yaml
30 | hosting:
31 |   platform: node
32 |   port: 3000
33 | 
34 | master_oauth:
35 |   authorization_endpoint: https://example.com/oauth/authorize
36 |   token_endpoint: https://example.com/oauth/token
37 |   client_id: master-mcp
38 |   redirect_uri: http://localhost:3000/oauth/callback
39 |   scopes: [openid]
40 | 
41 | servers:
42 |   - id: tools
43 |     type: local
44 |     auth_strategy: bypass_auth
45 |     config:
46 |       port: 3333
47 | ```
48 | 
49 | ## Run Dev Server
50 | 
51 | ```
52 | npm run dev
53 | ```
54 | 
55 | If your config is outside `config/`, set:
56 | 
57 | ```
58 | MASTER_CONFIG_PATH=examples/sample-configs/basic.yaml npm run dev
59 | ```
60 | 
61 | ## Verify
62 | 
63 | - `GET http://localhost:3000/health` → `{ ok: true }`
64 | - `POST http://localhost:3000/mcp/tools/list`
65 | - `POST http://localhost:3000/mcp/resources/list`
66 | 
67 | When calling tools/resources on protected backends, include `Authorization: Bearer <token>`.
68 | 
69 | ## Next Steps
70 | 
71 | - Read `docs/guides/authentication.md` for OAuth flows
72 | - See `examples/*` to run end-to-end scenarios
73 | - Deploy using `docs/deployment/*`
74 | 
75 | 
```

--------------------------------------------------------------------------------
/tests/unit/auth.multi-auth-manager.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import '../setup/test-setup.js'
 2 | import test from 'node:test'
 3 | import assert from 'node:assert/strict'
 4 | import { MultiAuthManager } from '../../src/auth/multi-auth-manager.js'
 5 | import { AuthStrategy } from '../../src/types/config.js'
 6 | 
 7 | const masterCfg = {
 8 |   authorization_endpoint: 'http://localhost/auth',
 9 |   token_endpoint: 'http://localhost/token',
10 |   client_id: 'master',
11 |   redirect_uri: 'http://localhost/cb',
12 |   scopes: ['openid'],
13 | }
14 | 
15 | test('MultiAuthManager pass-through and delegation', async (t) => {
16 |   try {
17 |     const mam = new MultiAuthManager(masterCfg as any)
18 |     mam.registerServerAuth('srv1', AuthStrategy.MASTER_OAUTH)
19 |     const h = await mam.prepareAuthForBackend('srv1', 'CLIENT')
20 |     assert.equal(h.Authorization, 'Bearer CLIENT')
21 | 
22 |     mam.registerServerAuth('srv2', AuthStrategy.DELEGATE_OAUTH, {
23 |       provider: 'custom', authorization_endpoint: 'http://p/auth', token_endpoint: 'http://p/token', client_id: 'c'
24 |     })
25 |     const d = await mam.prepareAuthForBackend('srv2', 'CLIENT') as any
26 |     assert.equal(d.type, 'oauth_delegation')
27 |   } catch (error) {
28 |     console.error('Test failed:', error)
29 |     throw error
30 |   }
31 | })
32 | 
33 | test('MultiAuthManager stores delegated server token', async (t) => {
34 |   try {
35 |     const mam = new MultiAuthManager(masterCfg as any)
36 |     await mam.storeDelegatedToken('CLIENT', 'srv', { access_token: 'S', expires_at: Date.now() + 1000, scope: [] })
37 |     const tok = await mam.getStoredServerToken('srv', 'CLIENT')
38 |     assert.equal(tok, 'S')
39 |   } catch (error) {
40 |     console.error('Test failed:', error)
41 |     throw error
42 |   }
43 | })
44 | 
45 | 
```

--------------------------------------------------------------------------------
/debug-stdio.js:
--------------------------------------------------------------------------------

```javascript
 1 | import { StdioManager } from './src/modules/stdio-manager.js'
 2 | import { Logger } from './src/utils/logger.js'
 3 | 
 4 | // Set logger to debug level
 5 | Logger.configure({ level: 'debug' })
 6 | 
 7 | async function testStdio() {
 8 |   const stdioManager = new StdioManager()
 9 |   const serverId = 'test-stdio-server'
10 |   const filePath = './examples/stdio-mcp-server.cjs'
11 |   
12 |   try {
13 |     console.log('Starting STDIO server...')
14 |     const serverProcess = await stdioManager.startServer(serverId, filePath)
15 |     console.log('STDIO server started successfully:', serverProcess)
16 |     
17 |     // Send a simple request to see if we can communicate
18 |     console.log('Sending initialize request...')
19 |     const initializeRequestId = Date.now()
20 |     const initializeRequest = {
21 |       jsonrpc: "2.0",
22 |       id: initializeRequestId,
23 |       method: "initialize",
24 |       params: {
25 |         protocolVersion: "2025-06-18",
26 |         capabilities: {},
27 |         clientInfo: { 
28 |           name: "debug-script",
29 |           version: "1.0.0"
30 |         }
31 |       }
32 |     }
33 |     
34 |     await stdioManager.sendMessage(serverId, initializeRequest)
35 |     console.log('Initialize request sent')
36 |     
37 |     // Wait for response
38 |     console.log('Waiting for response...')
39 |     const response = await stdioManager.waitForResponse(serverId, initializeRequestId, 5000) // 5 second timeout
40 |     console.log('Received response:', response)
41 |     
42 |     // Stop the server
43 |     console.log('Stopping server...')
44 |     await serverProcess.stop()
45 |     console.log('Server stopped')
46 |   } catch (error) {
47 |     console.error('Error in STDIO test:', error)
48 |   }
49 | }
50 | 
51 | testStdio()
```

--------------------------------------------------------------------------------
/debug-stdio.cjs:
--------------------------------------------------------------------------------

```
 1 | const { StdioManager } = require('./dist/node/modules/stdio-manager.js')
 2 | const { Logger } = require('./dist/node/utils/logger.js')
 3 | 
 4 | // Set logger to debug level
 5 | Logger.configure({ level: 'debug' })
 6 | 
 7 | async function testStdio() {
 8 |   const stdioManager = new StdioManager()
 9 |   const serverId = 'test-stdio-server'
10 |   const filePath = './examples/stdio-mcp-server.cjs'
11 |   
12 |   try {
13 |     console.log('Starting STDIO server...')
14 |     const serverProcess = await stdioManager.startServer(serverId, filePath)
15 |     console.log('STDIO server started successfully:', serverProcess)
16 |     
17 |     // Send a simple request to see if we can communicate
18 |     console.log('Sending initialize request...')
19 |     const initializeRequestId = Date.now()
20 |     const initializeRequest = {
21 |       jsonrpc: "2.0",
22 |       id: initializeRequestId,
23 |       method: "initialize",
24 |       params: {
25 |         protocolVersion: "2025-06-18",
26 |         capabilities: {},
27 |         clientInfo: { 
28 |           name: "debug-script",
29 |           version: "1.0.0"
30 |         }
31 |       }
32 |     }
33 |     
34 |     await stdioManager.sendMessage(serverId, initializeRequest)
35 |     console.log('Initialize request sent')
36 |     
37 |     // Wait for response
38 |     console.log('Waiting for response...')
39 |     const response = await stdioManager.waitForResponse(serverId, initializeRequestId, 5000) // 5 second timeout
40 |     console.log('Received response:', response)
41 |     
42 |     // Stop the server
43 |     console.log('Stopping server...')
44 |     await serverProcess.stop()
45 |     console.log('Server stopped')
46 |   } catch (error) {
47 |     console.error('Error in STDIO test:', error)
48 |   }
49 | }
50 | 
51 | testStdio()
```

--------------------------------------------------------------------------------
/tests/utils/fake-express.ts:
--------------------------------------------------------------------------------

```typescript
 1 | type Handler = (req: any, res: any) => void | Promise<void>
 2 | 
 3 | export class FakeExpressApp {
 4 |   routes: Record<string, { method: 'GET'|'POST'; handler: Handler }> = {}
 5 |   use(_arg: any): void { /* ignore middleware */ }
 6 |   get(path: string, handler: Handler): void { this.routes[`GET ${path}`] = { method: 'GET', handler } }
 7 |   post(path: string, handler: Handler): void { this.routes[`POST ${path}`] = { method: 'POST', handler } }
 8 |   async invoke(method: 'GET'|'POST', path: string, options?: { query?: Record<string,string>, headers?: Record<string,string>, body?: any }) {
 9 |     const key = `${method} ${path}`
10 |     const route = this.routes[key]
11 |     if (!route) throw new Error(`Route not found: ${key}`)
12 |     const req = {
13 |       method,
14 |       query: options?.query ?? {},
15 |       headers: options?.headers ?? {},
16 |       body: options?.body ?? undefined,
17 |       protocol: 'http',
18 |       get: (h: string) => (options?.headers?.[h.toLowerCase()] ?? options?.headers?.[h] ?? undefined),
19 |     }
20 |     let statusCode = 200
21 |     let sentHeaders: Record<string,string> = {}
22 |     let payload: any
23 |     const res = {
24 |       set: (k: string, v: string) => { sentHeaders[k.toLowerCase()] = v },
25 |       status: (c: number) => { statusCode = c; return res },
26 |       send: (b: any) => { payload = b },
27 |       json: (b: any) => { sentHeaders['content-type'] = 'application/json'; payload = JSON.stringify(b) },
28 |       redirect: (loc: string) => { statusCode = 302; sentHeaders['location'] = loc; payload = '' },
29 |     }
30 |     await route.handler(req, res)
31 |     return { status: statusCode, headers: sentHeaders, body: payload }
32 |   }
33 | }
34 | 
35 | 
```

--------------------------------------------------------------------------------
/docs/.vitepress/cache/deps/_metadata.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "hash": "3c026b6f",
 3 |   "configHash": "1d5e3756",
 4 |   "lockfileHash": "b26962c5",
 5 |   "browserHash": "5431331e",
 6 |   "optimized": {
 7 |     "vue": {
 8 |       "src": "../../../../node_modules/vue/dist/vue.runtime.esm-bundler.js",
 9 |       "file": "vue.js",
10 |       "fileHash": "7cfbfc66",
11 |       "needsInterop": false
12 |     },
13 |     "vitepress > @vue/devtools-api": {
14 |       "src": "../../../../node_modules/@vue/devtools-api/dist/index.js",
15 |       "file": "vitepress___@vue_devtools-api.js",
16 |       "fileHash": "89ef8781",
17 |       "needsInterop": false
18 |     },
19 |     "vitepress > @vueuse/core": {
20 |       "src": "../../../../node_modules/@vueuse/core/index.mjs",
21 |       "file": "vitepress___@vueuse_core.js",
22 |       "fileHash": "12a4fb0b",
23 |       "needsInterop": false
24 |     },
25 |     "vitepress > @vueuse/integrations/useFocusTrap": {
26 |       "src": "../../../../node_modules/@vueuse/integrations/useFocusTrap.mjs",
27 |       "file": "vitepress___@vueuse_integrations_useFocusTrap.js",
28 |       "fileHash": "b5a95a87",
29 |       "needsInterop": false
30 |     },
31 |     "vitepress > mark.js/src/vanilla.js": {
32 |       "src": "../../../../node_modules/mark.js/src/vanilla.js",
33 |       "file": "vitepress___mark__js_src_vanilla__js.js",
34 |       "fileHash": "38188df1",
35 |       "needsInterop": false
36 |     },
37 |     "vitepress > minisearch": {
38 |       "src": "../../../../node_modules/minisearch/dist/es/index.js",
39 |       "file": "vitepress___minisearch.js",
40 |       "fileHash": "996cffe0",
41 |       "needsInterop": false
42 |     }
43 |   },
44 |   "chunks": {
45 |     "chunk-P2XGSYO7": {
46 |       "file": "chunk-P2XGSYO7.js"
47 |     },
48 |     "chunk-HVR2FF6M": {
49 |       "file": "chunk-HVR2FF6M.js"
50 |     }
51 |   }
52 | }
```

--------------------------------------------------------------------------------
/tests/e2e/flow-controller.worker.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import '../setup/test-setup.js'
 2 | import test from 'node:test'
 3 | import assert from 'node:assert/strict'
 4 | import { OAuthFlowController } from '../../src/oauth/flow-controller.js'
 5 | import { createMockServer } from '../utils/mock-http.js'
 6 | 
 7 | test('OAuthFlowController Worker-style authorize and callback', async () => {
 8 |   const tokenSrv = await createMockServer([
 9 |     { method: 'POST', path: '/token', handler: () => ({ body: { access_token: 'AT', expires_in: 60, scope: 'openid' } }) },
10 |   ])
11 |   try {
12 |     const cfg = {
13 |       master_oauth: {
14 |         authorization_endpoint: tokenSrv.url + '/authorize',
15 |         token_endpoint: tokenSrv.url + '/token',
16 |         client_id: 'cid',
17 |         redirect_uri: 'http://localhost/oauth/callback',
18 |         scopes: ['openid'],
19 |       },
20 |       hosting: { platform: 'cloudflare-workers', base_url: 'http://localhost' },
21 |       servers: [],
22 |     }
23 |     const ctrl = new OAuthFlowController({ getConfig: () => cfg as any })
24 |     const base = 'http://localhost'
25 |     const authRes = await ctrl.handleRequest(new Request(base + '/oauth/authorize?provider=master', { method: 'GET' }))
26 |     assert.equal(authRes.status, 200)
27 |     const html = await authRes.text()
28 |     const m = html.match(/url=([^"\s]+)/)
29 |     assert.ok(m && m[1])
30 |     const urlStr = m[1].replace(/&amp;/g, '&') // Decode HTML entities
31 |     const state = new URL(urlStr).searchParams.get('state')!
32 |     const cbRes = await ctrl.handleRequest(new Request(base + `/oauth/callback?state=${encodeURIComponent(state)}&code=good&provider=master`, { method: 'GET' }))
33 |     assert.equal(cbRes.status, 200)
34 |   } finally {
35 |     await tokenSrv.close()
36 |   }
37 | })
38 | 
39 | 
```

--------------------------------------------------------------------------------
/tests/unit/oauth.pkce-state.test.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import '../setup/test-setup.js'
 2 | import test from 'node:test'
 3 | import assert from 'node:assert/strict'
 4 | import { PKCEManager } from '../../src/oauth/pkce-manager.js'
 5 | import { StateManager } from '../../src/oauth/state-manager.js'
 6 | import { FlowValidator } from '../../src/oauth/flow-validator.js'
 7 | 
 8 | test('PKCEManager generates and verifies', async () => {
 9 |   const pkce = new PKCEManager({ ttlMs: 1000 })
10 |   const state = 'abc'
11 |   const { challenge, method, verifier } = await pkce.generate(state)
12 |   assert.ok(challenge.length > 16)
13 |   assert.equal(method, 'S256')
14 |   const v = pkce.getVerifier(state)
15 |   assert.equal(v, verifier)
16 |   // consumed; second time should be undefined
17 |   assert.equal(pkce.getVerifier(state), undefined)
18 | })
19 | 
20 | test('StateManager create/consume with TTL', async () => {
21 |   const sm = new StateManager({ ttlMs: 10 })
22 |   const s = sm.create({ provider: 'p', issuedAt: 0 } as any)
23 |   const peek = sm.peek(s)
24 |   assert.ok(peek && peek.provider === 'p')
25 |   const used = sm.consume(s)
26 |   assert.ok(used)
27 |   assert.equal(sm.consume(s), null)
28 | })
29 | 
30 | test('FlowValidator validateReturnTo prevents open redirects', () => {
31 |   const fv = new FlowValidator(() => ({
32 |     master_oauth: {
33 |       authorization_endpoint: 'https://a', token_endpoint: 'https://t', client_id: 'x', redirect_uri: 'http://l', scopes: ['openid']
34 |     }, hosting: { platform: 'node' }, servers: []
35 |   } as any))
36 |   assert.equal(fv.validateReturnTo('http://evil.com', 'http://localhost:3000'), undefined)
37 |   assert.equal(fv.validateReturnTo('http://localhost:3000/path', 'http://localhost:3000'), '/path')
38 |   assert.equal(fv.validateReturnTo('/ok', 'http://x'), '/ok')
39 | })
40 | 
41 | 
```
Page 1/10FirstPrevNextLast