@wootsup/yt-builder-mcp 1.3.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/doctor-command.d.ts +21 -0
  3. package/dist/cli/doctor-command.d.ts.map +1 -0
  4. package/dist/cli/doctor-command.js +111 -0
  5. package/dist/cli/doctor-command.js.map +1 -0
  6. package/dist/cli/invocation-decision.d.ts.map +1 -1
  7. package/dist/cli/invocation-decision.js +2 -0
  8. package/dist/cli/invocation-decision.js.map +1 -1
  9. package/dist/client.d.ts +14 -0
  10. package/dist/client.d.ts.map +1 -1
  11. package/dist/client.js +9 -0
  12. package/dist/client.js.map +1 -1
  13. package/dist/diagnostics/ca-trust.d.ts +16 -0
  14. package/dist/diagnostics/ca-trust.d.ts.map +1 -0
  15. package/dist/diagnostics/ca-trust.js +54 -0
  16. package/dist/diagnostics/ca-trust.js.map +1 -0
  17. package/dist/diagnostics/diagnose-network-error.d.ts +37 -0
  18. package/dist/diagnostics/diagnose-network-error.d.ts.map +1 -0
  19. package/dist/diagnostics/diagnose-network-error.js +158 -0
  20. package/dist/diagnostics/diagnose-network-error.js.map +1 -0
  21. package/dist/diagnostics/doctor.d.ts +62 -0
  22. package/dist/diagnostics/doctor.d.ts.map +1 -0
  23. package/dist/diagnostics/doctor.js +165 -0
  24. package/dist/diagnostics/doctor.js.map +1 -0
  25. package/dist/gateway/essentials.d.ts +1 -1
  26. package/dist/gateway/essentials.d.ts.map +1 -1
  27. package/dist/gateway/essentials.js +5 -0
  28. package/dist/gateway/essentials.js.map +1 -1
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +35 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/install-skill.d.ts +1 -1
  33. package/dist/install-skill.js +1 -1
  34. package/dist/net/extra-headers.d.ts +66 -0
  35. package/dist/net/extra-headers.d.ts.map +1 -0
  36. package/dist/net/extra-headers.js +164 -0
  37. package/dist/net/extra-headers.js.map +1 -0
  38. package/dist/net/internal-host.d.ts +45 -0
  39. package/dist/net/internal-host.d.ts.map +1 -0
  40. package/dist/net/internal-host.js +164 -0
  41. package/dist/net/internal-host.js.map +1 -0
  42. package/dist/net/proxy-dispatcher.d.ts +40 -0
  43. package/dist/net/proxy-dispatcher.d.ts.map +1 -0
  44. package/dist/net/proxy-dispatcher.js +65 -0
  45. package/dist/net/proxy-dispatcher.js.map +1 -0
  46. package/dist/proxy/bridge.d.ts +45 -13
  47. package/dist/proxy/bridge.d.ts.map +1 -1
  48. package/dist/proxy/bridge.js +113 -7
  49. package/dist/proxy/bridge.js.map +1 -1
  50. package/dist/setup-ca-env.d.ts +40 -0
  51. package/dist/setup-ca-env.d.ts.map +1 -0
  52. package/dist/setup-ca-env.js +58 -0
  53. package/dist/setup-ca-env.js.map +1 -0
  54. package/dist/setup-ca-reprobe.d.ts +38 -0
  55. package/dist/setup-ca-reprobe.d.ts.map +1 -0
  56. package/dist/setup-ca-reprobe.js +68 -0
  57. package/dist/setup-ca-reprobe.js.map +1 -0
  58. package/dist/setup-cli.d.ts +37 -2
  59. package/dist/setup-cli.d.ts.map +1 -1
  60. package/dist/setup-cli.js +178 -4
  61. package/dist/setup-cli.js.map +1 -1
  62. package/dist/setup-npx-spec.d.ts +44 -0
  63. package/dist/setup-npx-spec.d.ts.map +1 -0
  64. package/dist/setup-npx-spec.js +66 -0
  65. package/dist/setup-npx-spec.js.map +1 -0
  66. package/dist/setup-prompts.d.ts +14 -1
  67. package/dist/setup-prompts.d.ts.map +1 -1
  68. package/dist/setup-prompts.js +53 -1
  69. package/dist/setup-prompts.js.map +1 -1
  70. package/dist/setup-wizard-defaults.d.ts.map +1 -1
  71. package/dist/setup-wizard-defaults.js +29 -5
  72. package/dist/setup-wizard-defaults.js.map +1 -1
  73. package/dist/setup-wizard-handshake.d.ts +4 -4
  74. package/dist/setup-wizard-handshake.d.ts.map +1 -1
  75. package/dist/setup-wizard-handshake.js +46 -12
  76. package/dist/setup-wizard-handshake.js.map +1 -1
  77. package/dist/setup-wizard-types.d.ts +81 -0
  78. package/dist/setup-wizard-types.d.ts.map +1 -1
  79. package/dist/setup-wizard.d.ts +2 -2
  80. package/dist/setup-wizard.d.ts.map +1 -1
  81. package/dist/setup-wizard.js +133 -18
  82. package/dist/setup-wizard.js.map +1 -1
  83. package/dist/sites/client-pool.d.ts +8 -1
  84. package/dist/sites/client-pool.d.ts.map +1 -1
  85. package/dist/sites/client-pool.js +13 -1
  86. package/dist/sites/client-pool.js.map +1 -1
  87. package/dist/tools/elements/builders.d.ts.map +1 -1
  88. package/dist/tools/elements/builders.js +4 -2
  89. package/dist/tools/elements/builders.js.map +1 -1
  90. package/dist/tools/elements/handlers.d.ts +2 -1
  91. package/dist/tools/elements/handlers.d.ts.map +1 -1
  92. package/dist/tools/elements/handlers.js +3 -22
  93. package/dist/tools/elements/handlers.js.map +1 -1
  94. package/dist/tools/format/health-format.d.ts +3 -0
  95. package/dist/tools/format/health-format.d.ts.map +1 -1
  96. package/dist/tools/format/health-format.js +21 -4
  97. package/dist/tools/format/health-format.js.map +1 -1
  98. package/dist/tools/health.d.ts.map +1 -1
  99. package/dist/tools/health.js +32 -0
  100. package/dist/tools/health.js.map +1 -1
  101. package/dist/tools/pages/builders.d.ts.map +1 -1
  102. package/dist/tools/pages/builders.js +78 -27
  103. package/dist/tools/pages/builders.js.map +1 -1
  104. package/dist/tools/pages/handlers-read.d.ts +36 -5
  105. package/dist/tools/pages/handlers-read.d.ts.map +1 -1
  106. package/dist/tools/pages/handlers-read.js +217 -34
  107. package/dist/tools/pages/handlers-read.js.map +1 -1
  108. package/dist/tools/pages/schemas.d.ts +20 -5
  109. package/dist/tools/pages/schemas.d.ts.map +1 -1
  110. package/dist/tools/pages/schemas.js +44 -6
  111. package/dist/tools/pages/schemas.js.map +1 -1
  112. package/dist/tools/shared-schemas.d.ts +3 -0
  113. package/dist/tools/shared-schemas.d.ts.map +1 -1
  114. package/dist/tools/shared-schemas.js +28 -0
  115. package/dist/tools/shared-schemas.js.map +1 -1
  116. package/dist/tools/sources/builders.d.ts.map +1 -1
  117. package/dist/tools/sources/builders.js +30 -5
  118. package/dist/tools/sources/builders.js.map +1 -1
  119. package/dist/tools/sources/handlers.d.ts +9 -1
  120. package/dist/tools/sources/handlers.d.ts.map +1 -1
  121. package/dist/tools/sources/handlers.js +62 -12
  122. package/dist/tools/sources/handlers.js.map +1 -1
  123. package/dist/tools/sparse-fields.d.ts +50 -0
  124. package/dist/tools/sparse-fields.d.ts.map +1 -1
  125. package/dist/tools/sparse-fields.js +107 -0
  126. package/dist/tools/sparse-fields.js.map +1 -1
  127. package/dist/update/update-check.d.ts +56 -0
  128. package/dist/update/update-check.d.ts.map +1 -0
  129. package/dist/update/update-check.js +155 -0
  130. package/dist/update/update-check.js.map +1 -0
  131. package/manifest.json +1 -1
  132. package/package.json +2 -1
  133. package/skills/yt-builder-mcp/SKILL.md +13 -12
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Classify a host as internal. A host is internal when ANY of:
3
+ * - it is `localhost`,
4
+ * - it is a private/loopback/link-local IPv4 or IPv6 literal,
5
+ * - it ends in an internal DNS suffix (`.local`, `.internal`, …),
6
+ * - it is a bare single-label hostname (no dot — an intranet short name).
7
+ *
8
+ * A normal public FQDN (`example.com`, `acme.co.uk`) is NOT internal.
9
+ */
10
+ export declare function isInternalHost(rawHost: string): boolean;
11
+ /** Extract a lowercased, bracket-stripped host from a URL string, or null. */
12
+ export declare function hostFromUrl(rawUrl: string): string | null;
13
+ export interface NoProxyDerivation {
14
+ /** True when this call would change NO_PROXY (host added). */
15
+ readonly changed: boolean;
16
+ /**
17
+ * The effective NO_PROXY value to use. When `changed` is false this is the
18
+ * input value verbatim (or undefined when it was unset and stays unset).
19
+ */
20
+ readonly noProxy: string | undefined;
21
+ /** The internal host that was added, or null when nothing was added. */
22
+ readonly addedHost: string | null;
23
+ /** Non-fatal reason when nothing was added (for an optional debug log). */
24
+ readonly reason?: string;
25
+ }
26
+ export interface DeriveNoProxyInput {
27
+ /** Source of env vars. */
28
+ readonly env: NodeJS.ProcessEnv;
29
+ /** The configured site URL (typically `YTB_MCP_SITE_URL`). */
30
+ readonly siteUrl: string | undefined;
31
+ }
32
+ /**
33
+ * Compute the NO_PROXY value to apply so an internal site host bypasses a
34
+ * configured corporate proxy. Idempotent + non-clobbering:
35
+ *
36
+ * - No proxy configured → no change (the agent isn't installed anyway).
37
+ * - `siteUrl` missing / unparseable / clearly public → no change.
38
+ * - Host already present in NO_PROXY (case-insensitive) → no change.
39
+ * - Otherwise → append the host to the existing operator NO_PROXY (preserved
40
+ * verbatim, comma-joined), or seed NO_PROXY with just the host when unset.
41
+ *
42
+ * Pure: returns the value to write; the caller mutates `process.env`.
43
+ */
44
+ export declare function deriveNoProxyForInternalSite(input: DeriveNoProxyInput): NoProxyDerivation;
45
+ //# sourceMappingURL=internal-host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal-host.d.ts","sourceRoot":"","sources":["../../src/net/internal-host.ts"],"names":[],"mappings":"AAmEA;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAWvD;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CASzD;AAeD,MAAM,WAAW,iBAAiB;IAC9B,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,wEAAwE;IACxE,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IAC/B,0BAA0B;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAChC,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,kBAAkB,GAAG,iBAAiB,CAwBzF"}
@@ -0,0 +1,164 @@
1
+ // packages/mcp/src/net/internal-host.ts
2
+ /**
3
+ * Classify a site host as internal vs public, and derive a NO_PROXY addition
4
+ * for an internal host when a forward proxy is configured (Glöckle gap #9).
5
+ *
6
+ * Why this exists: when a corporate `HTTP(S)_PROXY` is set, undici's
7
+ * `EnvHttpProxyAgent` routes EVERYTHING through it — including traffic to an
8
+ * intranet WordPress/Joomla that the proxy can't (or shouldn't) reach. The
9
+ * `NO_PROXY` exception list fixes that, but only if the operator pre-set it.
10
+ * A common Glöckle-class failure: the proxy reaches the public internet fine,
11
+ * but the internal CMS is direct-only (or vice-versa), and outbound MCP traffic
12
+ * silently dies.
13
+ *
14
+ * We therefore classify the configured `YTB_MCP_SITE_URL` host and, when a
15
+ * proxy is set AND the host is clearly internal, add it to the effective
16
+ * NO_PROXY the agent reads. **Conservative by construction:** only RFC1918 /
17
+ * loopback / link-local IPs, `.local` / `.internal` / `.intranet` suffixes, and
18
+ * bare single-label hostnames (no dot) are treated as internal. A normal
19
+ * public FQDN is NEVER routed to NO_PROXY.
20
+ *
21
+ * Pure + env-injectable so it is unit-testable offline. Never mutates input.
22
+ *
23
+ * @license MIT
24
+ */
25
+ /** Internal-by-convention DNS suffixes (RFC 6762 + common intranet TLDs). */
26
+ const INTERNAL_SUFFIXES = ['.local', '.internal', '.intranet', '.lan', '.home.arpa'];
27
+ /** Strip an `[…]` IPv6 bracket wrapper and a trailing `.` if present. */
28
+ function normalizeHost(host) {
29
+ let h = host.trim().toLowerCase();
30
+ if (h.startsWith('[') && h.endsWith(']'))
31
+ h = h.slice(1, -1);
32
+ if (h.endsWith('.'))
33
+ h = h.slice(0, -1);
34
+ return h;
35
+ }
36
+ /** Is `host` an IPv4 literal in a private/loopback/link-local range? */
37
+ function isPrivateIpv4(host) {
38
+ const m = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
39
+ if (m === null)
40
+ return false;
41
+ const octets = [m[1], m[2], m[3], m[4]].map((o) => Number.parseInt(o, 10));
42
+ if (octets.some((o) => o > 255))
43
+ return false;
44
+ const [a, b] = octets;
45
+ if (a === 10)
46
+ return true; // 10.0.0.0/8
47
+ if (a === 127)
48
+ return true; // 127.0.0.0/8 loopback
49
+ if (a === 192 && b === 168)
50
+ return true; // 192.168.0.0/16
51
+ if (a === 172 && b >= 16 && b <= 31)
52
+ return true; // 172.16.0.0/12
53
+ if (a === 169 && b === 254)
54
+ return true; // 169.254.0.0/16 link-local
55
+ return false;
56
+ }
57
+ /** Is `host` an IPv6 loopback / unique-local (fc00::/7) / link-local (fe80::/10)? */
58
+ function isPrivateIpv6(host) {
59
+ if (!host.includes(':'))
60
+ return false;
61
+ if (host === '::1')
62
+ return true; // loopback
63
+ const first = host.split(':')[0] ?? '';
64
+ if (first === '')
65
+ return false; // e.g. "::" unspecified — not a real site host
66
+ const prefix = Number.parseInt(first, 16);
67
+ if (Number.isNaN(prefix))
68
+ return false;
69
+ // fc00::/7 (unique-local) → first hextet 0xfc00–0xfdff.
70
+ if (prefix >= 0xfc00 && prefix <= 0xfdff)
71
+ return true;
72
+ // fe80::/10 (link-local) → first hextet 0xfe80–0xfebf.
73
+ if (prefix >= 0xfe80 && prefix <= 0xfebf)
74
+ return true;
75
+ return false;
76
+ }
77
+ /**
78
+ * Classify a host as internal. A host is internal when ANY of:
79
+ * - it is `localhost`,
80
+ * - it is a private/loopback/link-local IPv4 or IPv6 literal,
81
+ * - it ends in an internal DNS suffix (`.local`, `.internal`, …),
82
+ * - it is a bare single-label hostname (no dot — an intranet short name).
83
+ *
84
+ * A normal public FQDN (`example.com`, `acme.co.uk`) is NOT internal.
85
+ */
86
+ export function isInternalHost(rawHost) {
87
+ const host = normalizeHost(rawHost);
88
+ if (host === '')
89
+ return false;
90
+ if (host === 'localhost')
91
+ return true;
92
+ if (isPrivateIpv4(host))
93
+ return true;
94
+ if (isPrivateIpv6(host))
95
+ return true;
96
+ if (INTERNAL_SUFFIXES.some((s) => host.endsWith(s)))
97
+ return true;
98
+ // A bare hostname with no dot is an intranet short name (e.g. "wpserver").
99
+ // IPv6 literals contain ":" and are handled above; guard against them here.
100
+ if (!host.includes('.') && !host.includes(':'))
101
+ return true;
102
+ return false;
103
+ }
104
+ /** Extract a lowercased, bracket-stripped host from a URL string, or null. */
105
+ export function hostFromUrl(rawUrl) {
106
+ const url = rawUrl.trim();
107
+ if (url === '')
108
+ return null;
109
+ try {
110
+ const parsed = new URL(url);
111
+ return normalizeHost(parsed.hostname);
112
+ }
113
+ catch {
114
+ return null;
115
+ }
116
+ }
117
+ /** Is any forward-proxy configured in `env`? */
118
+ function hasProxyConfigured(env) {
119
+ return Boolean(env.HTTPS_PROXY ?? env.https_proxy ?? env.HTTP_PROXY ?? env.http_proxy);
120
+ }
121
+ /** Split a NO_PROXY string into trimmed, lowercased, non-empty entries. */
122
+ function splitNoProxy(value) {
123
+ return value
124
+ .split(',')
125
+ .map((e) => e.trim().toLowerCase())
126
+ .filter((e) => e !== '');
127
+ }
128
+ /**
129
+ * Compute the NO_PROXY value to apply so an internal site host bypasses a
130
+ * configured corporate proxy. Idempotent + non-clobbering:
131
+ *
132
+ * - No proxy configured → no change (the agent isn't installed anyway).
133
+ * - `siteUrl` missing / unparseable / clearly public → no change.
134
+ * - Host already present in NO_PROXY (case-insensitive) → no change.
135
+ * - Otherwise → append the host to the existing operator NO_PROXY (preserved
136
+ * verbatim, comma-joined), or seed NO_PROXY with just the host when unset.
137
+ *
138
+ * Pure: returns the value to write; the caller mutates `process.env`.
139
+ */
140
+ export function deriveNoProxyForInternalSite(input) {
141
+ const { env, siteUrl } = input;
142
+ const current = env.NO_PROXY ?? env.no_proxy;
143
+ if (!hasProxyConfigured(env)) {
144
+ return { changed: false, noProxy: current, addedHost: null, reason: 'no proxy configured' };
145
+ }
146
+ const host = siteUrl !== undefined ? hostFromUrl(siteUrl) : null;
147
+ if (host === null) {
148
+ return { changed: false, noProxy: current, addedHost: null, reason: 'no parseable site URL' };
149
+ }
150
+ if (!isInternalHost(host)) {
151
+ return { changed: false, noProxy: current, addedHost: null, reason: 'site host is public' };
152
+ }
153
+ const existing = current !== undefined ? splitNoProxy(current) : [];
154
+ if (existing.includes(host)) {
155
+ return { changed: false, noProxy: current, addedHost: null, reason: 'host already in NO_PROXY' };
156
+ }
157
+ // Append, preserving the operator's existing entries verbatim (original
158
+ // casing/order) — we only add the host at the end.
159
+ const next = current !== undefined && current.trim() !== ''
160
+ ? `${current},${host}`
161
+ : host;
162
+ return { changed: true, noProxy: next, addedHost: host };
163
+ }
164
+ //# sourceMappingURL=internal-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal-host.js","sourceRoot":"","sources":["../../src/net/internal-host.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import { type Dispatcher } from 'undici';
2
+ /**
3
+ * Injection seam for tests — production uses the real undici functions + env.
4
+ */
5
+ export interface ProxyDispatcherDeps {
6
+ /** Defaults to `process.env`. Read for HTTP(S)_PROXY presence. */
7
+ env?: NodeJS.ProcessEnv;
8
+ /** Defaults to undici's {@link undiciSetGlobalDispatcher}. */
9
+ setGlobalDispatcher?: (dispatcher: Dispatcher) => void;
10
+ /** Defaults to `() => new EnvHttpProxyAgent()`. */
11
+ makeEnvHttpProxyAgent?: () => Dispatcher;
12
+ /** Defaults to `console.error`. */
13
+ stderr?: (message: string) => void;
14
+ }
15
+ /**
16
+ * Install a process-global undici dispatcher that honors the enterprise
17
+ * `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY` environment variables at request
18
+ * time (undici's {@link EnvHttpProxyAgent}).
19
+ *
20
+ * Why this exists: Node's global `fetch` only auto-honors proxy env vars from
21
+ * **Node 24** (`NODE_USE_ENV_PROXY`). On the Node 18–23 floor this package
22
+ * supports, an enterprise forward/auth proxy is otherwise ignored and outbound
23
+ * MCP traffic silently fails. Node's global `fetch` reads the global dispatcher,
24
+ * and so does the MCP SDK's `StreamableHTTPClientTransport` (proxy mode) and the
25
+ * fat-mode `RestClient` — so one global dispatcher covers every outbound call.
26
+ *
27
+ * Installed ONLY when a forward proxy is actually configured
28
+ * (`HTTP_PROXY`/`HTTPS_PROXY`). With no proxy env, the default dispatcher (a
29
+ * direct connection) is already correct, so we skip — this also avoids undici's
30
+ * `EnvHttpProxyAgent is experimental` startup warning for the common, direct
31
+ * case. Corporate TLS-inspection root CAs are handled separately by Node's
32
+ * native `NODE_EXTRA_CA_CERTS` (undici's default connector honors it).
33
+ *
34
+ * Never throws: a failure to install (exotic runtime, frozen global) degrades
35
+ * to a stderr warning and a direct connection, returning `false`.
36
+ *
37
+ * @returns `true` if the dispatcher was installed, `false` if skipped/degraded.
38
+ */
39
+ export declare function installGlobalProxyDispatcher(deps?: ProxyDispatcherDeps): boolean;
40
+ //# sourceMappingURL=proxy-dispatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-dispatcher.d.ts","sourceRoot":"","sources":["../../src/net/proxy-dispatcher.ts"],"names":[],"mappings":"AACA,OAAO,EAAuE,KAAK,UAAU,EAAE,MAAM,QAAQ,CAAC;AAI9G;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAChC,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,8DAA8D;IAC9D,mBAAmB,CAAC,EAAE,CAAC,UAAU,EAAE,UAAU,KAAK,IAAI,CAAC;IACvD,mDAAmD;IACnD,qBAAqB,CAAC,EAAE,MAAM,UAAU,CAAC;IACzC,mCAAmC;IACnC,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAOD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,GAAE,mBAAwB,GAAG,OAAO,CAkCpF"}
@@ -0,0 +1,65 @@
1
+ // packages/mcp/src/net/proxy-dispatcher.ts
2
+ import { EnvHttpProxyAgent, setGlobalDispatcher as undiciSetGlobalDispatcher } from 'undici';
3
+ import { deriveNoProxyForInternalSite } from './internal-host.js';
4
+ /** Is any forward-proxy configured in the environment? */
5
+ function hasProxyConfigured(env) {
6
+ return Boolean(env.HTTPS_PROXY ?? env.https_proxy ?? env.HTTP_PROXY ?? env.http_proxy);
7
+ }
8
+ /**
9
+ * Install a process-global undici dispatcher that honors the enterprise
10
+ * `HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY` environment variables at request
11
+ * time (undici's {@link EnvHttpProxyAgent}).
12
+ *
13
+ * Why this exists: Node's global `fetch` only auto-honors proxy env vars from
14
+ * **Node 24** (`NODE_USE_ENV_PROXY`). On the Node 18–23 floor this package
15
+ * supports, an enterprise forward/auth proxy is otherwise ignored and outbound
16
+ * MCP traffic silently fails. Node's global `fetch` reads the global dispatcher,
17
+ * and so does the MCP SDK's `StreamableHTTPClientTransport` (proxy mode) and the
18
+ * fat-mode `RestClient` — so one global dispatcher covers every outbound call.
19
+ *
20
+ * Installed ONLY when a forward proxy is actually configured
21
+ * (`HTTP_PROXY`/`HTTPS_PROXY`). With no proxy env, the default dispatcher (a
22
+ * direct connection) is already correct, so we skip — this also avoids undici's
23
+ * `EnvHttpProxyAgent is experimental` startup warning for the common, direct
24
+ * case. Corporate TLS-inspection root CAs are handled separately by Node's
25
+ * native `NODE_EXTRA_CA_CERTS` (undici's default connector honors it).
26
+ *
27
+ * Never throws: a failure to install (exotic runtime, frozen global) degrades
28
+ * to a stderr warning and a direct connection, returning `false`.
29
+ *
30
+ * @returns `true` if the dispatcher was installed, `false` if skipped/degraded.
31
+ */
32
+ export function installGlobalProxyDispatcher(deps = {}) {
33
+ const env = deps.env ?? process.env;
34
+ if (!hasProxyConfigured(env)) {
35
+ // No proxy to honor — leave the default (direct) dispatcher in place.
36
+ return false;
37
+ }
38
+ const setDispatcher = deps.setGlobalDispatcher ?? undiciSetGlobalDispatcher;
39
+ const makeAgent = deps.makeEnvHttpProxyAgent ?? (() => new EnvHttpProxyAgent());
40
+ const warn = deps.stderr ?? ((message) => console.error(message));
41
+ // Glöckle gap #9 — when the configured site is INTERNAL (RFC1918 / .local /
42
+ // bare hostname / loopback), make sure its host is in NO_PROXY so intranet
43
+ // traffic bypasses the corporate proxy. Idempotent + non-clobbering: the
44
+ // operator's NO_PROXY is preserved verbatim, the host is only appended.
45
+ // We mutate `env` BEFORE constructing the agent because EnvHttpProxyAgent
46
+ // snapshots NO_PROXY at construction. Public hosts are never touched.
47
+ const noProxy = deriveNoProxyForInternalSite({ env, siteUrl: env.YTB_MCP_SITE_URL });
48
+ if (noProxy.changed && noProxy.noProxy !== undefined) {
49
+ // Set BOTH cases so undici reads it regardless of which it prefers.
50
+ env.NO_PROXY = noProxy.noProxy;
51
+ env.no_proxy = noProxy.noProxy;
52
+ warn(`[yt-builder-mcp] internal site host "${noProxy.addedHost ?? ''}" added to NO_PROXY so it bypasses the configured proxy.`);
53
+ }
54
+ try {
55
+ setDispatcher(makeAgent());
56
+ return true;
57
+ }
58
+ catch (err) {
59
+ const message = err instanceof Error ? err.message : String(err);
60
+ // stderr only — stdout is the JSON-RPC channel in stdio transport.
61
+ warn(`[yt-builder-mcp] proxy dispatcher init failed (continuing with a direct connection): ${message}`);
62
+ return false;
63
+ }
64
+ }
65
+ //# sourceMappingURL=proxy-dispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy-dispatcher.js","sourceRoot":"","sources":["../../src/net/proxy-dispatcher.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,IAAI,yBAAyB,EAAmB,MAAM,QAAQ,CAAC;AAE9G,OAAO,EAAE,4BAA4B,EAAE,MAAM,oBAAoB,CAAC;AAgBlE,0DAA0D;AAC1D,SAAS,kBAAkB,CAAC,GAAsB;IAC9C,OAAO,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,WAAW,IAAI,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;AAC3F,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,4BAA4B,CAAC,OAA4B,EAAE;IACvE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACpC,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,sEAAsE;QACtE,OAAO,KAAK,CAAC;IACjB,CAAC;IAED,MAAM,aAAa,GAAG,IAAI,CAAC,mBAAmB,IAAI,yBAAyB,CAAC;IAC5E,MAAM,SAAS,GAAG,IAAI,CAAC,qBAAqB,IAAI,CAAC,GAAe,EAAE,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAC;IAC5F,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,OAAe,EAAQ,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAEhF,4EAA4E;IAC5E,2EAA2E;IAC3E,yEAAyE;IACzE,wEAAwE;IACxE,0EAA0E;IAC1E,sEAAsE;IACtE,MAAM,OAAO,GAAG,4BAA4B,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACrF,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QACnD,oEAAoE;QACpE,GAAG,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,GAAG,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,wCAAwC,OAAO,CAAC,SAAS,IAAI,EAAE,0DAA0D,CAAC,CAAC;IACpI,CAAC;IAED,IAAI,CAAC;QACD,aAAa,CAAC,SAAS,EAAE,CAAC,CAAC;QAC3B,OAAO,IAAI,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,mEAAmE;QACnE,IAAI,CAAC,wFAAwF,OAAO,EAAE,CAAC,CAAC;QACxG,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC"}
@@ -1,8 +1,33 @@
1
1
  import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
2
+ /**
3
+ * Normalise the WordPress↔Joomla `/mcp` envelope asymmetry for `tools/call`
4
+ * responses.
5
+ *
6
+ * The WP mcp-adapter (`ToolsHandler`) treats an Ability's return value as raw
7
+ * data and `wp_json_encode`s our already-final `CallToolResult` into a fresh
8
+ * text-content block. Over the wire that yields a DOUBLE-wrapped result —
9
+ * `result.content[0].text` is itself a serialised `CallToolResult`
10
+ * (`{"content":[{"type":"text","text":"<real-data-json>"}],"isError":…}`).
11
+ * Joomla's `/api/` handler single-wraps: `result.content[0].text` is already
12
+ * the real data JSON. The proxy bridge is a verbatim pipe, so a WP customer
13
+ * would receive doubly-nested tool output while a Joomla customer would not.
14
+ *
15
+ * Strip EXACTLY ONE level of that nesting, and ONLY when the inner payload is
16
+ * unmistakably a nested `CallToolResult`. Every shape check is defensive
17
+ * (try/catch around the parse, strict block typing) so a genuine Joomla data
18
+ * payload is never touched. Non-`tools/call` frames (initialize, tools/list,
19
+ * JSON-RPC errors, notifications) are returned by reference, unchanged.
20
+ *
21
+ * Exported for unit tests.
22
+ */
23
+ export declare function normalizeProxyResponse(msg: unknown): unknown;
2
24
  /**
3
25
  * Wire two MCP transports into a transparent pipe: every message from one side
4
- * is relayed verbatim to the other, and a close/error on either side tears down
5
- * the other. No transformation the PHP server owns the protocol semantics.
26
+ * is relayed to the other, and a close/error on either side tears down the
27
+ * other. The local→remote direction is verbatim; the remote→local direction
28
+ * normalises the WP double-wrap (see `normalizeProxyResponse`) so WP and Joomla
29
+ * customers receive identical, spec-clean tool results. The PHP server otherwise
30
+ * owns the protocol semantics.
6
31
  * The caller is responsible for start()ing both transports.
7
32
  *
8
33
  * `StreamableHTTPClientTransport.send()` re-throws on any upstream failure
@@ -13,24 +38,31 @@ import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
13
38
  * therefore `.catch()`es its `send()`.
14
39
  */
15
40
  export declare function bridgeTransports(local: Transport, remote: Transport): void;
16
- /** Build the real transports + bridge them; resolves when EITHER side closes. */
17
- export declare function runProxy(config: {
41
+ /** Config the proxy run needs: the upstream endpoint, the Bearer, and any
42
+ * corporate extra headers (Glöckle gap #14) to attach to every upstream
43
+ * request. The Bearer always wins on collision. */
44
+ interface ProxyConfig {
18
45
  endpointUrl: URL;
19
46
  token: string;
20
- }, deps?: {
21
- makeTransports?: (c: {
22
- endpointUrl: URL;
23
- token: string;
24
- }) => {
47
+ /** Extra headers from `YTB_MCP_EXTRA_HEADERS` (Basic-Auth / WAF / gateway). */
48
+ extraHeaders?: Record<string, string>;
49
+ }
50
+ /**
51
+ * Build the upstream `requestInit.headers` for proxy mode: the Bearer is
52
+ * authoritative; corporate extra headers (Glöckle gap #14) only fill gaps —
53
+ * `Authorization` can NEVER be overwritten. Exported for unit tests.
54
+ */
55
+ export declare function buildProxyRequestHeaders(config: ProxyConfig): Record<string, string>;
56
+ /** Build the real transports + bridge them; resolves when EITHER side closes. */
57
+ export declare function runProxy(config: ProxyConfig, deps?: {
58
+ makeTransports?: (c: ProxyConfig) => {
25
59
  local: Transport;
26
60
  remote: Transport;
27
61
  };
28
62
  }): Promise<void>;
29
63
  /** Returns true if proxy mode handled the run; false → caller continues with fat. */
30
64
  export declare function maybeRunProxy(env: NodeJS.ProcessEnv, deps?: {
31
- runProxy?: (c: {
32
- endpointUrl: URL;
33
- token: string;
34
- }) => Promise<void>;
65
+ runProxy?: (c: ProxyConfig) => Promise<void>;
35
66
  }): Promise<boolean>;
67
+ export {};
36
68
  //# sourceMappingURL=bridge.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/proxy/bridge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AA6B/E;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI,CA2C1E;AAcD,iFAAiF;AACjF,wBAAsB,QAAQ,CAC5B,MAAM,EAAE;IAAE,WAAW,EAAE,GAAG,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EAC3C,IAAI,GAAE;IACJ,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE;QAAE,WAAW,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK;QAC3D,KAAK,EAAE,SAAS,CAAC;QACjB,MAAM,EAAE,SAAS,CAAC;KACnB,CAAC;CACE,GACL,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED,qFAAqF;AACrF,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE;QAAE,WAAW,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAAO,GAClF,OAAO,CAAC,OAAO,CAAC,CAMlB"}
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/proxy/bridge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAgE/E;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAoC5D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI,CAuD1E;AAED;;mDAEmD;AACnD,UAAU,WAAW;IACnB,WAAW,EAAE,GAAG,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAKpF;AAcD,iFAAiF;AACjF,wBAAsB,QAAQ,CAC5B,MAAM,EAAE,WAAW,EACnB,IAAI,GAAE;IACJ,cAAc,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK;QACnC,KAAK,EAAE,SAAS,CAAC;QACjB,MAAM,EAAE,SAAS,CAAC;KACnB,CAAC;CACE,GACL,OAAO,CAAC,IAAI,CAAC,CAyBf;AAED,qFAAqF;AACrF,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAAO,GAC1D,OAAO,CAAC,OAAO,CAAC,CAalB"}
@@ -1,6 +1,8 @@
1
1
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
2
2
  import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
3
3
  import { resolveMode } from './mode.js';
4
+ import { diagnoseNetworkError } from '../diagnostics/diagnose-network-error.js';
5
+ import { mergeExtraHeaders, parseExtraHeaders } from '../net/extra-headers.js';
4
6
  /** Narrow an unknown caught value to a human-readable message (no `any`). */
5
7
  function errorMessage(err) {
6
8
  if (err instanceof Error)
@@ -26,10 +28,87 @@ function requestId(msg) {
26
28
  }
27
29
  return null;
28
30
  }
31
+ function isTextContentBlock(v) {
32
+ return (v !== null &&
33
+ typeof v === 'object' &&
34
+ typeof v.type === 'string' &&
35
+ typeof v.text === 'string');
36
+ }
37
+ function isNestedCallToolResult(v) {
38
+ if (v === null || typeof v !== 'object')
39
+ return false;
40
+ const content = v.content;
41
+ return Array.isArray(content) && content.length > 0 && isTextContentBlock(content[0]);
42
+ }
43
+ /**
44
+ * Normalise the WordPress↔Joomla `/mcp` envelope asymmetry for `tools/call`
45
+ * responses.
46
+ *
47
+ * The WP mcp-adapter (`ToolsHandler`) treats an Ability's return value as raw
48
+ * data and `wp_json_encode`s our already-final `CallToolResult` into a fresh
49
+ * text-content block. Over the wire that yields a DOUBLE-wrapped result —
50
+ * `result.content[0].text` is itself a serialised `CallToolResult`
51
+ * (`{"content":[{"type":"text","text":"<real-data-json>"}],"isError":…}`).
52
+ * Joomla's `/api/` handler single-wraps: `result.content[0].text` is already
53
+ * the real data JSON. The proxy bridge is a verbatim pipe, so a WP customer
54
+ * would receive doubly-nested tool output while a Joomla customer would not.
55
+ *
56
+ * Strip EXACTLY ONE level of that nesting, and ONLY when the inner payload is
57
+ * unmistakably a nested `CallToolResult`. Every shape check is defensive
58
+ * (try/catch around the parse, strict block typing) so a genuine Joomla data
59
+ * payload is never touched. Non-`tools/call` frames (initialize, tools/list,
60
+ * JSON-RPC errors, notifications) are returned by reference, unchanged.
61
+ *
62
+ * Exported for unit tests.
63
+ */
64
+ export function normalizeProxyResponse(msg) {
65
+ if (msg === null || typeof msg !== 'object')
66
+ return msg;
67
+ const result = msg.result;
68
+ if (result === null || typeof result !== 'object')
69
+ return msg;
70
+ // Only tools/call responses carry a `result.content` array.
71
+ const content = result.content;
72
+ if (!Array.isArray(content))
73
+ return msg;
74
+ // A double-wrap is EXACTLY one text block whose text is a serialised result.
75
+ if (content.length !== 1)
76
+ return msg;
77
+ const block = content[0];
78
+ if (!isTextContentBlock(block) || block.type !== 'text')
79
+ return msg;
80
+ let inner;
81
+ try {
82
+ inner = JSON.parse(block.text);
83
+ }
84
+ catch {
85
+ // Joomla single-wrap (text is the real data JSON, not nested) or plain
86
+ // prose — leave the frame untouched.
87
+ return msg;
88
+ }
89
+ if (!isNestedCallToolResult(inner))
90
+ return msg;
91
+ // Unpack one level: keep the outer result's fields, swap in the inner
92
+ // content, and let the inner isError / structuredContent win when present
93
+ // (the inner is the REAL tool result; the outer is the adapter's wrapper).
94
+ const normalizedResult = {
95
+ ...result,
96
+ content: inner.content,
97
+ };
98
+ if (inner.isError !== undefined)
99
+ normalizedResult.isError = inner.isError;
100
+ if (inner.structuredContent !== undefined) {
101
+ normalizedResult.structuredContent = inner.structuredContent;
102
+ }
103
+ return { ...msg, result: normalizedResult };
104
+ }
29
105
  /**
30
106
  * Wire two MCP transports into a transparent pipe: every message from one side
31
- * is relayed verbatim to the other, and a close/error on either side tears down
32
- * the other. No transformation the PHP server owns the protocol semantics.
107
+ * is relayed to the other, and a close/error on either side tears down the
108
+ * other. The local→remote direction is verbatim; the remote→local direction
109
+ * normalises the WP double-wrap (see `normalizeProxyResponse`) so WP and Joomla
110
+ * customers receive identical, spec-clean tool results. The PHP server otherwise
111
+ * owns the protocol semantics.
33
112
  * The caller is responsible for start()ing both transports.
34
113
  *
35
114
  * `StreamableHTTPClientTransport.send()` re-throws on any upstream failure
@@ -43,8 +122,14 @@ export function bridgeTransports(local, remote) {
43
122
  local.onmessage = (msg) => {
44
123
  remote.send(msg).catch((err) => {
45
124
  const message = errorMessage(err);
125
+ // Turn an opaque transport failure (TLS-inspection CA, proxy, DNS,
126
+ // timeout) into an actionable hint — the Glöckle stress-test died with a
127
+ // 30s timeout that looked like an auth problem. Falls back to the generic
128
+ // config hint when the cause is not recognised.
129
+ const diag = diagnoseNetworkError(err);
130
+ const hint = diag !== null ? `${diag.summary} Fix: ${diag.fix}` : 'Check YTB_MCP_SITE_URL / YTB_MCP_BEARER_TOKEN.';
46
131
  // stderr only — stdout is the JSON-RPC channel.
47
- console.error('[yt-builder-proxy] upstream send failed:', message);
132
+ console.error('[yt-builder-proxy] upstream send failed:', message + (diag !== null ? `\n → ${diag.fix}` : ''));
48
133
  const id = requestId(msg);
49
134
  if (id !== null) {
50
135
  // Hand the client an actionable error instead of a dead pipe.
@@ -53,7 +138,7 @@ export function bridgeTransports(local, remote) {
53
138
  id,
54
139
  error: {
55
140
  code: -32000,
56
- message: `Proxy upstream error: ${message}. Check YTB_MCP_SITE_URL / YTB_MCP_BEARER_TOKEN.`,
141
+ message: `Proxy upstream error: ${message}. ${hint}`,
57
142
  },
58
143
  };
59
144
  local.send(frame).catch((sendErr) => {
@@ -67,7 +152,10 @@ export function bridgeTransports(local, remote) {
67
152
  });
68
153
  };
69
154
  remote.onmessage = (msg) => {
70
- local.send(msg).catch((err) => {
155
+ // Normalise the WP-only double-wrap so the client sees the same shape it
156
+ // would from Joomla. Non-tools/call frames pass through by reference.
157
+ const normalized = normalizeProxyResponse(msg);
158
+ local.send(normalized).catch((err) => {
71
159
  console.error('[yt-builder-proxy] downstream send failed:', errorMessage(err));
72
160
  });
73
161
  };
@@ -84,10 +172,21 @@ export function bridgeTransports(local, remote) {
84
172
  console.error('[yt-builder-proxy] remote transport error:', err.message);
85
173
  };
86
174
  }
175
+ /**
176
+ * Build the upstream `requestInit.headers` for proxy mode: the Bearer is
177
+ * authoritative; corporate extra headers (Glöckle gap #14) only fill gaps —
178
+ * `Authorization` can NEVER be overwritten. Exported for unit tests.
179
+ */
180
+ export function buildProxyRequestHeaders(config) {
181
+ const base = { Authorization: `Bearer ${config.token}` };
182
+ return config.extraHeaders !== undefined && Object.keys(config.extraHeaders).length > 0
183
+ ? mergeExtraHeaders(base, config.extraHeaders)
184
+ : base;
185
+ }
87
186
  /** Injection seam for tests — production builds the real SDK transports. */
88
187
  function defaultTransports(config) {
89
188
  const remote = new StreamableHTTPClientTransport(config.endpointUrl, {
90
- requestInit: { headers: { Authorization: `Bearer ${config.token}` } },
189
+ requestInit: { headers: buildProxyRequestHeaders(config) },
91
190
  });
92
191
  const local = new StdioServerTransport();
93
192
  return { local, remote };
@@ -123,7 +222,14 @@ export async function maybeRunProxy(env, deps = {}) {
123
222
  if (resolved.mode !== 'proxy')
124
223
  return false;
125
224
  const run = deps.runProxy ?? runProxy;
126
- await run({ endpointUrl: resolved.endpointUrl, token: resolved.token });
225
+ // Glöckle gap #14 — attach corporate extra headers (Basic-Auth / WAF / gateway)
226
+ // to every upstream request. parseExtraHeaders reads YTB_MCP_EXTRA_HEADERS.
227
+ const { headers: extraHeaders } = parseExtraHeaders(env);
228
+ await run({
229
+ endpointUrl: resolved.endpointUrl,
230
+ token: resolved.token,
231
+ ...(Object.keys(extraHeaders).length > 0 ? { extraHeaders } : {}),
232
+ });
127
233
  return true;
128
234
  }
129
235
  //# sourceMappingURL=bridge.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/proxy/bridge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/proxy/bridge.ts"],"names":[],"mappings":"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"}