@mcp-abap-adt/proxy 0.1.9 → 1.0.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/CHANGELOG.md +35 -7
- package/README.md +9 -9
- package/bin/mcp-abap-adt-proxy.js +32 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +55 -276
- package/dist/lib/config.d.ts +18 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +34 -1
- package/dist/lib/stores.d.ts +14 -0
- package/dist/lib/stores.d.ts.map +1 -1
- package/dist/lib/stores.js +1 -0
- package/dist/lib/transportConfig.d.ts +15 -2
- package/dist/lib/transportConfig.d.ts.map +1 -1
- package/dist/lib/transportConfig.js +41 -33
- package/dist/proxy/btpProxy.d.ts +8 -3
- package/dist/proxy/btpProxy.d.ts.map +1 -1
- package/dist/proxy/btpProxy.js +21 -5
- package/dist/proxy/reverseProxy.d.ts +7 -0
- package/dist/proxy/reverseProxy.d.ts.map +1 -0
- package/dist/proxy/reverseProxy.js +130 -0
- package/dist/router/headerAnalyzer.d.ts +3 -3
- package/dist/router/headerAnalyzer.js +7 -7
- package/dist/router/requestInterceptor.d.ts +2 -0
- package/dist/router/requestInterceptor.d.ts.map +1 -1
- package/dist/router/requestInterceptor.js +17 -15
- package/dist/tui/index.d.ts +8 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +11 -0
- package/dist/tui/serviceKeyCheck.d.ts +25 -0
- package/dist/tui/serviceKeyCheck.d.ts.map +1 -0
- package/dist/tui/serviceKeyCheck.js +62 -0
- package/dist/tui/wizard.d.ts +38 -0
- package/dist/tui/wizard.d.ts.map +1 -0
- package/dist/tui/wizard.js +321 -0
- package/package.json +4 -3
package/dist/lib/config.d.ts
CHANGED
|
@@ -27,6 +27,24 @@ export interface ProxyConfig {
|
|
|
27
27
|
* - If --config is NOT provided, load ONLY from command line parameters and environment variables
|
|
28
28
|
*/
|
|
29
29
|
export declare function loadConfig(configPath?: string): ProxyConfig;
|
|
30
|
+
/**
|
|
31
|
+
* Transport-related fields from config file (not part of ProxyConfig but needed by transportConfig)
|
|
32
|
+
*/
|
|
33
|
+
export interface FileTransportFields {
|
|
34
|
+
transport?: string;
|
|
35
|
+
httpPort?: number;
|
|
36
|
+
httpHost?: string;
|
|
37
|
+
ssePort?: number;
|
|
38
|
+
sseHost?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Extract transport-related fields from a raw config object
|
|
42
|
+
*/
|
|
43
|
+
export declare function extractTransportFields(raw: Record<string, unknown>): FileTransportFields;
|
|
44
|
+
/**
|
|
45
|
+
* Load raw config from file for transport field extraction
|
|
46
|
+
*/
|
|
47
|
+
export declare function loadRawConfigFile(filePath: string): Record<string, unknown> | null;
|
|
30
48
|
/**
|
|
31
49
|
* Get config file path from command line (--config or -c)
|
|
32
50
|
*/
|
package/dist/lib/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IAEjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAG/B,OAAO,CAAC,EAAE,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;IACzE,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,CAqC3D;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IAEjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAG/B,OAAO,CAAC,EAAE,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;IACzE,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,CAqC3D;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC3B,mBAAmB,CAQrB;AAgBD;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,GACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAYhC;AA0GD;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,GAAG,SAAS,CAElD;AAUD;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG;IACnD,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAoDA"}
|
package/dist/lib/config.js
CHANGED
|
@@ -37,6 +37,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
37
37
|
})();
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.loadConfig = loadConfig;
|
|
40
|
+
exports.extractTransportFields = extractTransportFields;
|
|
41
|
+
exports.loadRawConfigFile = loadRawConfigFile;
|
|
40
42
|
exports.getConfigPath = getConfigPath;
|
|
41
43
|
exports.validateConfig = validateConfig;
|
|
42
44
|
const fs = __importStar(require("node:fs"));
|
|
@@ -80,6 +82,18 @@ function loadConfig(configPath) {
|
|
|
80
82
|
// No --config provided: load ONLY from command line parameters and environment variables
|
|
81
83
|
return loadFromEnv();
|
|
82
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Extract transport-related fields from a raw config object
|
|
87
|
+
*/
|
|
88
|
+
function extractTransportFields(raw) {
|
|
89
|
+
return {
|
|
90
|
+
transport: typeof raw.transport === 'string' ? raw.transport : undefined,
|
|
91
|
+
httpPort: typeof raw.httpPort === 'number' ? raw.httpPort : undefined,
|
|
92
|
+
httpHost: typeof raw.httpHost === 'string' ? raw.httpHost : undefined,
|
|
93
|
+
ssePort: typeof raw.ssePort === 'number' ? raw.ssePort : undefined,
|
|
94
|
+
sseHost: typeof raw.sseHost === 'string' ? raw.sseHost : undefined,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
83
97
|
/**
|
|
84
98
|
* Load configuration from file (supports JSON and YAML)
|
|
85
99
|
*/
|
|
@@ -93,6 +107,24 @@ function loadConfigFile(filePath) {
|
|
|
93
107
|
return JSON.parse(configContent);
|
|
94
108
|
}
|
|
95
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* Load raw config from file for transport field extraction
|
|
112
|
+
*/
|
|
113
|
+
function loadRawConfigFile(filePath) {
|
|
114
|
+
try {
|
|
115
|
+
if (!fs.existsSync(filePath))
|
|
116
|
+
return null;
|
|
117
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
118
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
119
|
+
if (ext === '.yaml' || ext === '.yml') {
|
|
120
|
+
return yaml.load(content) || {};
|
|
121
|
+
}
|
|
122
|
+
return JSON.parse(content);
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
96
128
|
/**
|
|
97
129
|
* Apply default values to partial config (used when loading from file)
|
|
98
130
|
*/
|
|
@@ -104,6 +136,7 @@ function applyDefaults(fileConfig) {
|
|
|
104
136
|
sseHost: fileConfig.sseHost || '0.0.0.0',
|
|
105
137
|
logLevel: fileConfig.logLevel || 'info',
|
|
106
138
|
btpDestination: fileConfig.btpDestination,
|
|
139
|
+
targetUrl: fileConfig.targetUrl,
|
|
107
140
|
unsafe: fileConfig.unsafe ?? false,
|
|
108
141
|
maxRetries: fileConfig.maxRetries ?? 3,
|
|
109
142
|
retryDelay: fileConfig.retryDelay ?? 1000,
|
|
@@ -184,7 +217,7 @@ function validateConfig(config) {
|
|
|
184
217
|
// Check if BTP destination is provided
|
|
185
218
|
const hasDestination = config.btpDestination;
|
|
186
219
|
if (!hasDestination) {
|
|
187
|
-
warnings.push('No BTP destination provided (--btp). Proxy will not work unless requests include x-
|
|
220
|
+
warnings.push('No BTP destination provided (--btp). Proxy will not work unless requests include x-sap-destination header.');
|
|
188
221
|
}
|
|
189
222
|
if (config.httpPort < 1 || config.httpPort > 65535) {
|
|
190
223
|
errors.push('MCP_HTTP_PORT must be between 1 and 65535');
|
package/dist/lib/stores.d.ts
CHANGED
|
@@ -4,6 +4,20 @@
|
|
|
4
4
|
* depending on the unsafe configuration parameter
|
|
5
5
|
*/
|
|
6
6
|
import type { IServiceKeyStore, ISessionStore } from '@mcp-abap-adt/auth-broker';
|
|
7
|
+
/**
|
|
8
|
+
* Get platform-specific default paths for service keys and sessions
|
|
9
|
+
*
|
|
10
|
+
* Priority (matching mcp-abap-adt logic):
|
|
11
|
+
* 1. AUTH_BROKER_PATH environment variable
|
|
12
|
+
* 2. Platform-specific standard paths (only if no env paths were found):
|
|
13
|
+
* - Unix: ~/.config/mcp-abap-adt/{subfolder}
|
|
14
|
+
* - Windows: %USERPROFILE%\Documents\mcp-abap-adt\{subfolder}
|
|
15
|
+
* 3. Current working directory (process.cwd())
|
|
16
|
+
*
|
|
17
|
+
* @param subfolder Subfolder name ('service-keys' or 'sessions')
|
|
18
|
+
* @returns Array of resolved absolute paths
|
|
19
|
+
*/
|
|
20
|
+
export declare function getPlatformPaths(subfolder?: 'service-keys' | 'sessions'): string[];
|
|
7
21
|
/**
|
|
8
22
|
* Get platform-specific stores
|
|
9
23
|
* Returns XSUAA stores for BTP authentication:
|
package/dist/lib/stores.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stores.d.ts","sourceRoot":"","sources":["../../src/lib/stores.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACd,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"stores.d.ts","sourceRoot":"","sources":["../../src/lib/stores.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACd,MAAM,2BAA2B,CAAC;AAOnC;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,CAAC,EAAE,cAAc,GAAG,UAAU,GACtC,MAAM,EAAE,CAgEV;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,GAAE,OAAe,GAAG,OAAO,CAAC;IACxE,eAAe,EAAE,gBAAgB,CAAC;IAClC,YAAY,EAAE,aAAa,CAAC;CAC7B,CAAC,CAqBD"}
|
package/dist/lib/stores.js
CHANGED
|
@@ -38,6 +38,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
38
38
|
};
|
|
39
39
|
})();
|
|
40
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.getPlatformPaths = getPlatformPaths;
|
|
41
42
|
exports.getPlatformStores = getPlatformStores;
|
|
42
43
|
const os = __importStar(require("node:os"));
|
|
43
44
|
const path = __importStar(require("node:path"));
|
|
@@ -12,7 +12,20 @@ export interface TransportConfig {
|
|
|
12
12
|
enableDnsRebindingProtection?: boolean;
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* File-based config overrides for transport settings (from YAML/JSON config file)
|
|
16
16
|
*/
|
|
17
|
-
export
|
|
17
|
+
export interface FileTransportOverrides {
|
|
18
|
+
transport?: string;
|
|
19
|
+
httpPort?: number;
|
|
20
|
+
httpHost?: string;
|
|
21
|
+
ssePort?: number;
|
|
22
|
+
sseHost?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Parse transport configuration from command line arguments, environment variables,
|
|
26
|
+
* and optional file-based config overrides.
|
|
27
|
+
*
|
|
28
|
+
* Priority: CLI args > file config > env vars > auto-detect > defaults
|
|
29
|
+
*/
|
|
30
|
+
export declare function parseTransportConfig(fileOverrides?: FileTransportOverrides): TransportConfig;
|
|
18
31
|
//# sourceMappingURL=transportConfig.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transportConfig.d.ts","sourceRoot":"","sources":["../../src/lib/transportConfig.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,iBAAiB,GAAG,KAAK,CAAC;AAEhE,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,4BAA4B,CAAC,EAAE,OAAO,CAAC;CACxC;AAED;;GAEG;AACH,wBAAgB,oBAAoB,
|
|
1
|
+
{"version":3,"file":"transportConfig.d.ts","sourceRoot":"","sources":["../../src/lib/transportConfig.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,iBAAiB,GAAG,KAAK,CAAC;AAEhE,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,4BAA4B,CAAC,EAAE,OAAO,CAAC;CACxC;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAaD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,aAAa,CAAC,EAAE,sBAAsB,GACrC,eAAe,CAwHjB"}
|
|
@@ -5,33 +5,32 @@
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.parseTransportConfig = parseTransportConfig;
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Normalize transport value to TransportType
|
|
9
9
|
*/
|
|
10
|
-
function
|
|
10
|
+
function normalizeTransport(value) {
|
|
11
|
+
const v = value.toLowerCase();
|
|
12
|
+
if (v === 'stdio' || v === 'streamable-http' || v === 'http' || v === 'sse') {
|
|
13
|
+
return v === 'http' ? 'streamable-http' : v;
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Parse transport configuration from command line arguments, environment variables,
|
|
19
|
+
* and optional file-based config overrides.
|
|
20
|
+
*
|
|
21
|
+
* Priority: CLI args > file config > env vars > auto-detect > defaults
|
|
22
|
+
*/
|
|
23
|
+
function parseTransportConfig(fileOverrides) {
|
|
11
24
|
const args = process.argv;
|
|
12
|
-
// Check for explicit transport type
|
|
25
|
+
// Check for explicit transport type from CLI
|
|
13
26
|
let transportType = null;
|
|
14
27
|
for (let i = 0; i < args.length; i++) {
|
|
15
28
|
const arg = args[i];
|
|
16
29
|
if (arg.startsWith('--transport=')) {
|
|
17
|
-
|
|
18
|
-
if (value === 'stdio' ||
|
|
19
|
-
value === 'streamable-http' ||
|
|
20
|
-
value === 'http' ||
|
|
21
|
-
value === 'sse') {
|
|
22
|
-
transportType =
|
|
23
|
-
value === 'http' ? 'streamable-http' : value;
|
|
24
|
-
}
|
|
30
|
+
transportType = normalizeTransport(arg.split('=')[1]);
|
|
25
31
|
}
|
|
26
32
|
if (arg === '--transport' && i + 1 < args.length) {
|
|
27
|
-
|
|
28
|
-
if (value === 'stdio' ||
|
|
29
|
-
value === 'streamable-http' ||
|
|
30
|
-
value === 'http' ||
|
|
31
|
-
value === 'sse') {
|
|
32
|
-
transportType =
|
|
33
|
-
value === 'http' ? 'streamable-http' : value;
|
|
34
|
-
}
|
|
33
|
+
transportType = normalizeTransport(args[i + 1]);
|
|
35
34
|
}
|
|
36
35
|
if (arg === '--http')
|
|
37
36
|
transportType = 'streamable-http';
|
|
@@ -40,18 +39,13 @@ function parseTransportConfig() {
|
|
|
40
39
|
if (arg === '--sse')
|
|
41
40
|
transportType = 'sse';
|
|
42
41
|
}
|
|
42
|
+
// Check file config overrides
|
|
43
|
+
if (!transportType && fileOverrides?.transport) {
|
|
44
|
+
transportType = normalizeTransport(fileOverrides.transport);
|
|
45
|
+
}
|
|
43
46
|
// Check environment variable
|
|
44
47
|
if (!transportType && process.env.MCP_TRANSPORT) {
|
|
45
|
-
|
|
46
|
-
if (envTransport === 'stdio' ||
|
|
47
|
-
envTransport === 'streamable-http' ||
|
|
48
|
-
envTransport === 'http' ||
|
|
49
|
-
envTransport === 'sse') {
|
|
50
|
-
transportType =
|
|
51
|
-
envTransport === 'http'
|
|
52
|
-
? 'streamable-http'
|
|
53
|
-
: envTransport;
|
|
54
|
-
}
|
|
48
|
+
transportType = normalizeTransport(process.env.MCP_TRANSPORT);
|
|
55
49
|
}
|
|
56
50
|
// Auto-detect stdio mode: if stdin is not a TTY, we're likely in stdio mode
|
|
57
51
|
if (!transportType && !process.stdin.isTTY) {
|
|
@@ -63,8 +57,14 @@ function parseTransportConfig() {
|
|
|
63
57
|
}
|
|
64
58
|
// Parse SSE config
|
|
65
59
|
if (transportType === 'sse') {
|
|
66
|
-
const port = parseInt(getArgValue('--sse-port') ||
|
|
67
|
-
|
|
60
|
+
const port = parseInt(getArgValue('--sse-port') ||
|
|
61
|
+
(fileOverrides?.ssePort != null ? String(fileOverrides.ssePort) : '') ||
|
|
62
|
+
process.env.MCP_SSE_PORT ||
|
|
63
|
+
'3002', 10);
|
|
64
|
+
const host = getArgValue('--sse-host') ||
|
|
65
|
+
fileOverrides?.sseHost ||
|
|
66
|
+
process.env.MCP_SSE_HOST ||
|
|
67
|
+
'0.0.0.0';
|
|
68
68
|
return {
|
|
69
69
|
type: 'sse',
|
|
70
70
|
host,
|
|
@@ -76,8 +76,16 @@ function parseTransportConfig() {
|
|
|
76
76
|
}
|
|
77
77
|
// Parse HTTP/streamable-http config
|
|
78
78
|
if (transportType === 'streamable-http') {
|
|
79
|
-
const port = parseInt(getArgValue('--http-port') ||
|
|
80
|
-
|
|
79
|
+
const port = parseInt(getArgValue('--http-port') ||
|
|
80
|
+
(fileOverrides?.httpPort != null
|
|
81
|
+
? String(fileOverrides.httpPort)
|
|
82
|
+
: '') ||
|
|
83
|
+
process.env.MCP_HTTP_PORT ||
|
|
84
|
+
'3001', 10);
|
|
85
|
+
const host = getArgValue('--http-host') ||
|
|
86
|
+
fileOverrides?.httpHost ||
|
|
87
|
+
process.env.MCP_HTTP_HOST ||
|
|
88
|
+
'0.0.0.0';
|
|
81
89
|
return {
|
|
82
90
|
type: 'streamable-http',
|
|
83
91
|
host,
|
package/dist/proxy/btpProxy.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* BTP Proxy - Proxies requests to MCP servers with JWT authentication
|
|
3
3
|
*
|
|
4
|
-
* For requests with x-
|
|
4
|
+
* For requests with x-sap-destination, proxies to target MCP server
|
|
5
5
|
* with JWT token from auth-broker (XSUAA/BTP)
|
|
6
6
|
*/
|
|
7
7
|
import { AuthBroker } from '@mcp-abap-adt/auth-broker';
|
|
@@ -63,7 +63,12 @@ export declare class BtpProxy {
|
|
|
63
63
|
* @param destination Destination name
|
|
64
64
|
* @param forceRefresh Force token refresh
|
|
65
65
|
*/
|
|
66
|
-
|
|
66
|
+
getJwtToken(destination: string, forceRefresh?: boolean): Promise<string>;
|
|
67
|
+
/**
|
|
68
|
+
* Get the target service URL for a destination.
|
|
69
|
+
* Priority: config.targetUrl > service key's serviceUrl
|
|
70
|
+
*/
|
|
71
|
+
getTargetUrl(destination: string): Promise<string>;
|
|
67
72
|
/**
|
|
68
73
|
* Helper function to extract string value from header (handles arrays)
|
|
69
74
|
*/
|
|
@@ -74,7 +79,7 @@ export declare class BtpProxy {
|
|
|
74
79
|
* Process flow:
|
|
75
80
|
*
|
|
76
81
|
* 1. BTP Authentication (XSUAA):
|
|
77
|
-
* 1.1 If x-
|
|
82
|
+
* 1.1 If x-sap-destination header exists:
|
|
78
83
|
* - Check map for broker with key = destination, get or create, save to map
|
|
79
84
|
* - Get token from xsuaa broker
|
|
80
85
|
* - Add/replace Authorization: Bearer <token> header
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"btpProxy.d.ts","sourceRoot":"","sources":["../../src/proxy/btpProxy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAgB,MAAM,2BAA2B,CAAC;AAYrE,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGhE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AA4CnE;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAU3C;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAGD,MAAM,MAAM,YAAY,GAAG,mBAAmB,CAAC;AAE/C,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,OAAO,CAAC;KAChB,CAAC;CACH;AAED;;GAEG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,oBAAoB,CAAa;IACzC,OAAO,CAAC,cAAc,CAAsC;IAC5D,OAAO,CAAC,UAAU,CACN;IACZ,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAClD,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAU;gBAEZ,oBAAoB,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC;IAqF3E;;;OAGG;IACU,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB3D;;;;OAIG;YACW,wBAAwB;IAqFtC;;OAEG;YACW,uBAAuB;IAyFrC;;;;OAIG;
|
|
1
|
+
{"version":3,"file":"btpProxy.d.ts","sourceRoot":"","sources":["../../src/proxy/btpProxy.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAgB,MAAM,2BAA2B,CAAC;AAYrE,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGhE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AA4CnE;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAU3C;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAGD,MAAM,MAAM,YAAY,GAAG,mBAAmB,CAAC;AAE/C,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,OAAO,CAAC;KAChB,CAAC;CACH;AAED;;GAEG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,oBAAoB,CAAa;IACzC,OAAO,CAAC,cAAc,CAAsC;IAC5D,OAAO,CAAC,UAAU,CACN;IACZ,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAClD,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAU;gBAEZ,oBAAoB,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC;IAqF3E;;;OAGG;IACU,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB3D;;;;OAIG;YACW,wBAAwB;IAqFtC;;OAEG;YACW,uBAAuB;IAyFrC;;;;OAIG;IACG,WAAW,CACf,WAAW,EAAE,MAAM,EACnB,YAAY,GAAE,OAAe,GAC5B,OAAO,CAAC,MAAM,CAAC;IAqHlB;;;OAGG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAexD;;OAEG;IACH,OAAO,CAAC,cAAc;IAUtB;;;;;;;;;;;;;;;;OAgBG;YACW,iBAAiB;IAmT/B;;OAEG;IACG,YAAY,CAChB,eAAe,EAAE,YAAY,EAC7B,eAAe,EAAE,eAAe,EAChC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GAC7D,OAAO,CAAC,aAAa,CAAC;IA8JzB;;OAEG;WACiB,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC;CAyB7E;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAC5B,OAAO,CAAC,QAAQ,CAAC,CAEnB"}
|
package/dist/proxy/btpProxy.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* BTP Proxy - Proxies requests to MCP servers with JWT authentication
|
|
4
4
|
*
|
|
5
|
-
* For requests with x-
|
|
5
|
+
* For requests with x-sap-destination, proxies to target MCP server
|
|
6
6
|
* with JWT token from auth-broker (XSUAA/BTP)
|
|
7
7
|
*/
|
|
8
8
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
@@ -404,6 +404,22 @@ class BtpProxy {
|
|
|
404
404
|
throw new Error(errorMessage);
|
|
405
405
|
}
|
|
406
406
|
}
|
|
407
|
+
/**
|
|
408
|
+
* Get the target service URL for a destination.
|
|
409
|
+
* Priority: config.targetUrl > service key's serviceUrl
|
|
410
|
+
*/
|
|
411
|
+
async getTargetUrl(destination) {
|
|
412
|
+
if (this.config.targetUrl) {
|
|
413
|
+
return this.config.targetUrl;
|
|
414
|
+
}
|
|
415
|
+
const broker = await this.getOrCreateBtpAuthBroker(destination);
|
|
416
|
+
const connConfig = await broker.getConnectionConfig(destination);
|
|
417
|
+
if (connConfig?.serviceUrl) {
|
|
418
|
+
return connConfig.serviceUrl;
|
|
419
|
+
}
|
|
420
|
+
throw new Error(`No target URL found for destination "${destination}". ` +
|
|
421
|
+
`Set targetUrl in config or ensure service key contains abap.url.`);
|
|
422
|
+
}
|
|
407
423
|
/**
|
|
408
424
|
* Helper function to extract string value from header (handles arrays)
|
|
409
425
|
*/
|
|
@@ -421,7 +437,7 @@ class BtpProxy {
|
|
|
421
437
|
* Process flow:
|
|
422
438
|
*
|
|
423
439
|
* 1. BTP Authentication (XSUAA):
|
|
424
|
-
* 1.1 If x-
|
|
440
|
+
* 1.1 If x-sap-destination header exists:
|
|
425
441
|
* - Check map for broker with key = destination, get or create, save to map
|
|
426
442
|
* - Get token from xsuaa broker
|
|
427
443
|
* - Add/replace Authorization: Bearer <token> header
|
|
@@ -448,21 +464,21 @@ class BtpProxy {
|
|
|
448
464
|
// ============================================
|
|
449
465
|
// BTP Authentication (XSUAA)
|
|
450
466
|
// ============================================
|
|
451
|
-
const btpDestinationHeader = this.getHeaderValue(originalHeaders[interfaces_1.
|
|
467
|
+
const btpDestinationHeader = this.getHeaderValue(originalHeaders[interfaces_1.HEADER_SAP_DESTINATION]);
|
|
452
468
|
const btpDestinationFromParam = routingDecision.btpDestination && !btpDestinationHeader
|
|
453
469
|
? routingDecision.btpDestination
|
|
454
470
|
: undefined;
|
|
455
471
|
let btpDestination;
|
|
456
472
|
if (btpDestinationHeader) {
|
|
457
473
|
btpDestination = btpDestinationHeader;
|
|
458
|
-
logger_js_1.logger?.debug('Using x-
|
|
474
|
+
logger_js_1.logger?.debug('Using x-sap-destination from header', {
|
|
459
475
|
type: 'BTP_DESTINATION_FROM_HEADER',
|
|
460
476
|
destination: btpDestination,
|
|
461
477
|
});
|
|
462
478
|
}
|
|
463
479
|
else if (btpDestinationFromParam) {
|
|
464
480
|
btpDestination = btpDestinationFromParam;
|
|
465
|
-
logger_js_1.logger?.debug('Using x-
|
|
481
|
+
logger_js_1.logger?.debug('Using x-sap-destination from parameter', {
|
|
466
482
|
type: 'BTP_DESTINATION_FROM_PARAM',
|
|
467
483
|
destination: btpDestination,
|
|
468
484
|
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as http from 'node:http';
|
|
2
|
+
/**
|
|
3
|
+
* Forward an HTTP request to a target URL with JWT injection.
|
|
4
|
+
* Streams both request and response using pipe().
|
|
5
|
+
*/
|
|
6
|
+
export declare function forwardRequest(clientReq: http.IncomingMessage, clientRes: http.ServerResponse, targetBaseUrl: string, jwtToken: string): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=reverseProxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reverseProxy.d.ts","sourceRoot":"","sources":["../../src/proxy/reverseProxy.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAoBlC;;;GAGG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,IAAI,CAAC,eAAe,EAC/B,SAAS,EAAE,IAAI,CAAC,cAAc,EAC9B,aAAa,EAAE,MAAM,EACrB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CA+Ef"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.forwardRequest = forwardRequest;
|
|
37
|
+
// src/proxy/reverseProxy.ts
|
|
38
|
+
const http = __importStar(require("node:http"));
|
|
39
|
+
const https = __importStar(require("node:https"));
|
|
40
|
+
const node_url_1 = require("node:url");
|
|
41
|
+
const logger_js_1 = require("../lib/logger.js");
|
|
42
|
+
/**
|
|
43
|
+
* Hop-by-hop headers that should not be forwarded
|
|
44
|
+
*/
|
|
45
|
+
const HOP_BY_HOP_HEADERS = new Set([
|
|
46
|
+
'connection',
|
|
47
|
+
'keep-alive',
|
|
48
|
+
'proxy-authenticate',
|
|
49
|
+
'proxy-authorization',
|
|
50
|
+
'te',
|
|
51
|
+
'trailers',
|
|
52
|
+
'transfer-encoding',
|
|
53
|
+
'upgrade',
|
|
54
|
+
'host',
|
|
55
|
+
]);
|
|
56
|
+
/**
|
|
57
|
+
* Forward an HTTP request to a target URL with JWT injection.
|
|
58
|
+
* Streams both request and response using pipe().
|
|
59
|
+
*/
|
|
60
|
+
async function forwardRequest(clientReq, clientRes, targetBaseUrl, jwtToken) {
|
|
61
|
+
const targetUrl = new node_url_1.URL(clientReq.url || '/', targetBaseUrl);
|
|
62
|
+
// Build forwarded headers (skip hop-by-hop and replace auth)
|
|
63
|
+
const forwardedHeaders = {};
|
|
64
|
+
for (const [key, value] of Object.entries(clientReq.headers)) {
|
|
65
|
+
if (HOP_BY_HOP_HEADERS.has(key.toLowerCase()))
|
|
66
|
+
continue;
|
|
67
|
+
if (key.toLowerCase() === 'authorization')
|
|
68
|
+
continue;
|
|
69
|
+
if (value !== undefined) {
|
|
70
|
+
forwardedHeaders[key] = value;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// Inject JWT
|
|
74
|
+
if (jwtToken) {
|
|
75
|
+
forwardedHeaders.authorization = `Bearer ${jwtToken}`;
|
|
76
|
+
}
|
|
77
|
+
// Set correct host for target
|
|
78
|
+
forwardedHeaders.host = targetUrl.host;
|
|
79
|
+
const isHttps = targetUrl.protocol === 'https:';
|
|
80
|
+
const transport = isHttps ? https : http;
|
|
81
|
+
const options = {
|
|
82
|
+
hostname: targetUrl.hostname,
|
|
83
|
+
port: targetUrl.port || (isHttps ? 443 : 80),
|
|
84
|
+
path: targetUrl.pathname + targetUrl.search,
|
|
85
|
+
method: clientReq.method || 'GET',
|
|
86
|
+
headers: forwardedHeaders,
|
|
87
|
+
};
|
|
88
|
+
logger_js_1.logger?.info('Forwarding request', {
|
|
89
|
+
type: 'REVERSE_PROXY_FORWARD',
|
|
90
|
+
method: options.method,
|
|
91
|
+
target: targetUrl.toString(),
|
|
92
|
+
});
|
|
93
|
+
return new Promise((resolve) => {
|
|
94
|
+
const proxyReq = transport.request(options, (proxyRes) => {
|
|
95
|
+
// Forward status code
|
|
96
|
+
const statusCode = proxyRes.statusCode || 502;
|
|
97
|
+
// Forward response headers (skip hop-by-hop)
|
|
98
|
+
const responseHeaders = {};
|
|
99
|
+
for (const [key, value] of Object.entries(proxyRes.headers)) {
|
|
100
|
+
if (HOP_BY_HOP_HEADERS.has(key.toLowerCase()))
|
|
101
|
+
continue;
|
|
102
|
+
if (value !== undefined) {
|
|
103
|
+
responseHeaders[key] = value;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
logger_js_1.logger?.info('Backend responded', {
|
|
107
|
+
type: 'REVERSE_PROXY_RESPONSE',
|
|
108
|
+
statusCode,
|
|
109
|
+
contentType: proxyRes.headers['content-type'],
|
|
110
|
+
});
|
|
111
|
+
clientRes.writeHead(statusCode, responseHeaders);
|
|
112
|
+
proxyRes.pipe(clientRes);
|
|
113
|
+
proxyRes.on('end', resolve);
|
|
114
|
+
});
|
|
115
|
+
proxyReq.on('error', (err) => {
|
|
116
|
+
logger_js_1.logger?.error('Reverse proxy connection error', {
|
|
117
|
+
type: 'REVERSE_PROXY_ERROR',
|
|
118
|
+
error: err.message,
|
|
119
|
+
target: targetUrl.toString(),
|
|
120
|
+
});
|
|
121
|
+
if (!clientRes.headersSent) {
|
|
122
|
+
clientRes.writeHead(502, { 'Content-Type': 'application/json' });
|
|
123
|
+
clientRes.end(JSON.stringify({ error: `Proxy error: ${err.message}` }));
|
|
124
|
+
}
|
|
125
|
+
resolve();
|
|
126
|
+
});
|
|
127
|
+
// Pipe client request body to backend
|
|
128
|
+
clientReq.pipe(proxyReq);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
@@ -18,17 +18,17 @@ export interface RoutingDecision {
|
|
|
18
18
|
* Analyze headers and extract routing information
|
|
19
19
|
*
|
|
20
20
|
* Proxy validates only one header for authentication:
|
|
21
|
-
* - x-
|
|
21
|
+
* - x-sap-destination (or --btp): destination for BTP Cloud authorization token (Authorization: Bearer) and MCP server URL
|
|
22
22
|
*
|
|
23
23
|
|
|
24
24
|
*
|
|
25
25
|
* Command-line overrides (take precedence over headers):
|
|
26
|
-
* - --btp=<destination>: overrides x-
|
|
26
|
+
* - --btp=<destination>: overrides x-sap-destination header
|
|
27
27
|
*
|
|
28
28
|
* Other headers are passed directly to MCP server without validation.
|
|
29
29
|
*
|
|
30
30
|
* MPC server URL is obtained from:
|
|
31
|
-
* - service key for x-
|
|
31
|
+
* - service key for x-sap-destination (via auth-broker)
|
|
32
32
|
*
|
|
33
33
|
*
|
|
34
34
|
* Note: Proxy does NOT use .env files for connection configuration. Only destinations via auth-broker (service key files) are used.
|
|
@@ -19,17 +19,17 @@ var RoutingStrategy;
|
|
|
19
19
|
* Analyze headers and extract routing information
|
|
20
20
|
*
|
|
21
21
|
* Proxy validates only one header for authentication:
|
|
22
|
-
* - x-
|
|
22
|
+
* - x-sap-destination (or --btp): destination for BTP Cloud authorization token (Authorization: Bearer) and MCP server URL
|
|
23
23
|
*
|
|
24
24
|
|
|
25
25
|
*
|
|
26
26
|
* Command-line overrides (take precedence over headers):
|
|
27
|
-
* - --btp=<destination>: overrides x-
|
|
27
|
+
* - --btp=<destination>: overrides x-sap-destination header
|
|
28
28
|
*
|
|
29
29
|
* Other headers are passed directly to MCP server without validation.
|
|
30
30
|
*
|
|
31
31
|
* MPC server URL is obtained from:
|
|
32
|
-
* - service key for x-
|
|
32
|
+
* - service key for x-sap-destination (via auth-broker)
|
|
33
33
|
*
|
|
34
34
|
*
|
|
35
35
|
* Note: Proxy does NOT use .env files for connection configuration. Only destinations via auth-broker (service key files) are used.
|
|
@@ -48,9 +48,9 @@ function analyzeHeaders(headers, configOverrides) {
|
|
|
48
48
|
}
|
|
49
49
|
return typeof headerValue === 'string' ? headerValue.trim() : undefined;
|
|
50
50
|
};
|
|
51
|
-
// Extract authorization destination for BTP Cloud (x-
|
|
51
|
+
// Extract authorization destination for BTP Cloud (x-sap-destination)
|
|
52
52
|
// Command-line parameter --btp takes precedence over header
|
|
53
|
-
const btpDestinationHeader = getHeaderValue(interfaces_1.
|
|
53
|
+
const btpDestinationHeader = getHeaderValue(interfaces_1.HEADER_SAP_DESTINATION);
|
|
54
54
|
const extractedBtpDestination = configOverrides?.btpDestination
|
|
55
55
|
? configOverrides.btpDestination
|
|
56
56
|
: btpDestinationHeader;
|
|
@@ -72,10 +72,10 @@ function analyzeHeaders(headers, configOverrides) {
|
|
|
72
72
|
if (!extractedBtpDestination) {
|
|
73
73
|
return {
|
|
74
74
|
strategy: RoutingStrategy.UNKNOWN,
|
|
75
|
-
reason: 'No BTP destination provided (missing x-
|
|
75
|
+
reason: 'No BTP destination provided (missing x-sap-destination or --btp)',
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
|
-
// If x-
|
|
78
|
+
// If x-sap-destination is present, we can proxy with BTP authentication (URL will be obtained from service key)
|
|
79
79
|
// If x-mcp-url is provided, we can use it directly (for local testing)
|
|
80
80
|
logger_js_1.logger?.debug('Routing decision: PROXY', {
|
|
81
81
|
btpDestination: extractedBtpDestination,
|
|
@@ -18,6 +18,8 @@ export interface InterceptedRequest {
|
|
|
18
18
|
export declare function interceptRequest(req: IncomingMessage, body?: unknown, configOverrides?: {
|
|
19
19
|
btpDestination?: string;
|
|
20
20
|
targetUrl?: string;
|
|
21
|
+
}, options?: {
|
|
22
|
+
skipHeaderValidation?: boolean;
|
|
21
23
|
}): InterceptedRequest;
|
|
22
24
|
/**
|
|
23
25
|
* Sanitize headers for logging (remove sensitive data)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requestInterceptor.d.ts","sourceRoot":"","sources":["../../src/router/requestInterceptor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAajD,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3E,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,eAAe,EAAE,eAAe,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,eAAe,EACpB,IAAI,CAAC,EAAE,OAAO,EACd,eAAe,CAAC,EAAE;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GACA,kBAAkB,
|
|
1
|
+
{"version":3,"file":"requestInterceptor.d.ts","sourceRoot":"","sources":["../../src/router/requestInterceptor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAajD,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE3E,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;IACvD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,eAAe,EAAE,eAAe,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,eAAe,EACpB,IAAI,CAAC,EAAE,OAAO,EACd,eAAe,CAAC,EAAE;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,EACD,OAAO,CAAC,EAAE;IACR,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC,GACA,kBAAkB,CAuDpB;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,GACrD,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAmBxB"}
|