@alfe.ai/gateway 0.9.10 → 0.9.11
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/dist/health.js +301 -43
- package/package.json +2 -2
package/dist/health.js
CHANGED
|
@@ -312,7 +312,7 @@ var AlfeApiClient = class {
|
|
|
312
312
|
* would never reach the network — the `getToken: () => null` path would
|
|
313
313
|
* synthesize a 401 and fire onAuthFailure, breaking the entire flow.
|
|
314
314
|
*/
|
|
315
|
-
async
|
|
315
|
+
async _fetchResponse(path, options, skipAuth = false) {
|
|
316
316
|
try {
|
|
317
317
|
const url = `${this.apiBaseUrl}${path}`;
|
|
318
318
|
const headers = new Headers(options?.headers);
|
|
@@ -348,14 +348,14 @@ var AlfeApiClient = class {
|
|
|
348
348
|
}
|
|
349
349
|
};
|
|
350
350
|
}
|
|
351
|
-
const text = res.status === 204 ? "" : await res.text();
|
|
352
|
-
let body;
|
|
353
|
-
if (text) try {
|
|
354
|
-
body = JSON.parse(text);
|
|
355
|
-
} catch {
|
|
356
|
-
body = text;
|
|
357
|
-
}
|
|
358
351
|
if (!res.ok) {
|
|
352
|
+
const text = res.status === 204 ? "" : await res.text();
|
|
353
|
+
let body;
|
|
354
|
+
if (text) try {
|
|
355
|
+
body = JSON.parse(text);
|
|
356
|
+
} catch {
|
|
357
|
+
body = text;
|
|
358
|
+
}
|
|
359
359
|
const errBody = body;
|
|
360
360
|
return {
|
|
361
361
|
ok: false,
|
|
@@ -368,8 +368,7 @@ var AlfeApiClient = class {
|
|
|
368
368
|
}
|
|
369
369
|
return {
|
|
370
370
|
ok: true,
|
|
371
|
-
res
|
|
372
|
-
body
|
|
371
|
+
res
|
|
373
372
|
};
|
|
374
373
|
} catch (err) {
|
|
375
374
|
return {
|
|
@@ -381,6 +380,22 @@ var AlfeApiClient = class {
|
|
|
381
380
|
};
|
|
382
381
|
}
|
|
383
382
|
}
|
|
383
|
+
async _fetch(path, options, skipAuth = false) {
|
|
384
|
+
const response = await this._fetchResponse(path, options, skipAuth);
|
|
385
|
+
if (!response.ok) return response;
|
|
386
|
+
const text = response.res.status === 204 ? "" : await response.res.text();
|
|
387
|
+
let body;
|
|
388
|
+
if (text) try {
|
|
389
|
+
body = JSON.parse(text);
|
|
390
|
+
} catch {
|
|
391
|
+
body = text;
|
|
392
|
+
}
|
|
393
|
+
return {
|
|
394
|
+
ok: true,
|
|
395
|
+
res: response.res,
|
|
396
|
+
body
|
|
397
|
+
};
|
|
398
|
+
}
|
|
384
399
|
/**
|
|
385
400
|
* Make an authenticated request to an Alfe API endpoint.
|
|
386
401
|
* Unwraps the @auriclabs/api-core `{ data, timestamp, requestId }` envelope.
|
|
@@ -427,6 +442,30 @@ var AlfeApiClient = class {
|
|
|
427
442
|
data: result.body
|
|
428
443
|
};
|
|
429
444
|
}
|
|
445
|
+
/**
|
|
446
|
+
* Make an authenticated request without attempting text/JSON decoding.
|
|
447
|
+
* Use for downloads such as a Teams app ZIP where UTF-8 conversion would
|
|
448
|
+
* corrupt the payload.
|
|
449
|
+
*/
|
|
450
|
+
async binaryRequest(path, options) {
|
|
451
|
+
const result = await this._fetchResponse(path, options);
|
|
452
|
+
if (!result.ok) return result.result;
|
|
453
|
+
try {
|
|
454
|
+
return {
|
|
455
|
+
ok: true,
|
|
456
|
+
data: {
|
|
457
|
+
body: await result.res.arrayBuffer(),
|
|
458
|
+
contentType: result.res.headers.get("Content-Type") ?? void 0,
|
|
459
|
+
contentDisposition: result.res.headers.get("Content-Disposition") ?? void 0
|
|
460
|
+
}
|
|
461
|
+
};
|
|
462
|
+
} catch (err) {
|
|
463
|
+
return {
|
|
464
|
+
ok: false,
|
|
465
|
+
error: err instanceof Error ? err.message : "Failed to read binary response"
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
}
|
|
430
469
|
getApiBaseUrl() {
|
|
431
470
|
return this.apiBaseUrl;
|
|
432
471
|
}
|
|
@@ -4227,6 +4266,176 @@ object({
|
|
|
4227
4266
|
ttsModel: _enum(TTS_MODELS).optional(),
|
|
4228
4267
|
enabled: boolean().optional()
|
|
4229
4268
|
});
|
|
4269
|
+
//#endregion
|
|
4270
|
+
//#region ../../packages-internal/types/dist/access.js
|
|
4271
|
+
/**
|
|
4272
|
+
* Runtime catalog of declared permission subjects + allowed actions.
|
|
4273
|
+
*
|
|
4274
|
+
* Mirrors the compile-time `PermissionDefinitions` augmentation in
|
|
4275
|
+
* `@alfe/api-core/auriclabs-roles.ts`. Kept here so browser code
|
|
4276
|
+
* (dashboard) can consume it without pulling in server-only deps
|
|
4277
|
+
* (`@middy/core`, `aws-lambda`, etc.).
|
|
4278
|
+
*/
|
|
4279
|
+
const PERMISSION_CATALOG = {
|
|
4280
|
+
all: ["manage"],
|
|
4281
|
+
user: [
|
|
4282
|
+
"create",
|
|
4283
|
+
"read",
|
|
4284
|
+
"update",
|
|
4285
|
+
"delete",
|
|
4286
|
+
"manage"
|
|
4287
|
+
],
|
|
4288
|
+
agent: [
|
|
4289
|
+
"create",
|
|
4290
|
+
"read",
|
|
4291
|
+
"update",
|
|
4292
|
+
"delete",
|
|
4293
|
+
"exec",
|
|
4294
|
+
"chat",
|
|
4295
|
+
"manage"
|
|
4296
|
+
],
|
|
4297
|
+
chat: [
|
|
4298
|
+
"read",
|
|
4299
|
+
"write",
|
|
4300
|
+
"upload",
|
|
4301
|
+
"manage"
|
|
4302
|
+
],
|
|
4303
|
+
sync: [
|
|
4304
|
+
"read",
|
|
4305
|
+
"write",
|
|
4306
|
+
"manage"
|
|
4307
|
+
],
|
|
4308
|
+
integration: [
|
|
4309
|
+
"create",
|
|
4310
|
+
"read",
|
|
4311
|
+
"update",
|
|
4312
|
+
"delete",
|
|
4313
|
+
"manage"
|
|
4314
|
+
],
|
|
4315
|
+
gateway: ["connect", "manage"],
|
|
4316
|
+
voice: ["read", "manage"],
|
|
4317
|
+
identity: ["read", "manage"],
|
|
4318
|
+
token: [
|
|
4319
|
+
"create",
|
|
4320
|
+
"read",
|
|
4321
|
+
"update",
|
|
4322
|
+
"delete",
|
|
4323
|
+
"manage"
|
|
4324
|
+
],
|
|
4325
|
+
billing: ["read", "manage"],
|
|
4326
|
+
template: [
|
|
4327
|
+
"create",
|
|
4328
|
+
"read",
|
|
4329
|
+
"update",
|
|
4330
|
+
"delete",
|
|
4331
|
+
"manage"
|
|
4332
|
+
],
|
|
4333
|
+
team: [
|
|
4334
|
+
"create",
|
|
4335
|
+
"read",
|
|
4336
|
+
"update",
|
|
4337
|
+
"delete",
|
|
4338
|
+
"manage"
|
|
4339
|
+
],
|
|
4340
|
+
project: [
|
|
4341
|
+
"create",
|
|
4342
|
+
"read",
|
|
4343
|
+
"update",
|
|
4344
|
+
"delete",
|
|
4345
|
+
"manage"
|
|
4346
|
+
],
|
|
4347
|
+
org_file: ["read", "write"],
|
|
4348
|
+
org_knowledge: ["read", "write"],
|
|
4349
|
+
model_policy: ["read", "manage"],
|
|
4350
|
+
secret: [
|
|
4351
|
+
"create",
|
|
4352
|
+
"read",
|
|
4353
|
+
"update",
|
|
4354
|
+
"delete",
|
|
4355
|
+
"manage"
|
|
4356
|
+
],
|
|
4357
|
+
database: [
|
|
4358
|
+
"read",
|
|
4359
|
+
"write",
|
|
4360
|
+
"manage"
|
|
4361
|
+
],
|
|
4362
|
+
role_management: ["read", "manage"],
|
|
4363
|
+
org: ["read", "manage"],
|
|
4364
|
+
connection: [
|
|
4365
|
+
"create",
|
|
4366
|
+
"read",
|
|
4367
|
+
"update",
|
|
4368
|
+
"delete",
|
|
4369
|
+
"manage"
|
|
4370
|
+
],
|
|
4371
|
+
remote: ["control", "terminal"],
|
|
4372
|
+
subscription: ["read", "manage"],
|
|
4373
|
+
referral: ["manage"],
|
|
4374
|
+
promo_code: ["manage"],
|
|
4375
|
+
pricing: ["manage"],
|
|
4376
|
+
access_gate: ["manage"],
|
|
4377
|
+
dlq: ["read", "manage"],
|
|
4378
|
+
support: ["read"],
|
|
4379
|
+
discounts: ["manage"],
|
|
4380
|
+
stats: ["read"],
|
|
4381
|
+
mobile: ["read", "manage"],
|
|
4382
|
+
impersonation: ["manage"]
|
|
4383
|
+
};
|
|
4384
|
+
/**
|
|
4385
|
+
* Subjects a tenant may grant via a custom role.
|
|
4386
|
+
*
|
|
4387
|
+
* Excludes `all` (platform-admin escape hatch) and every platform-only
|
|
4388
|
+
* permission subject listed after it in the catalog.
|
|
4389
|
+
*/
|
|
4390
|
+
const TENANT_ALLOWED_SUBJECTS = [
|
|
4391
|
+
"agent",
|
|
4392
|
+
"chat",
|
|
4393
|
+
"sync",
|
|
4394
|
+
"integration",
|
|
4395
|
+
"secret",
|
|
4396
|
+
"database",
|
|
4397
|
+
"template",
|
|
4398
|
+
"org_file",
|
|
4399
|
+
"org_knowledge",
|
|
4400
|
+
"team",
|
|
4401
|
+
"project",
|
|
4402
|
+
"model_policy",
|
|
4403
|
+
"role_management",
|
|
4404
|
+
"billing",
|
|
4405
|
+
"identity",
|
|
4406
|
+
"token",
|
|
4407
|
+
"user",
|
|
4408
|
+
"gateway",
|
|
4409
|
+
"voice",
|
|
4410
|
+
"org",
|
|
4411
|
+
"connection",
|
|
4412
|
+
"remote",
|
|
4413
|
+
"subscription"
|
|
4414
|
+
];
|
|
4415
|
+
/**
|
|
4416
|
+
* Subjects a PLATFORM ADMIN may grant via a custom **admin** role (authored at
|
|
4417
|
+
* the flat `admin:` scope, stored under the `"system"` tenant). Two groups:
|
|
4418
|
+
*
|
|
4419
|
+
* 1. Platform-only subjects — every catalog subject that is NOT in
|
|
4420
|
+
* `TENANT_ALLOWED_SUBJECTS` (and never `all`). Derived from
|
|
4421
|
+
* `PERMISSION_CATALOG` so a newly-declared admin-only subject becomes
|
|
4422
|
+
* grantable in custom admin roles automatically.
|
|
4423
|
+
* 2. Dual-surface subjects an admin also curates platform-wide: `user`
|
|
4424
|
+
* (platform user management), `role_management` (admin role authoring),
|
|
4425
|
+
* and `subscription` (reviewing every tenant's plan/startup application).
|
|
4426
|
+
*
|
|
4427
|
+
* `all` is deliberately excluded — it is reserved for the built-in
|
|
4428
|
+
* `sys:admin:admin` super-admin role and must never be grantable through a
|
|
4429
|
+
* custom admin role. The complement of `TENANT_ALLOWED_SUBJECTS` keeps the
|
|
4430
|
+
* tenant vocabulary and the admin vocabulary from drifting into each other.
|
|
4431
|
+
*/
|
|
4432
|
+
const ADMIN_DUAL_SURFACE_SUBJECTS = [
|
|
4433
|
+
"user",
|
|
4434
|
+
"role_management",
|
|
4435
|
+
"subscription"
|
|
4436
|
+
];
|
|
4437
|
+
const TENANT_ALLOWED_SUBJECT_LOOKUP = new Set(TENANT_ALLOWED_SUBJECTS);
|
|
4438
|
+
[...Object.keys(PERMISSION_CATALOG).filter((subject) => subject !== "all" && !TENANT_ALLOWED_SUBJECT_LOOKUP.has(subject)), ...ADMIN_DUAL_SURFACE_SUBJECTS];
|
|
4230
4439
|
enumValues({
|
|
4231
4440
|
Org: "org",
|
|
4232
4441
|
Team: "team",
|
|
@@ -4592,7 +4801,7 @@ var AuthService = class {
|
|
|
4592
4801
|
}
|
|
4593
4802
|
prefix = "/auth";
|
|
4594
4803
|
validate(token) {
|
|
4595
|
-
return this.client.
|
|
4804
|
+
return this.client.publicRequest(`${this.prefix}/validate`, {
|
|
4596
4805
|
method: "POST",
|
|
4597
4806
|
body: JSON.stringify({ token })
|
|
4598
4807
|
});
|
|
@@ -4967,6 +5176,12 @@ var IntegrationsService = class {
|
|
|
4967
5176
|
listSlackChannels(agentId) {
|
|
4968
5177
|
return this.client.request(`/slack/agents/${encodeURIComponent(agentId)}/channels`);
|
|
4969
5178
|
}
|
|
5179
|
+
createSlackApp(agentId) {
|
|
5180
|
+
return this.client.request("/slack/apps/create", {
|
|
5181
|
+
method: "POST",
|
|
5182
|
+
body: JSON.stringify({ agentId })
|
|
5183
|
+
});
|
|
5184
|
+
}
|
|
4970
5185
|
sendSlackMessage(agentId, channel, text) {
|
|
4971
5186
|
return this.client.request(`/slack/agents/${encodeURIComponent(agentId)}/send`, {
|
|
4972
5187
|
method: "POST",
|
|
@@ -6416,25 +6631,44 @@ var ConfigReconciler = class {
|
|
|
6416
6631
|
status: "applied"
|
|
6417
6632
|
};
|
|
6418
6633
|
const failures = [];
|
|
6634
|
+
const inconclusiveKeys = [];
|
|
6419
6635
|
for (const [key, want] of entries) try {
|
|
6420
6636
|
if (getConfigRaw) {
|
|
6421
|
-
|
|
6637
|
+
let current;
|
|
6638
|
+
try {
|
|
6639
|
+
current = await getConfigRaw(key);
|
|
6640
|
+
} catch (err) {
|
|
6641
|
+
log$4.warn({
|
|
6642
|
+
key,
|
|
6643
|
+
err: err instanceof Error ? err.message : String(err)
|
|
6644
|
+
}, "Config diff read failed — attempting the write");
|
|
6645
|
+
}
|
|
6646
|
+
if (current === want) {
|
|
6422
6647
|
log$4.debug({ key }, "Config already at desired value — no-op");
|
|
6423
6648
|
continue;
|
|
6424
6649
|
}
|
|
6425
6650
|
}
|
|
6426
6651
|
await setConfigRaw(key, want);
|
|
6427
6652
|
if (getConfigRaw) {
|
|
6428
|
-
|
|
6653
|
+
const outcome = await this.verify(getConfigRaw, key, want);
|
|
6654
|
+
if (outcome === "mismatched") failures.push(`${key}: verify failed (read-back did not match)`);
|
|
6655
|
+
else if (outcome === "inconclusive") inconclusiveKeys.push(key);
|
|
6429
6656
|
}
|
|
6430
6657
|
} catch (err) {
|
|
6431
6658
|
const msg = err instanceof Error ? err.message : String(err);
|
|
6432
|
-
if (getConfigRaw
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
|
|
6436
|
-
|
|
6437
|
-
|
|
6659
|
+
if (getConfigRaw) {
|
|
6660
|
+
const outcome = await this.verify(getConfigRaw, key, want);
|
|
6661
|
+
if (outcome === "matched") {
|
|
6662
|
+
log$4.warn({
|
|
6663
|
+
key,
|
|
6664
|
+
err: msg
|
|
6665
|
+
}, "config set errored but value landed — treating as applied");
|
|
6666
|
+
continue;
|
|
6667
|
+
}
|
|
6668
|
+
if (outcome === "inconclusive") {
|
|
6669
|
+
inconclusiveKeys.push(key);
|
|
6670
|
+
continue;
|
|
6671
|
+
}
|
|
6438
6672
|
}
|
|
6439
6673
|
failures.push(`${key}: ${msg}`);
|
|
6440
6674
|
}
|
|
@@ -6451,6 +6685,13 @@ var ConfigReconciler = class {
|
|
|
6451
6685
|
reason
|
|
6452
6686
|
};
|
|
6453
6687
|
}
|
|
6688
|
+
if (inconclusiveKeys.length > 0) {
|
|
6689
|
+
log$4.warn({
|
|
6690
|
+
version: desired.version,
|
|
6691
|
+
keys: inconclusiveKeys
|
|
6692
|
+
}, "Config reconcile verification was inconclusive — leaving version pending");
|
|
6693
|
+
return null;
|
|
6694
|
+
}
|
|
6454
6695
|
log$4.info({
|
|
6455
6696
|
version: desired.version,
|
|
6456
6697
|
keys: entries.length
|
|
@@ -6461,11 +6702,21 @@ var ConfigReconciler = class {
|
|
|
6461
6702
|
};
|
|
6462
6703
|
}
|
|
6463
6704
|
async verify(getConfigRaw, key, want) {
|
|
6705
|
+
let observedValue = false;
|
|
6464
6706
|
for (let attempt = 0; attempt <= this.verifyRetries; attempt++) {
|
|
6465
|
-
|
|
6707
|
+
try {
|
|
6708
|
+
const current = await getConfigRaw(key);
|
|
6709
|
+
if (current === want) return "matched";
|
|
6710
|
+
if (current !== void 0) observedValue = true;
|
|
6711
|
+
} catch (err) {
|
|
6712
|
+
log$4.debug({
|
|
6713
|
+
key,
|
|
6714
|
+
err: err instanceof Error ? err.message : String(err)
|
|
6715
|
+
}, "Config verify read failed");
|
|
6716
|
+
}
|
|
6466
6717
|
if (attempt < this.verifyRetries && this.verifyRetryDelayMs > 0) await delay(this.verifyRetryDelayMs * 2 ** attempt);
|
|
6467
6718
|
}
|
|
6468
|
-
return
|
|
6719
|
+
return observedValue ? "mismatched" : "inconclusive";
|
|
6469
6720
|
}
|
|
6470
6721
|
};
|
|
6471
6722
|
//#endregion
|
|
@@ -7735,7 +7986,7 @@ function warnFailedMcpServers(bundler, log, reason) {
|
|
|
7735
7986
|
* List every server entry in the alfe bundler store. Lets agents inspect
|
|
7736
7987
|
* what they've already registered before adding a new one.
|
|
7737
7988
|
*/
|
|
7738
|
-
function handleMcpListServers(manager) {
|
|
7989
|
+
function handleMcpListServers(manager, liveStatusAvailable = manager?.serverStatuses !== void 0) {
|
|
7739
7990
|
if (!manager) return {
|
|
7740
7991
|
ok: false,
|
|
7741
7992
|
error: {
|
|
@@ -7743,21 +7994,24 @@ function handleMcpListServers(manager) {
|
|
|
7743
7994
|
message: "MCP manager not initialized"
|
|
7744
7995
|
}
|
|
7745
7996
|
};
|
|
7746
|
-
const statuses = manager.serverStatuses ? manager.serverStatuses() : [];
|
|
7997
|
+
const statuses = liveStatusAvailable && manager.serverStatuses ? manager.serverStatuses() : [];
|
|
7747
7998
|
const byName = new Map(statuses.map((s) => [s.name, s]));
|
|
7748
7999
|
return {
|
|
7749
8000
|
ok: true,
|
|
7750
|
-
payload: { servers: manager.listServers().map(({ id, entry }) =>
|
|
7751
|
-
id
|
|
7752
|
-
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7760
|
-
|
|
8001
|
+
payload: { servers: manager.listServers().map(({ id, entry }) => {
|
|
8002
|
+
const status = byName.get(id);
|
|
8003
|
+
return {
|
|
8004
|
+
id,
|
|
8005
|
+
entry: toPublicServerEntry(entry),
|
|
8006
|
+
fingerprint: serverLaunchFingerprint(entry),
|
|
8007
|
+
...liveStatusAvailable ? { status: status ?? {
|
|
8008
|
+
name: id,
|
|
8009
|
+
connected: false,
|
|
8010
|
+
toolCount: 0,
|
|
8011
|
+
consecutiveFailures: 0
|
|
8012
|
+
} } : {}
|
|
8013
|
+
};
|
|
8014
|
+
}) }
|
|
7761
8015
|
};
|
|
7762
8016
|
}
|
|
7763
8017
|
function toPublicServerEntry(entry) {
|
|
@@ -7786,10 +8040,12 @@ const MCP_ADD_WARM_TIMEOUT_MS = 12e3;
|
|
|
7786
8040
|
* server actually works. Owned as `'manual'` so the agent can later remove it
|
|
7787
8041
|
* without an expectedOwner conflict — matches what `alfe mcp add` does from the
|
|
7788
8042
|
* CLI. Registration is durable regardless of the probe outcome: a probe
|
|
7789
|
-
* failure
|
|
7790
|
-
*
|
|
8043
|
+
* failure still returns `ok`; the store watcher / runtime picks the entry up.
|
|
8044
|
+
* A runtime that mirrors the store but owns its MCP children (Hermes and
|
|
8045
|
+
* Claude Code) has no daemon-side status authority, so it omits connected/tool
|
|
8046
|
+
* fields instead of presenting unknown as a definite disconnection.
|
|
7791
8047
|
*/
|
|
7792
|
-
async function handleMcpAddServer(params, manager) {
|
|
8048
|
+
async function handleMcpAddServer(params, manager, liveStatusAvailable = manager?.warmServer !== void 0) {
|
|
7793
8049
|
if (!manager) return {
|
|
7794
8050
|
ok: false,
|
|
7795
8051
|
error: {
|
|
@@ -7833,7 +8089,7 @@ async function handleMcpAddServer(params, manager) {
|
|
|
7833
8089
|
};
|
|
7834
8090
|
}
|
|
7835
8091
|
let status = null;
|
|
7836
|
-
if (manager.warmServer) try {
|
|
8092
|
+
if (liveStatusAvailable && manager.warmServer) try {
|
|
7837
8093
|
status = await manager.warmServer(p.id, MCP_ADD_WARM_TIMEOUT_MS);
|
|
7838
8094
|
} catch (err) {
|
|
7839
8095
|
logger$1.warn({
|
|
@@ -7845,9 +8101,11 @@ async function handleMcpAddServer(params, manager) {
|
|
|
7845
8101
|
ok: true,
|
|
7846
8102
|
payload: {
|
|
7847
8103
|
id: p.id,
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
8104
|
+
...status ? {
|
|
8105
|
+
connected: status.connected,
|
|
8106
|
+
toolCount: status.toolCount,
|
|
8107
|
+
...status.lastError !== void 0 ? { error: status.lastError } : {}
|
|
8108
|
+
} : {}
|
|
7851
8109
|
}
|
|
7852
8110
|
};
|
|
7853
8111
|
}
|
|
@@ -25076,8 +25334,8 @@ function handlePluginRequest(method, params, pluginId) {
|
|
|
25076
25334
|
case "integration.report": return Promise.resolve(handleIntegrationReport(params, pluginId));
|
|
25077
25335
|
case "mcp.list_tools": return Promise.resolve(handleMcpListTools(mcpBundler));
|
|
25078
25336
|
case "mcp.call_tool": return handleMcpCallTool(mcpBundler, params);
|
|
25079
|
-
case "mcp.list_servers": return Promise.resolve(handleMcpListServers(mcpManagerRef));
|
|
25080
|
-
case "mcp.add_server": return handleMcpAddServer(params, mcpManagerRef);
|
|
25337
|
+
case "mcp.list_servers": return Promise.resolve(handleMcpListServers(mcpManagerRef, mcpBundler !== null));
|
|
25338
|
+
case "mcp.add_server": return handleMcpAddServer(params, mcpManagerRef, mcpBundler !== null);
|
|
25081
25339
|
case "mcp.remove_server": return handleMcpRemoveServer(params, mcpManagerRef);
|
|
25082
25340
|
default: return Promise.resolve({
|
|
25083
25341
|
ok: false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfe.ai/gateway",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.11",
|
|
4
4
|
"description": "Alfe local gateway daemon — persistent control plane for agent integrations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"pino-roll": "^1.2.0",
|
|
24
24
|
"smol-toml": ">=1.6.1",
|
|
25
25
|
"ws": "^8.18.0",
|
|
26
|
-
"@alfe.ai/agent-api-client": "^0.16.
|
|
26
|
+
"@alfe.ai/agent-api-client": "^0.16.1",
|
|
27
27
|
"@alfe.ai/ai-proxy-local": "^0.0.16",
|
|
28
28
|
"@alfe.ai/config": "^0.4.1",
|
|
29
29
|
"@alfe.ai/integration-manifest": "^0.3.6",
|