@hubex/mcp 0.6.20260910 → 0.8.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/CONNECTING.md +2 -0
- package/dist/auth.js +26 -3
- package/dist/generated/manifest.js +3643 -0
- package/dist/http.js +21 -5
- package/dist/token-prompt.js +3 -1
- package/dist/tools/types.js +1 -0
- package/package.json +1 -1
package/CONNECTING.md
CHANGED
|
@@ -92,6 +92,8 @@ npm run build
|
|
|
92
92
|
> покажут поле ввода; остальным нужно вызвать инструмент `hubex_set_token` и
|
|
93
93
|
> передать токен в него. По токену запрашивается refresh, дальше сессия
|
|
94
94
|
> продлевается сама; после перезапуска сервера токен спрашивается заново.
|
|
95
|
+
> Если HubEx отверг токен (ошибка 401), следующий запрос получит новый — по
|
|
96
|
+
> refresh, а если не выйдет, сервер снова попросит токен.
|
|
95
97
|
|
|
96
98
|
> Сервисный токен выпускается один раз администратором:
|
|
97
99
|
> `POST /fsm/AUTHZ/ServiceTokens` с Bearer и полномочием `ServiceTokenAdd`, тело — массив id
|
package/dist/auth.js
CHANGED
|
@@ -51,6 +51,11 @@ class RefreshingAuth {
|
|
|
51
51
|
prompter;
|
|
52
52
|
accessToken;
|
|
53
53
|
accessExp; // seconds since epoch
|
|
54
|
+
/**
|
|
55
|
+
* Set by `invalidate`. The rejected token is kept rather than dropped: `renew`
|
|
56
|
+
* still has to send it as `accessJwt` to preserve the token lifetime.
|
|
57
|
+
*/
|
|
58
|
+
accessRejected = false;
|
|
54
59
|
refreshToken;
|
|
55
60
|
refreshExp; // seconds since epoch
|
|
56
61
|
tenantId;
|
|
@@ -74,8 +79,12 @@ class RefreshingAuth {
|
|
|
74
79
|
this.absorb({ access_token: trimmed });
|
|
75
80
|
await this.acquireRefreshToken();
|
|
76
81
|
}
|
|
82
|
+
invalidate(token) {
|
|
83
|
+
if (token === this.accessToken)
|
|
84
|
+
this.accessRejected = true;
|
|
85
|
+
}
|
|
77
86
|
async getAccessToken() {
|
|
78
|
-
if (this.accessToken && !isExpired(this.accessExp)) {
|
|
87
|
+
if (this.accessToken && !this.accessRejected && !isExpired(this.accessExp)) {
|
|
79
88
|
return this.accessToken;
|
|
80
89
|
}
|
|
81
90
|
// De-duplicate concurrent acquisitions.
|
|
@@ -175,7 +184,12 @@ class RefreshingAuth {
|
|
|
175
184
|
}
|
|
176
185
|
/**
|
|
177
186
|
* A service-token login never carries a refresh token, so ask for one.
|
|
178
|
-
* Best-effort:
|
|
187
|
+
* Best-effort for "service"/"login": credentials were already proven by the
|
|
188
|
+
* preceding login call, so a failure here just means retrying at expiry.
|
|
189
|
+
* Fatal for "token": the user-typed token is otherwise never round-tripped
|
|
190
|
+
* against the server, so this request is the only thing that can catch a
|
|
191
|
+
* token issued for the wrong environment (dev/stg/prod) — swallowing it
|
|
192
|
+
* would report success on a token that doesn't actually work.
|
|
179
193
|
*/
|
|
180
194
|
async acquireRefreshToken() {
|
|
181
195
|
try {
|
|
@@ -186,6 +200,8 @@ class RefreshingAuth {
|
|
|
186
200
|
this.absorb(result);
|
|
187
201
|
}
|
|
188
202
|
catch (err) {
|
|
203
|
+
if (this.config.authMode === "token")
|
|
204
|
+
throw err;
|
|
189
205
|
console.error("[hubex-mcp] could not obtain a refresh token; will re-authenticate on expiry: " +
|
|
190
206
|
`${err.message}`);
|
|
191
207
|
}
|
|
@@ -201,7 +217,13 @@ class RefreshingAuth {
|
|
|
201
217
|
const res = await fetch(url, init);
|
|
202
218
|
if (!res.ok) {
|
|
203
219
|
const body = await res.text().catch(() => "");
|
|
204
|
-
|
|
220
|
+
let message = `${init.method ?? "GET"} ${url} failed (HTTP ${res.status}): ${body.slice(0, 500)}`;
|
|
221
|
+
if (res.status === 401 || res.status === 403) {
|
|
222
|
+
message +=
|
|
223
|
+
` Сейчас выбрано окружение HUBEX_ENV=${this.config.env}. Если токен получен в другом ` +
|
|
224
|
+
`окружении (dev/stg/prod), авторизация не пройдёт — проверь, что токен именно из ${this.config.env}.`;
|
|
225
|
+
}
|
|
226
|
+
throw new Error(message);
|
|
205
227
|
}
|
|
206
228
|
return (await res.json());
|
|
207
229
|
}
|
|
@@ -209,6 +231,7 @@ class RefreshingAuth {
|
|
|
209
231
|
absorb(result) {
|
|
210
232
|
if (result.access_token) {
|
|
211
233
|
this.accessToken = result.access_token;
|
|
234
|
+
this.accessRejected = false;
|
|
212
235
|
const claims = decodeJwt(result.access_token);
|
|
213
236
|
this.accessExp = claims?.exp;
|
|
214
237
|
if (!this.tenantId)
|