@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.
- package/README.md +1 -1
- package/dist/cli/doctor-command.d.ts +21 -0
- package/dist/cli/doctor-command.d.ts.map +1 -0
- package/dist/cli/doctor-command.js +111 -0
- package/dist/cli/doctor-command.js.map +1 -0
- package/dist/cli/invocation-decision.d.ts.map +1 -1
- package/dist/cli/invocation-decision.js +2 -0
- package/dist/cli/invocation-decision.js.map +1 -1
- package/dist/client.d.ts +14 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +9 -0
- package/dist/client.js.map +1 -1
- package/dist/diagnostics/ca-trust.d.ts +16 -0
- package/dist/diagnostics/ca-trust.d.ts.map +1 -0
- package/dist/diagnostics/ca-trust.js +54 -0
- package/dist/diagnostics/ca-trust.js.map +1 -0
- package/dist/diagnostics/diagnose-network-error.d.ts +37 -0
- package/dist/diagnostics/diagnose-network-error.d.ts.map +1 -0
- package/dist/diagnostics/diagnose-network-error.js +158 -0
- package/dist/diagnostics/diagnose-network-error.js.map +1 -0
- package/dist/diagnostics/doctor.d.ts +62 -0
- package/dist/diagnostics/doctor.d.ts.map +1 -0
- package/dist/diagnostics/doctor.js +165 -0
- package/dist/diagnostics/doctor.js.map +1 -0
- package/dist/gateway/essentials.d.ts +1 -1
- package/dist/gateway/essentials.d.ts.map +1 -1
- package/dist/gateway/essentials.js +5 -0
- package/dist/gateway/essentials.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -1
- package/dist/install-skill.d.ts +1 -1
- package/dist/install-skill.js +1 -1
- package/dist/net/extra-headers.d.ts +66 -0
- package/dist/net/extra-headers.d.ts.map +1 -0
- package/dist/net/extra-headers.js +164 -0
- package/dist/net/extra-headers.js.map +1 -0
- package/dist/net/internal-host.d.ts +45 -0
- package/dist/net/internal-host.d.ts.map +1 -0
- package/dist/net/internal-host.js +164 -0
- package/dist/net/internal-host.js.map +1 -0
- package/dist/net/proxy-dispatcher.d.ts +40 -0
- package/dist/net/proxy-dispatcher.d.ts.map +1 -0
- package/dist/net/proxy-dispatcher.js +65 -0
- package/dist/net/proxy-dispatcher.js.map +1 -0
- package/dist/proxy/bridge.d.ts +45 -13
- package/dist/proxy/bridge.d.ts.map +1 -1
- package/dist/proxy/bridge.js +113 -7
- package/dist/proxy/bridge.js.map +1 -1
- package/dist/setup-ca-env.d.ts +40 -0
- package/dist/setup-ca-env.d.ts.map +1 -0
- package/dist/setup-ca-env.js +58 -0
- package/dist/setup-ca-env.js.map +1 -0
- package/dist/setup-ca-reprobe.d.ts +38 -0
- package/dist/setup-ca-reprobe.d.ts.map +1 -0
- package/dist/setup-ca-reprobe.js +68 -0
- package/dist/setup-ca-reprobe.js.map +1 -0
- package/dist/setup-cli.d.ts +37 -2
- package/dist/setup-cli.d.ts.map +1 -1
- package/dist/setup-cli.js +178 -4
- package/dist/setup-cli.js.map +1 -1
- package/dist/setup-npx-spec.d.ts +44 -0
- package/dist/setup-npx-spec.d.ts.map +1 -0
- package/dist/setup-npx-spec.js +66 -0
- package/dist/setup-npx-spec.js.map +1 -0
- package/dist/setup-prompts.d.ts +14 -1
- package/dist/setup-prompts.d.ts.map +1 -1
- package/dist/setup-prompts.js +53 -1
- package/dist/setup-prompts.js.map +1 -1
- package/dist/setup-wizard-defaults.d.ts.map +1 -1
- package/dist/setup-wizard-defaults.js +29 -5
- package/dist/setup-wizard-defaults.js.map +1 -1
- package/dist/setup-wizard-handshake.d.ts +4 -4
- package/dist/setup-wizard-handshake.d.ts.map +1 -1
- package/dist/setup-wizard-handshake.js +46 -12
- package/dist/setup-wizard-handshake.js.map +1 -1
- package/dist/setup-wizard-types.d.ts +81 -0
- package/dist/setup-wizard-types.d.ts.map +1 -1
- package/dist/setup-wizard.d.ts +2 -2
- package/dist/setup-wizard.d.ts.map +1 -1
- package/dist/setup-wizard.js +133 -18
- package/dist/setup-wizard.js.map +1 -1
- package/dist/sites/client-pool.d.ts +8 -1
- package/dist/sites/client-pool.d.ts.map +1 -1
- package/dist/sites/client-pool.js +13 -1
- package/dist/sites/client-pool.js.map +1 -1
- package/dist/tools/elements/builders.d.ts.map +1 -1
- package/dist/tools/elements/builders.js +4 -2
- package/dist/tools/elements/builders.js.map +1 -1
- package/dist/tools/elements/handlers.d.ts +2 -1
- package/dist/tools/elements/handlers.d.ts.map +1 -1
- package/dist/tools/elements/handlers.js +3 -22
- package/dist/tools/elements/handlers.js.map +1 -1
- package/dist/tools/format/health-format.d.ts +3 -0
- package/dist/tools/format/health-format.d.ts.map +1 -1
- package/dist/tools/format/health-format.js +21 -4
- package/dist/tools/format/health-format.js.map +1 -1
- package/dist/tools/health.d.ts.map +1 -1
- package/dist/tools/health.js +32 -0
- package/dist/tools/health.js.map +1 -1
- package/dist/tools/pages/builders.d.ts.map +1 -1
- package/dist/tools/pages/builders.js +78 -27
- package/dist/tools/pages/builders.js.map +1 -1
- package/dist/tools/pages/handlers-read.d.ts +36 -5
- package/dist/tools/pages/handlers-read.d.ts.map +1 -1
- package/dist/tools/pages/handlers-read.js +217 -34
- package/dist/tools/pages/handlers-read.js.map +1 -1
- package/dist/tools/pages/schemas.d.ts +20 -5
- package/dist/tools/pages/schemas.d.ts.map +1 -1
- package/dist/tools/pages/schemas.js +44 -6
- package/dist/tools/pages/schemas.js.map +1 -1
- package/dist/tools/shared-schemas.d.ts +3 -0
- package/dist/tools/shared-schemas.d.ts.map +1 -1
- package/dist/tools/shared-schemas.js +28 -0
- package/dist/tools/shared-schemas.js.map +1 -1
- package/dist/tools/sources/builders.d.ts.map +1 -1
- package/dist/tools/sources/builders.js +30 -5
- package/dist/tools/sources/builders.js.map +1 -1
- package/dist/tools/sources/handlers.d.ts +9 -1
- package/dist/tools/sources/handlers.d.ts.map +1 -1
- package/dist/tools/sources/handlers.js +62 -12
- package/dist/tools/sources/handlers.js.map +1 -1
- package/dist/tools/sparse-fields.d.ts +50 -0
- package/dist/tools/sparse-fields.d.ts.map +1 -1
- package/dist/tools/sparse-fields.js +107 -0
- package/dist/tools/sparse-fields.js.map +1 -1
- package/dist/update/update-check.d.ts +56 -0
- package/dist/update/update-check.d.ts.map +1 -0
- package/dist/update/update-check.js +155 -0
- package/dist/update/update-check.js.map +1 -0
- package/manifest.json +1 -1
- package/package.json +2 -1
- 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"}
|
package/dist/proxy/bridge.d.ts
CHANGED
|
@@ -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
|
|
5
|
-
*
|
|
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
|
-
/**
|
|
17
|
-
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
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;
|
|
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"}
|
package/dist/proxy/bridge.js
CHANGED
|
@@ -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
|
|
32
|
-
*
|
|
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}.
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
package/dist/proxy/bridge.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/proxy/bridge.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/proxy/bridge.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE/E,6EAA6E;AAC7E,SAAS,YAAY,CAAC,GAAY;IAChC,IAAI,GAAG,YAAY,KAAK;QAAE,OAAO,GAAG,CAAC,OAAO,CAAC;IAC7C,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IACxC,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,eAAe,CAAC;IACzB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,SAAS,CAAC,GAAY;IAC7B,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,IAAI,IAAI,GAAG,EAAE,CAAC;QAC3D,MAAM,EAAE,GAAI,GAAuB,CAAC,EAAE,CAAC;QACvC,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,OAAO,EAAE,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC;IAClE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AASD,SAAS,kBAAkB,CAAC,CAAU;IACpC,OAAO,CACL,CAAC,KAAK,IAAI;QACV,OAAO,CAAC,KAAK,QAAQ;QACrB,OAAQ,CAAwB,CAAC,IAAI,KAAK,QAAQ;QAClD,OAAQ,CAAwB,CAAC,IAAI,KAAK,QAAQ,CACnD,CAAC;AACJ,CAAC;AAaD,SAAS,sBAAsB,CAAC,CAAU;IACxC,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,OAAO,GAAI,CAA2B,CAAC,OAAO,CAAC;IACrD,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AACxF,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAY;IACjD,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IACxD,MAAM,MAAM,GAAI,GAA4B,CAAC,MAAM,CAAC;IACpD,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IAE9D,4DAA4D;IAC5D,MAAM,OAAO,GAAI,MAAgC,CAAC,OAAO,CAAC;IAC1D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,GAAG,CAAC;IAExC,6EAA6E;IAC7E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IACrC,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACzB,IAAI,CAAC,kBAAkB,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,GAAG,CAAC;IAEpE,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,uEAAuE;QACvE,qCAAqC;QACrC,OAAO,GAAG,CAAC;IACb,CAAC;IACD,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC;IAE/C,sEAAsE;IACtE,0EAA0E;IAC1E,2EAA2E;IAC3E,MAAM,gBAAgB,GAA4B;QAChD,GAAI,MAAkC;QACtC,OAAO,EAAE,KAAK,CAAC,OAAO;KACvB,CAAC;IACF,IAAI,KAAK,CAAC,OAAO,KAAK,SAAS;QAAE,gBAAgB,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC1E,IAAI,KAAK,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;QAC1C,gBAAgB,CAAC,iBAAiB,GAAG,KAAK,CAAC,iBAAiB,CAAC;IAC/D,CAAC;IACD,OAAO,EAAE,GAAI,GAA+B,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;AAC3E,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAgB,EAAE,MAAiB;IAClE,KAAK,CAAC,SAAS,GAAG,CAAC,GAAG,EAAE,EAAE;QACxB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YACtC,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;YAClC,mEAAmE;YACnE,yEAAyE;YACzE,0EAA0E;YAC1E,gDAAgD;YAChD,MAAM,IAAI,GAAG,oBAAoB,CAAC,GAAG,CAAC,CAAC;YACvC,MAAM,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,OAAO,SAAS,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,gDAAgD,CAAC;YACnH,gDAAgD;YAChD,OAAO,CAAC,KAAK,CACX,0CAA0C,EAC1C,OAAO,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CACrD,CAAC;YACF,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;YAC1B,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC;gBAChB,8DAA8D;gBAC9D,MAAM,KAAK,GAAG;oBACZ,OAAO,EAAE,KAAK;oBACd,EAAE;oBACF,KAAK,EAAE;wBACL,IAAI,EAAE,CAAC,KAAK;wBACZ,OAAO,EAAE,yBAAyB,OAAO,KAAK,IAAI,EAAE;qBACrD;iBACF,CAAC;gBACF,KAAK,CAAC,IAAI,CAAC,KAAkC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAgB,EAAE,EAAE;oBACxE,OAAO,CAAC,KAAK,CAAC,mDAAmD,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC;gBAC5F,CAAC,CAAC,CAAC;YACL,CAAC;iBAAM,CAAC;gBACN,mEAAmE;gBACnE,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC;YACtB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IACF,MAAM,CAAC,SAAS,GAAG,CAAC,GAAG,EAAE,EAAE;QACzB,yEAAyE;QACzE,sEAAsE;QACtE,MAAM,UAAU,GAAG,sBAAsB,CAAC,GAAG,CAAmB,CAAC;QACjE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YAC5C,OAAO,CAAC,KAAK,CAAC,4CAA4C,EAAE,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC;QACjF,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IACF,KAAK,CAAC,OAAO,GAAG,GAAG,EAAE;QACnB,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC,CAAC;IACF,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE;QACpB,KAAK,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC,CAAC;IACF,KAAK,CAAC,OAAO,GAAG,CAAC,GAAG,EAAE,EAAE;QACtB,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IAC1E,CAAC,CAAC;IACF,MAAM,CAAC,OAAO,GAAG,CAAC,GAAG,EAAE,EAAE;QACvB,OAAO,CAAC,KAAK,CAAC,4CAA4C,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IAC3E,CAAC,CAAC;AACJ,CAAC;AAYD;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,MAAmB;IAC1D,MAAM,IAAI,GAA2B,EAAE,aAAa,EAAE,UAAU,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC;IACjF,OAAO,MAAM,CAAC,YAAY,KAAK,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,GAAG,CAAC;QACrF,CAAC,CAAC,iBAAiB,CAAC,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC;QAC9C,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED,4EAA4E;AAC5E,SAAS,iBAAiB,CAAC,MAAmB;IAI5C,MAAM,MAAM,GAAG,IAAI,6BAA6B,CAAC,MAAM,CAAC,WAAW,EAAE;QACnE,WAAW,EAAE,EAAE,OAAO,EAAE,wBAAwB,CAAC,MAAM,CAAC,EAAE;KAC3D,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,IAAI,oBAAoB,EAAE,CAAC;IACzC,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AAC3B,CAAC;AAED,iFAAiF;AACjF,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,MAAmB,EACnB,OAKI,EAAE;IAEN,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,cAAc,IAAI,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;IAE7E,wEAAwE;IACxE,2EAA2E;IAC3E,oCAAoC;IACpC,MAAM,MAAM,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAC3C,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAChC,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC;QACrC,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,CAAC;QACvC,KAAK,CAAC,OAAO,GAAG,GAAG,EAAE;YACnB,cAAc,EAAE,EAAE,CAAC;YACnB,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;QACF,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE;YACpB,eAAe,EAAE,EAAE,CAAC;YACpB,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,2EAA2E;IAC3E,+DAA+D;IAC/D,MAAM,KAAK,CAAC,KAAK,EAAE,CAAC;IACpB,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACrB,MAAM,MAAM,CAAC;AACf,CAAC;AAED,qFAAqF;AACrF,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,GAAsB,EACtB,OAAyD,EAAE;IAE3D,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;IAClC,IAAI,QAAQ,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IAC5C,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC;IACtC,gFAAgF;IAChF,4EAA4E;IAC5E,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACzD,MAAM,GAAG,CAAC;QACR,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,KAAK,EAAE,QAAQ,CAAC,KAAK;QACrB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAClE,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC"}
|