#
tokens: 49607/50000 43/252 files (page 2/8)
lines: off (toggle) GitHub
raw markdown copy
This is page 2 of 8. Use http://codebase.md/jakedismo/master-mcp-server?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

--------------------------------------------------------------------------------
/tests/integration/oauth.callback-handler.test.ts:
--------------------------------------------------------------------------------

```typescript
import '../setup/test-setup.js'
import test from 'node:test'
import assert from 'node:assert/strict'

// Test imports one by one to isolate the issue
console.log('Importing PKCEManager...')
import { PKCEManager } from '../../src/oauth/pkce-manager.js'
console.log('Importing StateManager...')
import { StateManager } from '../../src/oauth/state-manager.js'
console.log('Importing createMockServer...')
import { createMockServer } from '../utils/mock-http.js'
console.log('Importing CallbackHandler...')
import { CallbackHandler } from '../../src/oauth/callback-handler.js'
console.log('All imports successful')

test.skip('CallbackHandler exchanges code and stores token', async () => {
  const tokenSrv = await createMockServer([
    { method: 'POST', path: '/token', handler: (_req, body) => {
      if (body.code === 'good') return { body: { access_token: 'AT', expires_in: 60, scope: 'openid' } }
      return { status: 400, body: { error: 'bad code' } }
    } },
  ])
  try {
    try {
    const pkce = new PKCEManager()
    const stateMgr = new StateManager()
    const state = stateMgr.create({ provider: 'prov', serverId: 'srv', clientToken: 'CT', returnTo: '/done' })
    const { verifier } = await pkce.generate(state)
    // pkce manager consumes verifier on getVerifier(), which CallbackHandler will do
    const cfg: any = {
      master_oauth: { authorization_endpoint: tokenSrv.url + '/auth', token_endpoint: tokenSrv.url + '/token', client_id: 'cid', redirect_uri: tokenSrv.url + '/cb', scopes: ['openid'] },
      hosting: { platform: 'node' },
      servers: [],
    }
    let stored: any
    const cb = new CallbackHandler({ config: cfg, stateManager: stateMgr, pkceManager: pkce, baseUrl: tokenSrv.url, storeDelegatedToken: async (ct, sid, tok) => { stored = { ct, sid, tok } } })
    const res = await cb.handleCallback(new URLSearchParams({ state, code: 'good' }), { provider: 'custom', authorization_endpoint: tokenSrv.url + '/auth', token_endpoint: tokenSrv.url + '/token', client_id: 'cid' })
    assert.ok(res.token)
    assert.equal(stored.ct, 'CT')
    assert.equal(stored.sid, 'srv')
    assert.equal(stored.tok.access_token, 'AT')
    } catch (error) {
      console.error('Test error:', error)
      throw error
    }
  } finally {
    await tokenSrv.close()
  }
})


```

--------------------------------------------------------------------------------
/src/oauth/flow-validator.ts:
--------------------------------------------------------------------------------

```typescript
import type { MasterConfig, ServerAuthConfig } from '../types/config.js'

export interface ProviderResolution {
  providerId: string
  serverId?: string
  config: ServerAuthConfig
}

export class FlowValidator {
  constructor(private readonly getConfig: () => MasterConfig) {}

  resolveProvider(params: { provider?: string | null; serverId?: string | null }): ProviderResolution {
    const cfg = this.getConfig()
    const provider = params.provider ?? undefined
    const serverId = params.serverId ?? undefined

    if (!provider && !serverId) {
      return {
        providerId: 'master',
        config: {
          provider: 'custom',
          authorization_endpoint: cfg.master_oauth.authorization_endpoint,
          token_endpoint: cfg.master_oauth.token_endpoint,
          client_id: cfg.master_oauth.client_id,
          client_secret: cfg.master_oauth.client_secret,
          scopes: cfg.master_oauth.scopes,
        },
      }
    }

    if (provider === 'master') {
      return {
        providerId: 'master',
        config: {
          provider: 'custom',
          authorization_endpoint: cfg.master_oauth.authorization_endpoint,
          token_endpoint: cfg.master_oauth.token_endpoint,
          client_id: cfg.master_oauth.client_id,
          client_secret: cfg.master_oauth.client_secret,
          scopes: cfg.master_oauth.scopes,
        },
      }
    }

    if (serverId) {
      const server = cfg.servers.find((s) => s.id === serverId)
      if (!server || !server.auth_config) throw new Error('Unknown server or missing auth configuration')
      return { providerId: provider ?? serverId, serverId, config: server.auth_config }
    }

    const pre = cfg.oauth_delegation?.providers?.[String(provider)]
    if (!pre) throw new Error('Unknown provider')
    return { providerId: String(provider), config: pre }
  }

  validateReturnTo(returnTo: string | null | undefined, baseUrl?: string): string | undefined {
    if (!returnTo) return undefined
    try {
      // Allow relative paths only, or same-origin absolute if matches baseUrl
      if (returnTo.startsWith('/')) return returnTo
      if (baseUrl) {
        const origin = new URL(baseUrl).origin
        const u = new URL(returnTo)
        if (u.origin === origin) return u.pathname + u.search + u.hash
      }
      return undefined
    } catch {
      return undefined
    }
  }
}


```

--------------------------------------------------------------------------------
/docs/guides/client-integration.md:
--------------------------------------------------------------------------------

```markdown
---
title: Client Integration
---

# Client Integration

Connect your MCP clients to the Master MCP Server and verify end-to-end flows.

> Note: The Master MCP Server exposes HTTP endpoints for tools and resources (e.g., `/mcp/tools/call`). Custom clients can integrate directly over HTTP. For GUI clients like Claude Desktop, support for HTTP/remote servers may vary by version. If direct HTTP is unsupported, consider a small bridge (stdio → HTTP) or use the Node runtime directly inside your app.

## Custom Clients (HTTP)

Use any HTTP-capable client. Examples below:

```bash
curl -s -H 'content-type: application/json' \
  -X POST http://localhost:3000/mcp/tools/list -d '{"type":"list_tools"}'
```

Node (fetch):

```ts
import fetch from 'node-fetch'
const res = await fetch('http://localhost:3000/mcp/tools/call', {
  method: 'POST',
  headers: { 'content-type': 'application/json', authorization: 'Bearer YOUR_CLIENT_TOKEN' },
  body: JSON.stringify({ name: 'search.query', arguments: { q: 'hello' } })
})
console.log(await res.json())
```

See also: Getting Started → Quick Start and the <ApiPlayground /> on the landing page.

## Claude Desktop (Guidance)

Claude Desktop supports MCP servers via configuration. The exact configuration and supported transports can change; consult the latest Claude Desktop documentation.

Two approaches:

- If your Claude Desktop version supports remote/HTTP MCP servers, configure it to point at your master base URL (e.g., `http://localhost:3000`) and include a bearer token if required.
- Otherwise, run a small stdio bridge that speaks MCP to the client and forwards requests to the master HTTP endpoints. The bridge should:
  - Respond to tool/resource listing using the master’s `/mcp/*/list` endpoints
  - Forward tool calls and resource reads to `/mcp/tools/call` and `/mcp/resources/read`
  - Map names like `serverId.toolName` consistently

> Tip: Keep your bridge stateless. Let the master handle routing, retries, and auth strategies.

## Testing Connections

- Health: `GET /health` → `{ ok: true }`
- Capabilities: `GET /capabilities` → aggregated tools/resources
- Tools/Resources: use the POST endpoints under `/mcp/*`

## Troubleshooting

- 401/403: ensure your Authorization header is present and matches backend expectations.
- Missing tools/resources: confirm the backend servers are healthy and listed in config.
- Delegated OAuth required: follow the flow at `/oauth/authorize?server_id=<id>`.


```

--------------------------------------------------------------------------------
/tests/mocks/oauth/mock-oidc-provider.ts:
--------------------------------------------------------------------------------

```typescript
import { createTestServer } from '../../_utils/test-server.js'

export interface MockOidcOptions {
  issuer?: string
  clientId?: string
  clientSecret?: string
  scopes?: string[]
}

export async function startMockOidcProvider(opts?: MockOidcOptions): Promise<{
  issuer: string
  authorization_endpoint: string
  token_endpoint: string
  jwks_uri: string
  stop: () => Promise<void>
}> {
  const srv = await createTestServer()
  const issuer = opts?.issuer ?? `${srv.url}`
  const clientId = opts?.clientId ?? 'test-client'
  const scopes = opts?.scopes ?? ['openid', 'profile']

  const codeStore = new Map<string, { scope: string[] }>()

  // OIDC Discovery
  srv.register('GET', '/.well-known/openid-configuration', () => ({
    body: {
      issuer,
      authorization_endpoint: `${issuer}/authorize`,
      token_endpoint: `${issuer}/token`,
      jwks_uri: `${issuer}/jwks.json`,
      response_types_supported: ['code'],
      grant_types_supported: ['authorization_code', 'refresh_token'],
    },
  }))

  // Simplified authorize: immediately redirects back with code + state
  srv.register('GET', '/authorize', (_req, _raw) => {
    const url = new URL(_req.url || '/', issuer)
    const redirectUri = url.searchParams.get('redirect_uri') || ''
    const state = url.searchParams.get('state') || ''
    const scopeStr = url.searchParams.get('scope') || scopes.join(' ')
    const code = `code_${Math.random().toString(36).slice(2)}`
    codeStore.set(code, { scope: scopeStr.split(/[ ,]+/).filter(Boolean) })
    return {
      status: 302,
      headers: { location: `${redirectUri}?code=${encodeURIComponent(code)}&state=${encodeURIComponent(state)}` },
    }
  })

  // Token endpoint
  srv.register('POST', '/token', (_req, raw) => {
    const params = new URLSearchParams(raw || '')
    const code = params.get('code') || ''
    const rec = codeStore.get(code)
    if (!rec) return { status: 400, body: { error: 'invalid_grant' } }
    // Minimal token response
    return {
      body: {
        access_token: `at_${code}`,
        token_type: 'bearer',
        scope: rec.scope.join(' '),
        expires_in: 3600,
      },
    }
  })

  // Static JWKS (not strictly needed for current code paths)
  srv.register('GET', '/jwks.json', () => ({ body: { keys: [] } }))

  return {
    issuer,
    authorization_endpoint: `${issuer}/authorize`,
    token_endpoint: `${issuer}/token`,
    jwks_uri: `${issuer}/jwks.json`,
    stop: srv.close,
  }
}


```

--------------------------------------------------------------------------------
/examples/test-mcp-server.js:
--------------------------------------------------------------------------------

```javascript
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import express from 'express'
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'

// Create a simple test MCP server
const server = new McpServer({
  name: 'test-mcp-server',
  version: '1.0.0'
}, {
  capabilities: {
    tools: { listChanged: true },
    resources: { listChanged: true }
  }
})

// Register a simple tool
server.tool('echo', 'Echoes back the input', { message: { type: 'string' } }, async (args) => {
  return {
    content: [{
      type: 'text',
      text: `Echo: ${args.message}`
    }]
  }
})

// Register a simple resource
server.resource('test-resource', 'test://example', { description: 'A test resource' }, async () => {
  return {
    contents: [{
      uri: 'test://example',
      text: 'This is a test resource'
    }]
  }
})

// Create an Express app
const app = express()
app.use(express.json())

// Create the HTTP streaming transport
const transport = new StreamableHTTPServerTransport({
  sessionIdGenerator: undefined, // Stateless mode
  enableJsonResponse: false, // Use SSE by default
  enableDnsRebindingProtection: false
})

// Connect the server to the transport
await server.connect(transport)

// Handle MCP requests
app.post('/mcp', async (req, res) => {
  try {
    await transport.handleRequest(req, res, req.body)
  } catch (error) {
    console.error('MCP request handling failed', { error })
    res.status(500).json({
      error: 'Internal server error'
    })
  }
})

app.get('/mcp', async (req, res) => {
  try {
    await transport.handleRequest(req, res)
  } catch (error) {
    console.error('MCP request handling failed', { error })
    res.status(500).json({
      error: 'Internal server error'
    })
  }
})

// Expose the capabilities endpoint
app.get('/capabilities', (req, res) => {
  res.json({
    tools: [
      {
        name: 'echo',
        description: 'Echoes back the input',
        inputSchema: {
          type: 'object',
          properties: {
            message: {
              type: 'string'
            }
          },
          required: ['message']
        }
      }
    ],
    resources: [
      {
        uri: 'test://example',
        name: 'test-resource',
        description: 'A test resource'
      }
    ]
  })
})

// Start the server
const port = process.env.PORT || 3006
app.listen(port, () => {
  console.log(`Test MCP server listening on http://localhost:${port}`)
})
```

--------------------------------------------------------------------------------
/tests/servers/test-mcp-client.js:
--------------------------------------------------------------------------------

```javascript
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'

async function runTest() {
  try {
    console.log('Testing Master MCP Server...')
    
    // Create a streamable HTTP transport to connect to our MCP server
    const transport = new StreamableHTTPClientTransport(new URL('http://localhost:3005/mcp'))
    
    // Create the MCP client
    const client = new Client({
      name: 'test-client',
      version: '1.0.0'
    })
    
    // Initialize the client
    await client.connect(transport)
    console.log('✅ Server initialized')
    console.log('Server info:', client.getServerVersion())
    console.log('Server capabilities:', client.getServerCapabilities())
    
    // List tools
    console.log('\n--- Testing tools/list ---')
    const toolsResult = await client.listTools({})
    console.log('✅ tools/list successful')
    console.log('Number of tools:', toolsResult.tools.length)
    console.log('Tools:', toolsResult.tools.map(t => t.name))
    
    // List resources
    console.log('\n--- Testing resources/list ---')
    const resourcesResult = await client.listResources({})
    console.log('✅ resources/list successful')
    console.log('Number of resources:', resourcesResult.resources.length)
    console.log('Resources:', resourcesResult.resources.map(r => r.uri))
    
    // Test the health endpoint
    console.log('\n--- Testing health endpoint ---')
    try {
      const response = await fetch('http://localhost:3005/health')
      const health = await response.json()
      console.log('✅ Health endpoint successful')
      console.log('Health status:', health)
    } catch (error) {
      console.log('⚠️ Health endpoint test failed:', error.message)
    }
    
    // Test the metrics endpoint
    console.log('\n--- Testing metrics endpoint ---')
    try {
      const response = await fetch('http://localhost:3005/metrics')
      const metrics = await response.json()
      console.log('✅ Metrics endpoint successful')
      console.log('Metrics:', metrics)
    } catch (error) {
      console.log('⚠️ Metrics endpoint test failed:', error.message)
    }
    
    // Close the connection
    await client.close()
    console.log('\n✅ Disconnected from MCP server')
    console.log('\n🎉 All tests completed successfully!')
    
  } catch (error) {
    console.error('❌ Test failed:', error)
    console.error('Error stack:', error.stack)
  }
}

// Run the test
runTest()
```

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

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://example.com/master-mcp-config.schema.json",
  "type": "object",
  "required": ["master_oauth", "hosting", "servers"],
  "properties": {
    "master_oauth": {
      "type": "object",
      "required": ["authorization_endpoint", "token_endpoint", "client_id", "redirect_uri", "scopes"],
      "properties": {
        "issuer": { "type": "string" },
        "authorization_endpoint": { "type": "string" },
        "token_endpoint": { "type": "string" },
        "jwks_uri": { "type": "string" },
        "client_id": { "type": "string" },
        "client_secret": { "type": "string" },
        "redirect_uri": { "type": "string" },
        "scopes": { "type": "array", "items": { "type": "string" } },
        "audience": { "type": "string" }
      },
      "additionalProperties": true
    },
    "hosting": {
      "type": "object",
      "required": ["platform", "base_url"],
      "properties": {
        "platform": { "type": "string", "enum": ["node", "cloudflare-workers", "koyeb", "docker", "unknown"] },
        "port": { "type": "number" },
        "base_url": { "type": "string" },
        "storage_backend": { "type": "string" }
      },
      "additionalProperties": true
    },
    "logging": { "type": "object", "properties": { "level": { "type": "string", "enum": ["debug", "info", "warn", "error"] } } },
    "routing": { "type": "object", "additionalProperties": true },
    "security": { "type": "object", "additionalProperties": true },
    "servers": {
      "type": "array",
      "items": {
        "type": "object",
        "required": ["id", "type", "auth_strategy", "config"],
        "properties": {
          "id": { "type": "string" },
          "type": { "type": "string", "enum": ["git", "npm", "pypi", "docker", "local"] },
          "url": { "type": "string" },
          "package": { "type": "string" },
          "version": { "type": "string" },
          "branch": { "type": "string" },
          "auth_strategy": { "type": "string", "enum": ["master_oauth", "delegate_oauth", "bypass_auth", "proxy_oauth"] },
          "auth_config": { "type": "object", "additionalProperties": true },
          "config": {
            "type": "object",
            "properties": {
              "environment": { "type": "object", "additionalProperties": true },
              "args": { "type": "array", "items": { "type": "string" } },
              "port": { "type": "integer" }
            },
            "additionalProperties": true
          }
        },
        "additionalProperties": true
      }
    }
  },
  "additionalProperties": true
}


```

--------------------------------------------------------------------------------
/src/utils/string.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * String manipulation and parsing utilities.
 */

export function slugify(input: string): string {
  return input
    .normalize('NFKD')
    .replace(/[\u0300-\u036f]/g, '')
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/(^-|-$)+/g, '')
}

export function toCamelCase(input: string): string {
  return input
    .replace(/[-_\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))
    .replace(/^(.)/, (m) => m.toLowerCase())
}

export function toKebabCase(input: string): string {
  return input
    .replace(/([a-z])([A-Z])/g, '$1-$2')
    .replace(/[\s_]+/g, '-')
    .toLowerCase()
}

export function toSnakeCase(input: string): string {
  return input
    .replace(/([a-z])([A-Z])/g, '$1_$2')
    .replace(/[\s-]+/g, '_')
    .toLowerCase()
}

export function escapeHTML(input: string): string {
  return input
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;')
}

export function escapeRegExp(input: string): string {
  return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}

export function joinUrlPaths(...parts: string[]): string {
  const sanitized = parts.filter(Boolean).map((p) => p.replace(/(^\/+|\/+?$)/g, ''))
  const joined = sanitized.join('/')
  return `/${joined}`.replace(/\/+$/g, '') || '/'
}

export function trimSafe(input: unknown): string {
  return String(input ?? '').trim()
}

export function truncateMiddle(input: string, maxLength: number): string {
  if (input.length <= maxLength) return input
  if (maxLength <= 3) return input.slice(0, maxLength)
  const keep = Math.floor((maxLength - 3) / 2)
  return `${input.slice(0, keep)}...${input.slice(-keep)}`
}

export function toBase64(input: string): string {
  if (typeof btoa === 'function') return btoa(input)
  return Buffer.from(input, 'utf8').toString('base64')
}

export function fromBase64(input: string): string {
  if (typeof atob === 'function') return atob(input)
  return Buffer.from(input, 'base64').toString('utf8')
}

export function stableJSONStringify(value: unknown): string {
  return JSON.stringify(sortKeys(value))
}

function sortKeys(value: any): any {
  if (Array.isArray(value)) return value.map(sortKeys)
  if (value && typeof value === 'object') {
    const out: Record<string, any> = {}
    for (const key of Object.keys(value).sort()) out[key] = sortKeys(value[key])
    return out
  }
  return value
}

export function parseBoolean(input: unknown, defaultValue = false): boolean {
  const s = String(input ?? '').trim().toLowerCase()
  if (s === 'true' || s === '1' || s === 'yes' || s === 'y') return true
  if (s === 'false' || s === '0' || s === 'no' || s === 'n') return false
  return defaultValue
}

export function normalizeUrl(input: string): string {
  try {
    const u = new URL(input)
    u.hash = ''
    return u.toString()
  } catch {
    return input
  }
}


```

--------------------------------------------------------------------------------
/tests/integration/request-router.test.ts:
--------------------------------------------------------------------------------

```typescript
import '../setup/test-setup.js'
import test from 'node:test'
import assert from 'node:assert/strict'
import { RequestRouter } from '../../src/modules/request-router.js'
import { CapabilityAggregator } from '../../src/modules/capability-aggregator.js'
import { createMockServer } from '../utils/mock-http.js'

test('RequestRouter routes tool/resource with pass-through auth', async () => {
  const sOk = await createMockServer([
    { method: 'POST', path: '/mcp/tools/call', handler: (_req, body) => ({ body: { content: { ok: true, args: body.arguments } } }) },
    { method: 'POST', path: '/mcp/resources/read', handler: (_req, body) => ({ body: { contents: `read:${body.uri}`, mimeType: 'text/plain' } }) },
  ])
  try {
    const servers = new Map<string, any>([[
      's1', { id: 's1', type: 'node', endpoint: sOk.url, config: {} as any, status: 'running', lastHealthCheck: 0 }
    ]])
    const rr = new RequestRouter(servers as any, new CapabilityAggregator(), async (_sid, token) => token ? ({ Authorization: `Bearer ${token}` }) : undefined)
    const toolRes = await rr.routeCallTool({ name: 's1.echo', arguments: { a: 1 } }, 'CT')
    assert.equal((toolRes as any).content.ok, true)
    const readRes = await rr.routeReadResource({ uri: 's1.file' }, 'CT')
    assert.equal((readRes as any).contents, 'read:file')
  } finally {
    await sOk.close()
  }
})

test('RequestRouter returns delegation error when provider requires', async () => {
  const s = await createMockServer([
    { method: 'POST', path: '/mcp/tools/call', handler: (_req, _body) => ({ body: { content: { ok: true } } }) },
  ])
  try {
    const servers = new Map<string, any>([[ 's1', { id: 's1', type: 'node', endpoint: s.url, config: {} as any, status: 'running', lastHealthCheck: 0 } ]])
    const rr = new RequestRouter(servers as any, new CapabilityAggregator(), async () => ({ type: 'oauth_delegation', auth_endpoint: 'x', token_endpoint: 'y', client_info: {}, required_scopes: [], redirect_after_auth: true } as any))
    const res = await rr.routeCallTool({ name: 's1.x' }, 'CT')
    assert.equal((res as any).isError, true)
  } finally {
    await s.close()
  }
})

test('RequestRouter retries on transient failure and eventually succeeds', async () => {
  let n = 0
  const s = await createMockServer([
    { method: 'POST', path: '/mcp/tools/call', handler: () => {
      n++
      if (n < 3) return { status: 500, body: { error: 'boom' } }
      return { body: { content: { ok: true } } }
    } },
  ])
  try {
    const servers = new Map<string, any>([[ 's1', { id: 's1', type: 'node', endpoint: s.url, config: {} as any, status: 'running', lastHealthCheck: 0 } ]])
    const rr = new RequestRouter(servers as any, new CapabilityAggregator())
    const res = await rr.routeCallTool({ name: 's1.task' })
    // @ts-ignore
    assert.equal(res.content.ok, true)
  } finally {
    await s.close()
  }
})

```

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

```vue
<template>
  <div class="mcp-callout" style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
    <label>Endpoint
      <select v-model="endpoint" style="margin-left:8px">
        <option value="tools.list">POST /mcp/tools/list</option>
        <option value="tools.call">POST /mcp/tools/call</option>
        <option value="resources.list">POST /mcp/resources/list</option>
        <option value="resources.read">POST /mcp/resources/read</option>
      </select>
    </label>
    <label>Base URL <input v-model="baseUrl" placeholder="http://localhost:3000" /></label>
    <label>Token <input v-model="token" placeholder="optional bearer" /></label>
  </div>

  <div class="mcp-grid">
    <div class="mcp-col-6">
      <h4>Request Body</h4>
      <textarea v-model="body" rows="10" style="width:100%;font-family:var(--vp-font-family-mono)"></textarea>
    </div>
    <div class="mcp-col-6">
      <h4>curl</h4>
      <pre><code>{{ curl }}</code></pre>
      <h4 style="margin-top:10px">Node (fetch)</h4>
      <pre><code class="language-ts">{{ node }}</code></pre>
    </div>
  </div>
  <p style="color:var(--vp-c-text-2);font-size:.9rem;margin-top:6px">Note: This playground does not perform live requests in the docs site; copy commands to run locally.</p>
</template>

<script setup lang="ts">
import { computed, ref, watch } from 'vue'

const endpoint = ref<'tools.list'|'tools.call'|'resources.list'|'resources.read'>('tools.list')
const baseUrl = ref('http://localhost:3000')
const token = ref('')
const body = ref('')

const defaultBodies: Record<string, string> = {
  'tools.list': JSON.stringify({ type: 'list_tools' }, null, 2),
  'tools.call': JSON.stringify({ name: 'serverId.toolName', arguments: { query: 'hello' } }, null, 2),
  'resources.list': JSON.stringify({ type: 'list_resources' }, null, 2),
  'resources.read': JSON.stringify({ uri: 'serverId:resourceId' }, null, 2)
}

watch(endpoint, (v) => { body.value = defaultBodies[v] })
body.value = defaultBodies[endpoint.value]

const path = computed(() => {
  switch (endpoint.value) {
    case 'tools.list': return '/mcp/tools/list'
    case 'tools.call': return '/mcp/tools/call'
    case 'resources.list': return '/mcp/resources/list'
    case 'resources.read': return '/mcp/resources/read'
  }
})

const curl = computed(() => {
  const headers = ["-H 'content-type: application/json'"]
  if (token.value) headers.push(`-H 'authorization: Bearer ${token.value}'`)
  return `curl -s ${headers.join(' ')} -X POST ${baseUrl.value}${path.value} -d '${body.value.replace(/'/g, "'\\''")}'`
})

const node = computed(() => `import fetch from 'node-fetch'

const res = await fetch('${baseUrl.value}${path.value}', {
  method: 'POST',
  headers: {
    'content-type': 'application/json'${token.value ? ",\n    authorization: 'Bearer " + token.value + "'" : ''}
  },
  body: JSON.stringify(${body.value})
})
const data = await res.json()
console.log(data)
`)
</script>


```

--------------------------------------------------------------------------------
/src/oauth/pkce-manager.ts:
--------------------------------------------------------------------------------

```typescript
// PKCE (Proof Key for Code Exchange) manager with cross-platform support
// Generates code_verifier and S256 code_challenge and tracks them per state

export interface PkceRecord {
  verifier: string
  method: 'S256' | 'plain'
  createdAt: number
  expiresAt: number
}

export interface PkceManagerOptions {
  ttlMs?: number
}

function getCrypto(): any {
  const g: any = globalThis as any
  if (g.crypto && g.crypto.subtle && g.crypto.getRandomValues) return g.crypto as any
  // Node fallback
  try {
    // eslint-disable-next-line @typescript-eslint/no-var-requires
    const nodeCrypto = require('node:crypto')
    return nodeCrypto.webcrypto as any
  } catch {
    throw new Error('Secure crypto not available in this environment')
  }
}

function base64UrlEncode(bytes: Uint8Array): string {
  let str = ''
  for (let i = 0; i < bytes.length; i++) str += String.fromCharCode(bytes[i])
  // btoa is available in browser/worker; Node 18 has global btoa via Buffer workaround
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  // @ts-ignore
  const b64 = typeof btoa === 'function' ? btoa(str) : Buffer.from(bytes).toString('base64')
  return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '')
}

function randomString(length = 64): string {
  const crypto = getCrypto()
  const bytes = new Uint8Array(length)
  crypto.getRandomValues(bytes)
  // Allowed characters for verifier are [A-Z a-z 0-9 - . _ ~]
  const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~'
  let out = ''
  for (let i = 0; i < length; i++) out += chars[bytes[i] % chars.length]
  return out
}

export class PKCEManager {
  private readonly store = new Map<string, PkceRecord>()
  private readonly ttl: number

  constructor(options?: PkceManagerOptions) {
    this.ttl = options?.ttlMs ?? 10 * 60_000 // 10 minutes
  }

  async generate(state: string): Promise<{ challenge: string; method: 'S256'; verifier: string }> {
    const verifier = randomString(64)
    const challenge = await this.computeS256(verifier)
    const now = Date.now()
    this.store.set(state, {
      verifier,
      method: 'S256',
      createdAt: now,
      expiresAt: now + this.ttl,
    })
    return { challenge, method: 'S256', verifier }
  }

  getVerifier(state: string, consume = true): string | undefined {
    const rec = this.store.get(state)
    if (!rec) return undefined
    if (rec.expiresAt <= Date.now()) {
      this.store.delete(state)
      return undefined
    }
    if (consume) this.store.delete(state)
    return rec.verifier
  }

  cleanup(): void {
    const now = Date.now()
    for (const [k, v] of this.store) if (v.expiresAt <= now) this.store.delete(k)
  }

  private async computeS256(verifier: string): Promise<string> {
    const crypto = getCrypto()
    const enc = new TextEncoder().encode(verifier)
    const digest = await crypto.subtle.digest('SHA-256', enc)
    return base64UrlEncode(new Uint8Array(digest))
  }
}

```

--------------------------------------------------------------------------------
/scripts/generate-config-docs.ts:
--------------------------------------------------------------------------------

```typescript
/*
 * Generates docs/configuration/reference.md from the built-in JSON schema
 * and enriches with examples from examples/sample-configs.
 */
import { SchemaValidator } from '../src/config/schema-validator.js'
import { promises as fs } from 'node:fs'
import path from 'node:path'

type JSONSchema = any

async function main() {
  const schema: JSONSchema | undefined = await SchemaValidator.loadSchema()
  if (!schema) throw new Error('Unable to load configuration schema')

  const examplesDir = path.resolve('examples/sample-configs')
  const exampleFiles = await fs.readdir(examplesDir)
  const exampleSnippets: string[] = []
  for (const f of exampleFiles) {
    if (!f.endsWith('.yaml') && !f.endsWith('.yml')) continue
    const content = await fs.readFile(path.join(examplesDir, f), 'utf8')
    exampleSnippets.push(`## Example: ${f}\n\n\u0060\u0060\u0060yaml\n${content}\n\u0060\u0060\u0060\n`)
  }

  const lines: string[] = []
  lines.push('# Configuration Reference')
  lines.push('')
  lines.push('This reference is generated from the built-in JSON Schema used by the server to validate configuration.')
  lines.push('')
  lines.push('## Top-Level Fields')
  lines.push('')
  lines.push(renderObject(schema))
  lines.push('')
  lines.push('## Examples')
  lines.push('')
  lines.push(exampleSnippets.join('\n'))

  const target = path.resolve('docs/configuration/reference.md')
  const contents = await fs.readFile(target, 'utf8').catch(() => '')
  const start = '<!-- GENERATED:BEGIN -->'
  const end = '<!-- GENERATED:END -->'
  const prefix = contents.split(start)[0] ?? ''
  const suffix = contents.split(end)[1] ?? ''
  const generated = `${start}\n\n${lines.join('\n')}\n\n${end}`
  const next = `${prefix}${generated}${suffix}`
  await fs.writeFile(target, next, 'utf8')
}

function renderObject(schema: JSONSchema, indent = 0, name?: string): string {
  const pad = '  '.repeat(indent)
  if (!schema || typeof schema !== 'object') return ''
  let s = ''
  if (schema.type === 'object' || schema.properties) {
    const required = new Set<string>((schema.required || []) as string[])
    for (const [key, value] of Object.entries(schema.properties || {})) {
      const req = required.has(key) ? ' (required)' : ''
      s += `${pad}- \`${name ? name + '.' : ''}${key}\`${req}${renderType(value)}\n`
      if ((value as any).properties || (value as any).items) {
        s += renderObject(value, indent + 1, name ? `${name}.${key}` : key)
      }
    }
  }
  if (schema.items) {
    s += `${pad}  - items:${renderType(schema.items)}\n`
    s += renderObject(schema.items, indent + 2, name ? `${name}[]` : '[]')
  }
  return s
}

function renderType(schema: JSONSchema): string {
  const t = Array.isArray(schema.type) ? schema.type.join('|') : schema.type
  const enumVals = schema.enum ? `, enum: ${schema.enum.join(', ')}` : ''
  const fmt = schema.format ? `, format: ${schema.format}` : ''
  return t ? ` — type: ${t}${enumVals}${fmt}` : `${enumVals}${fmt}`
}

main().catch((err) => {
  console.error(err)
  process.exitCode = 1
})


```

--------------------------------------------------------------------------------
/src/server/dependency-container.ts:
--------------------------------------------------------------------------------

```typescript
import { ConfigManager } from './config-manager.js'
import { DefaultModuleLoader } from '../modules/module-loader.js'
import { CapabilityAggregator } from '../modules/capability-aggregator.js'
import { RequestRouter } from '../modules/request-router.js'
import { ProtocolHandler } from './protocol-handler.js'
import { MasterServer } from './master-server.js'
import { MultiAuthManager } from '../auth/multi-auth-manager.js'
import type { MasterConfig, ServerConfig } from '../types/config.js'
import { Logger } from '../utils/logger.js'

export class DependencyContainer {
  readonly configManager: ConfigManager
  readonly loader: DefaultModuleLoader
  readonly aggregator: CapabilityAggregator
  readonly master: MasterServer
  readonly authManager: MultiAuthManager
  readonly router: RequestRouter
  readonly handler: ProtocolHandler

  private config!: MasterConfig

  constructor() {
    this.configManager = new ConfigManager({ watch: true })
    this.loader = new DefaultModuleLoader()
    this.aggregator = new CapabilityAggregator()
    // Create a temporary router for early wiring; will be replaced after config load
    this.router = new RequestRouter(new Map(), this.aggregator)
    this.master = new MasterServer(undefined, undefined)
    // Temporarily construct auth manager with placeholder; will be replaced after config
    this.authManager = new MultiAuthManager({
      authorization_endpoint: 'about:blank',
      token_endpoint: 'about:blank',
      client_id: 'placeholder',
      redirect_uri: 'about:blank',
      scopes: ['openid'],
    })
    this.handler = this.master.handler
  }

  async initialize(clientToken?: string): Promise<void> {
    this.config = await this.configManager.load()
    // Recreate auth manager with real config
    const auth = new MultiAuthManager(this.config.master_oauth)
    this.registerServerAuth(auth, this.config.servers)
    this.master.attachAuthManager(auth)
    ;(this as any).authManager = auth

    // Load servers and discover capabilities
    await this.master.startFromConfig(this.config, clientToken)
    this.master.updateRouting(this.config.routing)

    // Recreate router/handler references for easy access
    ;(this as any).router = this.master.getRouter()
    ;(this as any).handler = this.master.handler

    // Watch for config changes and hot-reload
    this.configManager.onChange(async (cfg) => {
      try {
        Logger.info('Applying updated configuration to MasterServer')
        this.config = cfg
        this.registerServerAuth(this.authManager, cfg.servers)
        await this.master.loadServers(cfg.servers)
        await this.master.discoverAllCapabilities()
        this.master.updateRouting(cfg.routing)
      } catch (err) {
        Logger.warn('Failed to apply updated config', err)
      }
    })
  }

  getConfig(): MasterConfig {
    return this.config
  }

  private registerServerAuth(manager: MultiAuthManager, servers: ServerConfig[]): void {
    for (const s of servers) {
      try {
        manager.registerServerAuth(s.id, s.auth_strategy, s.auth_config)
      } catch (err) {
        Logger.warn(`Failed to register auth for server ${s.id}`, err)
      }
    }
  }
}


```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "master-mcp-server",
  "version": "0.1.0",
  "private": true,
  "description": "Master MCP Server that aggregates multiple MCP servers behind a single endpoint.",
  "license": "UNLICENSED",
  "type": "module",
  "engines": {
    "node": ">=18.17"
  },
  "scripts": {
    "prepare": "husky install || true",
    "clean": "rimraf dist .turbo tsconfig.tsbuildinfo",
    "typecheck": "tsc -p tsconfig.node.json --noEmit",
    "build": "npm run build:node && npm run build:worker",
    "build:node": "tsc -p tsconfig.node.json",
    "build:worker": "tsc -p tsconfig.worker.json",
    "dev": "node --loader ts-node/esm src/index.ts",
    "dev:watch": "nodemon --watch src --ext ts,tsx,json --exec 'node --loader ts-node/esm src/index.ts'",
    "start": "node dist/node/index.js",
    "start:prod": "NODE_ENV=production node dist/node/index.js",
    "lint": "eslint --config .eslintrc.cjs . --ext .ts,.tsx",
    "format": "prettier --write .",
    "test": "NODE_V8_COVERAGE=.coverage node --loader ts-node/esm --test",
    "test:unit": "node --loader ts-node/esm --test tests/unit/**/*.test.ts",
    "test:integration": "node --loader ts-node/esm --test tests/integration/**/*.test.ts",
    "test:e2e": "node --loader ts-node/esm --test tests/e2e/**/*.test.ts",
    "test:perf": "node --loader ts-node/esm --test tests/perf/**/*.test.ts",
    "test:security": "node --loader ts-node/esm --test tests/security/**/*.test.ts",
    "test:watch": "node --loader ts-node/esm --test --watch",
    "test:mcp": "node --loader ts-node/esm test-master-mcp.js",
    "test:streaming": "node --loader ts-node/esm tests/servers/test-streaming.js",
    "test:streaming-both": "node --loader ts-node/esm tests/servers/test-streaming-both.js",
    "test:streaming-both-full": "node --loader ts-node/esm tests/servers/test-streaming-both-full.js",
    "test:streaming-both-simple": "node --loader ts-node/esm tests/servers/test-streaming-both-simple.js",
    "test:streaming-both-complete": "node --loader ts-node/esm tests/servers/test-streaming-both-complete.js",
    "docs:api": "typedoc",
    "docs:config": "node --loader ts-node/esm scripts/generate-config-docs.ts",
    "docs:dev": "vitepress dev docs",
    "docs:build": "vitepress build docs",
    "docs:preview": "vitepress preview docs",
    "docs:pdf": "md-to-pdf docs/index.md --basedir docs",
    "docs:all": "npm run docs:api && npm run docs:config && npm run docs:build"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.17.3",
    "dotenv": "^17.2.1",
    "express": "5.1.0",
    "jose": "6.0.12",
    "node-fetch": "^3.3.2",
    "yaml": "^2.5.0"
  },
  "devDependencies": {
    "@types/express": "5.0.3",
    "@types/node": "24.3.0",
    "@typescript-eslint/eslint-plugin": "8.40.0",
    "@typescript-eslint/parser": "8.40.0",
    "eslint": "9.33.0",
    "eslint-config-prettier": "10.1.8",
    "eslint-plugin-import": "^2.29.1",
    "husky": "^9.1.6",
    "md-to-pdf": "^5.2.4",
    "nodemon": "^3.1.4",
    "prettier": "^3.3.2",
    "rimraf": "6.0.1",
    "ts-node": "^10.9.2",
    "typedoc": "^0.28.10",
    "typedoc-plugin-markdown": "^4.8.1",
    "typescript": "^5.5.4",
    "vitepress": "^1.6.4"
  },
  "main": "index.js",
  "keywords": [],
  "author": ""
}

```

--------------------------------------------------------------------------------
/src/routing/route-registry.ts:
--------------------------------------------------------------------------------

```typescript
import type { LoadedServer, ServerInstance } from '../types/server.js'
import { Logger } from '../utils/logger.js'
import { CircuitBreaker } from './circuit-breaker.js'
import { LoadBalancer } from './load-balancer.js'

export interface RouteRegistryOptions {
  // Mapping lifetime for cached routes (ms)
  cacheTtlMs?: number
}

export interface RouteResolution {
  serverId: string
  instance: ServerInstance
}

export class RouteRegistry {
  private readonly servers: Map<string, LoadedServer>
  private readonly circuit: CircuitBreaker
  private readonly lb: LoadBalancer
  private readonly cacheTtl: number
  private cache = new Map<string, { value: RouteResolution; expiresAt: number }>()

  constructor(
    servers: Map<string, LoadedServer>,
    circuit: CircuitBreaker,
    lb: LoadBalancer,
    options?: RouteRegistryOptions
  ) {
    this.servers = servers
    this.circuit = circuit
    this.lb = lb
    this.cacheTtl = options?.cacheTtlMs ?? 5_000
  }

  updateServers(servers: Map<string, LoadedServer>): void {
    // Shallow replace reference
    ;(this as any).servers = servers
    this.cache.clear()
  }

  getInstances(serverId: string): ServerInstance[] {
    const server = this.servers.get(serverId)
    if (!server) return []
    const instances = server.instances && server.instances.length
      ? server.instances
      : (server.endpoint && server.endpoint !== 'unknown'
        ? [{ id: `${serverId}-primary`, url: server.endpoint, weight: 1, healthScore: server.status === 'running' ? 100 : 0 }]
        : [])
    return instances
  }

  resolve(serverId: string): RouteResolution | undefined {
    const cached = this.cache.get(serverId)
    const now = Date.now()
    if (cached && cached.expiresAt > now) return cached.value

    const instances = this.getInstances(serverId)
    if (!instances.length) return undefined

    // Filter by circuit breaker allowance
    const allowed = instances.filter((i) => this.circuit.canExecute(this.key(serverId, i.id)).allowed)
    const pool = allowed.length ? allowed : instances
    const chosen = this.lb.select(serverId, pool)
    if (!chosen) return undefined

    const resolution: RouteResolution = { serverId, instance: chosen }
    this.cache.set(serverId, { value: resolution, expiresAt: now + this.cacheTtl })
    return resolution
  }

  markSuccess(serverId: string, instanceId: string): void {
    const key = this.key(serverId, instanceId)
    this.circuit.onSuccess(key)
    this.bumpHealth(serverId, instanceId, +5)
  }

  markFailure(serverId: string, instanceId: string): void {
    const key = this.key(serverId, instanceId)
    this.circuit.onFailure(key)
    this.bumpHealth(serverId, instanceId, -20)
  }

  private key(serverId: string, instanceId: string): string {
    return `${serverId}::${instanceId}`
  }

  private bumpHealth(serverId: string, instanceId: string, delta: number): void {
    const s = this.servers.get(serverId)
    if (!s) return
    const arr = s.instances
    if (!arr) return
    const inst = arr.find((i) => i.id === instanceId)
    if (!inst) return
    const prev = inst.healthScore ?? 50
    const next = Math.max(0, Math.min(100, prev + delta))
    inst.healthScore = next
    Logger.debug('Instance health updated', { serverId, instanceId, healthScore: next })
  }
}


```

--------------------------------------------------------------------------------
/src/oauth/callback-handler.ts:
--------------------------------------------------------------------------------

```typescript
import type { MasterConfig, ServerAuthConfig } from '../types/config.js'
import type { OAuthToken } from '../types/auth.js'
import { StateManager, type OAuthStatePayload } from './state-manager.js'
import { PKCEManager } from './pkce-manager.js'

export interface CallbackContext {
  config: MasterConfig
  stateManager: StateManager
  pkceManager: PKCEManager
  baseUrl: string
  // Store token callback: serverId and clientToken must identify the storage key
  storeDelegatedToken?: (clientToken: string, serverId: string, token: OAuthToken) => Promise<void>
}

function toOAuthToken(json: any): OAuthToken {
  const expiresIn = 'expires_in' in json ? Number(json.expires_in) : 3600
  const scope = Array.isArray(json.scope)
    ? (json.scope as string[])
    : typeof json.scope === 'string'
      ? (json.scope as string).split(/[ ,]+/).filter(Boolean)
      : []
  return {
    access_token: String(json.access_token),
    refresh_token: json.refresh_token ? String(json.refresh_token) : undefined,
    expires_at: Date.now() + expiresIn * 1000,
    scope,
  }
}

async function exchangeAuthorizationCode(
  code: string,
  cfg: ServerAuthConfig,
  redirectUri: string,
  codeVerifier: string
): Promise<OAuthToken> {
  const body = new URLSearchParams({
    grant_type: 'authorization_code',
    code,
    client_id: cfg.client_id,
    redirect_uri: redirectUri,
    code_verifier: codeVerifier,
  })
  if (cfg.client_secret) body.set('client_secret', String(cfg.client_secret))
  const res = await fetch(cfg.token_endpoint, {
    method: 'POST',
    headers: { 'content-type': 'application/x-www-form-urlencoded', accept: 'application/json' },
    body,
  })
  const text = await res.text()
  if (!res.ok) throw new Error(`Token endpoint error ${res.status}: ${text}`)
  let json: any
  try {
    json = JSON.parse(text)
  } catch {
    json = Object.fromEntries(new URLSearchParams(text))
  }
  return toOAuthToken(json)
}

export class CallbackHandler {
  constructor(private readonly ctx: CallbackContext) {}

  async handleCallback(params: URLSearchParams, providerConfig: ServerAuthConfig): Promise<{ token?: OAuthToken; error?: string; state?: OAuthStatePayload }>
  {
    const error = params.get('error')
    if (error) {
      const desc = params.get('error_description') ?? 'OAuth authorization failed'
      return { error: `${error}: ${desc}` }
    }
    const stateStr = params.get('state')
    const code = params.get('code')
    if (!stateStr || !code) return { error: 'Missing state or code' }

    const state = this.ctx.stateManager.consume(stateStr)
    if (!state) return { error: 'Invalid or expired state' }

    const verifier = this.ctx.pkceManager.getVerifier(stateStr)
    if (!verifier) return { error: 'PKCE verification failed' }

    const redirectUri = new URL('/oauth/callback', this.ctx.baseUrl).toString()
    try {
      const token = await exchangeAuthorizationCode(code, providerConfig, redirectUri, verifier)
      // Store if we can identify a client + server context
      if (state.clientToken && state.serverId && this.ctx.storeDelegatedToken) {
        await this.ctx.storeDelegatedToken(state.clientToken, state.serverId, token)
      }
      return { token, state }
    } catch (err: any) {
      return { error: err?.message ?? 'Token exchange failed' }
    }
  }
}


```

--------------------------------------------------------------------------------
/docs/stdio-servers.md:
--------------------------------------------------------------------------------

```markdown
# STDIO Server Support

The Master MCP Server now supports STDIO-based MCP servers in addition to HTTP-based servers. This allows you to aggregate both network-based and locally-running MCP servers through a single endpoint.

## Configuration

To configure a STDIO server, use a `file://` URL in your server configuration:

```json
{
  "servers": [
    {
      "id": "stdio-server",
      "type": "local",
      "url": "file://./path/to/your/stdio-mcp-server.cjs",
      "auth_strategy": "bypass_auth",
      "config": {
        "environment": {},
        "args": []
      }
    }
  ]
}
```

The Master MCP Server will automatically detect `file://` URLs and treat them as STDIO servers, starting them as child processes and communicating with them through stdin/stdout using JSON-RPC.

## How It Works

1. **Server Detection**: The Master MCP Server detects `file://` URLs and identifies them as STDIO servers
2. **Process Management**: STDIO servers are started as child processes
3. **Communication**: The Master MCP Server communicates with STDIO servers using JSON-RPC over stdin/stdout
4. **Capability Discovery**: The Master MCP Server discovers tools and resources from STDIO servers
5. **Request Routing**: Tool calls and resource reads are routed to the appropriate STDIO servers

## Benefits

- **Unified Interface**: Access both HTTP and STDIO servers through a single MCP endpoint
- **Process Isolation**: Each STDIO server runs in its own process for better isolation
- **Automatic Management**: The Master MCP Server handles process lifecycle management
- **Seamless Integration**: STDIO servers appear as regular MCP servers to clients

## Requirements

- STDIO servers must implement the MCP protocol using JSON-RPC over stdin/stdout
- STDIO servers should follow the MCP specification for initialization and capability discovery
- STDIO servers must be executable Node.js scripts (`.js` or `.cjs` files)

## Example STDIO Server

Here's a simple example of a STDIO server:

```javascript
// Simple STDIO server that implements the MCP protocol
// Save this as stdio-mcp-server.cjs and make it executable with chmod +x
```
process.stdin.on('data', async (data) => {
  try {
    const lines = data.toString().split('\n').filter(line => line.trim() !== '');
    for (const line of lines) {
      const request = JSON.parse(line);
      
      // Handle initialize request
      if (request.method === 'initialize') {
        const response = {
          jsonrpc: '2.0',
          id: request.id,
          result: {
            protocolVersion: '2025-06-18',
            capabilities: {
              tools: { listChanged: true },
              resources: { listChanged: true }
            },
            serverInfo: {
              name: 'example-stdio-server',
              version: '1.0.0'
            }
          }
        };
        process.stdout.write(JSON.stringify(response) + '\n');
      }
      // Handle other requests...
    }
  } catch (err) {
    const errorResponse = {
      jsonrpc: '2.0',
      id: null,
      error: {
        code: -32700,
        message: 'Parse error',
        data: err.message
      }
    };
    process.stdout.write(JSON.stringify(errorResponse) + '\n');
  }
});
```

Make sure to make your STDIO server executable:

```bash
chmod +x ./path/to/your/stdio-mcp-server.cjs
```
```

--------------------------------------------------------------------------------
/src/routing/retry-handler.ts:
--------------------------------------------------------------------------------

```typescript
import { Logger } from '../utils/logger.js'

export type JitterMode = 'none' | 'full'

export interface RetryPolicy {
  maxRetries: number
  baseDelayMs: number
  maxDelayMs: number
  backoffFactor: number // multiplier per attempt
  jitter: JitterMode
  timeoutMs?: number // overall timeout budget (optional)
  retryOn?: {
    networkErrors?: boolean
    httpStatuses?: number[]
    httpStatusClasses?: Array<4 | 5> // 4=4xx,5=5xx
  }
}

export interface RetryContext {
  attempt: number
  lastError?: unknown
  lastStatus?: number
}

function sleep(ms: number): Promise<void> {
  return new Promise((resolve) => setTimeout(resolve, ms))
}

function withJitter(base: number, mode: JitterMode): number {
  if (mode === 'none') return base
  // Full jitter: random between 0 and base
  return Math.floor(Math.random() * base)
}

function isRetryable(policy: RetryPolicy, _err: unknown, status?: number): boolean {
  if (status !== undefined) {
    if (policy.retryOn?.httpStatuses?.includes(status)) return true
    const klass = Math.floor(status / 100)
    if (klass === 5 && policy.retryOn?.httpStatusClasses?.includes(5)) return true
    if (klass === 4 && policy.retryOn?.httpStatusClasses?.includes(4)) return status === 408 || status === 429
    return false
  }
  // No status means a network error or thrown exception from fetch
  return Boolean(policy.retryOn?.networkErrors ?? true)
}

export class RetryHandler {
  private readonly policy: RetryPolicy

  constructor(policy?: Partial<RetryPolicy>) {
    this.policy = {
      maxRetries: policy?.maxRetries ?? 3,
      baseDelayMs: policy?.baseDelayMs ?? 200,
      maxDelayMs: policy?.maxDelayMs ?? 5_000,
      backoffFactor: policy?.backoffFactor ?? 2,
      jitter: policy?.jitter ?? 'full',
      timeoutMs: policy?.timeoutMs,
      retryOn: policy?.retryOn ?? { networkErrors: true, httpStatusClasses: [5], httpStatuses: [408, 429] },
    }
  }

  async execute<T>(op: () => Promise<T>, onRetry?: (ctx: RetryContext) => void): Promise<T> {
    const start = Date.now()
    let delay = this.policy.baseDelayMs
    let lastError: unknown
    for (let attempt = 0; attempt <= this.policy.maxRetries; attempt++) {
      try {
        const result = await op()
        return result
      } catch (err: any) {
        // If this looks like a fetch Response-like error, extract status
        let status: number | undefined
        if (err && typeof err === 'object' && 'status' in err && typeof (err as any).status === 'number') {
          status = (err as any).status
        }

        if (attempt >= this.policy.maxRetries || !isRetryable(this.policy, err, status)) {
          throw err
        }

        lastError = err
        const ctx: RetryContext = { attempt, lastError, lastStatus: status }
        try {
          onRetry?.(ctx)
        } catch { /* ignore */ }

        if (this.policy.timeoutMs && Date.now() - start + delay > this.policy.timeoutMs) {
          Logger.warn('Retry timeout budget exceeded')
          throw err
        }

        const wait = Math.min(this.policy.maxDelayMs, withJitter(delay, this.policy.jitter))
        await sleep(wait)
        delay = Math.min(this.policy.maxDelayMs, Math.floor(delay * this.policy.backoffFactor))
      }
    }
    // Should be unreachable
    throw lastError ?? new Error('RetryHandler failed without error')
  }
}

```

--------------------------------------------------------------------------------
/src/types/config.ts:
--------------------------------------------------------------------------------

```typescript
import type { OAuthDelegation } from './auth.js'

export interface MasterConfig {
  master_oauth: MasterOAuthConfig
  servers: ServerConfig[]
  oauth_delegation?: OAuthDelegationConfig
  hosting: HostingConfig
  routing?: RoutingConfig
  logging?: LoggingConfig
  security?: SecurityConfig
}

export interface ServerConfig {
  id: string
  type: 'git' | 'npm' | 'pypi' | 'docker' | 'local'
  url?: string
  package?: string
  version?: string
  branch?: string
  auth_strategy: AuthStrategy
  auth_config?: ServerAuthConfig
  config: {
    environment?: Record<string, string>
    args?: string[]
    port?: number
  }
}

export enum AuthStrategy {
  MASTER_OAUTH = 'master_oauth',
  DELEGATE_OAUTH = 'delegate_oauth',
  BYPASS_AUTH = 'bypass_auth',
  PROXY_OAUTH = 'proxy_oauth'
}

export interface MasterOAuthConfig {
  issuer?: string
  authorization_endpoint: string
  token_endpoint: string
  jwks_uri?: string
  client_id: string
  client_secret?: string
  redirect_uri: string
  scopes: string[]
  audience?: string
}

// Alias used by MultiAuthManager constructor in later phases
export type MasterAuthConfig = MasterOAuthConfig

export interface OAuthDelegationConfig {
  enabled: boolean
  callback_base_url?: string
  // Optional pre-configured providers by ID
  providers?: Record<string, ServerAuthConfig>
}

export interface HostingConfig {
  platform: 'node' | 'cloudflare-workers' | 'koyeb' | 'docker' | 'unknown'
  port?: number
  base_url?: string
  // Optional platform-specific storage/backend hints
  storage_backend?: 'memory' | 'fs' | 'durable_object' | 'kv' | 's3'
}

export interface LoggingConfig {
  level?: 'debug' | 'info' | 'warn' | 'error'
}

export interface SecurityConfig {
  // Env var name containing encryption key for config secrets
  config_key_env?: string
  // Enable audit logging for config changes
  audit?: boolean
  // Optional secret rotation policy in days
  rotation_days?: number
}

export interface ServerAuthConfig {
  provider: 'github' | 'google' | 'custom'
  authorization_endpoint: string
  token_endpoint: string
  client_id: string
  client_secret?: string
  scopes?: string[]
  // Additional provider-specific fields
  [key: string]: unknown
}

// Re-export for convenience in consumers
export type { OAuthDelegation }

// ---- Routing configuration ----
export type LoadBalancingStrategy = 'round_robin' | 'weighted' | 'health'

export interface LoadBalancerConfig {
  strategy?: LoadBalancingStrategy
}

export interface CircuitBreakerConfig {
  failureThreshold?: number
  successThreshold?: number
  recoveryTimeoutMs?: number
}

export interface RetryPolicyConfig {
  maxRetries?: number
  baseDelayMs?: number
  maxDelayMs?: number
  backoffFactor?: number
  jitter?: 'none' | 'full'
  retryOn?: {
    networkErrors?: boolean
    httpStatuses?: number[]
    httpStatusClasses?: Array<4 | 5>
  }
}

export interface RoutingConfig {
  loadBalancer?: LoadBalancerConfig
  circuitBreaker?: CircuitBreakerConfig
  retry?: RetryPolicyConfig
}

// Defaults for consumers that want a baseline configuration
export const DefaultRoutingConfig: RoutingConfig = {
  loadBalancer: { strategy: 'round_robin' },
  circuitBreaker: { failureThreshold: 5, successThreshold: 2, recoveryTimeoutMs: 30_000 },
  retry: { maxRetries: 2, baseDelayMs: 250, maxDelayMs: 4_000, backoffFactor: 2, jitter: 'full' },
}

export const DefaultHostingConfig: HostingConfig = {
  platform: 'node',
  port: 3000,
}

```

--------------------------------------------------------------------------------
/docs/guides/authentication.md:
--------------------------------------------------------------------------------

```markdown
# Authentication Guide

Master MCP Server supports multiple authentication strategies between the client (master) and each backend server.

## Strategies

- master_oauth: Pass the client token from the master directly to the backend.
- delegate_oauth: Instruct the client to complete an OAuth flow against the backend provider, then store a backend token.
- proxy_oauth: Use the master to refresh and proxy backend tokens, falling back to pass-through.
- bypass_auth: No auth headers are sent to the backend.

Configure per-server via `servers[].auth_strategy` and optional `servers[].auth_config`.

<AuthFlowDemo />

<CodeTabs :options="[
  { label: 'master_oauth', value: 'master' },
  { label: 'delegate_oauth', value: 'delegate' },
  { label: 'proxy_oauth', value: 'proxy' },
  { label: 'bypass_auth', value: 'bypass' }
]">
  <template #master>

```yaml
servers:
  - id: search
    type: local
    auth_strategy: master_oauth
    config: { port: 4100 }
```

  </template>
  <template #delegate>

```yaml
servers:
  - id: github-tools
    type: local
    auth_strategy: delegate_oauth
    auth_config:
      provider: github
      authorization_endpoint: https://github.com/login/oauth/authorize
      token_endpoint: https://github.com/login/oauth/access_token
      client_id: ${GITHUB_CLIENT_ID}
      client_secret: env:GITHUB_CLIENT_SECRET
      scopes: [repo, read:user]
    config: { port: 4010 }
```

  </template>
  <template #proxy>

```yaml
servers:
  - id: internal
    type: local
    auth_strategy: proxy_oauth
    auth_config:
      token_source: env:INTERNAL_BACKEND_TOKEN
    config: { port: 4200 }
```

  </template>
  <template #bypass>

```yaml
servers:
  - id: public
    type: local
    auth_strategy: bypass_auth
    config: { port: 4300 }
```

  </template>
</CodeTabs>

```yaml
servers:
  - id: github-tools
    type: local
    auth_strategy: delegate_oauth
    auth_config:
      provider: github
      authorization_endpoint: https://github.com/login/oauth/authorize
      token_endpoint: https://github.com/login/oauth/access_token
      client_id: ${GITHUB_CLIENT_ID}
      client_secret: env:GITHUB_CLIENT_SECRET
      scopes: [repo, read:user]
    config:
      port: 4010
```

## Flow Overview

1) Client calls a tool/resource via master with `Authorization: Bearer <client_token>`.
2) Master determines server strategy via `MultiAuthManager`.
3) If delegation is required, master responds with `{ type: 'oauth_delegation', ... }` metadata.
4) Client opens `GET /oauth/authorize?server_id=<id>` to initiate the auth code + PKCE flow.
5) Redirect back to `GET /oauth/callback` stores the backend token (associated with client token + server id).
6) Retries to the backend now include `Authorization: Bearer <server_token>` as needed.

## Endpoints

- `GET /oauth/authorize` → Starts flow; query: `server_id`, optional `provider` if preconfigured.
- `GET /oauth/callback` → Exchanges code for token and stores it.
- `GET /oauth/success` + `GET /oauth/error` → Result pages.

These are mounted automatically in the Node runtime (`src/index.ts`) and can be used in Workers via `OAuthFlowController.handleRequest()`.

## Customizing Auth

Attach a custom `MultiAuthManager` instance to the `MasterServer`:

```ts
import { MasterServer } from '../src/server/master-server'
import { MultiAuthManager } from '../src/auth/multi-auth-manager'

const master = new MasterServer()
const auth = new MultiAuthManager(config.master_oauth)
auth.registerServerAuth('github-tools', 'delegate_oauth', {/* provider config */})
master.attachAuthManager(auth)
```

See `examples/custom-auth` for a working example.

```

--------------------------------------------------------------------------------
/src/utils/errors.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Standardized error types and helpers.
 */

export type ErrorSeverity = 'fatal' | 'error' | 'warn'

export interface SerializedError {
  name: string
  message: string
  code?: string
  status?: number
  severity?: ErrorSeverity
  details?: unknown
  stack?: string
  cause?: SerializedError
}

export class AppError extends Error {
  code?: string
  status?: number
  severity: ErrorSeverity
  details?: unknown
  override cause?: unknown

  constructor(message: string, opts?: { code?: string; status?: number; severity?: ErrorSeverity; details?: unknown; cause?: unknown }) {
    super(message)
    this.name = this.constructor.name
    this.code = opts?.code
    this.status = opts?.status
    this.severity = opts?.severity ?? 'error'
    this.details = opts?.details
    this.cause = opts?.cause
  }

  toJSON(): SerializedError {
    return serializeError(this)
  }
}

export class ValidationError extends AppError {
  constructor(message: string, details?: unknown) {
    super(message, { code: 'VALIDATION_ERROR', status: 400, details, severity: 'warn' })
  }
}

export class AuthError extends AppError {
  constructor(message: string, details?: unknown) {
    super(message, { code: 'AUTH_ERROR', status: 401, details })
  }
}

export class PermissionError extends AppError {
  constructor(message: string, details?: unknown) {
    super(message, { code: 'FORBIDDEN', status: 403, details })
  }
}

export class NotFoundError extends AppError {
  constructor(message: string, details?: unknown) {
    super(message, { code: 'NOT_FOUND', status: 404, details, severity: 'warn' })
  }
}

export class RateLimitError extends AppError {
  constructor(message: string, details?: unknown) {
    super(message, { code: 'RATE_LIMITED', status: 429, details, severity: 'warn' })
  }
}

export class ExternalServiceError extends AppError {
  constructor(message: string, details?: unknown) {
    super(message, { code: 'EXTERNAL_SERVICE_ERROR', status: 502, details })
  }
}

export class CircuitBreakerError extends AppError {
  constructor(message: string, details?: unknown) {
    super(message, { code: 'CIRCUIT_OPEN', status: 503, details })
  }
}

export function serializeError(err: unknown): SerializedError {
  if (err instanceof AppError) {
    return {
      name: err.name,
      message: err.message,
      code: err.code,
      status: err.status,
      severity: err.severity,
      details: err.details,
      stack: err.stack,
      cause: err.cause ? serializeError(err.cause as any) : undefined,
    }
  }
  if (err instanceof Error) {
    return {
      name: err.name,
      message: err.message,
      stack: err.stack,
    }
  }
  return { name: 'Error', message: String(err) }
}

export function deserializeError(obj: SerializedError): AppError {
  const err = new AppError(obj.message, {
    code: obj.code,
    status: obj.status,
    severity: obj.severity,
    details: obj.details,
    cause: obj.cause ? deserializeError(obj.cause) : undefined,
  })
  err.name = obj.name
  err.stack = obj.stack
  return err
}

export function withErrorContext<T>(fn: () => Promise<T>, context: Record<string, unknown>): Promise<T> {
  return fn().catch((e) => {
    if (e instanceof AppError) throw new AppError(e.message, { ...e, details: { ...(e.details as any), ...context } })
    const err = new AppError('Unhandled error', { code: 'UNHANDLED', details: { cause: serializeError(e), ...context } })
    throw err
  })
}

export function stackTrace(e?: Error): string {
  const err = e ?? new Error('stack')
  return err.stack || ''
}

export function isAppError(e: unknown): e is AppError {
  return e instanceof AppError
}

```

--------------------------------------------------------------------------------
/examples/custom-auth/index.ts:
--------------------------------------------------------------------------------

```typescript
import express from 'express'
import type { Request, Response } from 'express'
import { ConfigLoader } from '../../src/config/config-loader.js'
import { MasterServer } from '../../src/server/master-server.js'
import { MultiAuthManager } from '../../src/auth/multi-auth-manager.js'
import { CapabilityAggregator } from '../../src/modules/capability-aggregator.js'
import { collectSystemMetrics } from '../../src/utils/monitoring.js'

// A custom auth manager that adds an extra header for a specific backend
class CustomAuthManager extends MultiAuthManager {
  override async handleMasterOAuth(serverId: string, clientToken: string) {
    const base = await super.handleMasterOAuth(serverId, clientToken)
    // Example: add a hint header for a particular backend
    if (serverId === 'custom-proxy') {
      return { ...base, 'X-Custom-Auth': 'enabled' }
    }
    return base
  }
}

async function main() {
  const configPath = process.env.MASTER_CONFIG_PATH || 'examples/custom-auth/config.yaml'
  const cfg = await ConfigLoader.load({ path: configPath })

  const master = new MasterServer()
  const customAuth = new CustomAuthManager(cfg.master_oauth)
  // Register per-server strategies from config
  for (const s of cfg.servers) customAuth.registerServerAuth(s.id, s.auth_strategy as any, s.auth_config as any)
  master.attachAuthManager(customAuth)

  await master.startFromConfig(cfg)

  const app = express()
  app.use(express.json())

  app.get('/health', (_req, res) => res.json({ ok: true }))
  app.get('/metrics', (_req, res) => res.json({ ok: true, system: collectSystemMetrics() }))

  // OAuth endpoints
  master.getOAuthFlowController().registerExpress(app)

  // Capabilities
  app.get('/capabilities', (_req: Request, res: Response) => {
    const agg = new CapabilityAggregator()
    const caps = agg.aggregate(Array.from(master.getRouter().getServers().values()))
    res.json(caps)
  })

  const getToken = (req: Request) => {
    const h = req.headers['authorization'] || req.headers['Authorization']
    return typeof h === 'string' && h.toLowerCase().startsWith('bearer ') ? h.slice(7) : undefined
  }

  // MCP endpoints
  app.post('/mcp/tools/list', async (_req: Request, res: Response) => {
    const handler = master.handler
    const result = await handler.handleListTools({ type: 'list_tools' } as any)
    res.json(result)
  })

  app.post('/mcp/tools/call', async (req: Request, res: Response) => {
    const token = getToken(req)
    const handler = new (master.handler.constructor as any)({
      aggregator: (master as any).aggregator,
      router: master.getRouter(),
      getClientToken: () => token,
    }) as typeof master.handler
    const result = await handler.handleCallTool({ name: req.body?.name, arguments: req.body?.arguments ?? {} } as any)
    res.json(result)
  })

  app.post('/mcp/resources/list', async (_req: Request, res: Response) => {
    const handler = master.handler
    const result = await handler.handleListResources({ type: 'list_resources' } as any)
    res.json(result)
  })

  app.post('/mcp/resources/read', async (req: Request, res: Response) => {
    const token = getToken(req)
    const handler = new (master.handler.constructor as any)({
      aggregator: (master as any).aggregator,
      router: master.getRouter(),
      getClientToken: () => token,
    }) as typeof master.handler
    const result = await handler.handleReadResource({ uri: req.body?.uri } as any)
    res.json(result)
  })

  const port = cfg.hosting.port || 3000
  app.listen(port, () => console.log(`Custom auth example on :${port}`))
}

main().catch((err) => {
  console.error(err)
  process.exit(1)
})


```

--------------------------------------------------------------------------------
/tests/unit/routing/circuit-breaker.test.ts:
--------------------------------------------------------------------------------

```typescript
import { test } from 'node:test'
import assert from 'node:assert'
import { CircuitBreaker, InMemoryCircuitStorage } from '../../../src/routing/circuit-breaker.js'

test('CircuitBreaker onSuccess in closed state should only reset failures', async () => {
  const storage = new InMemoryCircuitStorage()
  const breaker = new CircuitBreaker({
    failureThreshold: 2,
    successThreshold: 2,
    recoveryTimeoutMs: 100,
  }, storage)
  const key = 'test-key'

  // Simulate some failures, but not enough to open the circuit
  breaker.onFailure(key)
  let record = storage.get(key)
  assert.strictEqual(record?.failures, 1, 'should have 1 failure')
  assert.strictEqual(record?.state, 'closed', 'should be in closed state')

  // Simulate a success
  breaker.onSuccess(key)
  record = storage.get(key)
  assert.strictEqual(record?.failures, 0, 'failures should be reset to 0')
  assert.strictEqual(record?.successes, 0, 'successes should remain 0') // This is the key check for the bug
  assert.strictEqual(record?.state, 'closed', 'should remain in closed state')
})

test('CircuitBreaker should open after reaching failure threshold', async () => {
    const storage = new InMemoryCircuitStorage()
    const breaker = new CircuitBreaker({
      failureThreshold: 2,
      successThreshold: 2,
      recoveryTimeoutMs: 100,
    }, storage)
    const key = 'test-key'

    breaker.onFailure(key)
    breaker.onFailure(key)

    const record = storage.get(key)
    assert.strictEqual(record?.state, 'open', 'should be in open state')
    assert.strictEqual(record?.failures, 2, 'should have 2 failures')
})

test('CircuitBreaker should transition to half-open after recovery timeout', async () => {
    const storage = new InMemoryCircuitStorage()
    const breaker = new CircuitBreaker({
      failureThreshold: 2,
      successThreshold: 2,
      recoveryTimeoutMs: 50,
    }, storage)
    const key = 'test-key'

    // Open the circuit
    breaker.onFailure(key)
    breaker.onFailure(key)

    // Wait for recovery timeout
    await new Promise(resolve => setTimeout(resolve, 60))

    // First call should be allowed and move to half-open
    const gate = breaker.canExecute(key)
    assert.strictEqual(gate.allowed, true, 'execution should be allowed')

    const record = storage.get(key)
    assert.strictEqual(record?.state, 'half_open', 'should be in half-open state')
})

test('CircuitBreaker should close after successes in half-open state', async () => {
    const storage = new InMemoryCircuitStorage()
    const breaker = new CircuitBreaker({
      failureThreshold: 2,
      successThreshold: 2,
      recoveryTimeoutMs: 50,
    }, storage)
    const key = 'test-key'

    // Open the circuit
    breaker.onFailure(key)
    breaker.onFailure(key)

    // Wait for recovery timeout
    await new Promise(resolve => setTimeout(resolve, 60))

    // Transition to half-open
    breaker.canExecute(key)

    // Succeed twice
    breaker.onSuccess(key)
    breaker.onSuccess(key)

    const record = storage.get(key)
    assert.strictEqual(record?.state, 'closed', 'should be in closed state')
    assert.strictEqual(record?.failures, 0, 'failures should be reset')
    assert.strictEqual(record?.successes, 0, 'successes should be reset')
})

test('CircuitBreaker should re-open after failure in half-open state', async () => {
    const storage = new InMemoryCircuitStorage()
    const breaker = new CircuitBreaker({
      failureThreshold: 2,
      successThreshold: 2,
      recoveryTimeoutMs: 50,
    }, storage)
    const key = 'test-key'

    // Open the circuit
    breaker.onFailure(key)
    breaker.onFailure(key)

    // Wait for recovery timeout
    await new Promise(resolve => setTimeout(resolve, 60))

    // Transition to half-open
    breaker.canExecute(key)

    // Fail once
    breaker.onFailure(key)

    const record = storage.get(key)
    assert.strictEqual(record?.state, 'open', 'should be in open state again')
})
```

--------------------------------------------------------------------------------
/examples/test-stdio-server.js:
--------------------------------------------------------------------------------

```javascript
#!/usr/bin/env node

// Simple test STDIO server for testing purposes

// Simple JSON-RPC server that echoes back requests

// Function to send a response
function sendResponse(response) {
  process.stdout.write(JSON.stringify(response) + '\n');
}

// Function to send a notification
function sendNotification(notification) {
  process.stdout.write(JSON.stringify(notification) + '\n');
}

// Handle incoming requests
process.stdin.on('data', (data) => {
  try {
    const lines = data.toString().split('\n').filter(line => line.trim() !== '');
    for (const line of lines) {
      if (line.trim() === '') continue;
      
      const request = JSON.parse(line);
      
      // Handle initialize request
      if (request.method === 'initialize') {
        const response = {
          jsonrpc: '2.0',
          id: request.id,
          result: {
            protocolVersion: '2025-06-18',
            capabilities: {
              tools: {
                listChanged: true
              },
              resources: {
                listChanged: true
              }
            },
            serverInfo: {
              name: 'test-stdio-server',
              version: '1.0.0'
            }
          }
        };
        sendResponse(response);
      }
      // Handle tools/list request
      else if (request.method === 'tools/list') {
        const response = {
          jsonrpc: '2.0',
          id: request.id,
          result: {
            tools: [
              {
                name: 'stdio-echo',
                description: 'Echoes back the input',
                inputSchema: {
                  type: 'object',
                  properties: {
                    message: {
                      type: 'string'
                    }
                  },
                  required: ['message']
                }
              }
            ]
          }
        };
        sendResponse(response);
      }
      // Handle resources/list request
      else if (request.method === 'resources/list') {
        const response = {
          jsonrpc: '2.0',
          id: request.id,
          result: {
            resources: [
              {
                uri: 'stdio://example/resource',
                name: 'stdio-resource',
                description: 'A test resource from STDIO server'
              }
            ]
          }
        };
        sendResponse(response);
      }
      // Handle tools/call request
      else if (request.method === 'tools/call') {
        const response = {
          jsonrpc: '2.0',
          id: request.id,
          result: {
            content: [
              {
                type: 'text',
                text: `STDIO Echo: ${request.params.arguments?.message || 'No message'}`
              }
            ]
          }
        };
        sendResponse(response);
      }
      // Handle resources/read request
      else if (request.method === 'resources/read') {
        const response = {
          jsonrpc: '2.0',
          id: request.id,
          result: {
            contents: [
              {
                uri: request.params.uri,
                text: 'This is content from a STDIO server resource',
                mimeType: 'text/plain'
              }
            ]
          }
        };
        sendResponse(response);
      }
      // Handle unknown methods
      else {
        const response = {
          jsonrpc: '2.0',
          id: request.id,
          error: {
            code: -32601,
            message: `Method not found: ${request.method}`
          }
        };
        sendResponse(response);
      }
    }
  } catch (err) {
    // Send error response
    const errorResponse = {
      jsonrpc: '2.0',
      id: null,
      error: {
        code: -32700,
        message: 'Parse error',
        data: err.message
      }
    };
    sendResponse(errorResponse);
  }
});

// Send a notification that the server is ready
sendNotification({
  jsonrpc: '2.0',
  method: 'notifications/initialized',
  params: {}
});

console.error('Test STDIO server started');
```

--------------------------------------------------------------------------------
/src/utils/http.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * HTTP utilities for request/response handling, header manipulation, and content
 * type parsing. Minimal and cross-platform (Node 18+ and Workers).
 */

export type HeadersLike = Headers | Record<string, string> | Array<[string, string]>

export function normalizeHeaders(h: HeadersLike | undefined | null): Record<string, string> {
  const out: Record<string, string> = {}
  if (!h) return out
  if (typeof (h as any).forEach === 'function') {
    ;(h as Headers).forEach((v, k) => (out[k.toLowerCase()] = v))
    return out
  }
  if (Array.isArray(h)) {
    for (const [k, v] of h) out[k.toLowerCase()] = String(v)
    return out
  }
  for (const [k, v] of Object.entries(h)) out[k.toLowerCase()] = String(v)
  return out
}

export function getHeader(h: HeadersLike | undefined | null, name: string): string | undefined {
  const map = normalizeHeaders(h)
  return map[name.toLowerCase()]
}

export function setHeader(h: HeadersLike | undefined | null, name: string, value: string): HeadersLike {
  if (!h) return { [name]: value }
  if (typeof (h as any).set === 'function') {
    const copy = new Headers(h as Headers)
    copy.set(name, value)
    return copy
  }
  const map = normalizeHeaders(h)
  map[name.toLowerCase()] = value
  return map
}

export function getContentType(h: HeadersLike | undefined | null): string | undefined {
  return getHeader(h, 'content-type')
}

export function isJsonContentType(ct?: string): boolean {
  if (!ct) return false
  return /application\/json|\+json/i.test(ct)
}

export async function parseBody(req: Request, limitBytes = 1_000_000): Promise<any> {
  const ct = getContentType(req.headers)
  if (isJsonContentType(ct)) {
    const text = await readTextLimited(req, limitBytes)
    try {
      return JSON.parse(text)
    } catch (e) {
      throw new Error('Invalid JSON body')
    }
  }
  if (/text\//i.test(ct || '')) return readTextLimited(req, limitBytes)
  // default to arrayBuffer
  const buf = await req.arrayBuffer()
  if (buf.byteLength > limitBytes) throw new Error('Body too large')
  return buf
}

export async function readTextLimited(req: Request, limitBytes: number): Promise<string> {
  const buf = await req.arrayBuffer()
  if (buf.byteLength > limitBytes) throw new Error('Body too large')
  return new TextDecoder().decode(buf)
}

export function jsonResponse(body: unknown, init?: ResponseInit): Response {
  const headers = new Headers(init?.headers)
  headers.set('content-type', 'application/json; charset=utf-8')
  const payload = JSON.stringify(body)
  return new Response(payload, { ...init, headers })
}

export function buildQuery(params: Record<string, string | number | boolean | null | undefined>): string {
  const usp = new URLSearchParams()
  for (const [k, v] of Object.entries(params)) {
    if (v === undefined || v === null) continue
    usp.append(k, String(v))
  }
  const s = usp.toString()
  return s ? `?${s}` : ''
}

export function appendQuery(url: string, params: Record<string, string | number | boolean | null | undefined>): string {
  const u = new URL(url, 'http://localhost')
  for (const [k, v] of Object.entries(params)) {
    if (v === undefined || v === null) continue
    u.searchParams.set(k, String(v))
  }
  if (!/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(url)) {
    // Relative URL; return pathname+search only
    return `${u.pathname}${u.search}`
  }
  return u.toString()
}

export function ensureCorrelationId(headers?: HeadersLike | null): string {
  const existing = headers && getHeader(headers, 'x-correlation-id')
  if (existing) return existing
  return randomId()
}

export function randomId(): string {
  const g: any = globalThis as any
  try {
    if (g.crypto?.randomUUID) return g.crypto.randomUUID()
  } catch {
    // ignore
  }
  try {
    if (g.crypto?.getRandomValues) {
      const bytes = new Uint8Array(16)
      g.crypto.getRandomValues(bytes)
      return [...bytes].map((b) => b.toString(16).padStart(2, '0')).join('')
    }
  } catch {
    // ignore
  }
  return Math.random().toString(16).slice(2) + Math.random().toString(16).slice(2)
}


```

--------------------------------------------------------------------------------
/examples/stdio-mcp-server.cjs:
--------------------------------------------------------------------------------

```
#!/usr/bin/env node

// Simple test STDIO server for testing purposes
const fs = require('fs')

// Simple JSON-RPC server that echoes back requests
let messageId = 0

// Function to send a response
function sendResponse(response) {
  process.stdout.write(JSON.stringify(response) + '\n')
}

// Function to send a notification
function sendNotification(notification) {
  process.stdout.write(JSON.stringify(notification) + '\n')
}

// Handle incoming requests
process.stdin.on('data', (data) => {
  try {
    const lines = data.toString().split('\n').filter(line => line.trim() !== '')
    for (const line of lines) {
      if (line.trim() === '') continue
      
      const request = JSON.parse(line)
      
      // Handle initialize request
      if (request.method === 'initialize') {
        const response = {
          jsonrpc: '2.0',
          id: request.id,
          result: {
            protocolVersion: '2025-06-18',
            capabilities: {
              tools: {
                listChanged: true
              },
              resources: {
                listChanged: true
              }
            },
            serverInfo: {
              name: 'test-stdio-server',
              version: '1.0.0'
            }
          }
        }
        sendResponse(response)
      }
      // Handle tools/list request
      else if (request.method === 'tools/list') {
        const response = {
          jsonrpc: '2.0',
          id: request.id,
          result: {
            tools: [
              {
                name: 'stdio-echo',
                description: 'Echoes back the input',
                inputSchema: {
                  type: 'object',
                  properties: {
                    message: {
                      type: 'string'
                    }
                  },
                  required: ['message']
                }
              }
            ]
          }
        }
        sendResponse(response)
      }
      // Handle resources/list request
      else if (request.method === 'resources/list') {
        const response = {
          jsonrpc: '2.0',
          id: request.id,
          result: {
            resources: [
              {
                uri: 'stdio://example/resource',
                name: 'stdio-resource',
                description: 'A test resource from STDIO server'
              }
            ]
          }
        }
        sendResponse(response)
      }
      // Handle tools/call request
      else if (request.method === 'tools/call') {
        const response = {
          jsonrpc: '2.0',
          id: request.id,
          result: {
            content: [
              {
                type: 'text',
                text: `STDIO Echo: ${request.params.arguments?.message || 'No message'}`
              }
            ]
          }
        }
        sendResponse(response)
      }
      // Handle resources/read request
      else if (request.method === 'resources/read') {
        const response = {
          jsonrpc: '2.0',
          id: request.id,
          result: {
            contents: [
              {
                uri: request.params.uri,
                text: 'This is content from a STDIO server resource',
                mimeType: 'text/plain'
              }
            ]
          }
        }
        sendResponse(response)
      }
      // Handle unknown methods
      else {
        const response = {
          jsonrpc: '2.0',
          id: request.id,
          error: {
            code: -32601,
            message: `Method not found: ${request.method}`
          }
        }
        sendResponse(response)
      }
    }
  } catch (err) {
    // Send error response
    const errorResponse = {
      jsonrpc: '2.0',
      id: null,
      error: {
        code: -32700,
        message: 'Parse error',
        data: err.message
      }
    }
    sendResponse(errorResponse)
  }
})

// Send a notification that the server is ready
sendNotification({
  jsonrpc: '2.0',
  method: 'notifications/initialized',
  params: {}
})

console.error('Test STDIO server started')
```

--------------------------------------------------------------------------------
/src/modules/stdio-capability-discovery.ts:
--------------------------------------------------------------------------------

```typescript
import { Logger } from '../utils/logger.js'
import type { ServerCapabilities } from '../types/server.js'
import { StdioManager } from './stdio-manager.js'

export class StdioCapabilityDiscovery {
  constructor(private stdioManager: StdioManager = new StdioManager()) {}

  async discoverCapabilities(serverId: string, filePath: string): Promise<ServerCapabilities> {
    Logger.info('Discovering capabilities for STDIO server', { serverId, filePath })
    
    try {
      // Start the STDIO server process
      await this.stdioManager.startServer(serverId, filePath)
      
      // Send initialize request
      const initializeRequestId = Date.now()
      const initializeRequest = {
        jsonrpc: "2.0",
        id: initializeRequestId,
        method: "initialize",
        params: {
          protocolVersion: "2025-06-18",
          capabilities: {},
          clientInfo: { 
            name: "master-mcp-server",
            version: "1.0.0"
          }
        }
      }
      
      await this.stdioManager.sendMessage(serverId, initializeRequest)
      const initializeResponse = await this.stdioManager.waitForResponse(serverId, initializeRequestId)
      
      if (initializeResponse.error) {
        throw new Error(`Failed to initialize STDIO server: ${initializeResponse.error.message}`)
      }
      
      // Send tools/list request
      const toolsRequestId = Date.now() + 1
      const toolsRequest = {
        jsonrpc: "2.0",
        id: toolsRequestId,
        method: "tools/list",
        params: {}
      }
      
      await this.stdioManager.sendMessage(serverId, toolsRequest)
      const toolsResponse = await this.stdioManager.waitForResponse(serverId, toolsRequestId)
      
      if (toolsResponse.error) {
        throw new Error(`Failed to list tools from STDIO server: ${toolsResponse.error.message}`)
      }
      
      const tools = toolsResponse.result?.tools || []
      
      // Send resources/list request
      const resourcesRequestId = Date.now() + 2
      const resourcesRequest = {
        jsonrpc: "2.0",
        id: resourcesRequestId,
        method: "resources/list",
        params: {}
      }
      
      await this.stdioManager.sendMessage(serverId, resourcesRequest)
      const resourcesResponse = await this.stdioManager.waitForResponse(serverId, resourcesRequestId)
      
      if (resourcesResponse.error) {
        throw new Error(`Failed to list resources from STDIO server: ${resourcesResponse.error.message}`)
      }
      
      const resources = resourcesResponse.result?.resources || []
      
      Logger.info('Discovered STDIO server capabilities', { serverId, tools: tools.length, resources: resources.length })
      
      return { 
        tools, 
        resources 
      }
    } catch (error) {
      Logger.error('Failed to discover STDIO server capabilities', { serverId, error })
      throw error
    }
  }

  async callTool(serverId: string, toolName: string, args: any): Promise<any> {
    try {
      const toolRequestId = Date.now()
      const toolRequest = {
        jsonrpc: "2.0",
        id: toolRequestId,
        method: "tools/call",
        params: {
          name: toolName,
          arguments: args
        }
      }
      
      await this.stdioManager.sendMessage(serverId, toolRequest)
      const toolResponse = await this.stdioManager.waitForResponse(serverId, toolRequestId)
      
      if (toolResponse.error) {
        throw new Error(`Failed to call tool ${toolName} on STDIO server: ${toolResponse.error.message}`)
      }
      
      return toolResponse
    } catch (error) {
      Logger.error('STDIO tool call failed', { serverId, toolName, error })
      throw error
    }
  }

  async readResource(serverId: string, uri: string): Promise<any> {
    try {
      const resourceRequestId = Date.now()
      const resourceRequest = {
        jsonrpc: "2.0",
        id: resourceRequestId,
        method: "resources/read",
        params: { 
          uri
        }
      }
      
      await this.stdioManager.sendMessage(serverId, resourceRequest)
      const resourceResponse = await this.stdioManager.waitForResponse(serverId, resourceRequestId)
      
      if (resourceResponse.error) {
        throw new Error(`Failed to read resource ${uri} from STDIO server: ${resourceResponse.error.message}`)
      }
      
      return resourceResponse
    } catch (error) {
      Logger.error('STDIO resource read failed', { serverId, uri, error })
      throw error
    }
  }
}
```

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

```vue
<template>
  <div class="mcp-grid" style="margin: 8px 0 16px; align-items: start;">
    <div class="mcp-col-6">
      <h3 style="margin:6px 0">Master Settings</h3>
      <div class="mcp-callout">
        <label>Port
          <input v-model.number="state.port" type="number" min="1" max="65535" style="width:120px;margin-left:8px" />
        </label>
        <br />
        <label style="margin-top:8px;display:block">Base URL
          <input v-model="state.baseUrl" type="text" placeholder="https://your.domain" style="width:100%;margin-top:4px" />
        </label>
        <label style="margin-top:8px;display:block">Client Token (optional)
          <input v-model="state.clientToken" type="text" placeholder="Bearer token for testing" style="width:100%;margin-top:4px" />
        </label>
      </div>

      <h3 style="margin:12px 0 6px">Backends</h3>
      <div v-for="(s, i) in state.servers" :key="i" class="mcp-callout">
        <div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
          <label>Id <input v-model="s.id" placeholder="search" /></label>
          <label>Type
            <select v-model="s.type">
              <option>local</option>
              <option>git</option>
              <option>npm</option>
              <option>docker</option>
              <option>pypi</option>
            </select>
          </label>
          <label v-if="s.type==='local'">Port <input v-model.number="s.config.port" type="number" min="1" max="65535" style="width:100px" /></label>
          <label v-else>URL <input v-model="s.config.url" placeholder="http://host:port" /></label>
          <label>Auth
            <select v-model="s.auth_strategy">
              <option>master_oauth</option>
              <option>delegate_oauth</option>
              <option>proxy_oauth</option>
              <option>bypass_auth</option>
            </select>
          </label>
          <button class="mcp-cta" style="margin-left:auto" @click="remove(i)">Remove</button>
        </div>
      </div>
      <button class="mcp-cta" @click="add">Add Backend</button>
    </div>

    <div class="mcp-col-6">
      <h3 style="margin:6px 0">Generated config.yaml</h3>
      <div style="position:relative">
        <button class="mcp-cta" style="position:absolute;right:8px;top:8px" @click="copyText(yaml)">Copy</button>
        <pre><code class="language-yaml">{{ yaml }}</code></pre>
      </div>

      <h3 style="margin:12px 0 6px">config.json</h3>
      <div style="position:relative">
        <button class="mcp-cta" style="position:absolute;right:8px;top:8px" @click="copyText(json)">Copy</button>
        <pre><code class="language-json">{{ json }}</code></pre>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, reactive } from 'vue'

type Server = {
  id: string
  type: 'local' | 'git' | 'npm' | 'docker' | 'pypi'
  auth_strategy: 'master_oauth' | 'delegate_oauth' | 'proxy_oauth' | 'bypass_auth'
  config: { port?: number; url?: string }
}

const state = reactive({
  port: 3000,
  baseUrl: '',
  clientToken: '',
  servers: [
    { id: 'search', type: 'local', auth_strategy: 'master_oauth', config: { port: 4100 } } as Server,
  ],
})

function add() {
  state.servers.push({ id: '', type: 'local', auth_strategy: 'master_oauth', config: {} })
}
function remove(i: number) {
  state.servers.splice(i, 1)
}

const jsonObj = computed(() => ({
  hosting: {
    port: state.port,
    base_url: state.baseUrl || undefined,
  },
  servers: state.servers.map(s => ({
    id: s.id, type: s.type, auth_strategy: s.auth_strategy, config: s.config,
  })),
}))

const json = computed(() => JSON.stringify(jsonObj.value, null, 2))

function toYaml(obj: any, indent = 0): string {
  const pad = '  '.repeat(indent)
  if (obj === null || obj === undefined) return ''
  if (typeof obj !== 'object') return String(obj)
  if (Array.isArray(obj)) {
    return obj.map(v => `${pad}- ${typeof v === 'object' ? `\n${toYaml(v, indent + 1)}` : toYaml(v, indent)}`).join('\n')
  }
  return Object.entries(obj)
    .filter(([, v]) => v !== undefined)
    .map(([k, v]) => {
      if (v && typeof v === 'object') {
        const nested = toYaml(v, indent + 1)
        return `${pad}${k}:\n${nested}`
      }
      return `${pad}${k}: ${toYaml(v, 0)}`
    })
    .join('\n')
}

const yaml = computed(() => toYaml({
  hosting: { port: state.port, base_url: state.baseUrl || undefined },
  servers: jsonObj.value.servers,
}))

async function copyText(text: string) {
  try {
    await navigator.clipboard.writeText(text)
  } catch (e) {
    console.warn('Copy failed', e)
  }
}
</script>


```

--------------------------------------------------------------------------------
/src/config/secret-manager.ts:
--------------------------------------------------------------------------------

```typescript
import { CryptoUtils } from '../utils/crypto.js'
import { Logger } from '../utils/logger.js'

export interface SecretManagerOptions {
  // Name of env var that holds the encryption key used for configuration secrets
  keyEnvVar?: string
  // Optional explicit key value (discouraged in production)
  key?: string
}

export class SecretManager {
  private key: string

  constructor(options?: SecretManagerOptions) {
    const env = (globalThis as any)?.process?.env ?? {}
    const provided = options?.key || env[options?.keyEnvVar || 'MASTER_CONFIG_KEY'] || env.MASTER_SECRET_KEY
    const isProd = (env.NODE_ENV || env.MASTER_ENV) === 'production'
    if (!provided) {
      if (isProd) throw new Error('Missing MASTER_CONFIG_KEY for decrypting secrets in production')
      Logger.warn('MASTER_CONFIG_KEY missing; using ephemeral key (dev only)')
      this.key = CryptoUtils.generateSecureRandom(32)
    } else {
      this.key = String(provided)
    }
  }

  getKey(): string {
    return this.key
  }

  encrypt(value: string): string {
    return `enc:gcm:${CryptoUtils.encrypt(value, this.key)}`
  }

  decrypt(value: string): string {
    if (value.startsWith('enc:gcm:')) {
      const raw = value.slice('enc:gcm:'.length)
      return CryptoUtils.decrypt(raw, this.key)
    }
    return value
  }

  isEncrypted(value: string): boolean {
    return typeof value === 'string' && value.indexOf('enc:gcm:') === 0
  }

  // Resolve secret placeholders within a config object
  // - enc:gcm:<base64> → decrypted
  // - env:VARNAME → process.env[VARNAME]
  resolveSecrets<T>(obj: T): T {
    const env = (globalThis as any)?.process?.env ?? {}
    const visit = (v: any): any => {
      if (typeof v === 'string') {
        const vs: string = String(v)
        if (this.isEncrypted(vs)) return this.decrypt(vs)
        if (vs.slice(0, 4) === 'env:') return String(env[vs.slice(4)] ?? '')
        return v
      }
      if (Array.isArray(v)) return v.map((x) => visit(x))
      if (v && typeof v === 'object') {
        const out: Record<string, unknown> = {}
        for (const [k, vv] of Object.entries(v)) out[k] = visit(vv)
        return out
      }
      return v
    }
    return visit(obj)
  }

  redact<T>(obj: T): T {
    const secretKeyMatcher = /secret|token|password|key/i
    const visit = (v: any, keyHint?: string): any => {
      if (typeof v === 'string') {
        const vs: string = String(v)
        if (this.isEncrypted(vs)) return '***'
        if (keyHint && secretKeyMatcher.test(keyHint)) return '***'
        if (vs.slice(0, 4) === 'env:' && secretKeyMatcher.test(keyHint || '')) return '***'
        return v
      }
      if (Array.isArray(v)) return v.map((x) => visit(x, keyHint))
      if (v && typeof v === 'object') {
        const out: Record<string, unknown> = {}
        for (const [k, vv] of Object.entries(v)) out[k] = visit(vv, k)
        return out
      }
      return v
    }
    return visit(obj)
  }

  rotate<T extends Record<string, unknown>>(obj: T, newKey: string, secretPaths?: string[]): T {
    // Re-encrypt values under known secret paths
    const prevKey = this.key
    this.key = newKey
    const result = structuredClone(obj)
    const paths = secretPaths ?? inferSecretPaths(obj)
    for (const p of paths) {
      try {
        const cur = getByPath(result, p)
        if (typeof cur === 'string') {
          const plain = this.isEncrypted(cur) ? CryptoUtils.decrypt(cur.slice('enc:gcm:'.length), prevKey) : cur
          setByPath(result, p, this.encrypt(plain))
        }
      } catch (err) {
        Logger.warn(`Failed to rotate secret at ${p}`, String(err))
      }
    }
    return result
  }
}

function getByPath(obj: any, path: string): unknown {
  const parts = path.split('.')
  let cur = obj
  for (const p of parts) {
    if (!cur || typeof cur !== 'object') return undefined
    cur = cur[p]
  }
  return cur
}

function setByPath(obj: any, path: string, value: unknown): void {
  const parts = path.split('.')
  let cur = obj
  for (let i = 0; i < parts.length - 1; i++) {
    const p = parts[i]
    if (!cur[p] || typeof cur[p] !== 'object') cur[p] = {}
    cur = cur[p]
  }
  cur[parts[parts.length - 1]] = value
}

function inferSecretPaths(obj: Record<string, unknown>, base = ''): string[] {
  const out: string[] = []
  for (const [k, v] of Object.entries(obj)) {
    const p = base ? `${base}.${k}` : k
    if (typeof v === 'string') {
      if (/secret|token|password|key/i.test(k)) out.push(p)
      else if (v.startsWith('enc:gcm:') || v.startsWith('env:')) out.push(p)
    } else if (v && typeof v === 'object') {
      out.push(...inferSecretPaths(v as Record<string, unknown>, p))
    }
  }
  return out
}

```

--------------------------------------------------------------------------------
/src/mcp-server.ts:
--------------------------------------------------------------------------------

```typescript
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'
import type { Request, Response } from 'express'
import { Logger } from './utils/logger.js'
import { DependencyContainer } from './server/dependency-container.js'
import { CallToolResult } from '@modelcontextprotocol/sdk/types.js'

// Create an MCP server with the official SDK
export async function createMcpServer(container: DependencyContainer): Promise<{
  mcpServer: McpServer,
  transport: StreamableHTTPServerTransport,
  handleRequest: (req: Request, res: Response) => Promise<void>
}> {
  // Create the MCP server with server info
  const mcpServer = new McpServer({
    name: 'master-mcp-server',
    version: '0.1.0'
  }, {
    capabilities: {
      tools: { listChanged: true },
      resources: { listChanged: true },
      prompts: { listChanged: true }
    }
  })

  // Register tools from the aggregated servers BEFORE connecting to transport
  const aggregatedTools = container.master.getAggregatedTools()
  Logger.info('Aggregated tools', { count: aggregatedTools.length, tools: aggregatedTools.map(t => t.name) })
  for (const tool of aggregatedTools) {
    // Skip tools with names that might cause conflicts
    if (tool.name.includes('..')) continue;
    
    Logger.info('Registering tool', { name: tool.name, description: tool.description })
    // Register the tool with the MCP server
    mcpServer.tool(tool.name, tool.description ?? '', async (args) => {
      try {
        // Route the tool call to the appropriate backend server
        const result = await container.master.handler.handleCallTool({
          name: tool.name,
          arguments: args
        })
        return result as CallToolResult
      } catch (error) {
        Logger.error('Tool execution failed', { tool: tool.name, error })
        return {
          content: [{
            type: 'text',
            text: `Error executing tool ${tool.name}: ${error instanceof Error ? error.message : String(error)}`
          }],
          isError: true
        }
      }
    })
  }

  // Register resources from the aggregated servers BEFORE connecting to transport
  const aggregatedResources = container.master.getAggregatedResources()
  Logger.info('Aggregated resources', { count: aggregatedResources.length, resources: aggregatedResources.map(r => r.uri) })
  for (const resource of aggregatedResources) {
    // Skip resources with URIs that might cause conflicts
    if (resource.uri.includes('..')) continue;
    
    Logger.info('Registering resource', { name: resource.name, uri: resource.uri, description: resource.description })
    mcpServer.resource(
      resource.name ?? resource.uri,
      resource.uri,
      {
        description: resource.description,
        mimeType: resource.mimeType
      },
      async () => {
        try {
          // Route the resource read to the appropriate backend server
          const result = await container.master.handler.handleReadResource({
            uri: resource.uri
          })
          
          // Convert the result to the format expected by the MCP server
          if (typeof result.contents === 'string') {
            return {
              contents: [{
                uri: resource.uri,
                text: result.contents,
                mimeType: result.mimeType
              }]
            }
          } else {
            return {
              contents: [{
                uri: resource.uri,
                blob: Buffer.from(result.contents).toString('base64'),
                mimeType: result.mimeType
              }]
            }
          }
        } catch (error) {
          Logger.error('Resource read failed', { resource: resource.uri, error })
          throw new Error(`Error reading resource ${resource.uri}: ${error instanceof Error ? error.message : String(error)}`)
        }
      }
    )
  }

  // Create the HTTP streaming transport in stateless mode
  const transport = new StreamableHTTPServerTransport({
    sessionIdGenerator: undefined, // Stateless mode
    enableJsonResponse: false, // Use SSE by default
    enableDnsRebindingProtection: false
  })

  // Connect the server to the transport AFTER registering tools and resources
  await mcpServer.connect(transport)

  // Create a handler function for Express
  const handleRequest = async (req: Request, res: Response) => {
    try {
      await transport.handleRequest(req, res, req.body)
    } catch (error) {
      Logger.error('MCP request handling failed', { error })
      res.status(500).json({
        error: 'Internal server error'
      })
    }
  }

  return { mcpServer, transport, handleRequest }
}
```

--------------------------------------------------------------------------------
/src/auth/token-manager.ts:
--------------------------------------------------------------------------------

```typescript
import type { OAuthToken } from '../types/auth.js'
import { CryptoUtils } from '../utils/crypto.js'
import { Logger } from '../utils/logger.js'

export interface TokenStorage {
  set(key: string, value: string): Promise<void> | void
  get(key: string): Promise<string | undefined> | string | undefined
  delete(key: string): Promise<void> | void
  entries(): AsyncIterable<[string, string]> | Iterable<[string, string]>
}

class InMemoryTokenStorage implements TokenStorage {
  private map = new Map<string, string>()

  set(key: string, value: string): void {
    this.map.set(key, value)
  }
  get(key: string): string | undefined {
    return this.map.get(key)
  }
  delete(key: string): void {
    this.map.delete(key)
  }
  *entries(): Iterable<[string, string]> {
    yield* this.map.entries()
  }
}

export class TokenManager {
  private readonly storage: TokenStorage
  private readonly encKey: string

  constructor(options?: { storage?: TokenStorage; secret?: string }) {
    this.storage = options?.storage ?? autoDetectStorage()
    const g: any = globalThis as any
    const env = (g?.process?.env ?? g?.__WORKER_ENV ?? {}) as Record<string, string>
    const provided = options?.secret ?? (env as any).TOKEN_ENC_KEY

    if (!provided) {
      const envName = ((g?.process?.env ?? (g?.__WORKER_ENV ?? {})) as any).NODE_ENV ?? 'development'
      if (envName === 'production') {
        throw new Error('TOKEN_ENC_KEY is required in production for secure token storage')
      }
      Logger.warn('TOKEN_ENC_KEY missing; generating ephemeral dev key (tokens won\'t persist across restarts)')
      this.encKey = CryptoUtils.generateSecureRandom(32)
    } else {
      this.encKey = provided
    }
  }

  async storeToken(key: string, token: OAuthToken): Promise<void> {
    const serialized = JSON.stringify(token)
    const encrypted = CryptoUtils.encrypt(serialized, this.encKey)
    await this.storage.set(key, encrypted)
  }

  async getToken(key: string): Promise<OAuthToken | null> {
    const encrypted = await this.storage.get(key)
    if (!encrypted) return null
    try {
      const decrypted = CryptoUtils.decrypt(encrypted, this.encKey)
      return JSON.parse(decrypted) as OAuthToken
    } catch (err) {
      Logger.error('Failed to decrypt token; deleting corrupted entry', { key, err: String(err) })
      await this.storage.delete(key)
      return null
    }
  }

  async cleanupExpiredTokens(): Promise<void> {
    const now = Date.now()
    for await (const [k, v] of this.storage.entries() as AsyncIterable<[string, string]>) {
      try {
        const tok = JSON.parse(CryptoUtils.decrypt(v, this.encKey)) as OAuthToken
        if (typeof tok.expires_at === 'number' && tok.expires_at <= now) {
          await this.storage.delete(k)
        }
      } catch {
        await this.storage.delete(k)
      }
    }
  }

  generateState(data: unknown): string {
    const payload = JSON.stringify({ d: data, t: Date.now() })
    return CryptoUtils.encrypt(payload, this.encKey)
  }

  validateState(state: string, expectedData: unknown): boolean {
    try {
      const payload = JSON.parse(CryptoUtils.decrypt(state, this.encKey)) as { d: unknown }
      return JSON.stringify(payload.d) === JSON.stringify(expectedData)
    } catch {
      return false
    }
  }
}

export { InMemoryTokenStorage }

/**
 * Auto-detects the best available storage backend.
 * - Cloudflare Workers: KV namespace bound as `TOKENS`
 * - Fallback: in-memory (non-persistent)
 */
function autoDetectStorage(): TokenStorage {
  const g: any = globalThis as any
  const env = g.__WORKER_ENV || {}
  const kv = env.TOKENS || g.TOKENS || g.TOKENS_KV
  if (kv && typeof kv.get === 'function' && typeof kv.put === 'function' && typeof kv.delete === 'function') {
    return new KVTokenStorage(kv)
  }
  return new InMemoryTokenStorage()
}

class KVTokenStorage implements TokenStorage {
  constructor(private readonly kv: { get: (k: string) => Promise<string | null>; put: (k: string, v: string, opts?: any) => Promise<void>; delete: (k: string) => Promise<void>; list?: (opts?: any) => Promise<{ keys: { name: string }[] }> }) {}
  async set(key: string, value: string): Promise<void> {
    await this.kv.put(key, value)
  }
  async get(key: string): Promise<string | undefined> {
    const v = await this.kv.get(key)
    return v === null ? undefined : v
  }
  async delete(key: string): Promise<void> {
    await this.kv.delete(key)
  }
  async *entries(): AsyncIterable<[string, string]> {
    if (typeof this.kv.list === 'function') {
      const { keys } = await this.kv.list()
      for (const k of keys) {
        const v = await this.kv.get(k.name)
        if (v !== null) yield [k.name, v]
      }
    } else {
      // KV without list support: nothing to iterate
      return
    }
  }
}

```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
import 'dotenv/config'
import express from 'express'
import type { Request, Response } from 'express'
import { DependencyContainer } from './server/dependency-container.js'
import { collectSystemMetrics } from './utils/monitoring.js'
import { CapabilityAggregator } from './modules/capability-aggregator.js'
import { createMcpServer } from './mcp-server.js'

export interface RunningServer {
  name: string
  version: string
  container: DependencyContainer
  stop: () => Promise<void>
}

function isNode(): boolean {
  return Boolean((globalThis as any)?.process?.versions?.node)
}

export async function createServer(startHttp = true): Promise<RunningServer> {
  const version = (globalThis as any)?.process?.env?.APP_VERSION ?? '0.1.0'
  const container = new DependencyContainer()
  await container.initialize()

  const server: RunningServer = {
    name: 'master-mcp-server',
    version,
    container,
    stop: async () => {
      try {
        container.configManager.stop()
        await container.master.unloadAll()
      } catch {
        // ignore
      }
    },
  }

  if (isNode() && startHttp) {
    await startNodeHttp(container)
  }

  // Graceful shutdown (Node only)
  if (isNode()) {
    const onSig = async () => {
      await server.stop()
      ;(process as any).exit?.(0)
    }
    process.on('SIGINT', onSig)
    process.on('SIGTERM', onSig)
  }

  return server
}

async function startNodeHttp(container: DependencyContainer): Promise<void> {
  const app = express()
  app.use(express.json())
  // Serve static assets for OAuth pages
  // eslint-disable-next-line @typescript-eslint/no-var-requires
  const expressStatic = (express as any).static
  if (expressStatic) app.use('/static', expressStatic('static'))

  const getToken = (req: Request): string | undefined => {
    const h = req.headers['authorization'] || req.headers['Authorization']
    if (typeof h === 'string' && h.toLowerCase().startsWith('bearer ')) return h.slice(7)
    return undefined
  }

  app.get('/health', (_req, res) => res.json({ ok: true }))
  app.get('/metrics', (_req, res) => {
    try {
      res.json({ ok: true, system: collectSystemMetrics() })
    } catch {
      res.json({ ok: true })
    }
  })
  // Mount OAuth endpoints using the master server's controller
  try {
    container.master.getOAuthFlowController().registerExpress(app)
  } catch {
    // If not available yet, ignore; will be mounted on demand if needed
  }
  app.get('/capabilities', (_req, res) => {
    const agg = new CapabilityAggregator()
    const caps = agg.aggregate(Array.from(container.master.getRouter().getServers().values()))
    res.json(caps)
  })

  // Create the MCP server with HTTP streaming transport
  const { handleRequest } = await createMcpServer(container)
  
  // Register MCP endpoints
  app.post('/mcp', handleRequest)
  app.get('/mcp', handleRequest)
  app.delete('/mcp', handleRequest)

  // Keep the existing endpoints for backward compatibility
  app.post('/mcp/tools/list', async (_req: Request, res: Response) => {
    const handler = container.master.handler
    const result = await handler.handleListTools({ type: 'list_tools' })
    res.json(result)
  })

  app.post('/mcp/tools/call', async (req: Request, res: Response) => {
    const token = getToken(req)
    const handler = new (container.master.handler.constructor as any)({
      aggregator: container.aggregator,
      router: container.master.getRouter(),
      getClientToken: () => token,
    }) as typeof container.master.handler
    const result = await handler.handleCallTool({ name: req.body?.name, arguments: req.body?.arguments ?? {} })
    res.json(result)
  })

  app.post('/mcp/resources/list', async (_req: Request, res: Response) => {
    const handler = container.master.handler
    const result = await handler.handleListResources({ type: 'list_resources' })
    res.json(result)
  })

  app.post('/mcp/resources/read', async (req: Request, res: Response) => {
    const token = getToken(req)
    const handler = new (container.master.handler.constructor as any)({
      aggregator: container.aggregator,
      router: container.master.getRouter(),
      getClientToken: () => token,
    }) as typeof container.master.handler
    const result = await handler.handleReadResource({ uri: req.body?.uri })
    res.json(result)
  })

  const port = container.getConfig().hosting.port ?? 3000
  await new Promise<void>((resolve) => {
    app.listen(port, () => {
      // eslint-disable-next-line no-console
      console.log(`Master MCP listening on http://localhost:${port}`)
      resolve()
    })
  })
}

export default createServer

// If this file is being run directly (not imported), start the server
if (import.meta.url === `file://${process.argv[1]}`) {
  createServer().catch((err) => {
    console.error('Failed to start server:', err)
    process.exit(1)
  })
}

```

--------------------------------------------------------------------------------
/src/utils/monitoring.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * Lightweight metrics, health checks, and profiling utilities.
 */

export type Labels = Record<string, string>

export class Counter {
  private value = 0
  inc(delta = 1): void {
    this.value += delta
  }
  get(): number {
    return this.value
  }
}

export class Gauge {
  private value = 0
  set(v: number): void {
    this.value = v
  }
  add(delta: number): void {
    this.value += delta
  }
  get(): number {
    return this.value
  }
}

export class Histogram {
  private readonly buckets: number[]
  private counts: number[]
  private sum = 0
  constructor(buckets = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10]) {
    this.buckets = [...buckets].sort((a, b) => a - b)
    this.counts = Array(this.buckets.length + 1).fill(0)
  }
  observe(value: number): void {
    this.sum += value
    for (let i = 0; i < this.buckets.length; i++) {
      if (value <= this.buckets[i]) {
        this.counts[i]++
        return
      }
    }
    this.counts[this.counts.length - 1]++
  }
  snapshot(): { buckets: number[]; counts: number[]; sum: number } {
    return { buckets: [...this.buckets], counts: [...this.counts], sum: this.sum }
  }
}

export class MetricRegistry {
  private counters = new Map<string, Counter>()
  private gauges = new Map<string, Gauge>()
  private histograms = new Map<string, Histogram>()

  counter(name: string): Counter {
    let c = this.counters.get(name)
    if (!c) {
      c = new Counter()
      this.counters.set(name, c)
    }
    return c
  }

  gauge(name: string): Gauge {
    let g = this.gauges.get(name)
    if (!g) {
      g = new Gauge()
      this.gauges.set(name, g)
    }
    return g
  }

  histogram(name: string, buckets?: number[]): Histogram {
    let h = this.histograms.get(name)
    if (!h) {
      h = new Histogram(buckets)
      this.histograms.set(name, h)
    }
    return h
  }

  list(): { counters: Record<string, number>; gauges: Record<string, number>; histograms: Record<string, ReturnType<Histogram['snapshot']>> } {
    const counters: Record<string, number> = {}
    const gauges: Record<string, number> = {}
    const histograms: Record<string, ReturnType<Histogram['snapshot']>> = {}
    for (const [k, v] of this.counters.entries()) counters[k] = v.get()
    for (const [k, v] of this.gauges.entries()) gauges[k] = v.get()
    for (const [k, v] of this.histograms.entries()) histograms[k] = v.snapshot()
    return { counters, gauges, histograms }
  }
}

export class HealthCheckRegistry {
  private checks = new Map<string, () => Promise<{ ok: boolean; info?: unknown }>>()
  register(name: string, fn: () => Promise<{ ok: boolean; info?: unknown }>): void {
    this.checks.set(name, fn)
  }
  unregister(name: string): void {
    this.checks.delete(name)
  }
  async run(): Promise<{ status: 'ok' | 'degraded' | 'fail'; results: Record<string, { ok: boolean; info?: unknown }> }> {
    const entries: [string, { ok: boolean; info?: unknown }][] = []
    for (const [name, fn] of this.checks) {
      try {
        const res = await fn()
        entries.push([name, res])
      } catch (e) {
        entries.push([name, { ok: false, info: e instanceof Error ? e.message : String(e) }])
      }
    }
    const results = Object.fromEntries(entries)
    const oks = entries.filter(([, r]) => r.ok).length
    const status: 'ok' | 'degraded' | 'fail' = oks === entries.length ? 'ok' : oks > 0 ? 'degraded' : 'fail'
    return { status, results }
  }
}

/** Monitors event loop delay by scheduling microtasks. Returns a stop function. */
export function monitorEventLoopLag(callback: (lagMs: number) => void, intervalMs = 500): () => void {
  let timer: any
  let stopped = false
  const tick = () => {
    if (stopped) return
    const start = now()
    timer = setTimeout(() => {
      const lag = now() - start - intervalMs
      callback(Math.max(0, lag))
      tick()
    }, intervalMs)
  }
  tick()
  return () => {
    stopped = true
    if (typeof clearTimeout === 'function' && timer) clearTimeout(timer)
  }
}

export function now(): number {
  if (typeof performance !== 'undefined' && typeof performance.now === 'function') return performance.now()
  return Date.now()
}

export function collectSystemMetrics(): Record<string, unknown> {
  const g: any = globalThis as any
  const out: Record<string, unknown> = { timestamp: new Date().toISOString() }
  try {
    if (g.process?.memoryUsage) {
      const m = g.process.memoryUsage()
      out.memory = {
        rss: m.rss,
        heapTotal: m.heapTotal,
        heapUsed: m.heapUsed,
        external: m.external,
      }
    }
    if (g.os?.loadavg) {
      const l = g.os.loadavg()
      out.loadavg = { '1m': l[0], '5m': l[1], '15m': l[2] }
    }
  } catch {
    // ignore
  }
  // Workers: best-effort
  if (!out.memory && (performance as any)?.memory) {
    out.memory = (performance as any).memory
  }
  return out
}


```

--------------------------------------------------------------------------------
/src/routing/circuit-breaker.ts:
--------------------------------------------------------------------------------

```typescript
import { Logger } from '../utils/logger.js'

export type CircuitState = 'closed' | 'open' | 'half_open'

export interface CircuitRecord {
  state: CircuitState
  failures: number
  successes: number
  nextTryAt: number // epoch ms when half-open trial is permitted
  openedAt?: number
  halfOpenInProgress?: boolean
}

export interface CircuitBreakerOptions {
  failureThreshold: number // failures before opening circuit
  successThreshold: number // successes in half-open before closing
  recoveryTimeoutMs: number // time to wait before permitting a half-open trial
  name?: string
}

export interface CircuitStorage {
  get(key: string): CircuitRecord | undefined
  set(key: string, value: CircuitRecord): void
  delete?(key: string): void
}

export class InMemoryCircuitStorage implements CircuitStorage {
  private readonly map = new Map<string, CircuitRecord>()
  get(key: string): CircuitRecord | undefined {
    return this.map.get(key)
  }
  set(key: string, value: CircuitRecord): void {
    this.map.set(key, value)
  }
  delete(key: string): void {
    this.map.delete(key)
  }
}

export class CircuitOpenError extends Error {
  readonly retryAfterMs?: number
  constructor(message: string, retryAfterMs?: number) {
    super(message)
    this.name = 'CircuitOpenError'
    this.retryAfterMs = retryAfterMs
  }
}

export class CircuitBreaker {
  private readonly storage: CircuitStorage
  private readonly opts: Required<CircuitBreakerOptions>

  constructor(options?: Partial<CircuitBreakerOptions>, storage?: CircuitStorage) {
    this.opts = {
      failureThreshold: options?.failureThreshold ?? 5,
      successThreshold: options?.successThreshold ?? 2,
      recoveryTimeoutMs: options?.recoveryTimeoutMs ?? 30_000,
      name: options?.name ?? 'default',
    }
    this.storage = storage ?? new InMemoryCircuitStorage()
  }

  private now(): number {
    return Date.now()
  }

  private initial(): CircuitRecord {
    return { state: 'closed', failures: 0, successes: 0, nextTryAt: 0 }
  }

  private getRecord(key: string): CircuitRecord {
    return this.storage.get(key) ?? this.initial()
  }

  canExecute(key: string): { allowed: boolean; state: CircuitState; retryAfterMs?: number } {
    const rec = this.getRecord(key)
    const now = this.now()
    if (rec.state === 'open') {
      if (now >= rec.nextTryAt && !rec.halfOpenInProgress) {
        rec.state = 'half_open'
        rec.halfOpenInProgress = true
        rec.successes = 0
        this.storage.set(key, rec)
        return { allowed: true, state: rec.state }
      }
      return { allowed: false, state: 'open', retryAfterMs: Math.max(0, rec.nextTryAt - now) }
    }
    if (rec.state === 'half_open') {
      // Only permit one in-flight trial at a time
      if (rec.halfOpenInProgress) return { allowed: false, state: 'half_open', retryAfterMs: this.opts.recoveryTimeoutMs }
      rec.halfOpenInProgress = true
      this.storage.set(key, rec)
      return { allowed: true, state: rec.state }
    }
    return { allowed: true, state: rec.state }
  }

  onSuccess(key: string): void {
    const rec = this.getRecord(key)
    if (rec.state === 'half_open') {
      rec.successes += 1
      rec.halfOpenInProgress = false
      if (rec.successes >= this.opts.successThreshold) {
        // Close the circuit after consecutive successes
        this.storage.set(key, this.initial())
        Logger.debug(`[Circuit] CLOSED after half-open successes`, { key, name: this.opts.name })
        return
      }
      this.storage.set(key, rec)
      return
    }
    // Closed state: reset failures on success
    rec.failures = 0
    this.storage.set(key, rec)
  }

  onFailure(key: string, _error?: unknown): void {
    const rec = this.getRecord(key)
    const now = this.now()
    if (rec.state === 'half_open') {
      // Failure during half-open => immediately open again
      rec.state = 'open'
      rec.failures = this.opts.failureThreshold
      rec.successes = 0
      rec.openedAt = now
      rec.nextTryAt = now + this.opts.recoveryTimeoutMs
      rec.halfOpenInProgress = false
      this.storage.set(key, rec)
      Logger.debug(`[Circuit] RE-OPEN after half-open failure`, { key, name: this.opts.name })
      return
    }

    rec.failures += 1
    if (rec.failures >= this.opts.failureThreshold) {
      rec.state = 'open'
      rec.openedAt = now
      rec.nextTryAt = now + this.opts.recoveryTimeoutMs
      this.storage.set(key, rec)
      Logger.debug(`[Circuit] OPEN due to failures`, { key, name: this.opts.name, failures: rec.failures })
    } else {
      this.storage.set(key, rec)
    }
  }

  async execute<T>(key: string, fn: () => Promise<T>): Promise<T> {
    const gate = this.canExecute(key)
    if (!gate.allowed) throw new CircuitOpenError('Circuit open', gate.retryAfterMs)
    try {
      const result = await fn()
      this.onSuccess(key)
      return result
    } catch (err) {
      this.onFailure(key, err)
      throw err
    }
  }
}


```

--------------------------------------------------------------------------------
/tests/servers/test-streaming-both-simple.js:
--------------------------------------------------------------------------------

```javascript
#!/usr/bin/env node

import { spawn } from 'node:child_process'
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'

async function startHttpServer() {
  console.log('Starting HTTP test server...')
  
  // Start the HTTP server as a background process
  const httpServer = spawn('node', ['examples/test-mcp-server.js'], {
    stdio: ['ignore', 'pipe', 'pipe'],
    env: { ...process.env, PORT: '3006' }
  })
  
  // Capture stdout and stderr
  httpServer.stdout.on('data', (data) => {
    console.log(`[HTTP Server] ${data.toString().trim()}`)
  })
  
  httpServer.stderr.on('data', (data) => {
    console.error(`[HTTP Server ERROR] ${data.toString().trim()}`)
  })
  
  // Wait for the server to start
  await new Promise((resolve, reject) => {
    let timeout = setTimeout(() => {
      reject(new Error('HTTP server startup timeout'))
    }, 5000)
    
    httpServer.stdout.on('data', (data) => {
      if (data.toString().includes('Test MCP server listening')) {
        clearTimeout(timeout)
        resolve()
      }
    })
  })
  
  return httpServer
}

async function runStreamingTest() {
  try {
    console.log('Testing Master MCP Server with HTTP Streaming...')
    
    // Create a streamable HTTP transport to connect to our MCP server
    const transport = new StreamableHTTPClientTransport(new URL('http://localhost:3005/mcp'))
    
    // Create the MCP client
    const client = new Client({
      name: 'master-mcp-streaming-test-client',
      version: '1.0.0'
    })
    
    // Initialize the client
    await client.connect(transport)
    console.log('✅ Server initialized with streaming transport')
    console.log('Server info:', client.getServerVersion())
    console.log('Server capabilities:', client.getServerCapabilities())
    
    // List tools using streaming
    console.log('\n--- Testing tools/list with streaming ---')
    const toolsResult = await client.listTools({})
    console.log('✅ tools/list successful with streaming')
    console.log('Number of tools:', toolsResult.tools.length)
    console.log('Tools:', toolsResult.tools.map(t => t.name))
    
    // Verify both servers are present
    const hasHttpTool = toolsResult.tools.some(t => t.name === 'test-server.echo')
    const hasStdioTool = toolsResult.tools.some(t => t.name === 'stdio-server.stdio-echo')
    
    if (hasHttpTool) {
      console.log('✅ HTTP server tool found')
    } else {
      console.log('❌ HTTP server tool not found')
    }
    
    if (hasStdioTool) {
      console.log('✅ STDIO server tool found')
    } else {
      console.log('❌ STDIO server tool not found')
    }
    
    // List resources using streaming
    console.log('\n--- Testing resources/list with streaming ---')
    const resourcesResult = await client.listResources({})
    console.log('✅ resources/list successful with streaming')
    console.log('Number of resources:', resourcesResult.resources.length)
    console.log('Resources:', resourcesResult.resources.map(r => r.uri))
    
    // Verify both servers are present
    const hasHttpResource = resourcesResult.resources.some(r => r.uri === 'test-server.test://example')
    const hasStdioResource = resourcesResult.resources.some(r => r.uri === 'stdio-server.stdio://example/resource')
    
    if (hasHttpResource) {
      console.log('✅ HTTP server resource found')
    } else {
      console.log('❌ HTTP server resource not found')
    }
    
    if (hasStdioResource) {
      console.log('✅ STDIO server resource found')
    } else {
      console.log('❌ STDIO server resource not found')
    }
    
    // Test ping
    console.log('\n--- Testing ping with streaming ---')
    const pingResult = await client.ping()
    console.log('✅ ping successful with streaming')
    console.log('Ping result:', pingResult)
    
    // Summary
    console.log('\n--- Test Summary ---')
    if (hasHttpTool && hasStdioTool && hasHttpResource && hasStdioResource) {
      console.log('🎉 All tests passed! Both HTTP and STDIO servers are working correctly.')
    } else {
      console.log('⚠️ Some tests failed. Check the output above for details.')
    }
    
    // Close the connection
    await client.close()
    console.log('\n✅ Disconnected from MCP server')
    
  } catch (error) {
    console.error('❌ Streaming test failed:', error)
    console.error('Error stack:', error.stack)
  }
}

async function main() {
  let httpServer
  
  try {
    // Start the HTTP server
    httpServer = await startHttpServer()
    
    // Wait a bit for the master server to discover the HTTP server
    console.log('Waiting for server discovery...')
    await new Promise(resolve => setTimeout(resolve, 3000))
    
    // Run the streaming test
    await runStreamingTest()
  } catch (error) {
    console.error('Test failed:', error)
  } finally {
    // Clean up: kill the HTTP server
    if (httpServer) {
      console.log('Stopping HTTP server...')
      httpServer.kill()
    }
  }
}

// Run the test
main()
```

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

```vue
<template>
  <div class="mcp-callout">
    <label>Strategy
      <select v-model="strategy" style="margin-left:8px">
        <option value="master_oauth">master_oauth</option>
        <option value="delegate_oauth">delegate_oauth</option>
        <option value="proxy_oauth">proxy_oauth</option>
        <option value="bypass_auth">bypass_auth</option>
      </select>
    </label>
  </div>

  <div class="mcp-grid" style="align-items:start">
    <div class="mcp-col-6">
      <h4 style="margin:8px 0">Flow</h4>
      <ul>
        <li v-for="(s, i) in flow.steps" :key="i">{{ s }}</li>
      </ul>
      <div class="mcp-callout" v-if="flow.note">{{ flow.note }}</div>
    </div>
    <div class="mcp-col-6">
      <h4 style="margin:8px 0">Diagram</h4>
      <div class="mcp-diagram">
        <svg viewBox="0 0 600 240" width="100%" height="180">
          <defs>
            <marker id="arrow" markerWidth="10" markerHeight="10" refX="6" refY="3" orient="auto">
              <path d="M0,0 L0,6 L6,3 z" fill="currentColor" />
            </marker>
          </defs>
          <!-- Nodes -->
          <rect x="30" y="30" width="140" height="40" rx="8" fill="none" stroke="currentColor" />
          <text x="100" y="55" text-anchor="middle">Client</text>
          <rect x="230" y="30" width="140" height="40" rx="8" fill="none" stroke="currentColor" />
          <text x="300" y="55" text-anchor="middle">Master</text>
          <rect x="430" y="30" width="140" height="40" rx="8" fill="none" stroke="currentColor" />
          <text x="500" y="55" text-anchor="middle">Backend</text>

          <!-- Arrows vary by strategy -->
          <g v-if="strategy==='master_oauth'">
            <path d="M170,50 L230,50" stroke="currentColor" marker-end="url(#arrow)" />
            <text x="200" y="40" text-anchor="middle">Bearer client_token</text>
            <path d="M370,50 L430,50" stroke="currentColor" marker-end="url(#arrow)" />
            <text x="400" y="40" text-anchor="middle">Bearer client_token</text>
          </g>
          <g v-else-if="strategy==='delegate_oauth'">
            <path d="M170,50 L230,50" stroke="currentColor" marker-end="url(#arrow)" />
            <text x="200" y="40" text-anchor="middle">call tool</text>
            <path d="M230,90 L120,160" stroke="currentColor" marker-end="url(#arrow)" />
            <text x="170" y="130" text-anchor="middle">302 authorize</text>
            <path d="M120,160 L430,50" stroke="currentColor" marker-end="url(#arrow)" />
            <text x="275" y="120" text-anchor="middle">code + PKCE</text>
            <path d="M430,50 L230,50" stroke="currentColor" marker-end="url(#arrow)" />
            <text x="330" y="40" text-anchor="middle">token stored</text>
          </g>
          <g v-else-if="strategy==='proxy_oauth'">
            <path d="M170,50 L230,50" stroke="currentColor" marker-end="url(#arrow)" />
            <text x="200" y="40" text-anchor="middle">call tool</text>
            <path d="M370,50 L430,50" stroke="currentColor" marker-end="url(#arrow)" />
            <text x="400" y="40" text-anchor="middle">Bearer backend_token</text>
            <path d="M300,70 L300,120 L430,120" stroke="currentColor" marker-end="url(#arrow)" />
            <text x="360" y="110" text-anchor="middle">refresh if needed</text>
          </g>
          <g v-else>
            <path d="M170,50 L230,50" stroke="currentColor" marker-end="url(#arrow)" />
            <path d="M370,50 L430,50" stroke="currentColor" marker-end="url(#arrow)" />
            <text x="400" y="40" text-anchor="middle">no auth header</text>
          </g>
        </svg>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, ref } from 'vue'

const strategy = ref<'master_oauth'|'delegate_oauth'|'proxy_oauth'|'bypass_auth'>('master_oauth')

const flow = computed(() => {
  switch (strategy.value) {
    case 'master_oauth':
      return {
        steps: [
          'Client calls master with Authorization: Bearer <client_token>',
          'Master forwards same token to backend',
          'Backend validates token and serves the request'
        ],
        note: 'Simple and effective when backends trust the same issuer/audience as the client.'
      }
    case 'delegate_oauth':
      return {
        steps: [
          'Client calls master; master requires backend auth',
          'Master responds with OAuth delegation metadata',
          'Client completes provider auth via /oauth/authorize and callback',
          'Master stores backend token and retries the call'
        ],
        note: 'Use PKCE + state. Configure provider endpoints and client credentials.'
      }
    case 'proxy_oauth':
      return {
        steps: [
          'Master manages backend tokens and refresh cycles',
          'Requests include backend token; refresh on expiry',
          'Fallback to delegation or pass-through as configured'
        ],
        note: 'Centralizes token lifecycle with fewer client prompts.'
      }
    default:
      return {
        steps: [
          'No authentication is added by master',
          'Backend must not require Authorization for selected endpoints'
        ],
        note: 'Use only for public or development backends.'
      }
  }
})
</script>


```

--------------------------------------------------------------------------------
/docs/.vitepress/config.ts:
--------------------------------------------------------------------------------

```typescript
import { defineConfig } from 'vitepress'

export default defineConfig({
  title: 'Master MCP Server',
  description: 'Aggregate and orchestrate multiple MCP servers behind one endpoint',
  lastUpdated: true,
  cleanUrls: true,
  head: [
    ['meta', { name: 'theme-color', content: '#0ea5e9' }],
    ['meta', { name: 'viewport', content: 'width=device-width, initial-scale=1' }],
  ],
  themeConfig: {
    logo: '/logo.svg',
    siteTitle: 'Master MCP Server',
    search: {
      provider: 'local'
    },
    socialLinks: [
      { icon: 'github', link: 'https://github.com/your-org/master-mcp-server' }
    ],
    outline: [2, 6],
    nav: [
      { text: 'Getting Started', link: '/getting-started/overview' },
      { text: 'Guides', link: '/guides/index' },
      { text: 'API', link: '/api/index' },
      { text: 'Configuration', link: '/configuration/overview' },
      { text: 'Deployment', link: '/deployment/index' },
      { text: 'Examples', link: '/examples/index' },
      { text: 'Advanced', link: '/advanced/index' },
      { text: 'Troubleshooting', link: '/troubleshooting/index' },
      { text: 'Contributing', link: '/contributing/index' }
    ],
    sidebar: {
      '/getting-started/': [
        {
          text: 'Getting Started',
          items: [
            { text: 'Overview', link: '/getting-started/overview' },
            { text: 'Installation', link: '/getting-started/installation' },
            { text: 'Quick Start', link: '/getting-started/quick-start' },
            { text: 'Quickstart (Node)', link: '/getting-started/quickstart-node' },
            { text: 'Quickstart (Workers)', link: '/getting-started/quickstart-workers' },
            { text: 'Core Concepts', link: '/getting-started/concepts' }
          ]
        }
      ],
      '/guides/': [
        {
          text: 'User Guides',
          items: [
            { text: 'Authentication', link: '/guides/authentication' },
            { text: 'OAuth Delegation', link: '/guides/oauth-delegation' },
            { text: 'Client Integration', link: '/guides/client-integration' },
            { text: 'Server Sharing', link: '/guides/server-sharing' },
            { text: 'Module Loading', link: '/guides/module-loading' },
            { text: 'Request Routing', link: '/guides/request-routing' },
            { text: 'Configuration', link: '/guides/configuration' },
            { text: 'Testing Strategy', link: '/guides/testing' }
          ]
        }
      ],
      '/api/': [
        {
          text: 'API Reference',
          items: [
            { text: 'Overview', link: '/api/index' },
            { text: 'Types', link: '/api/reference/modules' }
          ]
        }
      ],
      '/configuration/': [
        {
          text: 'Configuration',
          items: [
            { text: 'Overview', link: '/configuration/overview' },
            { text: 'Reference', link: '/configuration/reference' },
            { text: 'Examples', link: '/configuration/examples' },
            { text: 'Environment Variables', link: '/configuration/environment' }
          ]
        }
      ],
      '/deployment/': [
        {
          text: 'Deployment',
          items: [
            { text: 'Overview', link: '/deployment/index' },
            { text: 'Docker', link: '/deployment/docker' },
            { text: 'Cloudflare Workers', link: '/deployment/cloudflare-workers' },
            { text: 'Koyeb', link: '/deployment/koyeb' },
            { text: 'Docs Site', link: '/deployment/docs-site' }
          ]
        }
      ],
      '/examples/': [
        {
          text: 'Examples',
          items: [
            { text: 'Index', link: '/examples/index' },
            { text: 'Basic Node Aggregator', link: '/examples/basic-node' },
            { text: 'Cloudflare Worker', link: '/examples/cloudflare-worker' },
            { text: 'Advanced Routing', link: '/examples/advanced-routing' },
            { text: 'OAuth Delegation', link: '/examples/oauth-delegation' },
            { text: 'Testing Patterns', link: '/examples/testing' }
          ]
        }
      ],
      '/advanced/': [
        {
          text: 'Advanced Topics',
          items: [
            { text: 'Security Hardening', link: '/advanced/security' },
            { text: 'Performance & Scalability', link: '/advanced/performance' },
            { text: 'Monitoring & Logging', link: '/advanced/monitoring' },
            { text: 'Extensibility & Plugins', link: '/advanced/extensibility' }
          ]
        }
      ],
      '/troubleshooting/': [
        {
          text: 'Troubleshooting',
          items: [
            { text: 'Common Issues', link: '/troubleshooting/index' },
            { text: 'OAuth & Tokens', link: '/troubleshooting/oauth' },
            { text: 'Routing & Modules', link: '/troubleshooting/routing' },
            { text: 'Deployment', link: '/troubleshooting/deployment' }
          ]
        }
      ],
      '/contributing/': [
        {
          text: 'Contributing',
          items: [
            { text: 'Overview', link: '/contributing/index' },
            { text: 'Development Setup', link: '/contributing/dev-setup' },
            { text: 'Coding & Docs Guidelines', link: '/contributing/guidelines' }
          ]
        }
      ]
    }
  }
})

```

--------------------------------------------------------------------------------
/src/server/config-manager.ts:
--------------------------------------------------------------------------------

```typescript
import type { MasterConfig, RoutingConfig, ServerConfig } from '../types/config.js'
import { ConfigLoader } from '../config/config-loader.js'
import { Logger } from '../utils/logger.js'
import { EnvironmentManager } from '../config/environment-manager.js'
import { SecretManager } from '../config/secret-manager.js'

export interface ConfigManagerOptions {
  // If provided, watch the file for changes (Node only)
  watch?: boolean
}

type Listener = (config: MasterConfig) => void

export class ConfigManager {
  private config: MasterConfig | null = null
  private readonly listeners: Set<Listener> = new Set()
  private stopWatcher?: () => void
  private readonly secrets = new SecretManager()
  private watchPaths: string[] = []

  constructor(private readonly options?: ConfigManagerOptions) {}

  async load(): Promise<MasterConfig> {
    const explicit = EnvironmentManager.getExplicitConfigPath()
    let loaded: MasterConfig
    try {
      loaded = await ConfigLoader.load({ path: explicit })
    } catch (err) {
      Logger.warn('Primary config load failed; attempting env-only load', String(err))
      loaded = await ConfigLoader.loadFromEnv()
    }
    const normalized = this.applyDefaults(loaded)
    this.config = normalized
    const redacted = this.secrets.redact(normalized)
    Logger.info('Configuration loaded', {
      servers: normalized.servers.length,
      hosting: normalized.hosting.platform,
      redacted,
    })
    if (this.options?.watch) this.prepareWatcher(explicit)
    return normalized
  }

  getConfig(): MasterConfig {
    if (!this.config) throw new Error('Config not loaded')
    return this.config
  }

  getRouting(): RoutingConfig | undefined {
    return this.config?.routing
  }

  onChange(listener: Listener): () => void {
    this.listeners.add(listener)
    return () => this.listeners.delete(listener)
  }

  async reload(): Promise<void> {
    await this.load()
    if (this.config) this.emit(this.config)
  }

  stop(): void {
    try {
      this.stopWatcher?.()
    } catch {
      // ignore
    }
  }

  private emit(config: MasterConfig): void {
    for (const l of this.listeners) {
      try {
        l(config)
      } catch (err) {
        Logger.warn('Config listener threw', err)
      }
    }
  }

  private applyDefaults(cfg: MasterConfig): MasterConfig {
    // Shallow copy to avoid mutation
    const copy: MasterConfig = {
      ...cfg,
      hosting: {
        platform: cfg.hosting.platform ?? 'node',
        port: cfg.hosting.port ?? 3000,
        base_url: cfg.hosting.base_url,
      },
      routing: cfg.routing ? { ...cfg.routing } : {},
      master_oauth: { ...cfg.master_oauth },
      servers: cfg.servers.map((s) => this.normalizeServer(s)),
    }
    return copy
  }

  private normalizeServer(s: ServerConfig): ServerConfig {
    const port = s.config?.port
    const normalized: ServerConfig = {
      ...s,
      config: {
        environment: s.config?.environment ?? {},
        args: s.config?.args ?? [],
        ...(port ? { port } : {}),
      },
    }
    return normalized
  }

  private prepareWatcher(explicitPath?: string): void {
    const isNode = Boolean((globalThis as any)?.process?.versions?.node)
    if (!isNode) return
    const { base, env } = EnvironmentManager.getConfigPaths('config')
    this.watchPaths = []
    if (explicitPath) this.watchPaths.push(explicitPath)
    if (base) this.watchPaths.push(base)
    if (env) this.watchPaths.push(env)
    this.startWatcher()
  }

  private startWatcher(): void {
    const isNode = Boolean((globalThis as any)?.process?.versions?.node)
    if (!isNode || this.watchPaths.length === 0) return
    import('node:fs').then((fs) => {
      const watchers: any[] = []
      const onChange = async () => {
        try {
          Logger.info('Config change detected; validating and reloading...')
          const prev = this.config
          const newCfg = await ConfigLoader.load({ path: EnvironmentManager.getExplicitConfigPath() })
          const applied = this.applyDefaults(newCfg)
          if (prev) this.auditDiff(prev, applied)
          this.config = applied
          this.emit(this.config)
        } catch (err) {
          Logger.warn('Hot-reload failed to apply new config', String(err))
        }
      }
      for (const p of this.watchPaths) {
        try {
          watchers.push((fs as any).watch(p, { persistent: false }, onChange))
        } catch (err) {
          Logger.warn(`Failed to watch ${p}`, String(err))
        }
      }
      this.stopWatcher = () => {
        for (const w of watchers) {
          try {
            w?.close?.()
          } catch {
            // ignore
          }
        }
      }
    }).catch((err) => Logger.warn('Failed to start config file watcher', String(err)))
  }

  private auditDiff(oldCfg: MasterConfig, newCfg: MasterConfig): void {
    const diff: Record<string, { from: unknown; to: unknown }> = {}
    const keys = new Set([...Object.keys(oldCfg), ...Object.keys(newCfg)])
    for (const k of keys) {
      const a: any = (oldCfg as any)[k]
      const b: any = (newCfg as any)[k]
      if (JSON.stringify(a) !== JSON.stringify(b)) diff[k] = { from: a, to: b }
    }
    const redacted = this.secrets.redact(diff)
    // Highlight non-hot-reloadable settings
    if (oldCfg.hosting?.port !== newCfg.hosting?.port) {
      Logger.warn('Hosting port changed; restart required to apply')
    }
    Logger.info('Config change audit', redacted)
  }
}

```

--------------------------------------------------------------------------------
/docs/configuration/reference.md:
--------------------------------------------------------------------------------

```markdown
# Configuration Reference

Configuration can be provided as JSON or YAML. The loader merges:

1) `config/default.json`
2) `config/<env>.json` (`MASTER_ENV` or `NODE_ENV`)
3) Environment overrides
4) CLI overrides
5) Explicit file from `MASTER_CONFIG_PATH`

Validated against `config/schema.json` (or embedded fallback).

## Top-Level Fields

- `master_oauth` (required): OAuth settings for the master/client tokens
  - `authorization_endpoint` (url)
  - `token_endpoint` (url)
  - `client_id` (string)
  - `client_secret` (string | `env:VAR` | `enc:gcm:...`)
  - `redirect_uri` (string)
  - `scopes` (string[])
  - `issuer?` (string)
  - `jwks_uri?` (string)
  - `audience?` (string)
- `hosting` (required)
  - `platform`: `node` | `cloudflare-workers` | `koyeb` | `docker` | `unknown`
  - `port?`: integer (Node only)
  - `base_url?`: used for OAuth redirect URL construction
  - `storage_backend?`: hints (e.g., `kv`, `durable_object`, `fs`)
- `logging`
  - `level`: `debug` | `info` | `warn` | `error`
- `routing`
  - `loadBalancer.strategy`: `round_robin` | `weighted` | `health`
  - `circuitBreaker`: `failureThreshold`, `successThreshold`, `recoveryTimeoutMs`
  - `retry`: `maxRetries`, `baseDelayMs`, `maxDelayMs`, `backoffFactor`, `jitter`, `retryOn.*`
- `security`
  - `config_key_env?`: env var name containing config secret key (defaults to `MASTER_CONFIG_KEY`)
  - `audit?`: enable config change audit logs
  - `rotation_days?`: secret rotation policy hint
- `servers` (required) — array of:
  - `id` (string)
  - `type`: `git` | `npm` | `pypi` | `docker` | `local`
  - `auth_strategy`: `master_oauth` | `delegate_oauth` | `bypass_auth` | `proxy_oauth`
  - `auth_config?`: provider-specific details
  - `config`:
    - `port?` (integer)
    - `environment?` (map)
    - `args?` (string[])

## YAML Example

```yaml
hosting:
  platform: node
  port: 3000

logging:
  level: info

routing:
  loadBalancer: { strategy: round_robin }
  circuitBreaker: { failureThreshold: 5, successThreshold: 2, recoveryTimeoutMs: 30000 }
  retry: { maxRetries: 2, baseDelayMs: 250, maxDelayMs: 4000, backoffFactor: 2, jitter: full }

master_oauth:
  authorization_endpoint: https://example.com/oauth/authorize
  token_endpoint: https://example.com/oauth/token
  client_id: master-mcp
  client_secret: env:MASTER_OAUTH_CLIENT_SECRET
  redirect_uri: http://localhost:3000/oauth/callback
  scopes: [openid]

servers:
  - id: tools
    type: local
    auth_strategy: bypass_auth
    config:
      port: 3333
```

<!-- GENERATED:BEGIN -->

# Configuration Reference

This reference is generated from the built-in JSON Schema used by the server to validate configuration.

## Top-Level Fields

- `master_oauth` (required) — type: object
  - `master_oauth.issuer` — type: string
  - `master_oauth.authorization_endpoint` (required) — type: string, format: url
  - `master_oauth.token_endpoint` (required) — type: string, format: url
  - `master_oauth.jwks_uri` — type: string
  - `master_oauth.client_id` (required) — type: string
  - `master_oauth.client_secret` — type: string
  - `master_oauth.redirect_uri` (required) — type: string
  - `master_oauth.scopes` (required) — type: array
      - items: — type: string
  - `master_oauth.audience` — type: string
- `hosting` (required) — type: object
  - `hosting.platform` (required) — type: string, enum: node, cloudflare-workers, koyeb, docker, unknown
  - `hosting.port` — type: number, format: integer
  - `hosting.base_url` — type: string
- `logging` — type: object
  - `logging.level` — type: string, enum: debug, info, warn, error
- `routing` — type: object
  - `routing.loadBalancer` — type: object
    - `routing.loadBalancer.strategy` — type: string
  - `routing.circuitBreaker` — type: object
  - `routing.retry` — type: object
- `servers` (required) — type: array
    - items: — type: object
      - `servers[].id` (required) — type: string
      - `servers[].type` (required) — type: string, enum: git, npm, pypi, docker, local
      - `servers[].url` — type: string
      - `servers[].package` — type: string
      - `servers[].version` — type: string
      - `servers[].branch` — type: string
      - `servers[].auth_strategy` (required) — type: string, enum: master_oauth, delegate_oauth, bypass_auth, proxy_oauth
      - `servers[].auth_config` — type: object
      - `servers[].config` (required) — type: object
        - `servers[].config.environment` — type: object
        - `servers[].config.args` — type: array
            - items: — type: string
        - `servers[].config.port` — type: number, format: integer


## Examples

## Example: basic.yaml

```yaml
hosting:
  platform: node
  port: 3000

master_oauth:
  authorization_endpoint: https://example.com/auth
  token_endpoint: https://example.com/token
  client_id: demo-client
  redirect_uri: http://localhost:3000/callback
  scopes:
    - openid

servers:
  - id: example
    type: local
    auth_strategy: master_oauth
    config:
      environment: {}
      args: []
      port: 3333


```

## Example: simple-setup.yaml

```yaml
hosting:
  platform: node
  port: 3000

master_oauth:
  authorization_endpoint: https://auth.example.com/authorize
  token_endpoint: https://auth.example.com/token
  client_id: master-mcp
  redirect_uri: http://localhost:3000/oauth/callback
  scopes: [openid, profile]

servers:
  - id: local-simple
    type: local
    auth_strategy: bypass_auth
    config:
      port: 4001
      environment: {}


```


<!-- GENERATED:END -->
```

--------------------------------------------------------------------------------
/tests/servers/test-streaming-both.js:
--------------------------------------------------------------------------------

```javascript
#!/usr/bin/env node

import { spawn } from 'node:child_process'
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'

async function startHttpServer() {
  console.log('Starting HTTP test server...')
  
  // Start the HTTP server as a background process
  const httpServer = spawn('node', ['examples/test-mcp-server.js'], {
    stdio: ['ignore', 'pipe', 'pipe'],
    env: { ...process.env, PORT: '3006' }
  })
  
  // Capture stdout and stderr
  httpServer.stdout.on('data', (data) => {
    console.log(`[HTTP Server] ${data.toString().trim()}`)
  })
  
  httpServer.stderr.on('data', (data) => {
    console.error(`[HTTP Server ERROR] ${data.toString().trim()}`)
  })
  
  // Wait a moment for the server to start
  await new Promise(resolve => setTimeout(resolve, 2000))
  
  return httpServer
}

async function runStreamingTest() {
  try {
    console.log('Testing Master MCP Server with HTTP Streaming...')
    
    // Create a streamable HTTP transport to connect to our MCP server
    const transport = new StreamableHTTPClientTransport(new URL('http://localhost:3005/mcp'))
    
    // Create the MCP client
    const client = new Client({
      name: 'master-mcp-streaming-test-client',
      version: '1.0.0'
    })
    
    // Initialize the client
    await client.connect(transport)
    console.log('✅ Server initialized with streaming transport')
    console.log('Server info:', client.getServerVersion())
    console.log('Server capabilities:', client.getServerCapabilities())
    
    // List tools using streaming
    console.log('\n--- Testing tools/list with streaming ---')
    const toolsResult = await client.listTools({})
    console.log('✅ tools/list successful with streaming')
    console.log('Number of tools:', toolsResult.tools.length)
    console.log('Tools:', toolsResult.tools.map(t => t.name))
    
    // List resources using streaming
    console.log('\n--- Testing resources/list with streaming ---')
    const resourcesResult = await client.listResources({})
    console.log('✅ resources/list successful with streaming')
    console.log('Number of resources:', resourcesResult.resources.length)
    console.log('Resources:', resourcesResult.resources.map(r => r.uri))
    
    // Test ping
    console.log('\n--- Testing ping with streaming ---')
    const pingResult = await client.ping()
    console.log('✅ ping successful with streaming')
    console.log('Ping result:', pingResult)
    
    // Try calling a tool from the HTTP server
    console.log('\n--- Testing tool call to HTTP server ---')
    try {
      const httpToolCallResult = await client.callTool({
        name: 'test-server.echo',  // Prefixed with server ID
        arguments: { message: 'Hello from HTTP server!' }
      })
      console.log('✅ HTTP tool call successful')
      console.log('HTTP tool result:', JSON.stringify(httpToolCallResult, null, 2))
    } catch (error) {
      console.log('⚠️ HTTP tool call failed (might not be available):', error.message)
    }
    
    // Try calling a tool from the STDIO server
    console.log('\n--- Testing tool call to STDIO server ---')
    try {
      const stdioToolCallResult = await client.callTool({
        name: 'stdio-server.stdio-echo',  // Prefixed with server ID
        arguments: { message: 'Hello from STDIO server!' }
      })
      console.log('✅ STDIO tool call successful')
      console.log('STDIO tool result:', JSON.stringify(stdioToolCallResult, null, 2))
    } catch (error) {
      console.log('⚠️ STDIO tool call failed (might not be available):', error.message)
    }
    
    // Try reading a resource from the HTTP server
    console.log('\n--- Testing resource read from HTTP server ---')
    try {
      const httpResourceResult = await client.readResource({
        uri: 'test://example'  // This should be prefixed with server ID if needed
      })
      console.log('✅ HTTP resource read successful')
      console.log('HTTP resource result:', JSON.stringify(httpResourceResult, null, 2))
    } catch (error) {
      console.log('⚠️ HTTP resource read failed (might not be available):', error.message)
    }
    
    // Try reading a resource from the STDIO server
    console.log('\n--- Testing resource read from STDIO server ---')
    try {
      const stdioResourceResult = await client.readResource({
        uri: 'stdio-server.stdio://example/resource'  // Prefixed with server ID
      })
      console.log('✅ STDIO resource read successful')
      console.log('STDIO resource result:', JSON.stringify(stdioResourceResult, null, 2))
    } catch (error) {
      console.log('⚠️ STDIO resource read failed (might not be available):', error.message)
    }
    
    // Close the connection
    await client.close()
    console.log('\n✅ Disconnected from MCP server')
    console.log('\n🎉 All streaming tests completed successfully!')
    
  } catch (error) {
    console.error('❌ Streaming test failed:', error)
    console.error('Error stack:', error.stack)
  }
}

async function main() {
  let httpServer
  
  try {
    // Start the HTTP server
    httpServer = await startHttpServer()
    
    // Run the streaming test
    await runStreamingTest()
  } catch (error) {
    console.error('Test failed:', error)
  } finally {
    // Clean up: kill the HTTP server
    if (httpServer) {
      console.log('Stopping HTTP server...')
      httpServer.kill()
    }
  }
}

// Run the test
main()
```

--------------------------------------------------------------------------------
/src/config/environment-manager.ts:
--------------------------------------------------------------------------------

```typescript
import type { HostingConfig, MasterConfig } from '../types/config.js'
import { Logger } from '../utils/logger.js'

export type EnvironmentName = 'development' | 'staging' | 'production' | 'test'

function isNode(): boolean {
  return Boolean((globalThis as any)?.process?.versions?.node)
}

export class EnvironmentManager {
  static detectEnvironment(): EnvironmentName {
    const env = ((globalThis as any)?.process?.env?.MASTER_ENV ||
      (globalThis as any)?.process?.env?.NODE_ENV ||
      'development') as string
    const normalized = env.toLowerCase()
    if (normalized === 'prod') return 'production'
    if (normalized === 'stage' || normalized === 'staging') return 'staging'
    if (normalized === 'test') return 'test'
    return 'development'
  }

  static detectPlatform(): HostingConfig['platform'] {
    if (isNode()) return 'node'
    // Heuristic: in CF workers, 'WebSocketPair' and 'navigator' often exist
    // We default to workers if Node.js globals are absent
    return 'cloudflare-workers'
  }

  static getConfigPaths(baseDir = 'config'): { base?: string; env?: string; schema?: string } {
    const env = this.detectEnvironment()
    return {
      base: `${baseDir}/default.json`,
      env: `${baseDir}/${env}.json`,
      schema: `${baseDir}/schema.json`,
    }
  }

  static getExplicitConfigPath(): string | undefined {
    const fromEnv = (globalThis as any)?.process?.env?.MASTER_CONFIG_PATH
    const fromArg = isNode() ? EnvironmentManager.parseCliArgs().configPath : undefined
    return (fromArg as string | undefined) || (fromEnv as string | undefined)
  }

  static parseCliArgs(): { [k: string]: unknown; configPath?: string } {
    if (!isNode()) return {}
    const args = (process.argv || []).slice(2)
    const result: Record<string, unknown> = {}
    for (const a of args) {
      if (!a.startsWith('--')) continue
      const eq = a.indexOf('=')
      let key = a
      let val: unknown = true
      if (eq > -1) {
        key = a.slice(0, eq)
        const raw = a.slice(eq + 1)
        try {
          val = JSON.parse(raw)
        } catch {
          val = raw
        }
      }
      key = key.replace(/^--/, '')
      if (key === 'config' || key === 'config-path') {
        ;(result as any).configPath = String(val)
        continue
      }
      // Support dotted keys: --hosting.port=4000
      setByPath(result, key, val)
    }
    return result
  }

  static loadEnvOverrides(): Partial<MasterConfig> {
    // Map env vars to config fields. All are optional overrides.
    const env = (globalThis as any)?.process?.env ?? {}
    const hosting: Partial<HostingConfig> = {}
    if (env.MASTER_HOSTING_PLATFORM) hosting.platform = env.MASTER_HOSTING_PLATFORM as HostingConfig['platform']
    if (env.MASTER_HOSTING_PORT) hosting.port = Number(env.MASTER_HOSTING_PORT)
    if (env.MASTER_BASE_URL) hosting.base_url = String(env.MASTER_BASE_URL)

    const logging: Partial<NonNullable<MasterConfig['logging']>> = {}
    if (env.MASTER_LOG_LEVEL) logging.level = env.MASTER_LOG_LEVEL as any

    const master_oauth: Partial<MasterConfig['master_oauth']> = {}
    if (env.MASTER_OAUTH_ISSUER) master_oauth.issuer = String(env.MASTER_OAUTH_ISSUER)
    if (env.MASTER_OAUTH_AUTHORIZATION_ENDPOINT)
      master_oauth.authorization_endpoint = String(env.MASTER_OAUTH_AUTHORIZATION_ENDPOINT)
    if (env.MASTER_OAUTH_TOKEN_ENDPOINT) master_oauth.token_endpoint = String(env.MASTER_OAUTH_TOKEN_ENDPOINT)
    if (env.MASTER_OAUTH_JWKS_URI) master_oauth.jwks_uri = String(env.MASTER_OAUTH_JWKS_URI)
    if (env.MASTER_OAUTH_CLIENT_ID) master_oauth.client_id = String(env.MASTER_OAUTH_CLIENT_ID)
    if (env.MASTER_OAUTH_CLIENT_SECRET) master_oauth.client_secret = `env:MASTER_OAUTH_CLIENT_SECRET`
    if (env.MASTER_OAUTH_REDIRECT_URI) master_oauth.redirect_uri = String(env.MASTER_OAUTH_REDIRECT_URI)
    if (env.MASTER_OAUTH_SCOPES) master_oauth.scopes = String(env.MASTER_OAUTH_SCOPES)
      .split(',')
      .map((s) => s.trim())
      .filter(Boolean)
    if (env.MASTER_OAUTH_AUDIENCE) master_oauth.audience = String(env.MASTER_OAUTH_AUDIENCE)

    // Servers can be provided as JSON in MASTER_SERVERS or YAML in MASTER_SERVERS_YAML
    let servers: MasterConfig['servers'] | undefined
    try {
      if (env.MASTER_SERVERS) servers = JSON.parse(String(env.MASTER_SERVERS))
    } catch (err) {
      Logger.warn('Failed to parse MASTER_SERVERS JSON; ignoring', String(err))
    }
    if (!servers && env.MASTER_SERVERS_YAML) {
      try {
        // External import avoided in workers; only parse if Node
        const YAML = isNode() ? (require('yaml') as typeof import('yaml')) : undefined
        if (YAML) servers = YAML.parse(String(env.MASTER_SERVERS_YAML))
      } catch (err) {
        Logger.warn('Failed to parse MASTER_SERVERS_YAML; ignoring', String(err))
      }
    }

    const override: Partial<MasterConfig> = {}
    if (Object.keys(hosting).length) (override as any).hosting = hosting
    if (Object.keys(logging).length) (override as any).logging = logging
    if (Object.keys(master_oauth).length) (override as any).master_oauth = master_oauth
    if (servers) (override as any).servers = servers
    return override
  }
}

function setByPath(target: Record<string, unknown>, dottedKey: string, value: unknown): void {
  const parts = dottedKey.split('.')
  let cur: any = target
  for (let i = 0; i < parts.length - 1; i++) {
    const p = parts[i]
    if (typeof cur[p] !== 'object' || cur[p] === null) cur[p] = {}
    cur = cur[p]
  }
  cur[parts[parts.length - 1]] = value
}


```

--------------------------------------------------------------------------------
/docs/.vitepress/cache/deps/vue.js:
--------------------------------------------------------------------------------

```javascript
import {
  BaseTransition,
  BaseTransitionPropsValidators,
  Comment,
  DeprecationTypes,
  EffectScope,
  ErrorCodes,
  ErrorTypeStrings,
  Fragment,
  KeepAlive,
  ReactiveEffect,
  Static,
  Suspense,
  Teleport,
  Text,
  TrackOpTypes,
  Transition,
  TransitionGroup,
  TriggerOpTypes,
  VueElement,
  assertNumber,
  callWithAsyncErrorHandling,
  callWithErrorHandling,
  camelize,
  capitalize,
  cloneVNode,
  compatUtils,
  compile,
  computed,
  createApp,
  createBaseVNode,
  createBlock,
  createCommentVNode,
  createElementBlock,
  createHydrationRenderer,
  createPropsRestProxy,
  createRenderer,
  createSSRApp,
  createSlots,
  createStaticVNode,
  createTextVNode,
  createVNode,
  customRef,
  defineAsyncComponent,
  defineComponent,
  defineCustomElement,
  defineEmits,
  defineExpose,
  defineModel,
  defineOptions,
  defineProps,
  defineSSRCustomElement,
  defineSlots,
  devtools,
  effect,
  effectScope,
  getCurrentInstance,
  getCurrentScope,
  getCurrentWatcher,
  getTransitionRawChildren,
  guardReactiveProps,
  h,
  handleError,
  hasInjectionContext,
  hydrate,
  hydrateOnIdle,
  hydrateOnInteraction,
  hydrateOnMediaQuery,
  hydrateOnVisible,
  initCustomFormatter,
  initDirectivesForSSR,
  inject,
  isMemoSame,
  isProxy,
  isReactive,
  isReadonly,
  isRef,
  isRuntimeOnly,
  isShallow,
  isVNode,
  markRaw,
  mergeDefaults,
  mergeModels,
  mergeProps,
  nextTick,
  normalizeClass,
  normalizeProps,
  normalizeStyle,
  onActivated,
  onBeforeMount,
  onBeforeUnmount,
  onBeforeUpdate,
  onDeactivated,
  onErrorCaptured,
  onMounted,
  onRenderTracked,
  onRenderTriggered,
  onScopeDispose,
  onServerPrefetch,
  onUnmounted,
  onUpdated,
  onWatcherCleanup,
  openBlock,
  popScopeId,
  provide,
  proxyRefs,
  pushScopeId,
  queuePostFlushCb,
  reactive,
  readonly,
  ref,
  registerRuntimeCompiler,
  render,
  renderList,
  renderSlot,
  resolveComponent,
  resolveDirective,
  resolveDynamicComponent,
  resolveFilter,
  resolveTransitionHooks,
  setBlockTracking,
  setDevtoolsHook,
  setTransitionHooks,
  shallowReactive,
  shallowReadonly,
  shallowRef,
  ssrContextKey,
  ssrUtils,
  stop,
  toDisplayString,
  toHandlerKey,
  toHandlers,
  toRaw,
  toRef,
  toRefs,
  toValue,
  transformVNodeArgs,
  triggerRef,
  unref,
  useAttrs,
  useCssModule,
  useCssVars,
  useHost,
  useId,
  useModel,
  useSSRContext,
  useShadowRoot,
  useSlots,
  useTemplateRef,
  useTransitionState,
  vModelCheckbox,
  vModelDynamic,
  vModelRadio,
  vModelSelect,
  vModelText,
  vShow,
  version,
  warn,
  watch,
  watchEffect,
  watchPostEffect,
  watchSyncEffect,
  withAsyncContext,
  withCtx,
  withDefaults,
  withDirectives,
  withKeys,
  withMemo,
  withModifiers,
  withScopeId
} from "./chunk-HVR2FF6M.js";
export {
  BaseTransition,
  BaseTransitionPropsValidators,
  Comment,
  DeprecationTypes,
  EffectScope,
  ErrorCodes,
  ErrorTypeStrings,
  Fragment,
  KeepAlive,
  ReactiveEffect,
  Static,
  Suspense,
  Teleport,
  Text,
  TrackOpTypes,
  Transition,
  TransitionGroup,
  TriggerOpTypes,
  VueElement,
  assertNumber,
  callWithAsyncErrorHandling,
  callWithErrorHandling,
  camelize,
  capitalize,
  cloneVNode,
  compatUtils,
  compile,
  computed,
  createApp,
  createBlock,
  createCommentVNode,
  createElementBlock,
  createBaseVNode as createElementVNode,
  createHydrationRenderer,
  createPropsRestProxy,
  createRenderer,
  createSSRApp,
  createSlots,
  createStaticVNode,
  createTextVNode,
  createVNode,
  customRef,
  defineAsyncComponent,
  defineComponent,
  defineCustomElement,
  defineEmits,
  defineExpose,
  defineModel,
  defineOptions,
  defineProps,
  defineSSRCustomElement,
  defineSlots,
  devtools,
  effect,
  effectScope,
  getCurrentInstance,
  getCurrentScope,
  getCurrentWatcher,
  getTransitionRawChildren,
  guardReactiveProps,
  h,
  handleError,
  hasInjectionContext,
  hydrate,
  hydrateOnIdle,
  hydrateOnInteraction,
  hydrateOnMediaQuery,
  hydrateOnVisible,
  initCustomFormatter,
  initDirectivesForSSR,
  inject,
  isMemoSame,
  isProxy,
  isReactive,
  isReadonly,
  isRef,
  isRuntimeOnly,
  isShallow,
  isVNode,
  markRaw,
  mergeDefaults,
  mergeModels,
  mergeProps,
  nextTick,
  normalizeClass,
  normalizeProps,
  normalizeStyle,
  onActivated,
  onBeforeMount,
  onBeforeUnmount,
  onBeforeUpdate,
  onDeactivated,
  onErrorCaptured,
  onMounted,
  onRenderTracked,
  onRenderTriggered,
  onScopeDispose,
  onServerPrefetch,
  onUnmounted,
  onUpdated,
  onWatcherCleanup,
  openBlock,
  popScopeId,
  provide,
  proxyRefs,
  pushScopeId,
  queuePostFlushCb,
  reactive,
  readonly,
  ref,
  registerRuntimeCompiler,
  render,
  renderList,
  renderSlot,
  resolveComponent,
  resolveDirective,
  resolveDynamicComponent,
  resolveFilter,
  resolveTransitionHooks,
  setBlockTracking,
  setDevtoolsHook,
  setTransitionHooks,
  shallowReactive,
  shallowReadonly,
  shallowRef,
  ssrContextKey,
  ssrUtils,
  stop,
  toDisplayString,
  toHandlerKey,
  toHandlers,
  toRaw,
  toRef,
  toRefs,
  toValue,
  transformVNodeArgs,
  triggerRef,
  unref,
  useAttrs,
  useCssModule,
  useCssVars,
  useHost,
  useId,
  useModel,
  useSSRContext,
  useShadowRoot,
  useSlots,
  useTemplateRef,
  useTransitionState,
  vModelCheckbox,
  vModelDynamic,
  vModelRadio,
  vModelSelect,
  vModelText,
  vShow,
  version,
  warn,
  watch,
  watchEffect,
  watchPostEffect,
  watchSyncEffect,
  withAsyncContext,
  withCtx,
  withDefaults,
  withDirectives,
  withKeys,
  withMemo,
  withModifiers,
  withScopeId
};
//# sourceMappingURL=vue.js.map

```

--------------------------------------------------------------------------------
/src/config/config-loader.ts:
--------------------------------------------------------------------------------

```typescript
import type { MasterConfig } from '../types/config.js'
import { EnvironmentManager } from './environment-manager.js'
import { SecretManager } from './secret-manager.js'
import { SchemaValidator } from './schema-validator.js'
import { Logger } from '../utils/logger.js'

type LoadOptions = {
  // Explicit path to config file; when provided, overrides environment-based discovery
  path?: string
  // Optional base directory for default and env configs
  baseDir?: string
  // Provide a schema path override
  schemaPath?: string
}

function isNode(): boolean {
  return Boolean((globalThis as any)?.process?.versions?.node)
}

export class ConfigLoader {

  static async load(options?: LoadOptions): Promise<MasterConfig> {
    const envName = EnvironmentManager.detectEnvironment()
    const platform = EnvironmentManager.detectPlatform()
    const explicit = options?.path ?? EnvironmentManager.getExplicitConfigPath()
    const baseDir = options?.baseDir ?? 'config'
    const paths = EnvironmentManager.getConfigPaths(baseDir)
    const schemaPath = options?.schemaPath ?? paths.schema

    let fileConfig: Partial<MasterConfig> = {}
    const loadedFiles: string[] = []

    if (explicit && isNode()) {
      const cfg = await this.loadFromFile(explicit)
      fileConfig = deepMerge(fileConfig, cfg)
      loadedFiles.push(explicit)
    } else if (isNode()) {
      // Load default.json then <env>.json if present
      const fs = await import('node:fs/promises')
      const fsc = await import('node:fs')
      if (paths.base && fsc.existsSync(paths.base)) {
        fileConfig = deepMerge(fileConfig, await this.loadFromFile(paths.base))
        loadedFiles.push(paths.base)
      }
      if (paths.env && fsc.existsSync(paths.env)) {
        fileConfig = deepMerge(fileConfig, await this.loadFromFile(paths.env))
        loadedFiles.push(paths.env)
      }
      // If nothing loaded and config dir doesn't exist, try a default path
      ;(void fs)
    }

    Logger.info('File config loaded', { fileConfig, loadedFiles })

    // Environment variables
    const envOverrides = EnvironmentManager.loadEnvOverrides()
    Logger.info('Environment overrides', { envOverrides })
    fileConfig = deepMerge(fileConfig, envOverrides)

    // CLI args nested overrides
    const cli = EnvironmentManager.parseCliArgs()
    Logger.info('CLI args', { cli })
    fileConfig = deepMerge(fileConfig, cli as any)

    // Ensure hosting.platform and env awareness
    const normalized: Partial<MasterConfig> = {
      ...fileConfig,
      hosting: { ...fileConfig.hosting, platform },
    }

    Logger.info('Normalized config', { normalized })

    // Schema validation and secret resolution
    const schema = await SchemaValidator.loadSchema(schemaPath)
    const validated = SchemaValidator.assertValid<MasterConfig>(normalized, schema!)
    const secrets = new SecretManager()
    const resolved = secrets.resolveSecrets(validated)

    // Cache with key based on env and paths
    // In-memory caching can be added if needed; omitted to keep memory footprint small

    Logger.info('Configuration loaded', {
      files: loadedFiles,
      platform,
      env: envName,
    })
    return resolved
  }

  static async loadFromFile(filePath: string): Promise<Partial<MasterConfig>> {
    if (!isNode()) throw new Error('File loading is only supported in Node.js runtime')
    const fs = await import('node:fs/promises')
    const path = await import('node:path')
    const raw = await fs.readFile(filePath, 'utf8')
    Logger.info('Loading config from file', { filePath, raw })
    const ext = path.extname(filePath).toLowerCase()
    let parsed: any
    if (ext === '.json') parsed = JSON.parse(raw)
    else if (ext === '.yaml' || ext === '.yml') parsed = (await import('yaml')).parse(raw)
    else {
      // Fallback: try JSON then YAML
      try {
        parsed = JSON.parse(raw)
      } catch {
        parsed = (await import('yaml')).parse(raw)
      }
    }
    Logger.info('Parsed config from file', { filePath, parsed })
    return parsed as Partial<MasterConfig>
  }

  static async loadFromEnv(): Promise<MasterConfig> {
    // For compatibility with older phases
    const override = EnvironmentManager.loadEnvOverrides()
    const defaults: Partial<MasterConfig> = {
      hosting: {
        platform: EnvironmentManager.detectPlatform(),
        port: (globalThis as any)?.process?.env?.PORT ? Number((globalThis as any)?.process?.env?.PORT) : 3000,
        base_url: (globalThis as any)?.process?.env?.BASE_URL,
      },
      servers: [],
      master_oauth: {
        authorization_endpoint: 'https://example.com/auth',
        token_endpoint: 'https://example.com/token',
        client_id: 'placeholder',
        redirect_uri: 'http://localhost/callback',
        scopes: ['openid'],
      },
    }
    const merged = deepMerge(defaults, override) as MasterConfig
    const schema = await SchemaValidator.loadSchema()
    return SchemaValidator.assertValid(merged, schema!)
  }
}

function deepMerge<T>(base: T, override: Partial<T>): T {
  if (Array.isArray(base) && Array.isArray(override)) return override as unknown as T
  if (base && typeof base === 'object' && override && typeof override === 'object') {
    const out: any = { ...(base as any) }
    for (const [k, v] of Object.entries(override as any)) {
      if (v === undefined) continue
      if (Array.isArray(v)) out[k] = v
      else if (typeof v === 'object' && v !== null) out[k] = deepMerge((base as any)[k], v)
      else out[k] = v
    }
    return out
  }
  return (override as T) ?? base
}

```
Page 2/8FirstPrevNextLast