@mcp-abap-adt/proxy 2.0.0 → 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 +181 -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 +65 -616
- 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,187 @@ 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
|
+
|
|
10
191
|
## [2.0.0] - 2026-08-01
|
|
11
192
|
|
|
12
193
|
### Breaking Changes
|