@mcp-abap-adt/calm-server 0.2.1 → 0.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/CHANGELOG.md +97 -0
- package/README.md +45 -0
- package/dist/server/auth/buildBroker.d.ts +22 -0
- package/dist/server/auth/buildBroker.d.ts.map +1 -0
- package/dist/server/auth/buildBroker.js +55 -0
- package/dist/server/auth/buildBroker.js.map +1 -0
- package/dist/server/auth/legacyEnvShim.d.ts +10 -0
- package/dist/server/auth/legacyEnvShim.d.ts.map +1 -0
- package/dist/server/auth/legacyEnvShim.js +23 -0
- package/dist/server/auth/legacyEnvShim.js.map +1 -0
- package/dist/server/buildClient.d.ts +17 -5
- package/dist/server/buildClient.d.ts.map +1 -1
- package/dist/server/buildClient.js +22 -64
- package/dist/server/buildClient.js.map +1 -1
- package/dist/server/config.d.ts +3 -0
- package/dist/server/config.d.ts.map +1 -1
- package/dist/server/config.js +19 -3
- package/dist/server/config.js.map +1 -1
- package/dist/server/connection/AbstractCalmConnection.d.ts +43 -0
- package/dist/server/connection/AbstractCalmConnection.d.ts.map +1 -0
- package/dist/server/connection/AbstractCalmConnection.js +155 -0
- package/dist/server/connection/AbstractCalmConnection.js.map +1 -0
- package/dist/server/connection/OAuth2CalmConnection.d.ts +13 -0
- package/dist/server/connection/OAuth2CalmConnection.d.ts.map +1 -0
- package/dist/server/connection/OAuth2CalmConnection.js +27 -0
- package/dist/server/connection/OAuth2CalmConnection.js.map +1 -0
- package/dist/server/connection/SandboxCalmConnection.d.ts +10 -0
- package/dist/server/connection/SandboxCalmConnection.d.ts.map +1 -0
- package/dist/server/connection/SandboxCalmConnection.js +16 -0
- package/dist/server/connection/SandboxCalmConnection.js.map +1 -0
- package/dist/server/connection/XsuaaRefresher.d.ts +18 -0
- package/dist/server/connection/XsuaaRefresher.d.ts.map +1 -0
- package/dist/server/connection/XsuaaRefresher.js +51 -0
- package/dist/server/connection/XsuaaRefresher.js.map +1 -0
- package/dist/server/connection/createCalmConnection.d.ts +13 -0
- package/dist/server/connection/createCalmConnection.d.ts.map +1 -0
- package/dist/server/connection/createCalmConnection.js +28 -0
- package/dist/server/connection/createCalmConnection.js.map +1 -0
- package/dist/server/connection/index.d.ts +10 -0
- package/dist/server/connection/index.d.ts.map +1 -0
- package/dist/server/connection/index.js +16 -0
- package/dist/server/connection/index.js.map +1 -0
- package/dist/server/connection/serviceRoutes.d.ts +16 -0
- package/dist/server/connection/serviceRoutes.d.ts.map +1 -0
- package/dist/server/connection/serviceRoutes.js +27 -0
- package/dist/server/connection/serviceRoutes.js.map +1 -0
- package/dist/server/runStdio.js +2 -2
- package/dist/server/runStdio.js.map +1 -1
- package/dist/tools/features/getFeatureByDisplayId.d.ts +1 -0
- package/dist/tools/features/getFeatureByDisplayId.d.ts.map +1 -1
- package/dist/tools/features/getFeatureByDisplayId.js +11 -5
- package/dist/tools/features/getFeatureByDisplayId.js.map +1 -1
- package/dist/tools/features/listFeatures.d.ts.map +1 -1
- package/dist/tools/features/listFeatures.js +5 -2
- package/dist/tools/features/listFeatures.js.map +1 -1
- package/dist/tools/tasks/listTasks.d.ts.map +1 -1
- package/dist/tools/tasks/listTasks.js +19 -15
- package/dist/tools/tasks/listTasks.js.map +1 -1
- package/package.json +13 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,102 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.4.0 — 2026-05-24
|
|
4
|
+
|
|
5
|
+
Follows `@mcp-abap-adt/calm-client@0.4.0` (connection moved out of the
|
|
6
|
+
client). Combines the auth-broker integration (M19) with a
|
|
7
|
+
server-owned connection layer.
|
|
8
|
+
|
|
9
|
+
### Changed (BREAKING)
|
|
10
|
+
|
|
11
|
+
- **The server now owns the CALM connection.** New
|
|
12
|
+
`src/server/connection/` module on native `fetch`:
|
|
13
|
+
`AbstractCalmConnection`, `SandboxCalmConnection` (api-key),
|
|
14
|
+
`OAuth2CalmConnection` (Bearer via `ITokenRefresher`, one-shot
|
|
15
|
+
refresh+retry on 401/403), and the
|
|
16
|
+
`createCalmConnection(config, overrides?)` factory. Exposed via the
|
|
17
|
+
`./connection` subpath export. `@mcp-abap-adt/calm-client` no longer
|
|
18
|
+
ships `CalmConnection` (peer bumped to `^0.4.0`).
|
|
19
|
+
- **`CALM_BASE_URL` is consumed verbatim** — service routes are appended
|
|
20
|
+
by plain concatenation; no `/api` injection. Paste `endpoints.Api`
|
|
21
|
+
from the service-key as-is (it already includes `/api`). Fixes the
|
|
22
|
+
silent double-`/api` 404 against live tenants.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- **Token acquisition via `@mcp-abap-adt/auth-broker`** (M19):
|
|
27
|
+
`buildCalmClient` is `async`, honours `CALM_AUTH_FLOW`
|
|
28
|
+
(`client_credentials` | `authorization_code`), and sources UAA creds
|
|
29
|
+
from inline `CALM_UAA_*` (legacy shim) or `./{destination}.env`
|
|
30
|
+
(produced by the `mcp-auth` CLI). The broker yields the
|
|
31
|
+
`ITokenRefresher` that is injected into `OAuth2CalmConnection` via the
|
|
32
|
+
factory's `tokenRefresher` override.
|
|
33
|
+
- **Request-lifecycle logging** in the connection via an optional
|
|
34
|
+
`ILogger` (debug on request/response/retry, warn on transport
|
|
35
|
+
failure), threaded from `runStdio` through the stderr-safe
|
|
36
|
+
`StderrLogger`.
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- `dotenv` moved from `devDependencies` to `dependencies` (imported at
|
|
41
|
+
runtime by `config.ts`).
|
|
42
|
+
|
|
43
|
+
## 0.3.0 — 2026-05-13
|
|
44
|
+
|
|
45
|
+
Follows `@mcp-abap-adt/calm-client@0.3.0` (issue / PR #3 / #4 there).
|
|
46
|
+
Closes a wider class of the same bug fixed in 0.2.1: every list
|
|
47
|
+
endpoint whose Spring controller takes `@RequestParam UUID projectId`
|
|
48
|
+
must carry `projectId` on the URL, not in OData `$filter`. After the
|
|
49
|
+
earlier deliverables/workstreams fix, two more came out the moment a
|
|
50
|
+
sandbox `projectId` became available: `listTasks` and `listFeatures`.
|
|
51
|
+
|
|
52
|
+
### Changed (BREAKING for two tool input schemas)
|
|
53
|
+
|
|
54
|
+
- **`calm_features_get_by_display_id`** — `projectId` is now
|
|
55
|
+
`required`. The `getFeatureByDisplayId` endpoint delegates through
|
|
56
|
+
`listFeatures`, which now needs project scope; and the displayId
|
|
57
|
+
itself (`6-123`) is project-scoped anyway, so this matches the
|
|
58
|
+
underlying data model.
|
|
59
|
+
|
|
60
|
+
### Fixed (internal, no schema impact)
|
|
61
|
+
|
|
62
|
+
- **`calm_tasks_list` / `calm_features_list`** — projectId is now
|
|
63
|
+
forwarded positionally to the calm-client (not stuffed into
|
|
64
|
+
`$filter`), aligning with the server's `?projectId=<uuid>` URL
|
|
65
|
+
contract.
|
|
66
|
+
- **`calm_tasks_list`** — Tasks service rejects every OData query
|
|
67
|
+
parameter (`$select`, `$top`, `$filter` all return 400 "not
|
|
68
|
+
supported yet") despite returning an OData-collection shape. The
|
|
69
|
+
tool now calls `calm.getTasks().list(projectId)` with no query and
|
|
70
|
+
performs status/assignee filtering and limit/offset pagination
|
|
71
|
+
locally. The `fields` arg is kept for API symmetry but accepted as
|
|
72
|
+
a downstream hint only — the full record comes back from the wire.
|
|
73
|
+
|
|
74
|
+
### Updated
|
|
75
|
+
|
|
76
|
+
- Peer dependency `@mcp-abap-adt/calm-client` bumped `^0.2.0` →
|
|
77
|
+
`^0.3.0`. Required by the projectId-positional signatures on
|
|
78
|
+
`list` / `getByDisplayId`.
|
|
79
|
+
|
|
80
|
+
### Discovery / debugging
|
|
81
|
+
|
|
82
|
+
- The bug was latent until a borrowed sandbox `projectId` (leaked
|
|
83
|
+
through a public `test_case.projectId`) activated the
|
|
84
|
+
`describeWithProject` integration gate. Five tests failed with the
|
|
85
|
+
same HTTP 400 root cause, plus two more Tasks-only "not supported
|
|
86
|
+
yet" 400s on `$select` / `$top`.
|
|
87
|
+
- The Tasks service's non-OData nature is now documented in the
|
|
88
|
+
source (and via this entry) — future tools targeting `/tasks/*`
|
|
89
|
+
should not assume OData semantics.
|
|
90
|
+
|
|
91
|
+
### Tests
|
|
92
|
+
|
|
93
|
+
- Updated unit tests for `listFeatures` (URL-based projectId, no
|
|
94
|
+
`$filter` for it), `listTasks` (no OData query at all, client-side
|
|
95
|
+
filter), and `getByDisplayId` (projectId+displayId positional args).
|
|
96
|
+
- Integration sandbox suite now exercises five project-scoped reads
|
|
97
|
+
end-to-end against a borrowed projectId — 230 passed / 2 skipped
|
|
98
|
+
(oauth2 only) / 1 todo.
|
|
99
|
+
|
|
3
100
|
## 0.2.1 — 2026-05-13
|
|
4
101
|
|
|
5
102
|
Same-day follow-up to 0.2.0: realigns two bonus tools with
|
package/README.md
CHANGED
|
@@ -83,6 +83,51 @@ npm run build && node dist/bin/stdio.js
|
|
|
83
83
|
The server speaks MCP over stdio. Misconfiguration is reported to
|
|
84
84
|
`stderr` with a non-zero exit code.
|
|
85
85
|
|
|
86
|
+
## Authentication setup
|
|
87
|
+
|
|
88
|
+
`calm-mcp` supports two OAuth2 flows for live tenants, selectable via
|
|
89
|
+
`CALM_AUTH_FLOW`:
|
|
90
|
+
|
|
91
|
+
| Flow | Use case | Browser? | Refresh token? |
|
|
92
|
+
|---|---|---|---|
|
|
93
|
+
| `client_credentials` (default) | technical service-binding (`sb-*` client) | no | no |
|
|
94
|
+
| `authorization_code` | end-user dev workflow, full user scope | once | yes |
|
|
95
|
+
|
|
96
|
+
### Option A — quick CC setup (technical user)
|
|
97
|
+
|
|
98
|
+
Plain `.env` with inline `CALM_UAA_URL` / `CALM_UAA_CLIENT_ID` /
|
|
99
|
+
`CALM_UAA_CLIENT_SECRET` works as before — no extra steps. The broker uses
|
|
100
|
+
an in-memory session shim for these inline creds.
|
|
101
|
+
|
|
102
|
+
### Option B — broker-backed setup (CC or AC)
|
|
103
|
+
|
|
104
|
+
Use the bundled [`mcp-auth`](https://www.npmjs.com/package/@mcp-abap-adt/auth-broker)
|
|
105
|
+
CLI to convert a BTP service key into a token-bearing `.env`:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# CC (no browser)
|
|
109
|
+
npx mcp-auth --service-key ./sk.json --output ./DEFAULT.env \
|
|
110
|
+
--type xsuaa --credential
|
|
111
|
+
|
|
112
|
+
# AC (browser pops once; refresh_token persists)
|
|
113
|
+
npx mcp-auth --service-key ./sk.json --output ./DEFAULT.env \
|
|
114
|
+
--type xsuaa --browser auto
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Then in your `.env`:
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
CALM_MODE=oauth2
|
|
121
|
+
CALM_BASE_URL=https://<tenant>.<region>.alm.cloud.sap
|
|
122
|
+
CALM_AUTH_FLOW=authorization_code # or client_credentials
|
|
123
|
+
CALM_DESTINATION=DEFAULT
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The server's runtime auth pipeline is `@mcp-abap-adt/auth-broker`.
|
|
127
|
+
|
|
128
|
+
> Note: `buildCalmClient` is async since v0.4.0 (was sync in v0.3.x). Library
|
|
129
|
+
> consumers must `await` it.
|
|
130
|
+
|
|
86
131
|
### 3. Wire into Claude Desktop
|
|
87
132
|
|
|
88
133
|
Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { AuthBroker } from '@mcp-abap-adt/auth-broker';
|
|
2
|
+
import type { ILogger } from '@mcp-abap-adt/interfaces';
|
|
3
|
+
import type { ICalmServerConfig } from '../config';
|
|
4
|
+
/**
|
|
5
|
+
* Assemble an `AuthBroker` from server config.
|
|
6
|
+
*
|
|
7
|
+
* - Chooses `ClientCredentialsProvider` or `AuthorizationCodeProvider`
|
|
8
|
+
* based on `config.authFlow`.
|
|
9
|
+
* - Chooses session store: legacy `SafeXsuaaSessionStore` shim when the
|
|
10
|
+
* `.env` still inlines `CALM_UAA_*`, otherwise file-based
|
|
11
|
+
* `XsuaaSessionStore` rooted at cwd (loads `./{destination}.env`).
|
|
12
|
+
* - `browser: 'none'` always — the runtime server never pops a browser;
|
|
13
|
+
* interactive AC login is the job of the `mcp-auth` CLI.
|
|
14
|
+
* - `allowBrowserAuth` is flow-aware: `true` for CC (broker has a hard
|
|
15
|
+
* gate that fires when a session lacks a refresh_token, regardless of
|
|
16
|
+
* provider type — CC providers never need a browser anyway, so we let
|
|
17
|
+
* the gate pass), `false` for AC (fail fast when refresh_token is
|
|
18
|
+
* missing rather than try to launch a browser the stdio process
|
|
19
|
+
* cannot show).
|
|
20
|
+
*/
|
|
21
|
+
export declare function buildAuthBroker(config: ICalmServerConfig, logger?: ILogger): Promise<AuthBroker>;
|
|
22
|
+
//# sourceMappingURL=buildBroker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildBroker.d.ts","sourceRoot":"","sources":["../../../src/server/auth/buildBroker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAMvD,OAAO,KAAK,EACV,OAAO,EAGR,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAGnD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,iBAAiB,EACzB,MAAM,CAAC,EAAE,OAAO,GACf,OAAO,CAAC,UAAU,CAAC,CA6CrB"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildAuthBroker = buildAuthBroker;
|
|
4
|
+
const auth_broker_1 = require("@mcp-abap-adt/auth-broker");
|
|
5
|
+
const auth_providers_1 = require("@mcp-abap-adt/auth-providers");
|
|
6
|
+
const auth_stores_1 = require("@mcp-abap-adt/auth-stores");
|
|
7
|
+
const legacyEnvShim_1 = require("./legacyEnvShim");
|
|
8
|
+
/**
|
|
9
|
+
* Assemble an `AuthBroker` from server config.
|
|
10
|
+
*
|
|
11
|
+
* - Chooses `ClientCredentialsProvider` or `AuthorizationCodeProvider`
|
|
12
|
+
* based on `config.authFlow`.
|
|
13
|
+
* - Chooses session store: legacy `SafeXsuaaSessionStore` shim when the
|
|
14
|
+
* `.env` still inlines `CALM_UAA_*`, otherwise file-based
|
|
15
|
+
* `XsuaaSessionStore` rooted at cwd (loads `./{destination}.env`).
|
|
16
|
+
* - `browser: 'none'` always — the runtime server never pops a browser;
|
|
17
|
+
* interactive AC login is the job of the `mcp-auth` CLI.
|
|
18
|
+
* - `allowBrowserAuth` is flow-aware: `true` for CC (broker has a hard
|
|
19
|
+
* gate that fires when a session lacks a refresh_token, regardless of
|
|
20
|
+
* provider type — CC providers never need a browser anyway, so we let
|
|
21
|
+
* the gate pass), `false` for AC (fail fast when refresh_token is
|
|
22
|
+
* missing rather than try to launch a browser the stdio process
|
|
23
|
+
* cannot show).
|
|
24
|
+
*/
|
|
25
|
+
async function buildAuthBroker(config, logger) {
|
|
26
|
+
const shimStore = await (0, legacyEnvShim_1.buildLegacyShimStore)(config);
|
|
27
|
+
const sessionStore = shimStore ?? new auth_stores_1.XsuaaSessionStore(process.cwd(), config.baseUrl, logger);
|
|
28
|
+
// Resolve UAA credentials: inline config wins, otherwise read from
|
|
29
|
+
// session store (populated from `./{destination}.env` by `mcp-auth`).
|
|
30
|
+
const sessionAuth = await sessionStore.getAuthorizationConfig(config.destination);
|
|
31
|
+
const uaaUrl = config.uaaUrl || sessionAuth?.uaaUrl;
|
|
32
|
+
const uaaClientId = config.uaaClientId || sessionAuth?.uaaClientId;
|
|
33
|
+
const uaaClientSecret = config.uaaClientSecret || sessionAuth?.uaaClientSecret;
|
|
34
|
+
if (!uaaUrl || !uaaClientId || !uaaClientSecret) {
|
|
35
|
+
throw new Error(`[calm-mcp] UAA credentials missing for destination "${config.destination}". ` +
|
|
36
|
+
`Either inline CALM_UAA_URL/CALM_UAA_CLIENT_ID/CALM_UAA_CLIENT_SECRET in .env, ` +
|
|
37
|
+
`or run 'npx mcp-auth --service-key ./sk.json --output ./${config.destination}.env --type xsuaa' first.`);
|
|
38
|
+
}
|
|
39
|
+
const tokenProvider = config.authFlow === 'authorization_code'
|
|
40
|
+
? new auth_providers_1.AuthorizationCodeProvider({
|
|
41
|
+
uaaUrl,
|
|
42
|
+
clientId: uaaClientId,
|
|
43
|
+
clientSecret: uaaClientSecret,
|
|
44
|
+
browser: 'none',
|
|
45
|
+
logger,
|
|
46
|
+
})
|
|
47
|
+
: new auth_providers_1.ClientCredentialsProvider({
|
|
48
|
+
uaaUrl,
|
|
49
|
+
clientId: uaaClientId,
|
|
50
|
+
clientSecret: uaaClientSecret,
|
|
51
|
+
});
|
|
52
|
+
const allowBrowserAuth = config.authFlow !== 'authorization_code';
|
|
53
|
+
return new auth_broker_1.AuthBroker({ sessionStore, tokenProvider, allowBrowserAuth }, 'none', logger);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=buildBroker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildBroker.js","sourceRoot":"","sources":["../../../src/server/auth/buildBroker.ts"],"names":[],"mappings":";;AA+BA,0CAgDC;AA/ED,2DAAuD;AACvD,iEAGsC;AACtC,2DAA8D;AAO9D,mDAAuD;AAEvD;;;;;;;;;;;;;;;;GAgBG;AACI,KAAK,UAAU,eAAe,CACnC,MAAyB,EACzB,MAAgB;IAEhB,MAAM,SAAS,GAAG,MAAM,IAAA,oCAAoB,EAAC,MAAM,CAAC,CAAC;IACrD,MAAM,YAAY,GAChB,SAAS,IAAI,IAAI,+BAAiB,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAE5E,mEAAmE;IACnE,sEAAsE;IACtE,MAAM,WAAW,GAAG,MAAM,YAAY,CAAC,sBAAsB,CAC3D,MAAM,CAAC,WAAW,CACnB,CAAC;IACF,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,WAAW,EAAE,MAAM,CAAC;IACpD,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,IAAI,WAAW,EAAE,WAAW,CAAC;IACnE,MAAM,eAAe,GACnB,MAAM,CAAC,eAAe,IAAI,WAAW,EAAE,eAAe,CAAC;IAEzD,IAAI,CAAC,MAAM,IAAI,CAAC,WAAW,IAAI,CAAC,eAAe,EAAE,CAAC;QAChD,MAAM,IAAI,KAAK,CACb,uDAAuD,MAAM,CAAC,WAAW,KAAK;YAC5E,gFAAgF;YAChF,2DAA2D,MAAM,CAAC,WAAW,2BAA2B,CAC3G,CAAC;IACJ,CAAC;IAED,MAAM,aAAa,GACjB,MAAM,CAAC,QAAQ,KAAK,oBAAoB;QACtC,CAAC,CAAC,IAAI,0CAAyB,CAAC;YAC5B,MAAM;YACN,QAAQ,EAAE,WAAW;YACrB,YAAY,EAAE,eAAe;YAC7B,OAAO,EAAE,MAAM;YACf,MAAM;SACP,CAAC;QACJ,CAAC,CAAC,IAAI,0CAAyB,CAAC;YAC5B,MAAM;YACN,QAAQ,EAAE,WAAW;YACrB,YAAY,EAAE,eAAe;SAC9B,CAAC,CAAC;IAET,MAAM,gBAAgB,GAAG,MAAM,CAAC,QAAQ,KAAK,oBAAoB,CAAC;IAElE,OAAO,IAAI,wBAAU,CACnB,EAAE,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,EACjD,MAAM,EACN,MAAM,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { ISessionStore } from '@mcp-abap-adt/interfaces';
|
|
2
|
+
import type { ICalmServerConfig } from '../config';
|
|
3
|
+
/**
|
|
4
|
+
* If the user's `.env` still inlines `CALM_UAA_URL`/`CALM_UAA_CLIENT_ID`/
|
|
5
|
+
* `CALM_UAA_CLIENT_SECRET` (pre-broker convention), build an in-memory
|
|
6
|
+
* SafeXsuaaSessionStore preloaded with those creds. Returns null if any
|
|
7
|
+
* of the three are missing — caller falls back to file-based store.
|
|
8
|
+
*/
|
|
9
|
+
export declare function buildLegacyShimStore(config: ICalmServerConfig): Promise<ISessionStore | null>;
|
|
10
|
+
//# sourceMappingURL=legacyEnvShim.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacyEnvShim.d.ts","sourceRoot":"","sources":["../../../src/server/auth/legacyEnvShim.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAEnD;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAW/B"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildLegacyShimStore = buildLegacyShimStore;
|
|
4
|
+
const auth_stores_1 = require("@mcp-abap-adt/auth-stores");
|
|
5
|
+
/**
|
|
6
|
+
* If the user's `.env` still inlines `CALM_UAA_URL`/`CALM_UAA_CLIENT_ID`/
|
|
7
|
+
* `CALM_UAA_CLIENT_SECRET` (pre-broker convention), build an in-memory
|
|
8
|
+
* SafeXsuaaSessionStore preloaded with those creds. Returns null if any
|
|
9
|
+
* of the three are missing — caller falls back to file-based store.
|
|
10
|
+
*/
|
|
11
|
+
async function buildLegacyShimStore(config) {
|
|
12
|
+
const { uaaUrl, uaaClientId, uaaClientSecret, baseUrl, destination } = config;
|
|
13
|
+
if (!uaaUrl || !uaaClientId || !uaaClientSecret)
|
|
14
|
+
return null;
|
|
15
|
+
const store = new auth_stores_1.SafeXsuaaSessionStore(baseUrl);
|
|
16
|
+
await store.setAuthorizationConfig(destination, {
|
|
17
|
+
uaaUrl,
|
|
18
|
+
uaaClientId,
|
|
19
|
+
uaaClientSecret,
|
|
20
|
+
});
|
|
21
|
+
return store;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=legacyEnvShim.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacyEnvShim.js","sourceRoot":"","sources":["../../../src/server/auth/legacyEnvShim.ts"],"names":[],"mappings":";;AAUA,oDAaC;AAvBD,2DAAkE;AAIlE;;;;;GAKG;AACI,KAAK,UAAU,oBAAoB,CACxC,MAAyB;IAEzB,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,eAAe,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,CAAC;IAC9E,IAAI,CAAC,MAAM,IAAI,CAAC,WAAW,IAAI,CAAC,eAAe;QAAE,OAAO,IAAI,CAAC;IAE7D,MAAM,KAAK,GAAG,IAAI,mCAAqB,CAAC,OAAO,CAAC,CAAC;IACjD,MAAM,KAAK,CAAC,sBAAsB,CAAC,WAAW,EAAE;QAC9C,MAAM;QACN,WAAW;QACX,eAAe;KAChB,CAAC,CAAC;IACH,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
import { CalmClient } from '@mcp-abap-adt/calm-client';
|
|
2
|
+
import type { ILogger } from '@mcp-abap-adt/interfaces';
|
|
2
3
|
import type { ICalmServerConfig } from './config';
|
|
4
|
+
export interface BuildCalmClientOptions {
|
|
5
|
+
logger?: ILogger;
|
|
6
|
+
}
|
|
3
7
|
/**
|
|
4
|
-
* Build a ready-to-use `CalmClient` from a `ICalmServerConfig`.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
+
* Build a ready-to-use `CalmClient` from a `ICalmServerConfig`.
|
|
9
|
+
*
|
|
10
|
+
* Connection construction (fetch transport, verbatim base URL, request
|
|
11
|
+
* logging) lives in `./connection`. Token acquisition is delegated:
|
|
12
|
+
*
|
|
13
|
+
* - `oauth2` mode: `@mcp-abap-adt/auth-broker` produces the
|
|
14
|
+
* `ITokenRefresher` (honouring `CALM_AUTH_FLOW` + session stores);
|
|
15
|
+
* it is injected into the connection via the factory's
|
|
16
|
+
* `tokenRefresher` override. Pass `options.logger` (e.g.
|
|
17
|
+
* `StderrLogger`) in stdio mode so broker + connection logs go to
|
|
18
|
+
* stderr, never the MCP stdout frame stream.
|
|
19
|
+
* - `sandbox` mode: direct API-key auth, no broker involved.
|
|
8
20
|
*/
|
|
9
|
-
export declare function buildCalmClient(config: ICalmServerConfig): CalmClient
|
|
21
|
+
export declare function buildCalmClient(config: ICalmServerConfig, options?: BuildCalmClientOptions): Promise<CalmClient>;
|
|
10
22
|
//# sourceMappingURL=buildClient.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buildClient.d.ts","sourceRoot":"","sources":["../../src/server/buildClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"buildClient.d.ts","sourceRoot":"","sources":["../../src/server/buildClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AAExD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAGlD,MAAM,WAAW,sBAAsB;IACrC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,iBAAiB,EACzB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,UAAU,CAAC,CAcrB"}
|
|
@@ -2,73 +2,31 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.buildCalmClient = buildCalmClient;
|
|
4
4
|
const calm_client_1 = require("@mcp-abap-adt/calm-client");
|
|
5
|
+
const buildBroker_1 = require("./auth/buildBroker");
|
|
6
|
+
const createCalmConnection_1 = require("./connection/createCalmConnection");
|
|
5
7
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* Build a ready-to-use `CalmClient` from a `ICalmServerConfig`.
|
|
9
|
+
*
|
|
10
|
+
* Connection construction (fetch transport, verbatim base URL, request
|
|
11
|
+
* logging) lives in `./connection`. Token acquisition is delegated:
|
|
12
|
+
*
|
|
13
|
+
* - `oauth2` mode: `@mcp-abap-adt/auth-broker` produces the
|
|
14
|
+
* `ITokenRefresher` (honouring `CALM_AUTH_FLOW` + session stores);
|
|
15
|
+
* it is injected into the connection via the factory's
|
|
16
|
+
* `tokenRefresher` override. Pass `options.logger` (e.g.
|
|
17
|
+
* `StderrLogger`) in stdio mode so broker + connection logs go to
|
|
18
|
+
* stderr, never the MCP stdout frame stream.
|
|
19
|
+
* - `sandbox` mode: direct API-key auth, no broker involved.
|
|
11
20
|
*/
|
|
12
|
-
|
|
13
|
-
uaaUrl;
|
|
14
|
-
clientId;
|
|
15
|
-
clientSecret;
|
|
16
|
-
cached;
|
|
17
|
-
constructor(uaaUrl, clientId, clientSecret) {
|
|
18
|
-
this.uaaUrl = uaaUrl;
|
|
19
|
-
this.clientId = clientId;
|
|
20
|
-
this.clientSecret = clientSecret;
|
|
21
|
-
}
|
|
22
|
-
async getToken() {
|
|
23
|
-
if (!this.cached)
|
|
24
|
-
return this.refreshToken();
|
|
25
|
-
return this.cached;
|
|
26
|
-
}
|
|
27
|
-
async refreshToken() {
|
|
28
|
-
const url = `${this.uaaUrl.replace(/\/$/, '')}/oauth/token`;
|
|
29
|
-
const basic = Buffer.from(`${this.clientId}:${this.clientSecret}`).toString('base64');
|
|
30
|
-
const response = await fetch(url, {
|
|
31
|
-
method: 'POST',
|
|
32
|
-
headers: {
|
|
33
|
-
Authorization: `Basic ${basic}`,
|
|
34
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
35
|
-
Accept: 'application/json',
|
|
36
|
-
},
|
|
37
|
-
body: 'grant_type=client_credentials',
|
|
38
|
-
});
|
|
39
|
-
if (!response.ok) {
|
|
40
|
-
const body = await response.text().catch(() => '');
|
|
41
|
-
throw new Error(`XSUAA token request failed: ${response.status} ${response.statusText} — ${body.slice(0, 200)}`);
|
|
42
|
-
}
|
|
43
|
-
const json = (await response.json());
|
|
44
|
-
if (!json.access_token) {
|
|
45
|
-
throw new Error('XSUAA token response missing access_token');
|
|
46
|
-
}
|
|
47
|
-
this.cached = json.access_token;
|
|
48
|
-
return this.cached;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Build a ready-to-use `CalmClient` from a `ICalmServerConfig`. Picks
|
|
53
|
-
* OAuth2 or sandbox mode based on config.mode. The returned connection
|
|
54
|
-
* is stateless from the server's perspective — constructing a fresh
|
|
55
|
-
* CalmClient per process is cheap.
|
|
56
|
-
*/
|
|
57
|
-
function buildCalmClient(config) {
|
|
21
|
+
async function buildCalmClient(config, options = {}) {
|
|
58
22
|
if (config.mode === 'oauth2') {
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
tokenRefresher
|
|
63
|
-
|
|
64
|
-
});
|
|
65
|
-
return new calm_client_1.CalmClient(connection);
|
|
23
|
+
const broker = await (0, buildBroker_1.buildAuthBroker)(config, options.logger);
|
|
24
|
+
const tokenRefresher = broker.createTokenRefresher(config.destination);
|
|
25
|
+
return new calm_client_1.CalmClient((0, createCalmConnection_1.createCalmConnection)(config, {
|
|
26
|
+
tokenRefresher,
|
|
27
|
+
logger: options.logger,
|
|
28
|
+
}));
|
|
66
29
|
}
|
|
67
|
-
|
|
68
|
-
baseUrl: config.baseUrl,
|
|
69
|
-
apiKey: config.apiKey,
|
|
70
|
-
defaultTimeout: config.timeoutMs,
|
|
71
|
-
});
|
|
72
|
-
return new calm_client_1.CalmClient(connection);
|
|
30
|
+
return new calm_client_1.CalmClient((0, createCalmConnection_1.createCalmConnection)(config, { logger: options.logger }));
|
|
73
31
|
}
|
|
74
32
|
//# sourceMappingURL=buildClient.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buildClient.js","sourceRoot":"","sources":["../../src/server/buildClient.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"buildClient.js","sourceRoot":"","sources":["../../src/server/buildClient.ts"],"names":[],"mappings":";;AAwBA,0CAiBC;AAzCD,2DAAuD;AAEvD,oDAAqD;AAErD,4EAAyE;AAMzE;;;;;;;;;;;;;GAaG;AACI,KAAK,UAAU,eAAe,CACnC,MAAyB,EACzB,UAAkC,EAAE;IAEpC,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,MAAM,IAAA,6BAAe,EAAC,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAC7D,MAAM,cAAc,GAAG,MAAM,CAAC,oBAAoB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACvE,OAAO,IAAI,wBAAU,CACnB,IAAA,2CAAoB,EAAC,MAAM,EAAE;YAC3B,cAAc;YACd,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CACH,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,wBAAU,CACnB,IAAA,2CAAoB,EAAC,MAAM,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CACzD,CAAC;AACJ,CAAC"}
|
package/dist/server/config.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
export declare function loadEnv(): void;
|
|
7
7
|
export type CalmServerMode = 'oauth2' | 'sandbox';
|
|
8
|
+
export type CalmAuthFlow = 'client_credentials' | 'authorization_code';
|
|
8
9
|
export interface ICalmServerConfig {
|
|
9
10
|
mode: CalmServerMode;
|
|
10
11
|
baseUrl: string;
|
|
@@ -13,6 +14,8 @@ export interface ICalmServerConfig {
|
|
|
13
14
|
uaaClientSecret?: string;
|
|
14
15
|
apiKey?: string;
|
|
15
16
|
timeoutMs: number;
|
|
17
|
+
authFlow: CalmAuthFlow;
|
|
18
|
+
destination: string;
|
|
16
19
|
}
|
|
17
20
|
export declare function readConfig(): ICalmServerConfig;
|
|
18
21
|
//# sourceMappingURL=config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/server/config.ts"],"names":[],"mappings":"AAMA;;;;GAIG;AACH,wBAAgB,OAAO,IAAI,IAAI,CAU9B;AAED,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/server/config.ts"],"names":[],"mappings":"AAMA;;;;GAIG;AACH,wBAAgB,OAAO,IAAI,IAAI,CAU9B;AAED,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,SAAS,CAAC;AAClD,MAAM,MAAM,YAAY,GAAG,oBAAoB,GAAG,oBAAoB,CAAC;AAEvE,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,YAAY,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;CACrB;AAYD,wBAAgB,UAAU,IAAI,iBAAiB,CAsD9C"}
|
package/dist/server/config.js
CHANGED
|
@@ -38,6 +38,18 @@ function readConfig() {
|
|
|
38
38
|
if (!mode) {
|
|
39
39
|
throw new Error('[calm-mcp] CALM_MODE is required (oauth2 or sandbox). See .env.example.');
|
|
40
40
|
}
|
|
41
|
+
const rawAuthFlow = process.env.CALM_AUTH_FLOW;
|
|
42
|
+
let authFlow = 'client_credentials';
|
|
43
|
+
if (rawAuthFlow) {
|
|
44
|
+
if (rawAuthFlow === 'client_credentials' ||
|
|
45
|
+
rawAuthFlow === 'authorization_code') {
|
|
46
|
+
authFlow = rawAuthFlow;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
throw new Error(`[calm-mcp] CALM_AUTH_FLOW must be 'client_credentials' or 'authorization_code', got "${rawAuthFlow}".`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const destination = process.env.CALM_DESTINATION || 'DEFAULT';
|
|
41
53
|
const timeoutMs = process.env.CALM_TIMEOUT
|
|
42
54
|
? Number(process.env.CALM_TIMEOUT)
|
|
43
55
|
: 30_000;
|
|
@@ -45,10 +57,12 @@ function readConfig() {
|
|
|
45
57
|
return {
|
|
46
58
|
mode,
|
|
47
59
|
baseUrl: required('CALM_BASE_URL'),
|
|
48
|
-
uaaUrl:
|
|
49
|
-
uaaClientId:
|
|
50
|
-
uaaClientSecret:
|
|
60
|
+
uaaUrl: process.env.CALM_UAA_URL,
|
|
61
|
+
uaaClientId: process.env.CALM_UAA_CLIENT_ID,
|
|
62
|
+
uaaClientSecret: process.env.CALM_UAA_CLIENT_SECRET,
|
|
51
63
|
timeoutMs,
|
|
64
|
+
authFlow,
|
|
65
|
+
destination,
|
|
52
66
|
};
|
|
53
67
|
}
|
|
54
68
|
if (mode === 'sandbox') {
|
|
@@ -57,6 +71,8 @@ function readConfig() {
|
|
|
57
71
|
baseUrl: process.env.CALM_BASE_URL || 'https://sandbox.api.sap.com/SAPCALM',
|
|
58
72
|
apiKey: required('CALM_API_KEY'),
|
|
59
73
|
timeoutMs,
|
|
74
|
+
authFlow,
|
|
75
|
+
destination,
|
|
60
76
|
};
|
|
61
77
|
}
|
|
62
78
|
throw new Error(`[calm-mcp] unknown CALM_MODE "${mode}"`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/server/config.ts"],"names":[],"mappings":";;AAWA,0BAUC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/server/config.ts"],"names":[],"mappings":";;AAWA,0BAUC;AA2BD,gCAsDC;AAtGD,qCAAqC;AACrC,yCAAoC;AACpC,mCAAgD;AAEhD,IAAI,MAAM,GAAG,KAAK,CAAC;AAEnB;;;;GAIG;AACH,SAAgB,OAAO;IACrB,IAAI,MAAM;QAAE,OAAO;IACnB,MAAM,GAAG,IAAI,CAAC;IACd,qEAAqE;IACrE,mEAAmE;IACnE,kEAAkE;IAClE,2EAA2E;IAC3E,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;QAAE,OAAO;IACvC,MAAM,IAAI,GAAG,IAAA,mBAAO,EAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC;IAC5C,IAAI,IAAA,oBAAU,EAAC,IAAI,CAAC;QAAE,IAAA,eAAY,EAAC,EAAE,IAAI,EAAE,CAAC,CAAC;AAC/C,CAAC;AAiBD,SAAS,QAAQ,CAAC,IAAY;IAC5B,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,IAAI,KAAK,CACb,sBAAsB,IAAI,6CAA6C,CACxE,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAgB,UAAU;IACxB,OAAO,EAAE,CAAC;IACV,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,WAAW,EAElC,CAAC;IACd,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CACb,yEAAyE,CAC1E,CAAC;IACJ,CAAC;IACD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC/C,IAAI,QAAQ,GAAiB,oBAAoB,CAAC;IAClD,IAAI,WAAW,EAAE,CAAC;QAChB,IACE,WAAW,KAAK,oBAAoB;YACpC,WAAW,KAAK,oBAAoB,EACpC,CAAC;YACD,QAAQ,GAAG,WAAW,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CACb,wFAAwF,WAAW,IAAI,CACxG,CAAC;QACJ,CAAC;IACH,CAAC;IACD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,IAAI,SAAS,CAAC;IAE9D,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY;QACxC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;QAClC,CAAC,CAAC,MAAM,CAAC;IAEX,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,OAAO;YACL,IAAI;YACJ,OAAO,EAAE,QAAQ,CAAC,eAAe,CAAC;YAClC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY;YAChC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB;YAC3C,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB;YACnD,SAAS;YACT,QAAQ;YACR,WAAW;SACZ,CAAC;IACJ,CAAC;IACD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO;YACL,IAAI;YACJ,OAAO,EACL,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,qCAAqC;YACpE,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC;YAChC,SAAS;YACT,QAAQ;YACR,WAAW;SACZ,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,iCAAiC,IAAI,GAAG,CAAC,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { CalmService, ICalmConnection, ICalmRequestOptions, ICalmResponse, ILogger } from '@mcp-abap-adt/interfaces';
|
|
2
|
+
import { type CalmServiceRouteMap } from './serviceRoutes';
|
|
3
|
+
export interface IAbstractCalmConnectionOptions {
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
defaultTimeout?: number;
|
|
6
|
+
serviceRoutes?: Partial<CalmServiceRouteMap>;
|
|
7
|
+
defaultHeaders?: Record<string, string>;
|
|
8
|
+
/**
|
|
9
|
+
* Optional logger. Request lifecycle is logged at `debug`; transport
|
|
10
|
+
* failures at `warn`. In a stdio MCP runtime this MUST be a
|
|
11
|
+
* stderr-only logger (see `StderrLogger`) — never one that writes to
|
|
12
|
+
* stdout.
|
|
13
|
+
*/
|
|
14
|
+
logger?: ILogger;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Shared fetch-based transport for Cloud ALM. Subclasses provide
|
|
18
|
+
* `attachAuth()` and may override `onAuthFailure()`. `baseUrl` is used
|
|
19
|
+
* verbatim — NO prefix injection.
|
|
20
|
+
*/
|
|
21
|
+
export declare abstract class AbstractCalmConnection implements ICalmConnection {
|
|
22
|
+
protected readonly baseUrl: string;
|
|
23
|
+
protected readonly defaultTimeout: number;
|
|
24
|
+
protected readonly defaultHeaders: Record<string, string>;
|
|
25
|
+
protected readonly serviceRoutes: CalmServiceRouteMap;
|
|
26
|
+
protected readonly logger?: ILogger;
|
|
27
|
+
constructor(options: IAbstractCalmConnectionOptions);
|
|
28
|
+
/** Subclass: return auth headers for a request. */
|
|
29
|
+
protected abstract attachAuth(): Promise<Record<string, string>>;
|
|
30
|
+
/**
|
|
31
|
+
* Subclass hook on 401/403. Return true to retry once. Default: no
|
|
32
|
+
* retry.
|
|
33
|
+
*/
|
|
34
|
+
protected onAuthFailure(_status: number): Promise<boolean>;
|
|
35
|
+
connect(): Promise<void>;
|
|
36
|
+
getBaseUrl(): Promise<string>;
|
|
37
|
+
getServiceUrl(service: CalmService): Promise<string>;
|
|
38
|
+
makeRequest<T = unknown, D = unknown>(options: ICalmRequestOptions): Promise<ICalmResponse<T, D>>;
|
|
39
|
+
private logFail;
|
|
40
|
+
private normalizeError;
|
|
41
|
+
private execute;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=AbstractCalmConnection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AbstractCalmConnection.d.ts","sourceRoot":"","sources":["../../../src/server/connection/AbstractCalmConnection.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,OAAO,EACR,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,mBAAmB,EAEzB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,8BAA8B;IAC7C,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC7C,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAuBD;;;;GAIG;AACH,8BAAsB,sBAAuB,YAAW,eAAe;IACrE,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACnC,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAC1C,SAAS,CAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1D,SAAS,CAAC,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAC;IACtD,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;gBAExB,OAAO,EAAE,8BAA8B;IAcnD,mDAAmD;IACnD,SAAS,CAAC,QAAQ,CAAC,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhE;;;OAGG;cACa,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI1D,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAExB,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAI7B,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAIpD,WAAW,CAAC,CAAC,GAAG,OAAO,EAAE,CAAC,GAAG,OAAO,EACxC,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IA+B/B,OAAO,CAAC,OAAO;IAkBf,OAAO,CAAC,cAAc;YAQR,OAAO;CA0CtB"}
|