@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.
Files changed (62) hide show
  1. package/CHANGELOG.md +181 -0
  2. package/LICENSE +669 -17
  3. package/README.md +79 -8
  4. package/bin/mcp-abap-adt-proxy-mcp.js +113 -0
  5. package/dist/index.d.ts +10 -4
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +54 -97
  8. package/dist/lib/stores.d.ts +23 -2
  9. package/dist/lib/stores.d.ts.map +1 -1
  10. package/dist/lib/stores.js +56 -1
  11. package/dist/mcp/cli.d.ts +2 -0
  12. package/dist/mcp/cli.d.ts.map +1 -0
  13. package/dist/mcp/cli.js +21 -0
  14. package/dist/mcp/configs.d.ts +33 -0
  15. package/dist/mcp/configs.d.ts.map +1 -0
  16. package/dist/mcp/configs.js +142 -0
  17. package/dist/mcp/ports.d.ts +15 -0
  18. package/dist/mcp/ports.d.ts.map +1 -0
  19. package/dist/mcp/ports.js +35 -0
  20. package/dist/mcp/registry.d.ts +57 -0
  21. package/dist/mcp/registry.d.ts.map +1 -0
  22. package/dist/mcp/registry.js +145 -0
  23. package/dist/mcp/server.d.ts +34 -0
  24. package/dist/mcp/server.d.ts.map +1 -0
  25. package/dist/mcp/server.js +79 -0
  26. package/dist/mcp/shutdown.d.ts +37 -0
  27. package/dist/mcp/shutdown.d.ts.map +1 -0
  28. package/dist/mcp/shutdown.js +82 -0
  29. package/dist/mcp/supervisor.d.ts +125 -0
  30. package/dist/mcp/supervisor.d.ts.map +1 -0
  31. package/dist/mcp/supervisor.js +330 -0
  32. package/dist/mcp/tools.d.ts +28 -0
  33. package/dist/mcp/tools.d.ts.map +1 -0
  34. package/dist/mcp/tools.js +152 -0
  35. package/dist/proxy/btpProxy.d.ts +24 -73
  36. package/dist/proxy/btpProxy.d.ts.map +1 -1
  37. package/dist/proxy/btpProxy.js +65 -616
  38. package/dist/proxy/credentials.d.ts +45 -0
  39. package/dist/proxy/credentials.d.ts.map +1 -0
  40. package/dist/proxy/credentials.js +41 -0
  41. package/dist/proxy/requestHandler.d.ts +38 -0
  42. package/dist/proxy/requestHandler.d.ts.map +1 -0
  43. package/dist/proxy/requestHandler.js +73 -0
  44. package/dist/proxy/reverseProxy.d.ts +11 -2
  45. package/dist/proxy/reverseProxy.d.ts.map +1 -1
  46. package/dist/proxy/reverseProxy.js +52 -9
  47. package/dist/router/headerAnalyzer.js +2 -2
  48. package/dist/router/requestInterceptor.js +9 -9
  49. package/docs/API.md +172 -0
  50. package/docs/ARCHITECTURE.md +322 -0
  51. package/docs/CLIENT_SETUP.md +413 -0
  52. package/docs/CONFIGURATION.md +258 -0
  53. package/docs/MIGRATION-4.0.md +125 -0
  54. package/docs/ROUTING_LOGIC.md +126 -0
  55. package/docs/TROUBLESHOOTING.md +488 -0
  56. package/docs/USAGE.md +422 -0
  57. package/docs/YAML_CONFIG.md +273 -0
  58. package/docs/mcp-proxy-config.example.yaml +62 -0
  59. package/package.json +17 -10
  60. package/dist/proxy/cloudLlmHubProxy.d.ts +0 -2
  61. package/dist/proxy/cloudLlmHubProxy.d.ts.map +0 -1
  62. 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