@mcp-abap-adt/header-validator 0.1.2 → 0.1.3
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 +31 -0
- package/dist/headerValidator.js +51 -51
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,37 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.1.3] - 2025-12-01
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **x-mcp-destination validation** – fixed issue where `x-mcp-destination` header incorrectly required `x-sap-url`:
|
|
12
|
+
- `x-mcp-destination` now works identically to `x-sap-destination` - URL is automatically derived from service key
|
|
13
|
+
- `x-sap-url` is now optional for `x-mcp-destination` (and will be ignored with a warning if provided)
|
|
14
|
+
- Fixed validation logic to check `x-mcp-destination` immediately after `x-sap-destination`, regardless of `x-sap-url` presence
|
|
15
|
+
- This fixes issues on Windows where `x-mcp-destination` was being ignored
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- **Header case handling** – improved header value extraction to check both lowercase and original case:
|
|
19
|
+
- `getHeaderValue()` now checks lowercase first (Node.js normalizes headers), then original case for compatibility
|
|
20
|
+
- Both `validateSapDestinationAuth()` and `validateMcpDestinationAuth()` check headers in both cases
|
|
21
|
+
- Better cross-platform compatibility, especially for Windows
|
|
22
|
+
|
|
23
|
+
- **Validation order** – improved validation priority logic:
|
|
24
|
+
- `x-mcp-destination` is now checked immediately after `x-sap-destination`, before checking for `x-sap-url`
|
|
25
|
+
- This ensures destination-based authentication is prioritized correctly
|
|
26
|
+
- URL validation only happens for non-destination authentication methods
|
|
27
|
+
|
|
28
|
+
- **Documentation updates** – updated architecture documentation:
|
|
29
|
+
- Updated `ARCHITECTURE.md` to reflect that `x-sap-url` is not required for `x-mcp-destination`
|
|
30
|
+
- Updated `PRIORITY_DIAGRAM.md` with correct header requirements
|
|
31
|
+
- Updated examples to show `x-mcp-destination` without `x-sap-url`
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
- **Test coverage** – added tests for new validation behavior:
|
|
35
|
+
- Test for `x-mcp-destination` without `x-sap-url` (should work)
|
|
36
|
+
- Test for warning when `x-sap-url` is provided with `x-mcp-destination`
|
|
37
|
+
- Updated existing tests to reflect new validation logic
|
|
38
|
+
|
|
8
39
|
## [0.1.2] - 2025-11-30
|
|
9
40
|
|
|
10
41
|
### Changed
|
package/dist/headerValidator.js
CHANGED
|
@@ -12,9 +12,15 @@ exports.validateAuthHeaders = validateAuthHeaders;
|
|
|
12
12
|
const types_1 = require("./types");
|
|
13
13
|
/**
|
|
14
14
|
* Extract header value (handles array values)
|
|
15
|
+
* Node.js normalizes headers to lowercase, but check both cases for safety
|
|
15
16
|
*/
|
|
16
17
|
function getHeaderValue(headers, name) {
|
|
17
|
-
|
|
18
|
+
// Try lowercase first (Node.js normalizes to lowercase)
|
|
19
|
+
let value = headers[name.toLowerCase()];
|
|
20
|
+
// If not found, try original case (for compatibility)
|
|
21
|
+
if (!value) {
|
|
22
|
+
value = headers[name];
|
|
23
|
+
}
|
|
18
24
|
if (!value) {
|
|
19
25
|
return undefined;
|
|
20
26
|
}
|
|
@@ -41,7 +47,8 @@ function isValidUrl(url) {
|
|
|
41
47
|
* URL is taken from destination (service key or .env), not from x-sap-url header
|
|
42
48
|
*/
|
|
43
49
|
function validateSapDestinationAuth(headers) {
|
|
44
|
-
|
|
50
|
+
// Check both lowercase and original case (Node.js normalizes to lowercase, but check both for safety)
|
|
51
|
+
const destinationRaw = headers['x-sap-destination'] || headers['X-SAP-Destination'];
|
|
45
52
|
if (!destinationRaw) {
|
|
46
53
|
return null;
|
|
47
54
|
}
|
|
@@ -94,10 +101,12 @@ function validateSapDestinationAuth(headers) {
|
|
|
94
101
|
/**
|
|
95
102
|
* Validate MCP destination-based authentication (medium-high priority)
|
|
96
103
|
* x-mcp-destination - uses AuthBroker, always JWT (no x-sap-auth-type needed)
|
|
97
|
-
*
|
|
104
|
+
* URL is taken from destination (service key or .env), not from x-sap-url header
|
|
105
|
+
* x-sap-url is optional - if provided, it will be ignored (warning issued)
|
|
98
106
|
*/
|
|
99
107
|
function validateMcpDestinationAuth(headers, sapUrl) {
|
|
100
|
-
|
|
108
|
+
// Check both lowercase and original case (Node.js normalizes to lowercase, but check both for safety)
|
|
109
|
+
const destinationRaw = headers['x-mcp-destination'] || headers['X-MCP-Destination'];
|
|
101
110
|
if (!destinationRaw) {
|
|
102
111
|
return null;
|
|
103
112
|
}
|
|
@@ -110,21 +119,14 @@ function validateMcpDestinationAuth(headers, sapUrl) {
|
|
|
110
119
|
return {
|
|
111
120
|
priority: types_1.AuthMethodPriority.NONE,
|
|
112
121
|
authType: 'jwt', // MCP destination always uses JWT
|
|
113
|
-
sapUrl:
|
|
122
|
+
sapUrl: '', // URL will be loaded from destination
|
|
114
123
|
errors,
|
|
115
124
|
warnings,
|
|
116
125
|
};
|
|
117
126
|
}
|
|
118
|
-
// x-sap-url is
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
return {
|
|
122
|
-
priority: types_1.AuthMethodPriority.NONE,
|
|
123
|
-
authType: 'jwt',
|
|
124
|
-
sapUrl: '',
|
|
125
|
-
errors,
|
|
126
|
-
warnings,
|
|
127
|
-
};
|
|
127
|
+
// Warning if x-sap-url is provided (URL comes from destination, not header)
|
|
128
|
+
if (sapUrl) {
|
|
129
|
+
warnings.push('x-sap-url is ignored when x-mcp-destination is present (URL is loaded from destination service key or .env file)');
|
|
128
130
|
}
|
|
129
131
|
// Warning if x-sap-auth-type is provided (not needed for x-mcp-destination)
|
|
130
132
|
const authType = getHeaderValue(headers, 'x-sap-auth-type');
|
|
@@ -141,7 +143,7 @@ function validateMcpDestinationAuth(headers, sapUrl) {
|
|
|
141
143
|
return {
|
|
142
144
|
priority: types_1.AuthMethodPriority.MCP_DESTINATION,
|
|
143
145
|
authType: 'jwt', // Always JWT for x-mcp-destination
|
|
144
|
-
sapUrl,
|
|
146
|
+
sapUrl: '', // URL will be loaded from destination (service key or .env)
|
|
145
147
|
sapClient,
|
|
146
148
|
destination,
|
|
147
149
|
errors,
|
|
@@ -267,53 +269,48 @@ function validateAuthHeaders(headers) {
|
|
|
267
269
|
};
|
|
268
270
|
}
|
|
269
271
|
}
|
|
270
|
-
//
|
|
272
|
+
// Check for MCP destination (doesn't require x-sap-url, URL comes from destination)
|
|
271
273
|
const sapUrl = getHeaderValue(headers, 'x-sap-url');
|
|
272
|
-
|
|
273
|
-
if (
|
|
274
|
-
//
|
|
275
|
-
if (
|
|
276
|
-
errors.push(`x-sap-url is not a valid URL: ${sapUrl}`);
|
|
274
|
+
const mcpDestinationConfig = validateMcpDestinationAuth(headers, sapUrl);
|
|
275
|
+
if (mcpDestinationConfig) {
|
|
276
|
+
// MCP destination found - URL comes from destination, not header
|
|
277
|
+
if (mcpDestinationConfig.errors.length === 0) {
|
|
277
278
|
return {
|
|
278
|
-
isValid:
|
|
279
|
-
|
|
280
|
-
|
|
279
|
+
isValid: true,
|
|
280
|
+
config: mcpDestinationConfig,
|
|
281
|
+
errors: [],
|
|
282
|
+
warnings: mcpDestinationConfig.warnings,
|
|
281
283
|
};
|
|
282
284
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
warnings: mcpDestinationConfig.warnings,
|
|
291
|
-
};
|
|
292
|
-
}
|
|
293
|
-
else {
|
|
294
|
-
return {
|
|
295
|
-
isValid: false,
|
|
296
|
-
errors: mcpDestinationConfig.errors,
|
|
297
|
-
warnings: mcpDestinationConfig.warnings,
|
|
298
|
-
};
|
|
299
|
-
}
|
|
285
|
+
else {
|
|
286
|
+
// Has errors, continue to check other methods or return error
|
|
287
|
+
return {
|
|
288
|
+
isValid: false,
|
|
289
|
+
errors: mcpDestinationConfig.errors,
|
|
290
|
+
warnings: mcpDestinationConfig.warnings,
|
|
291
|
+
};
|
|
300
292
|
}
|
|
301
293
|
}
|
|
302
|
-
//
|
|
294
|
+
// For other auth methods, x-sap-url is required
|
|
303
295
|
if (!sapUrl) {
|
|
296
|
+
// If no auth headers at all, return empty result (not an error - may use .env file)
|
|
304
297
|
return {
|
|
305
298
|
isValid: false,
|
|
306
299
|
errors: [],
|
|
307
300
|
warnings: [],
|
|
308
301
|
};
|
|
309
302
|
}
|
|
303
|
+
// Validate URL format
|
|
304
|
+
if (!isValidUrl(sapUrl)) {
|
|
305
|
+
errors.push(`x-sap-url is not a valid URL: ${sapUrl}`);
|
|
306
|
+
return {
|
|
307
|
+
isValid: false,
|
|
308
|
+
errors,
|
|
309
|
+
warnings,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
310
312
|
// Try to validate authentication methods in priority order
|
|
311
313
|
const configs = [];
|
|
312
|
-
// 2. MCP destination-based auth (medium-high priority) - doesn't require x-sap-auth-type
|
|
313
|
-
const mcpDestinationConfig = validateMcpDestinationAuth(headers, sapUrl);
|
|
314
|
-
if (mcpDestinationConfig) {
|
|
315
|
-
configs.push(mcpDestinationConfig);
|
|
316
|
-
}
|
|
317
314
|
// 3. Other auth methods require x-sap-auth-type
|
|
318
315
|
const sapAuthType = getHeaderValue(headers, 'x-sap-auth-type');
|
|
319
316
|
if (sapAuthType) {
|
|
@@ -357,9 +354,12 @@ function validateAuthHeaders(headers) {
|
|
|
357
354
|
errors.push('Basic authentication requires x-sap-login and x-sap-password headers');
|
|
358
355
|
}
|
|
359
356
|
}
|
|
360
|
-
else
|
|
361
|
-
// MCP destination was found but has errors
|
|
362
|
-
|
|
357
|
+
else {
|
|
358
|
+
// Check if MCP destination was found but has errors
|
|
359
|
+
const mcpConfig = validateMcpDestinationAuth(headers, sapUrl);
|
|
360
|
+
if (mcpConfig && mcpConfig.errors.length > 0) {
|
|
361
|
+
errors.push(...mcpConfig.errors);
|
|
362
|
+
}
|
|
363
363
|
}
|
|
364
364
|
return {
|
|
365
365
|
isValid: false,
|
package/package.json
CHANGED