@wootsup/yt-builder-mcp 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +18 -11
- package/dist/proxy/bridge.d.ts.map +1 -1
- package/dist/proxy/bridge.js +30 -4
- 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
|
@@ -13,24 +13,31 @@ import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
|
|
|
13
13
|
* therefore `.catch()`es its `send()`.
|
|
14
14
|
*/
|
|
15
15
|
export declare function bridgeTransports(local: Transport, remote: Transport): void;
|
|
16
|
-
/**
|
|
17
|
-
|
|
16
|
+
/** Config the proxy run needs: the upstream endpoint, the Bearer, and any
|
|
17
|
+
* corporate extra headers (Glöckle gap #14) to attach to every upstream
|
|
18
|
+
* request. The Bearer always wins on collision. */
|
|
19
|
+
interface ProxyConfig {
|
|
18
20
|
endpointUrl: URL;
|
|
19
21
|
token: string;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
/** Extra headers from `YTB_MCP_EXTRA_HEADERS` (Basic-Auth / WAF / gateway). */
|
|
23
|
+
extraHeaders?: Record<string, string>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Build the upstream `requestInit.headers` for proxy mode: the Bearer is
|
|
27
|
+
* authoritative; corporate extra headers (Glöckle gap #14) only fill gaps —
|
|
28
|
+
* `Authorization` can NEVER be overwritten. Exported for unit tests.
|
|
29
|
+
*/
|
|
30
|
+
export declare function buildProxyRequestHeaders(config: ProxyConfig): Record<string, string>;
|
|
31
|
+
/** Build the real transports + bridge them; resolves when EITHER side closes. */
|
|
32
|
+
export declare function runProxy(config: ProxyConfig, deps?: {
|
|
33
|
+
makeTransports?: (c: ProxyConfig) => {
|
|
25
34
|
local: Transport;
|
|
26
35
|
remote: Transport;
|
|
27
36
|
};
|
|
28
37
|
}): Promise<void>;
|
|
29
38
|
/** Returns true if proxy mode handled the run; false → caller continues with fat. */
|
|
30
39
|
export declare function maybeRunProxy(env: NodeJS.ProcessEnv, deps?: {
|
|
31
|
-
runProxy?: (c:
|
|
32
|
-
endpointUrl: URL;
|
|
33
|
-
token: string;
|
|
34
|
-
}) => Promise<void>;
|
|
40
|
+
runProxy?: (c: ProxyConfig) => Promise<void>;
|
|
35
41
|
}): Promise<boolean>;
|
|
42
|
+
export {};
|
|
36
43
|
//# 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;AA+B/E;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI,CAoD1E;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)
|
|
@@ -43,8 +45,14 @@ export function bridgeTransports(local, remote) {
|
|
|
43
45
|
local.onmessage = (msg) => {
|
|
44
46
|
remote.send(msg).catch((err) => {
|
|
45
47
|
const message = errorMessage(err);
|
|
48
|
+
// Turn an opaque transport failure (TLS-inspection CA, proxy, DNS,
|
|
49
|
+
// timeout) into an actionable hint — the Glöckle stress-test died with a
|
|
50
|
+
// 30s timeout that looked like an auth problem. Falls back to the generic
|
|
51
|
+
// config hint when the cause is not recognised.
|
|
52
|
+
const diag = diagnoseNetworkError(err);
|
|
53
|
+
const hint = diag !== null ? `${diag.summary} Fix: ${diag.fix}` : 'Check YTB_MCP_SITE_URL / YTB_MCP_BEARER_TOKEN.';
|
|
46
54
|
// stderr only — stdout is the JSON-RPC channel.
|
|
47
|
-
console.error('[yt-builder-proxy] upstream send failed:', message);
|
|
55
|
+
console.error('[yt-builder-proxy] upstream send failed:', message + (diag !== null ? `\n → ${diag.fix}` : ''));
|
|
48
56
|
const id = requestId(msg);
|
|
49
57
|
if (id !== null) {
|
|
50
58
|
// Hand the client an actionable error instead of a dead pipe.
|
|
@@ -53,7 +61,7 @@ export function bridgeTransports(local, remote) {
|
|
|
53
61
|
id,
|
|
54
62
|
error: {
|
|
55
63
|
code: -32000,
|
|
56
|
-
message: `Proxy upstream error: ${message}.
|
|
64
|
+
message: `Proxy upstream error: ${message}. ${hint}`,
|
|
57
65
|
},
|
|
58
66
|
};
|
|
59
67
|
local.send(frame).catch((sendErr) => {
|
|
@@ -84,10 +92,21 @@ export function bridgeTransports(local, remote) {
|
|
|
84
92
|
console.error('[yt-builder-proxy] remote transport error:', err.message);
|
|
85
93
|
};
|
|
86
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Build the upstream `requestInit.headers` for proxy mode: the Bearer is
|
|
97
|
+
* authoritative; corporate extra headers (Glöckle gap #14) only fill gaps —
|
|
98
|
+
* `Authorization` can NEVER be overwritten. Exported for unit tests.
|
|
99
|
+
*/
|
|
100
|
+
export function buildProxyRequestHeaders(config) {
|
|
101
|
+
const base = { Authorization: `Bearer ${config.token}` };
|
|
102
|
+
return config.extraHeaders !== undefined && Object.keys(config.extraHeaders).length > 0
|
|
103
|
+
? mergeExtraHeaders(base, config.extraHeaders)
|
|
104
|
+
: base;
|
|
105
|
+
}
|
|
87
106
|
/** Injection seam for tests — production builds the real SDK transports. */
|
|
88
107
|
function defaultTransports(config) {
|
|
89
108
|
const remote = new StreamableHTTPClientTransport(config.endpointUrl, {
|
|
90
|
-
requestInit: { headers:
|
|
109
|
+
requestInit: { headers: buildProxyRequestHeaders(config) },
|
|
91
110
|
});
|
|
92
111
|
const local = new StdioServerTransport();
|
|
93
112
|
return { local, remote };
|
|
@@ -123,7 +142,14 @@ export async function maybeRunProxy(env, deps = {}) {
|
|
|
123
142
|
if (resolved.mode !== 'proxy')
|
|
124
143
|
return false;
|
|
125
144
|
const run = deps.runProxy ?? runProxy;
|
|
126
|
-
|
|
145
|
+
// Glöckle gap #14 — attach corporate extra headers (Basic-Auth / WAF / gateway)
|
|
146
|
+
// to every upstream request. parseExtraHeaders reads YTB_MCP_EXTRA_HEADERS.
|
|
147
|
+
const { headers: extraHeaders } = parseExtraHeaders(env);
|
|
148
|
+
await run({
|
|
149
|
+
endpointUrl: resolved.endpointUrl,
|
|
150
|
+
token: resolved.token,
|
|
151
|
+
...(Object.keys(extraHeaders).length > 0 ? { extraHeaders } : {}),
|
|
152
|
+
});
|
|
127
153
|
return true;
|
|
128
154
|
}
|
|
129
155
|
//# 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;AAED;;;;;;;;;;;;GAYG;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,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YACrC,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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `setup-ca-env` — translate a wizard/CLI CA choice into MCP-server env keys.
|
|
3
|
+
*
|
|
4
|
+
* G-D #7: corporate TLS-inspection has two trust strategies, and exactly which
|
|
5
|
+
* env the server entry needs depends on the running Node:
|
|
6
|
+
*
|
|
7
|
+
* - **file mode** (`caCertPath`): write `NODE_EXTRA_CA_CERTS=<path>`. Works on
|
|
8
|
+
* every supported Node; the only option below the system-CA floor.
|
|
9
|
+
* - **system mode** (`caMode: 'system'`): write `NODE_OPTIONS=--use-system-ca`
|
|
10
|
+
* so Node reads the OS trust store (Windows CryptoAPI / macOS Keychain) —
|
|
11
|
+
* the zero-export path, but only on Node ≥ 22.15. Below that floor we emit
|
|
12
|
+
* NOTHING and warn to supply a `.pem` instead, so we never write a flag the
|
|
13
|
+
* target Node would reject at startup.
|
|
14
|
+
*
|
|
15
|
+
* Pure + Node-version-injectable so it is unit-testable offline. Never disables
|
|
16
|
+
* TLS verification.
|
|
17
|
+
*
|
|
18
|
+
* @license MIT
|
|
19
|
+
*/
|
|
20
|
+
/** The CA-trust portion of a {@link WizardAnswers}. */
|
|
21
|
+
export interface CaChoice {
|
|
22
|
+
readonly caCertPath?: string;
|
|
23
|
+
readonly caMode?: 'system';
|
|
24
|
+
}
|
|
25
|
+
export interface CaEnvResult {
|
|
26
|
+
/** Env keys to merge into the MCP server entry's env block. */
|
|
27
|
+
readonly env: Record<string, string>;
|
|
28
|
+
/** Non-fatal warnings (e.g. system-CA requested on too-old a Node). */
|
|
29
|
+
readonly warnings: readonly string[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Resolve the CA env-block keys for `choice` under `nodeVersion` (default
|
|
33
|
+
* `process.version`). `currentEnv` (default `process.env`) is only read to
|
|
34
|
+
* preserve a pre-existing `NODE_OPTIONS` when appending the system-CA flag.
|
|
35
|
+
*
|
|
36
|
+
* File mode wins deterministically if both are set (an explicit `.pem` is the
|
|
37
|
+
* stronger signal). Pure — returns a fresh object, mutates nothing.
|
|
38
|
+
*/
|
|
39
|
+
export declare function buildCaEnv(choice: CaChoice, nodeVersion?: string, currentEnv?: NodeJS.ProcessEnv): CaEnvResult;
|
|
40
|
+
//# sourceMappingURL=setup-ca-env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-ca-env.d.ts","sourceRoot":"","sources":["../src/setup-ca-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAIH,uDAAuD;AACvD,MAAM,WAAW,QAAQ;IACrB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC;CAC9B;AAED,MAAM,WAAW,WAAW;IACxB,+DAA+D;IAC/D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC;AAYD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CACtB,MAAM,EAAE,QAAQ,EAChB,WAAW,GAAE,MAAwB,EACrC,UAAU,GAAE,MAAM,CAAC,UAAwB,GAC5C,WAAW,CAoBb"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `setup-ca-env` — translate a wizard/CLI CA choice into MCP-server env keys.
|
|
3
|
+
*
|
|
4
|
+
* G-D #7: corporate TLS-inspection has two trust strategies, and exactly which
|
|
5
|
+
* env the server entry needs depends on the running Node:
|
|
6
|
+
*
|
|
7
|
+
* - **file mode** (`caCertPath`): write `NODE_EXTRA_CA_CERTS=<path>`. Works on
|
|
8
|
+
* every supported Node; the only option below the system-CA floor.
|
|
9
|
+
* - **system mode** (`caMode: 'system'`): write `NODE_OPTIONS=--use-system-ca`
|
|
10
|
+
* so Node reads the OS trust store (Windows CryptoAPI / macOS Keychain) —
|
|
11
|
+
* the zero-export path, but only on Node ≥ 22.15. Below that floor we emit
|
|
12
|
+
* NOTHING and warn to supply a `.pem` instead, so we never write a flag the
|
|
13
|
+
* target Node would reject at startup.
|
|
14
|
+
*
|
|
15
|
+
* Pure + Node-version-injectable so it is unit-testable offline. Never disables
|
|
16
|
+
* TLS verification.
|
|
17
|
+
*
|
|
18
|
+
* @license MIT
|
|
19
|
+
*/
|
|
20
|
+
import { supportsSystemCa } from './diagnostics/ca-trust.js';
|
|
21
|
+
const SYSTEM_CA_FLAG = '--use-system-ca';
|
|
22
|
+
/** Append `--use-system-ca` to an existing NODE_OPTIONS without duplicating it. */
|
|
23
|
+
function withSystemCaFlag(existing) {
|
|
24
|
+
const trimmed = (existing ?? '').trim();
|
|
25
|
+
if (trimmed === '')
|
|
26
|
+
return SYSTEM_CA_FLAG;
|
|
27
|
+
if (trimmed.split(/\s+/).includes(SYSTEM_CA_FLAG))
|
|
28
|
+
return trimmed;
|
|
29
|
+
return `${trimmed} ${SYSTEM_CA_FLAG}`;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Resolve the CA env-block keys for `choice` under `nodeVersion` (default
|
|
33
|
+
* `process.version`). `currentEnv` (default `process.env`) is only read to
|
|
34
|
+
* preserve a pre-existing `NODE_OPTIONS` when appending the system-CA flag.
|
|
35
|
+
*
|
|
36
|
+
* File mode wins deterministically if both are set (an explicit `.pem` is the
|
|
37
|
+
* stronger signal). Pure — returns a fresh object, mutates nothing.
|
|
38
|
+
*/
|
|
39
|
+
export function buildCaEnv(choice, nodeVersion = process.version, currentEnv = process.env) {
|
|
40
|
+
const path = choice.caCertPath?.trim();
|
|
41
|
+
if (path !== undefined && path !== '') {
|
|
42
|
+
return { env: { NODE_EXTRA_CA_CERTS: path }, warnings: [] };
|
|
43
|
+
}
|
|
44
|
+
if (choice.caMode === 'system') {
|
|
45
|
+
if (supportsSystemCa(nodeVersion)) {
|
|
46
|
+
return { env: { NODE_OPTIONS: withSystemCaFlag(currentEnv.NODE_OPTIONS) }, warnings: [] };
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
env: {},
|
|
50
|
+
warnings: [
|
|
51
|
+
`OS trust store (--use-system-ca) needs Node ≥ 22.15 — this Node is ${nodeVersion}. ` +
|
|
52
|
+
'Re-run setup with `--ca <path-to-corp-root-ca.pem>` (export your corporate root CA to a .pem) instead. Never disable TLS verification.',
|
|
53
|
+
],
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return { env: {}, warnings: [] };
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=setup-ca-env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-ca-env.js","sourceRoot":"","sources":["../src/setup-ca-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAe7D,MAAM,cAAc,GAAG,iBAAiB,CAAC;AAEzC,mFAAmF;AACnF,SAAS,gBAAgB,CAAC,QAA4B;IAClD,MAAM,OAAO,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,IAAI,OAAO,KAAK,EAAE;QAAE,OAAO,cAAc,CAAC;IAC1C,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC;QAAE,OAAO,OAAO,CAAC;IAClE,OAAO,GAAG,OAAO,IAAI,cAAc,EAAE,CAAC;AAC1C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CACtB,MAAgB,EAChB,cAAsB,OAAO,CAAC,OAAO,EACrC,aAAgC,OAAO,CAAC,GAAG;IAE3C,MAAM,IAAI,GAAG,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC;IACvC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QACpC,OAAO,EAAE,GAAG,EAAE,EAAE,mBAAmB,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAChE,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC7B,IAAI,gBAAgB,CAAC,WAAW,CAAC,EAAE,CAAC;YAChC,OAAO,EAAE,GAAG,EAAE,EAAE,YAAY,EAAE,gBAAgB,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;QAC9F,CAAC;QACD,OAAO;YACH,GAAG,EAAE,EAAE;YACP,QAAQ,EAAE;gBACN,sEAAsE,WAAW,IAAI;oBACjF,wIAAwI;aAC/I;SACJ,CAAC;IACN,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `setup-ca-reprobe` — default `WizardDeps.applyAndReProbe` (G-D #6/#8).
|
|
3
|
+
*
|
|
4
|
+
* After the user picks a corporate-CA strategy, RE-PROBE the connection so the
|
|
5
|
+
* wizard can print ✅/❌ now instead of leaving a silent first-tool-call
|
|
6
|
+
* timeout for after the restart:
|
|
7
|
+
*
|
|
8
|
+
* - **file mode**: read the `.pem` and run the probes through an undici
|
|
9
|
+
* `Agent` whose connector trusts that CA — this validates in-process,
|
|
10
|
+
* immediately, without a restart.
|
|
11
|
+
* - **system mode**: the OS trust store is only consulted when Node is
|
|
12
|
+
* (re)started with `--use-system-ca`, which the written config now does —
|
|
13
|
+
* so we re-run the ordinary probes (best-effort) and report the truthful
|
|
14
|
+
* current state; the config is already correct for the next launch.
|
|
15
|
+
*
|
|
16
|
+
* Never disables TLS verification.
|
|
17
|
+
*
|
|
18
|
+
* @license MIT
|
|
19
|
+
*/
|
|
20
|
+
import type { AuthProbeResult, CaPromptChoice, HealthProbeResult } from './setup-wizard-types.js';
|
|
21
|
+
/**
|
|
22
|
+
* Probe health + auth for `wpUrl`/`bearer` under the chosen CA. The probes are
|
|
23
|
+
* injected (default to the real handshake probes) so this stays testable; the
|
|
24
|
+
* file-mode CA wiring is the only real-I/O part and is exercised by an
|
|
25
|
+
* integration probe, never a unit mock.
|
|
26
|
+
*/
|
|
27
|
+
export declare function defaultApplyAndReProbe(input: {
|
|
28
|
+
readonly wpUrl: string;
|
|
29
|
+
readonly bearer: string;
|
|
30
|
+
readonly choice: CaPromptChoice;
|
|
31
|
+
}, probes?: {
|
|
32
|
+
probeHealth?: (wpUrl: string, fetchImpl?: typeof fetch) => Promise<HealthProbeResult>;
|
|
33
|
+
probeAuth?: (wpUrl: string, bearer: string, fetchImpl?: typeof fetch) => Promise<AuthProbeResult>;
|
|
34
|
+
}): Promise<{
|
|
35
|
+
health: HealthProbeResult;
|
|
36
|
+
auth: AuthProbeResult;
|
|
37
|
+
}>;
|
|
38
|
+
//# sourceMappingURL=setup-ca-reprobe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup-ca-reprobe.d.ts","sourceRoot":"","sources":["../src/setup-ca-reprobe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAOH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAElG;;;;;GAKG;AACH,wBAAsB,sBAAsB,CACxC,KAAK,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAA;CAAE,EAC3F,MAAM,GAAE;IACJ,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,KAAK,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;IACtF,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,OAAO,KAAK,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;CAChG,GACP,OAAO,CAAC;IAAE,MAAM,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC,CAkB/D"}
|