@hubex/mcp 0.7.0 → 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 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.
@@ -222,6 +231,7 @@ class RefreshingAuth {
222
231
  absorb(result) {
223
232
  if (result.access_token) {
224
233
  this.accessToken = result.access_token;
234
+ this.accessRejected = false;
225
235
  const claims = decodeJwt(result.access_token);
226
236
  this.accessExp = claims?.exp;
227
237
  if (!this.tenantId)
package/dist/http.js CHANGED
@@ -122,6 +122,11 @@ export class HubexClient {
122
122
  exposed[name] = value;
123
123
  }
124
124
  if (!res.ok) {
125
+ // 401 — токен отвергнут (отозван, другое окружение), хотя по exp ещё жив.
126
+ // Без сброса провайдер отдавал бы его до истечения срока, и каждый запрос
127
+ // падал бы так же. Сам запрос не повторяем: POST не идемпотентен.
128
+ if (res.status === 401)
129
+ this.auth.invalidate(token);
125
130
  throw new HubexApiError(res.status, req.service, req.path, visible ?? text, this.config.env);
126
131
  }
127
132
  return { status: res.status, data: visible, headers: exposed };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubex/mcp",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "type": "module",
5
5
  "description": "MCP server for managing HubEx test data (tasks, assets, companies, users) via the HubEx REST API",
6
6
  "author": "HubEx Team",