@mcp-abap-adt/proxy 1.6.4 → 4.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 +217 -0
- package/LICENSE +669 -17
- package/README.md +79 -8
- package/bin/mcp-abap-adt-proxy-mcp.js +113 -0
- package/dist/index.d.ts +10 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +54 -97
- package/dist/lib/stores.d.ts +23 -2
- package/dist/lib/stores.d.ts.map +1 -1
- package/dist/lib/stores.js +56 -1
- package/dist/mcp/cli.d.ts +2 -0
- package/dist/mcp/cli.d.ts.map +1 -0
- package/dist/mcp/cli.js +21 -0
- package/dist/mcp/configs.d.ts +33 -0
- package/dist/mcp/configs.d.ts.map +1 -0
- package/dist/mcp/configs.js +142 -0
- package/dist/mcp/ports.d.ts +15 -0
- package/dist/mcp/ports.d.ts.map +1 -0
- package/dist/mcp/ports.js +35 -0
- package/dist/mcp/registry.d.ts +57 -0
- package/dist/mcp/registry.d.ts.map +1 -0
- package/dist/mcp/registry.js +145 -0
- package/dist/mcp/server.d.ts +34 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +79 -0
- package/dist/mcp/shutdown.d.ts +37 -0
- package/dist/mcp/shutdown.d.ts.map +1 -0
- package/dist/mcp/shutdown.js +82 -0
- package/dist/mcp/supervisor.d.ts +125 -0
- package/dist/mcp/supervisor.d.ts.map +1 -0
- package/dist/mcp/supervisor.js +330 -0
- package/dist/mcp/tools.d.ts +28 -0
- package/dist/mcp/tools.d.ts.map +1 -0
- package/dist/mcp/tools.js +152 -0
- package/dist/proxy/btpProxy.d.ts +24 -73
- package/dist/proxy/btpProxy.d.ts.map +1 -1
- package/dist/proxy/btpProxy.js +116 -631
- package/dist/proxy/credentials.d.ts +45 -0
- package/dist/proxy/credentials.d.ts.map +1 -0
- package/dist/proxy/credentials.js +41 -0
- package/dist/proxy/requestHandler.d.ts +38 -0
- package/dist/proxy/requestHandler.d.ts.map +1 -0
- package/dist/proxy/requestHandler.js +73 -0
- package/dist/proxy/reverseProxy.d.ts +11 -2
- package/dist/proxy/reverseProxy.d.ts.map +1 -1
- package/dist/proxy/reverseProxy.js +52 -9
- package/dist/router/headerAnalyzer.js +2 -2
- package/dist/router/requestInterceptor.js +9 -9
- package/docs/API.md +172 -0
- package/docs/ARCHITECTURE.md +322 -0
- package/docs/CLIENT_SETUP.md +413 -0
- package/docs/CONFIGURATION.md +258 -0
- package/docs/MIGRATION-4.0.md +125 -0
- package/docs/ROUTING_LOGIC.md +126 -0
- package/docs/TROUBLESHOOTING.md +488 -0
- package/docs/USAGE.md +422 -0
- package/docs/YAML_CONFIG.md +273 -0
- package/docs/mcp-proxy-config.example.yaml +62 -0
- package/package.json +17 -10
- package/dist/proxy/cloudLlmHubProxy.d.ts +0 -2
- package/dist/proxy/cloudLlmHubProxy.d.ts.map +0 -1
- package/dist/proxy/cloudLlmHubProxy.js +0 -3
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,223 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [4.0.0] - 2026-09-24
|
|
11
|
+
|
|
12
|
+
**The proxy stops re-implementing the broker, there is one forwarding path
|
|
13
|
+
instead of two, and a second command manages proxies for a client that cannot
|
|
14
|
+
start them itself.** No existing configuration key changes meaning and no flag is
|
|
15
|
+
added to `mcp-abap-adt-proxy`; what changes is what the proxy holds while it runs,
|
|
16
|
+
how an SSE response reaches the client, and which packages the contracts come
|
|
17
|
+
from.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- **BREAKING** — `@mcp-abap-adt/interfaces` is no longer a dependency.
|
|
22
|
+
The contracts now come from the packages they live in, and
|
|
23
|
+
`@mcp-abap-adt/connection` arrives for the credential:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
@mcp-abap-adt/interfaces ^7.0.0 → removed
|
|
27
|
+
@mcp-abap-adt/interfaces-network (new) → ^2.0.0 every HTTP header constant
|
|
28
|
+
@mcp-abap-adt/interfaces-auth (new) → ^1.2.0 ITokenRefresher
|
|
29
|
+
@mcp-abap-adt/interfaces-auth-sap (new) → ^1.0.0 IAuthorizationConfig
|
|
30
|
+
@mcp-abap-adt/connection (new) → ^9.2.0 TokenAuthProvider
|
|
31
|
+
@mcp-abap-adt/auth-broker ^1.0.8 → ^2.2.0 (a major)
|
|
32
|
+
@mcp-abap-adt/auth-providers ^2.0.0 → ^2.2.2
|
|
33
|
+
@mcp-abap-adt/auth-stores ^1.0.4 → ^1.2.0
|
|
34
|
+
@mcp-abap-adt/header-validator ^0.1.8 → ^0.3.0
|
|
35
|
+
@mcp-abap-adt/logger ^0.1.4 → ^0.4.0
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`interfaces-adt` was taken and then dropped: the contracts moved twice while
|
|
39
|
+
this release was being written, and after the second move nothing here imports
|
|
40
|
+
anything from it. The old umbrella name is 376 deprecated re-exports; a
|
|
41
|
+
consumer importing contract types through this package's tree now installs the
|
|
42
|
+
package it names.
|
|
43
|
+
|
|
44
|
+
**Copies of the deprecated umbrella left in the tree: 6 → 0.** The last two
|
|
45
|
+
were declared by `auth-broker` and `header-validator`; both have since moved
|
|
46
|
+
onto the split packages themselves, so taking their latest removed the final
|
|
47
|
+
two. Every contract package now resolves to exactly one copy, except
|
|
48
|
+
`interfaces-utils`, which appears six times at the same version — a consequence
|
|
49
|
+
of this repository's `install-strategy=nested`, not of version skew.
|
|
50
|
+
|
|
51
|
+
- **BREAKING** — `BtpProxy.getJwtToken()` is replaced by
|
|
52
|
+
`getAuthorizationHeader()`, which answers a complete header VALUE
|
|
53
|
+
(`Bearer <token>`) or `null` where a credential is not a header at all.
|
|
54
|
+
`proxyRequest()`, `buildProxyRequest()` and the `ProxyRequest` / `ProxyResponse`
|
|
55
|
+
types are gone with the axios path they served.
|
|
56
|
+
|
|
57
|
+
- `forwardRequest()` takes an `Authorization` header value rather than a bare
|
|
58
|
+
token, and optionally a body a caller has already read off the request.
|
|
59
|
+
- `forwardRequest()` destroys the upstream connection when the client goes away.
|
|
60
|
+
It did not, so an abandoned event stream left a live connection to the target
|
|
61
|
+
after the client socket was gone — a released port reported while a socket was
|
|
62
|
+
still held, accumulating across repeated start/stop.
|
|
63
|
+
|
|
64
|
+
### Added
|
|
65
|
+
|
|
66
|
+
- **A second command, `mcp-abap-adt-proxy-mcp`.** It speaks MCP over stdio and
|
|
67
|
+
its tools start and stop proxies: `proxy_start`, `proxy_stop`,
|
|
68
|
+
`proxy_status`. A client that wants to BE proxied still uses
|
|
69
|
+
`mcp-abap-adt-proxy`; this one is for a client that wants to MANAGE proxies,
|
|
70
|
+
and the two are kept apart so every plain proxy does not carry a management
|
|
71
|
+
surface it never uses.
|
|
72
|
+
|
|
73
|
+
**It works from the proxy configs already on disk** —
|
|
74
|
+
`~/.config/mcp-abap-adt/proxy/<name>.yaml`, the same files
|
|
75
|
+
`mcp-abap-adt-proxy --config` takes. `proxy_configs` lists them and
|
|
76
|
+
`proxy_start` takes one by name, so starting a proxy is choosing a name
|
|
77
|
+
rather than assembling settings, and credentials stay in the config behind
|
|
78
|
+
`${VAR}` interpolation instead of travelling through a tool call.
|
|
79
|
+
|
|
80
|
+
The config NAME is the unit, not the destination: several configs commonly
|
|
81
|
+
name the same `btpDestination` and differ in target URL and headers, so a
|
|
82
|
+
destination cannot identify one.
|
|
83
|
+
|
|
84
|
+
Each proxy takes a **free port**, and the port written in the config is
|
|
85
|
+
deliberately ignored — four of the configs in a real directory say 3001, so
|
|
86
|
+
honouring it is precisely the collision this mode exists to end.
|
|
87
|
+
`proxy_start` returns the URL actually bound.
|
|
88
|
+
`proxy_stop` frees the port and releases the credential; it never touches a
|
|
89
|
+
proxy another session started, which `proxy_status` shows and marks as such.
|
|
90
|
+
|
|
91
|
+
Every proxy runs inside the management process, and closing the session — or
|
|
92
|
+
`SIGINT`, or `SIGTERM` — stops all of them. A spawned child would be orphaned
|
|
93
|
+
by any signal the parent did not forward and would go on holding its HTTP and
|
|
94
|
+
OAuth callback ports, which is the same reason `bin/mcp-abap-adt-proxy.js`
|
|
95
|
+
has always loaded the server in-process.
|
|
96
|
+
|
|
97
|
+
A proxy nobody has used for 30 minutes (`idleTimeoutMs`) stops itself. It is
|
|
98
|
+
a backstop for a client that finished and forgot, not a substitute for
|
|
99
|
+
`proxy_stop` — which the tool descriptions say, and say again beside the URL.
|
|
100
|
+
The countdown runs only while nothing is in flight, so an open SSE connection
|
|
101
|
+
is never called idle however quiet it is.
|
|
102
|
+
|
|
103
|
+
Records under `runtime/` carry the machine's boot time, because a pid is
|
|
104
|
+
unique only within a boot: after a restart the same number can belong to an
|
|
105
|
+
unrelated live process, and a record would then be reported as another
|
|
106
|
+
session's proxy forever. They are written to a temporary name and renamed, so
|
|
107
|
+
a concurrent reader sees a whole record or no file, never a truncated one.
|
|
108
|
+
|
|
109
|
+
- `src/lib/stores.ts` now holds the whole path convention: four folders under
|
|
110
|
+
one relocatable base — `service-keys/`, `sessions/`, `proxy/` and the new
|
|
111
|
+
`runtime/` — through `storeBaseDir()` and `storeDir()`. `proxy/` and
|
|
112
|
+
`runtime/` had each grown a private copy of the platform logic in the module
|
|
113
|
+
that used them, which is three places for one convention to drift.
|
|
114
|
+
|
|
115
|
+
`storeDir()` deliberately has no working-directory fallback, unlike the
|
|
116
|
+
search path `getPlatformPaths()` returns: a runtime record written beside
|
|
117
|
+
wherever a client happened to be launched from is a record the next session
|
|
118
|
+
will not find.
|
|
119
|
+
|
|
120
|
+
- **The SSE transport imposes no headers of its own.** The deleted axios path set
|
|
121
|
+
`Accept: application/json, application/x-ndjson, text/event-stream` and
|
|
122
|
+
`Content-Type: application/json` on every request and forwarded none of the
|
|
123
|
+
client's. The proxy is transparent and answers for the authorization header
|
|
124
|
+
only, so the client's headers now go through as sent. A target that needs a
|
|
125
|
+
particular `Accept` gets it from that proxy's `defaultHeaders`, where it is
|
|
126
|
+
visible in the config rather than hidden in the proxy.
|
|
127
|
+
- **The upstream path is the client's path.** The old SSE path had three
|
|
128
|
+
branches: an explicit `targetUrl` meant base + the client's path; a service-key
|
|
129
|
+
URL already containing `/mcp` was used as-is with the client's path DISCARDED;
|
|
130
|
+
anything else got `/mcp/stream/http` appended. Now it is always base + the
|
|
131
|
+
client's path. Configs that set `targetUrl` — which is the documented way and
|
|
132
|
+
what every config in practice does — are unaffected; a config relying on the
|
|
133
|
+
service key's own URL should set `targetUrl` explicitly.
|
|
134
|
+
- The SSE transport forwards through the same transparent pipe as every other
|
|
135
|
+
transport. It used to rebuild the request by hand, carry it over axios, buffer
|
|
136
|
+
the answer and rewrap it as a JSON-RPC envelope — so an SSE response now
|
|
137
|
+
streams rather than arriving whole. Error envelopes still echo the JSON-RPC
|
|
138
|
+
`id`, which is why the body is still read before forwarding; the bytes handed
|
|
139
|
+
on are the ones that arrived, so `content-length` stays true.
|
|
140
|
+
|
|
141
|
+
### Removed
|
|
142
|
+
|
|
143
|
+
- **The circuit breaker.** It only ever guarded the buffered axios forward that
|
|
144
|
+
this release deletes, and the streaming path has nowhere to put one without
|
|
145
|
+
buffering the response again — which is the thing being fixed.
|
|
146
|
+
`circuitBreakerThreshold` and `circuitBreakerTimeout` are still accepted so
|
|
147
|
+
existing configs load unchanged, and are now documented as inert.
|
|
148
|
+
`MCP_PROXY_CIRCUIT_BREAKER_THRESHOLD` likewise.
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
- The token cache, its TTL, the JWT `exp` decoder, and the proactive-refresh
|
|
152
|
+
timer per destination. The broker caches and knows expiry, and
|
|
153
|
+
`authorizationHeader()` renews behind the call — the timer was a `setTimeout`
|
|
154
|
+
per destination, alive for the life of the process, topping up a cache that
|
|
155
|
+
duplicated the broker.
|
|
156
|
+
- `src/proxy/cloudLlmHubProxy.ts`, whose entire contents were `// DELETED`.
|
|
157
|
+
- `src/proxy/btpProxy.ts` goes from 1248 lines to 490.
|
|
158
|
+
|
|
159
|
+
### Documentation
|
|
160
|
+
|
|
161
|
+
- `docs/MIGRATION-4.0.md` (new): what a consumer does about each breaking change,
|
|
162
|
+
and which of them do not apply to them. Per the repository's release rule, a
|
|
163
|
+
breaking release owes one.
|
|
164
|
+
- **`docs/` now ships.** It did not, so `README.md` linked to nine pages that
|
|
165
|
+
were absent from the installed package — including the migration note this
|
|
166
|
+
release owes. The internal design document under `docs/superpowers/` is
|
|
167
|
+
deliberately still excluded.
|
|
168
|
+
|
|
169
|
+
- `docs/API.md` described `CloudLlmHubProxy.proxyRequest()` and an import path
|
|
170
|
+
for a file containing one comment. It now documents the facade and the pipe.
|
|
171
|
+
- `docs/ARCHITECTURE.md` and `CLAUDE.md` described a proxy client that caches
|
|
172
|
+
tokens for 30 minutes, and pointed at `cloudLlmHubProxy.ts` for it.
|
|
173
|
+
- `CLAUDE.md` pointed test instructions at `cloudLlmHubProxy.test.ts`, which has
|
|
174
|
+
not existed for some time.
|
|
175
|
+
|
|
176
|
+
## [3.0.0] - 2026-09-03
|
|
177
|
+
|
|
178
|
+
### Licence
|
|
179
|
+
|
|
180
|
+
- **This tool is now `GPL-3.0-only`.** It was MIT up to and including 2.0.0, and
|
|
181
|
+
those versions stay MIT — a licence change is not retroactive.
|
|
182
|
+
|
|
183
|
+
A finished tool rather than a library to build on, so it takes the full GPL
|
|
184
|
+
rather than the LGPL its own dependencies carry: running it and using it on your
|
|
185
|
+
own data carries no conditions, while distributing it — or a modified version —
|
|
186
|
+
means passing on the same freedoms, source included.
|
|
187
|
+
|
|
188
|
+
Copyright © 2025–2026 Oleksii Kyslytsia.
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
## [2.0.0] - 2026-08-01
|
|
192
|
+
|
|
193
|
+
### Breaking Changes
|
|
194
|
+
- **Pasting the authorization code into the proxy's terminal no longer works.** A headless login
|
|
195
|
+
(`--browser none`/`headless`) used to accept the code three ways; the terminal was one of them.
|
|
196
|
+
`auth-providers@2.0.0`'s callback strategy reads no stdin at all — deliberately, since under an
|
|
197
|
+
MCP stdio transport stdin carries the protocol itself, and reading from it there would corrupt
|
|
198
|
+
the stream. **If you relied on terminal paste**, switch to one of the two remaining paths: let
|
|
199
|
+
the automatic callback reach the proxy (browser on the same machine), or open
|
|
200
|
+
`http://<proxy-host>:<browser-auth-port>/` and use the paste form the callback server already
|
|
201
|
+
serves there — it covers the same "my browser is elsewhere" case without touching stdin. See
|
|
202
|
+
[Configuration Guide](./docs/CONFIGURATION.md#headless-login---browser-none).
|
|
203
|
+
- **Requires `@mcp-abap-adt/auth-providers` `^2.0.0`** (was `^1.2.0`). That release is what removes
|
|
204
|
+
the terminal-paste channel above; it also replaces the `browser`/`redirectPort` fields on
|
|
205
|
+
`AuthorizationCodeProviderConfig` with an `authorization` strategy the consumer supplies. The
|
|
206
|
+
proxy now builds one with `browserCallbackStrategy({ browser, port, timeoutMs })` at both places
|
|
207
|
+
it constructs the provider — an internal change with no configuration impact (see below).
|
|
208
|
+
|
|
209
|
+
### Fixed
|
|
210
|
+
- **The no-destination placeholder broker's callback port collided with the proxy's own.** The
|
|
211
|
+
`AuthorizationCodeProvider` built for `BtpProxy.create()`'s default broker never had its own
|
|
212
|
+
port fallback; an unset `browserAuthPort` fell through to `auth-providers@1.2.0`'s internal
|
|
213
|
+
default of `3001` — the same port the proxy's own HTTP server listens on by default. Making the
|
|
214
|
+
migration to `auth-providers@2.0.0` explicit is what surfaced it. Both call sites now share the
|
|
215
|
+
documented `3333` default. This only affects logins with no destination configured, which use
|
|
216
|
+
placeholder credentials and could never complete a real login anyway.
|
|
217
|
+
|
|
218
|
+
### Changed
|
|
219
|
+
- **`--browser-auth-port` keeps its meaning and its `3333` default.** Nothing changes for existing
|
|
220
|
+
configs or CLI invocations — the port still lands inside the strategy instead of a bare config
|
|
221
|
+
field.
|
|
222
|
+
- **The login timeout is now explicit and longer.** `browserCallbackStrategy` defaults to a
|
|
223
|
+
30-second `timeoutMs`, sized for an unattended caller; this proxy drives a browser login for a
|
|
224
|
+
person, so both call sites now pass 5 minutes instead, giving room to open a tab, sign in and
|
|
225
|
+
clear MFA before the callback server gives up.
|
|
226
|
+
|
|
10
227
|
## [1.6.4] - 2026-07-29
|
|
11
228
|
|
|
12
229
|
### Fixed
|