gogcli-mcp-contacts 4.0.1 → 4.2.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/README.md +1 -1
- package/SKILL.md +1 -1
- package/dist/index.js +738 -21
- package/manifest.json +2 -2
- package/package.json +2 -2
package/README.md
CHANGED
package/SKILL.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -5,6 +5,32 @@ var __export = (target, all) => {
|
|
|
5
5
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
+
// ../../node_modules/@chrischall/mcp-utils/dist/cancel/index.js
|
|
9
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
10
|
+
var storage = new AsyncLocalStorage();
|
|
11
|
+
function withCallSignal(signal, fn) {
|
|
12
|
+
return signal ? storage.run({ signal }, fn) : fn();
|
|
13
|
+
}
|
|
14
|
+
function currentCallSignal() {
|
|
15
|
+
return storage.getStore()?.signal;
|
|
16
|
+
}
|
|
17
|
+
function killOnCancel(child, signal = "SIGTERM") {
|
|
18
|
+
const ambient = currentCallSignal();
|
|
19
|
+
if (!ambient)
|
|
20
|
+
return () => {
|
|
21
|
+
};
|
|
22
|
+
if (ambient.aborted) {
|
|
23
|
+
child.kill(signal);
|
|
24
|
+
return () => {
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const onAbort = () => {
|
|
28
|
+
child.kill(signal);
|
|
29
|
+
};
|
|
30
|
+
ambient.addEventListener("abort", onAbort, { once: true });
|
|
31
|
+
return () => ambient.removeEventListener("abort", onAbort);
|
|
32
|
+
}
|
|
33
|
+
|
|
8
34
|
// ../../node_modules/@modelcontextprotocol/server/dist/chunk-Br0eD_fh.mjs
|
|
9
35
|
var __create = Object.create;
|
|
10
36
|
var __defProp2 = Object.defineProperty;
|
|
@@ -20845,6 +20871,7 @@ function missingClientCapabilities(required2, declared) {
|
|
|
20845
20871
|
return Object.keys(missing).length > 0 ? missing : void 0;
|
|
20846
20872
|
}
|
|
20847
20873
|
var FIRST_MODERN_PROTOCOL_VERSION = "2026-07-28";
|
|
20874
|
+
var SUPPORTED_MODERN_PROTOCOL_VERSIONS = [FIRST_MODERN_PROTOCOL_VERSION];
|
|
20848
20875
|
function isModernProtocolVersion(version2) {
|
|
20849
20876
|
return version2 >= FIRST_MODERN_PROTOCOL_VERSION;
|
|
20850
20877
|
}
|
|
@@ -23403,6 +23430,25 @@ function isSpecNotificationMethod(method) {
|
|
|
23403
23430
|
return ALL_CODECS.some((codec2) => codec2.hasNotificationMethod(method));
|
|
23404
23431
|
}
|
|
23405
23432
|
var ALL_CODECS = [rev2025Codec, rev2026Codec];
|
|
23433
|
+
function isPlainObject$3(value) {
|
|
23434
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
23435
|
+
}
|
|
23436
|
+
function requestMetaOf(params) {
|
|
23437
|
+
if (!isPlainObject$3(params)) return void 0;
|
|
23438
|
+
const meta3 = params["_meta"];
|
|
23439
|
+
return isPlainObject$3(meta3) ? meta3 : void 0;
|
|
23440
|
+
}
|
|
23441
|
+
function hasEnvelopeClaim(params) {
|
|
23442
|
+
const meta3 = requestMetaOf(params);
|
|
23443
|
+
return meta3 !== void 0 && PROTOCOL_VERSION_META_KEY in meta3;
|
|
23444
|
+
}
|
|
23445
|
+
function envelopeClaimVersion(params) {
|
|
23446
|
+
const value = requestMetaOf(params)?.[PROTOCOL_VERSION_META_KEY];
|
|
23447
|
+
return typeof value === "string" ? value : void 0;
|
|
23448
|
+
}
|
|
23449
|
+
function validateEnvelopeMeta(meta3) {
|
|
23450
|
+
return codecForVersion(MODERN_WIRE_REVISION).validateEnvelopeMeta(meta3);
|
|
23451
|
+
}
|
|
23406
23452
|
var schemas_exports3 = /* @__PURE__ */ __exportAll({
|
|
23407
23453
|
AnnotationsSchema: () => AnnotationsSchema,
|
|
23408
23454
|
AudioContentSchema: () => AudioContentSchema,
|
|
@@ -23753,6 +23799,45 @@ var LADDER_ERROR_HTTP_STATUS = {
|
|
|
23753
23799
|
[ProtocolErrorCode.MissingRequiredClientCapability]: 400,
|
|
23754
23800
|
[HEADER_MISMATCH_ERROR_CODE]: 400
|
|
23755
23801
|
};
|
|
23802
|
+
function rejection(rung, cell, httpStatus, error62, settled) {
|
|
23803
|
+
return {
|
|
23804
|
+
kind: "reject",
|
|
23805
|
+
rung,
|
|
23806
|
+
cell,
|
|
23807
|
+
httpStatus,
|
|
23808
|
+
code: error62.code,
|
|
23809
|
+
message: error62.message,
|
|
23810
|
+
...error62.data !== void 0 && { data: error62.data },
|
|
23811
|
+
settled
|
|
23812
|
+
};
|
|
23813
|
+
}
|
|
23814
|
+
function carriesValidModernEnvelopeClaim(params) {
|
|
23815
|
+
if (!hasEnvelopeClaim(params)) return false;
|
|
23816
|
+
const claimedVersion = envelopeClaimVersion(params);
|
|
23817
|
+
if (claimedVersion === void 0 || !isModernProtocolVersion(claimedVersion)) return false;
|
|
23818
|
+
const meta3 = requestMetaOf(params);
|
|
23819
|
+
return meta3 !== void 0 && validateEnvelopeMeta(meta3).length === 0;
|
|
23820
|
+
}
|
|
23821
|
+
function modernOnlyStrictRejection(route, supportedVersions) {
|
|
23822
|
+
switch (route.reason) {
|
|
23823
|
+
case "http-method":
|
|
23824
|
+
return rejection("http-method", "modern-only-method-not-allowed", 405, new ProtocolError(-32e3, "Method not allowed."), true);
|
|
23825
|
+
case "batch":
|
|
23826
|
+
return rejection("jsonrpc-shape", "modern-only-batch-not-supported", 400, new ProtocolError(ProtocolErrorCode.InvalidRequest, "Bad Request: JSON-RPC batches are not supported by this endpoint"), true);
|
|
23827
|
+
case "response":
|
|
23828
|
+
return rejection("jsonrpc-shape", "modern-only-response-post", 400, new ProtocolError(ProtocolErrorCode.InvalidRequest, "Bad Request: JSON-RPC responses cannot be posted to this endpoint"), true);
|
|
23829
|
+
case "notification":
|
|
23830
|
+
return;
|
|
23831
|
+
case "initialize":
|
|
23832
|
+
case "no-claim": {
|
|
23833
|
+
const requested = route.requestedVersion;
|
|
23834
|
+
return rejection("era-classification", "modern-only-missing-envelope", 400, requested === void 0 ? new ProtocolError(ProtocolErrorCode.UnsupportedProtocolVersion, "Unsupported protocol version: the request did not name a protocol version", { supported: [...supportedVersions] }) : new UnsupportedProtocolVersionError({
|
|
23835
|
+
supported: [...supportedVersions],
|
|
23836
|
+
requested
|
|
23837
|
+
}), true);
|
|
23838
|
+
}
|
|
23839
|
+
}
|
|
23840
|
+
}
|
|
23756
23841
|
function parseSchema(schema, data) {
|
|
23757
23842
|
return safeParse2(schema, data);
|
|
23758
23843
|
}
|
|
@@ -24314,6 +24399,9 @@ function withRequestStateValue(ctx, value) {
|
|
|
24314
24399
|
};
|
|
24315
24400
|
}
|
|
24316
24401
|
var writeNegotiatedProtocolVersion;
|
|
24402
|
+
function setNegotiatedProtocolVersion(instance, version2) {
|
|
24403
|
+
writeNegotiatedProtocolVersion(instance, version2);
|
|
24404
|
+
}
|
|
24317
24405
|
var Protocol = class {
|
|
24318
24406
|
_transport;
|
|
24319
24407
|
_requestMessageId = 0;
|
|
@@ -32257,6 +32345,190 @@ function getCompleter(schema) {
|
|
|
32257
32345
|
return schema[COMPLETABLE_SYMBOL]?.complete;
|
|
32258
32346
|
}
|
|
32259
32347
|
var MAX_TIMER_DELAY_MS = 2 ** 31 - 1;
|
|
32348
|
+
function listenFilterAccepts(filter, event) {
|
|
32349
|
+
switch (event.kind) {
|
|
32350
|
+
case "tools_list_changed":
|
|
32351
|
+
return filter.toolsListChanged === true;
|
|
32352
|
+
case "prompts_list_changed":
|
|
32353
|
+
return filter.promptsListChanged === true;
|
|
32354
|
+
case "resources_list_changed":
|
|
32355
|
+
return filter.resourcesListChanged === true;
|
|
32356
|
+
case "resource_updated":
|
|
32357
|
+
return filter.resourceSubscriptions !== void 0 && filter.resourceSubscriptions.includes(event.uri);
|
|
32358
|
+
}
|
|
32359
|
+
}
|
|
32360
|
+
function honoredSubset(requested, capabilities) {
|
|
32361
|
+
const honored = {};
|
|
32362
|
+
const allow = (bit) => capabilities === void 0 || bit === true;
|
|
32363
|
+
if (requested.toolsListChanged === true && allow(capabilities?.tools?.listChanged)) honored.toolsListChanged = true;
|
|
32364
|
+
if (requested.promptsListChanged === true && allow(capabilities?.prompts?.listChanged)) honored.promptsListChanged = true;
|
|
32365
|
+
if (requested.resourcesListChanged === true && allow(capabilities?.resources?.listChanged)) honored.resourcesListChanged = true;
|
|
32366
|
+
if (requested.resourceSubscriptions !== void 0 && requested.resourceSubscriptions.length > 0 && allow(capabilities?.resources?.subscribe)) honored.resourceSubscriptions = [...requested.resourceSubscriptions];
|
|
32367
|
+
return honored;
|
|
32368
|
+
}
|
|
32369
|
+
var DEFAULT_MAX_SUBSCRIPTIONS = 1024;
|
|
32370
|
+
function stampSubscriptionId(notification, subscriptionId) {
|
|
32371
|
+
return {
|
|
32372
|
+
method: notification.method,
|
|
32373
|
+
params: {
|
|
32374
|
+
...notification.params,
|
|
32375
|
+
_meta: {
|
|
32376
|
+
...notification.params?._meta,
|
|
32377
|
+
[SUBSCRIPTION_ID_META_KEY]: subscriptionId
|
|
32378
|
+
}
|
|
32379
|
+
}
|
|
32380
|
+
};
|
|
32381
|
+
}
|
|
32382
|
+
function parseListenFilter(message) {
|
|
32383
|
+
const outcome = codecForVersion(MODERN_WIRE_REVISION).validateRequest("subscriptions/listen", message);
|
|
32384
|
+
return outcome.ok ? outcome.value.params?.notifications : void 0;
|
|
32385
|
+
}
|
|
32386
|
+
var CHANGE_NOTIFICATION_METHODS = /* @__PURE__ */ new Set([
|
|
32387
|
+
"notifications/tools/list_changed",
|
|
32388
|
+
"notifications/prompts/list_changed",
|
|
32389
|
+
"notifications/resources/list_changed",
|
|
32390
|
+
"notifications/resources/updated"
|
|
32391
|
+
]);
|
|
32392
|
+
var StdioListenRouter = class {
|
|
32393
|
+
/** Active subscriptions, keyed by the listen request's JSON-RPC id verbatim. */
|
|
32394
|
+
_subs = /* @__PURE__ */ new Map();
|
|
32395
|
+
/**
|
|
32396
|
+
* The serving instance's declared capabilities. Filled in by the entry
|
|
32397
|
+
* once the modern instance is constructed (the router is created before
|
|
32398
|
+
* the instance exists), so the acknowledged filter is narrowed against
|
|
32399
|
+
* what the server can actually deliver.
|
|
32400
|
+
*/
|
|
32401
|
+
_serverCapabilities;
|
|
32402
|
+
/**
|
|
32403
|
+
* The serving instance's identity, stamped onto the graceful-close
|
|
32404
|
+
* results' `_meta` (the spec's `SubscriptionsListenResultMeta` extends
|
|
32405
|
+
* `ResultMetaObject`). Handed over together with the capabilities.
|
|
32406
|
+
*/
|
|
32407
|
+
_serverInfo;
|
|
32408
|
+
constructor(_maxSubscriptions = DEFAULT_MAX_SUBSCRIPTIONS, serverCapabilities, serverInfo) {
|
|
32409
|
+
this._maxSubscriptions = _maxSubscriptions;
|
|
32410
|
+
this._serverCapabilities = serverCapabilities;
|
|
32411
|
+
this._serverInfo = serverInfo;
|
|
32412
|
+
}
|
|
32413
|
+
/**
|
|
32414
|
+
* Record the serving instance's declared capabilities and identity once
|
|
32415
|
+
* it has been constructed. Called by `serveStdio`'s connect path;
|
|
32416
|
+
* subsequent `serve()` calls narrow the honored filter against the
|
|
32417
|
+
* capabilities, and `teardownAll()` stamps the identity.
|
|
32418
|
+
*/
|
|
32419
|
+
setServerCapabilities(capabilities, serverInfo) {
|
|
32420
|
+
this._serverCapabilities = capabilities;
|
|
32421
|
+
if (serverInfo !== void 0) this._serverInfo = serverInfo;
|
|
32422
|
+
}
|
|
32423
|
+
/** Whether `id` is an active listen subscription on this connection. */
|
|
32424
|
+
has(id) {
|
|
32425
|
+
return this._subs.has(id);
|
|
32426
|
+
}
|
|
32427
|
+
/**
|
|
32428
|
+
* Serve one inbound `subscriptions/listen` request: registers the
|
|
32429
|
+
* subscription and returns the stamped acknowledged notification (or, on
|
|
32430
|
+
* capacity / params rejection, the in-band JSON-RPC error response).
|
|
32431
|
+
*
|
|
32432
|
+
* @throws when called before {@linkcode setServerCapabilities} (or the
|
|
32433
|
+
* constructor) has supplied the serving instance's capabilities. Honoring a
|
|
32434
|
+
* filter without knowing the server's advertised capabilities would fail
|
|
32435
|
+
* open (deliver unadvertised types); the entry guarantees capabilities are
|
|
32436
|
+
* set before any listen request is routed here.
|
|
32437
|
+
*/
|
|
32438
|
+
serve(message) {
|
|
32439
|
+
if (this._serverCapabilities === void 0) throw new Error("StdioListenRouter.serve() called before setServerCapabilities(); refusing to honor a filter without capabilities");
|
|
32440
|
+
if (this._subs.size >= this._maxSubscriptions) return {
|
|
32441
|
+
jsonrpc: "2.0",
|
|
32442
|
+
id: message.id,
|
|
32443
|
+
error: {
|
|
32444
|
+
code: -32603,
|
|
32445
|
+
message: "Subscription limit reached"
|
|
32446
|
+
}
|
|
32447
|
+
};
|
|
32448
|
+
const filter = parseListenFilter(message);
|
|
32449
|
+
if (filter === void 0) return {
|
|
32450
|
+
jsonrpc: "2.0",
|
|
32451
|
+
id: message.id,
|
|
32452
|
+
error: {
|
|
32453
|
+
code: -32602,
|
|
32454
|
+
message: "Invalid params: 'notifications' is required and must be a valid SubscriptionFilter"
|
|
32455
|
+
}
|
|
32456
|
+
};
|
|
32457
|
+
const honored = honoredSubset(filter, this._serverCapabilities);
|
|
32458
|
+
this._subs.set(message.id, honored);
|
|
32459
|
+
return stampSubscriptionId({
|
|
32460
|
+
method: "notifications/subscriptions/acknowledged",
|
|
32461
|
+
params: { notifications: honored }
|
|
32462
|
+
}, message.id);
|
|
32463
|
+
}
|
|
32464
|
+
/**
|
|
32465
|
+
* Tear down one subscription (inbound `notifications/cancelled`). Returns
|
|
32466
|
+
* `true` when a subscription was removed. After this call NOTHING further
|
|
32467
|
+
* is delivered for that subscription id (the post-cancel hardening).
|
|
32468
|
+
*/
|
|
32469
|
+
cancel(id) {
|
|
32470
|
+
return this._subs.delete(id);
|
|
32471
|
+
}
|
|
32472
|
+
/**
|
|
32473
|
+
* Route an outbound notification through the active subscriptions.
|
|
32474
|
+
*
|
|
32475
|
+
* - For a subscription-gated change notification, returns one stamped copy
|
|
32476
|
+
* per subscription that opted in to it (an empty array means it is
|
|
32477
|
+
* dropped — the modern era never delivers an un-requested change type).
|
|
32478
|
+
* - For any other outbound message, returns `'passthrough'` (the entry
|
|
32479
|
+
* forwards it as-is).
|
|
32480
|
+
*/
|
|
32481
|
+
routeOutbound(message) {
|
|
32482
|
+
if (!CHANGE_NOTIFICATION_METHODS.has(message.method)) return "passthrough";
|
|
32483
|
+
const uriParam = message.params?.["uri"];
|
|
32484
|
+
const uri = typeof uriParam === "string" ? uriParam : void 0;
|
|
32485
|
+
const event = notificationToServerEvent(message.method, uri);
|
|
32486
|
+
const out = [];
|
|
32487
|
+
for (const [subscriptionId, filter] of this._subs) if (listenFilterAccepts(filter, event)) out.push(stampSubscriptionId({
|
|
32488
|
+
method: message.method,
|
|
32489
|
+
params: message.params ?? {}
|
|
32490
|
+
}, subscriptionId));
|
|
32491
|
+
return out;
|
|
32492
|
+
}
|
|
32493
|
+
/**
|
|
32494
|
+
* Server-side graceful teardown of every active subscription: returns the
|
|
32495
|
+
* empty `subscriptions/listen` JSON-RPC result for each subscription id —
|
|
32496
|
+
* the spec's graceful-close signal, `_meta` carrying the subscription id
|
|
32497
|
+
* and the serving instance's identity — for the entry to emit before
|
|
32498
|
+
* closing the wire. Clears the set so nothing further is delivered.
|
|
32499
|
+
*/
|
|
32500
|
+
teardownAll() {
|
|
32501
|
+
const out = [];
|
|
32502
|
+
for (const id of this._subs.keys()) out.push({
|
|
32503
|
+
jsonrpc: "2.0",
|
|
32504
|
+
id,
|
|
32505
|
+
result: {
|
|
32506
|
+
resultType: "complete",
|
|
32507
|
+
_meta: {
|
|
32508
|
+
[SUBSCRIPTION_ID_META_KEY]: id,
|
|
32509
|
+
...this._serverInfo !== void 0 && { [SERVER_INFO_META_KEY]: this._serverInfo }
|
|
32510
|
+
}
|
|
32511
|
+
}
|
|
32512
|
+
});
|
|
32513
|
+
this._subs.clear();
|
|
32514
|
+
return out;
|
|
32515
|
+
}
|
|
32516
|
+
};
|
|
32517
|
+
function notificationToServerEvent(method, uri) {
|
|
32518
|
+
switch (method) {
|
|
32519
|
+
case "notifications/tools/list_changed":
|
|
32520
|
+
return { kind: "tools_list_changed" };
|
|
32521
|
+
case "notifications/prompts/list_changed":
|
|
32522
|
+
return { kind: "prompts_list_changed" };
|
|
32523
|
+
case "notifications/resources/list_changed":
|
|
32524
|
+
return { kind: "resources_list_changed" };
|
|
32525
|
+
default:
|
|
32526
|
+
return {
|
|
32527
|
+
kind: "resource_updated",
|
|
32528
|
+
uri: uri ?? ""
|
|
32529
|
+
};
|
|
32530
|
+
}
|
|
32531
|
+
}
|
|
32260
32532
|
var DEFAULT_LEGACY_SHIM_MAX_ROUNDS = 8;
|
|
32261
32533
|
var DEFAULT_LEGACY_SHIM_ROUND_TIMEOUT_MS = 6e5;
|
|
32262
32534
|
function resolveLegacyShimOptions(options) {
|
|
@@ -32394,6 +32666,12 @@ var INPUT_REQUIRED_CAPABLE_METHODS = /* @__PURE__ */ new Set([
|
|
|
32394
32666
|
var writeClientIdentity;
|
|
32395
32667
|
var installDiscoverHandler;
|
|
32396
32668
|
var readServerIdentity;
|
|
32669
|
+
function installModernOnlyHandlers(server, servedModernVersions) {
|
|
32670
|
+
installDiscoverHandler(server, servedModernVersions);
|
|
32671
|
+
}
|
|
32672
|
+
function serverIdentityOf(server) {
|
|
32673
|
+
return readServerIdentity(server);
|
|
32674
|
+
}
|
|
32397
32675
|
var Server = class extends Protocol {
|
|
32398
32676
|
_clientCapabilities;
|
|
32399
32677
|
_clientVersion;
|
|
@@ -33668,6 +33946,400 @@ var StdioServerTransport = class {
|
|
|
33668
33946
|
});
|
|
33669
33947
|
}
|
|
33670
33948
|
};
|
|
33949
|
+
var DISCARD_ANSWER_TIMEOUT_MS = 3e3;
|
|
33950
|
+
var StdioConnectionChannel = class {
|
|
33951
|
+
onclose;
|
|
33952
|
+
onerror;
|
|
33953
|
+
onmessage;
|
|
33954
|
+
_closed = false;
|
|
33955
|
+
/** Request ids the entry delivered to the instance that the instance has not yet answered. */
|
|
33956
|
+
_pendingRequests = /* @__PURE__ */ new Set();
|
|
33957
|
+
_drainWaiters = [];
|
|
33958
|
+
constructor(_wire, _onInstanceClose, _outboundIntercept) {
|
|
33959
|
+
this._wire = _wire;
|
|
33960
|
+
this._onInstanceClose = _onInstanceClose;
|
|
33961
|
+
this._outboundIntercept = _outboundIntercept;
|
|
33962
|
+
}
|
|
33963
|
+
async start() {
|
|
33964
|
+
}
|
|
33965
|
+
async send(message, options) {
|
|
33966
|
+
if (isJSONRPCResultResponse(message) || isJSONRPCErrorResponse(message)) {
|
|
33967
|
+
const { id } = message;
|
|
33968
|
+
if (id !== void 0) this._settle(id);
|
|
33969
|
+
}
|
|
33970
|
+
if (this._closed) return;
|
|
33971
|
+
if (this._outboundIntercept?.(message) === "handled") return;
|
|
33972
|
+
return this._wire.send(message, options);
|
|
33973
|
+
}
|
|
33974
|
+
setProtocolVersion = (version2) => {
|
|
33975
|
+
this._wire.setProtocolVersion?.(version2);
|
|
33976
|
+
};
|
|
33977
|
+
/** Forwards one inbound message to the connected instance. */
|
|
33978
|
+
deliver(message, extra) {
|
|
33979
|
+
if (this._closed) return;
|
|
33980
|
+
if (isJSONRPCRequest(message)) this._pendingRequests.add(message.id);
|
|
33981
|
+
else if (isJSONRPCNotification(message) && message.method === "notifications/cancelled") {
|
|
33982
|
+
const cancelledId = message.params?.requestId;
|
|
33983
|
+
if (cancelledId !== void 0) this._settle(cancelledId);
|
|
33984
|
+
}
|
|
33985
|
+
this.onmessage?.(message, extra);
|
|
33986
|
+
}
|
|
33987
|
+
/**
|
|
33988
|
+
* Resolves once every request delivered to the instance has been answered
|
|
33989
|
+
* through {@linkcode send}, settled by a delivered cancellation, or the
|
|
33990
|
+
* channel has been closed and nothing further can be answered. The wait is
|
|
33991
|
+
* bounded by `timeoutMs` as a backstop so no edge can hold the caller
|
|
33992
|
+
* indefinitely; resolves `false` only when the bound elapsed with requests
|
|
33993
|
+
* still unanswered. Used by the probe-discard path so a probe request the
|
|
33994
|
+
* entry accepted is never silently dropped.
|
|
33995
|
+
*/
|
|
33996
|
+
async whenRequestsAnswered(timeoutMs) {
|
|
33997
|
+
if (this._closed || this._pendingRequests.size === 0) return true;
|
|
33998
|
+
return await new Promise((resolve) => {
|
|
33999
|
+
const waiter = () => {
|
|
34000
|
+
clearTimeout(timer);
|
|
34001
|
+
resolve(true);
|
|
34002
|
+
};
|
|
34003
|
+
const timer = setTimeout(() => {
|
|
34004
|
+
this._drainWaiters = this._drainWaiters.filter((pending) => pending !== waiter);
|
|
34005
|
+
resolve(false);
|
|
34006
|
+
}, timeoutMs);
|
|
34007
|
+
this._drainWaiters.push(waiter);
|
|
34008
|
+
});
|
|
34009
|
+
}
|
|
34010
|
+
async close() {
|
|
34011
|
+
if (this._closed) return;
|
|
34012
|
+
this._closed = true;
|
|
34013
|
+
this._pendingRequests.clear();
|
|
34014
|
+
this._releaseDrainWaiters();
|
|
34015
|
+
try {
|
|
34016
|
+
this._onInstanceClose();
|
|
34017
|
+
} finally {
|
|
34018
|
+
this.onclose?.();
|
|
34019
|
+
}
|
|
34020
|
+
}
|
|
34021
|
+
_settle(id) {
|
|
34022
|
+
this._pendingRequests.delete(id);
|
|
34023
|
+
if (this._pendingRequests.size === 0) this._releaseDrainWaiters();
|
|
34024
|
+
}
|
|
34025
|
+
_releaseDrainWaiters() {
|
|
34026
|
+
const waiters = this._drainWaiters;
|
|
34027
|
+
this._drainWaiters = [];
|
|
34028
|
+
for (const waiter of waiters) waiter();
|
|
34029
|
+
}
|
|
34030
|
+
};
|
|
34031
|
+
function classifyOpeningMessage(message) {
|
|
34032
|
+
const params = message.params;
|
|
34033
|
+
if (message.method === "initialize" && !carriesValidModernEnvelopeClaim(params)) {
|
|
34034
|
+
const requestedVersion = params !== null && typeof params === "object" && typeof params.protocolVersion === "string" ? params.protocolVersion : void 0;
|
|
34035
|
+
return {
|
|
34036
|
+
kind: "legacy",
|
|
34037
|
+
reason: "initialize",
|
|
34038
|
+
...requestedVersion !== void 0 && { requestedVersion }
|
|
34039
|
+
};
|
|
34040
|
+
}
|
|
34041
|
+
if (!hasEnvelopeClaim(params)) return {
|
|
34042
|
+
kind: "legacy",
|
|
34043
|
+
reason: "no-claim"
|
|
34044
|
+
};
|
|
34045
|
+
const meta3 = requestMetaOf(params);
|
|
34046
|
+
const firstIssue = (meta3 === void 0 ? [] : validateEnvelopeMeta(meta3))[0];
|
|
34047
|
+
if (firstIssue !== void 0) return {
|
|
34048
|
+
kind: "invalid-envelope",
|
|
34049
|
+
issue: firstIssue
|
|
34050
|
+
};
|
|
34051
|
+
const claimedVersion = envelopeClaimVersion(params);
|
|
34052
|
+
if (claimedVersion === void 0 || !SUPPORTED_MODERN_PROTOCOL_VERSIONS.includes(claimedVersion)) return {
|
|
34053
|
+
kind: "unsupported-revision",
|
|
34054
|
+
requested: claimedVersion ?? "unknown"
|
|
34055
|
+
};
|
|
34056
|
+
return {
|
|
34057
|
+
kind: "modern",
|
|
34058
|
+
revision: claimedVersion,
|
|
34059
|
+
classification: {
|
|
34060
|
+
era: "modern",
|
|
34061
|
+
revision: claimedVersion
|
|
34062
|
+
}
|
|
34063
|
+
};
|
|
34064
|
+
}
|
|
34065
|
+
function serveStdio(factory, options = {}) {
|
|
34066
|
+
const legacyMode = options.legacy ?? "serve";
|
|
34067
|
+
const wire = options.transport ?? new StdioServerTransport();
|
|
34068
|
+
let state = { phase: "opening" };
|
|
34069
|
+
let discarding;
|
|
34070
|
+
let closing = false;
|
|
34071
|
+
const isTornDown = () => closing || state.phase === "closed";
|
|
34072
|
+
const reportError = (error62) => {
|
|
34073
|
+
try {
|
|
34074
|
+
options.onerror?.(error62);
|
|
34075
|
+
} catch {
|
|
34076
|
+
}
|
|
34077
|
+
};
|
|
34078
|
+
const writeErrorResponse = (id, code, message, data) => wire.send({
|
|
34079
|
+
jsonrpc: "2.0",
|
|
34080
|
+
id,
|
|
34081
|
+
error: {
|
|
34082
|
+
code,
|
|
34083
|
+
message,
|
|
34084
|
+
...data !== void 0 && { data }
|
|
34085
|
+
}
|
|
34086
|
+
}).catch((error62) => reportError(toError(error62)));
|
|
34087
|
+
const listenRouter = new StdioListenRouter(options.maxSubscriptions ?? DEFAULT_MAX_SUBSCRIPTIONS);
|
|
34088
|
+
const modernOutboundIntercept = (message) => {
|
|
34089
|
+
if (!isJSONRPCNotification(message)) return void 0;
|
|
34090
|
+
const routed = listenRouter.routeOutbound(message);
|
|
34091
|
+
if (routed === "passthrough") return void 0;
|
|
34092
|
+
for (const stamped of routed) wire.send({
|
|
34093
|
+
jsonrpc: "2.0",
|
|
34094
|
+
...stamped
|
|
34095
|
+
}).catch((error62) => reportError(toError(error62)));
|
|
34096
|
+
return "handled";
|
|
34097
|
+
};
|
|
34098
|
+
const tryServeListen = async (message) => {
|
|
34099
|
+
if (isJSONRPCRequest(message) && message.method === "subscriptions/listen") {
|
|
34100
|
+
const meta3 = requestMetaOf(message.params);
|
|
34101
|
+
const issue2 = hasEnvelopeClaim(message.params) ? (meta3 === void 0 ? [] : validateEnvelopeMeta(meta3))[0] : {
|
|
34102
|
+
key: "_meta",
|
|
34103
|
+
problem: "the per-request envelope is required on protocol revision 2026-07-28"
|
|
34104
|
+
};
|
|
34105
|
+
const claimedVersion = envelopeClaimVersion(message.params);
|
|
34106
|
+
let reply;
|
|
34107
|
+
if (issue2 !== void 0) reply = {
|
|
34108
|
+
jsonrpc: "2.0",
|
|
34109
|
+
id: message.id,
|
|
34110
|
+
error: {
|
|
34111
|
+
code: -32602,
|
|
34112
|
+
message: `Invalid _meta envelope: ${issue2.key}: ${issue2.problem}`
|
|
34113
|
+
}
|
|
34114
|
+
};
|
|
34115
|
+
else if (claimedVersion === void 0 || !SUPPORTED_MODERN_PROTOCOL_VERSIONS.includes(claimedVersion)) {
|
|
34116
|
+
const error62 = new UnsupportedProtocolVersionError({
|
|
34117
|
+
supported: [...SUPPORTED_MODERN_PROTOCOL_VERSIONS],
|
|
34118
|
+
requested: claimedVersion ?? "unknown"
|
|
34119
|
+
});
|
|
34120
|
+
reply = {
|
|
34121
|
+
jsonrpc: "2.0",
|
|
34122
|
+
id: message.id,
|
|
34123
|
+
error: {
|
|
34124
|
+
code: error62.code,
|
|
34125
|
+
message: error62.message,
|
|
34126
|
+
data: error62.data
|
|
34127
|
+
}
|
|
34128
|
+
};
|
|
34129
|
+
} else reply = listenRouter.serve(message);
|
|
34130
|
+
await wire.send("error" in reply ? reply : {
|
|
34131
|
+
jsonrpc: "2.0",
|
|
34132
|
+
method: reply.method,
|
|
34133
|
+
params: reply.params
|
|
34134
|
+
}).catch((error62) => reportError(toError(error62)));
|
|
34135
|
+
return true;
|
|
34136
|
+
}
|
|
34137
|
+
if (isJSONRPCNotification(message) && message.method === "notifications/cancelled") {
|
|
34138
|
+
const cancelledId = message.params?.requestId;
|
|
34139
|
+
if (cancelledId !== void 0 && listenRouter.cancel(cancelledId)) return true;
|
|
34140
|
+
}
|
|
34141
|
+
return false;
|
|
34142
|
+
};
|
|
34143
|
+
const answerLegacyRejection = (request, reason, requestedVersion) => {
|
|
34144
|
+
const rejection2 = modernOnlyStrictRejection({
|
|
34145
|
+
kind: "legacy",
|
|
34146
|
+
reason,
|
|
34147
|
+
...requestedVersion !== void 0 && { requestedVersion }
|
|
34148
|
+
}, SUPPORTED_MODERN_PROTOCOL_VERSIONS);
|
|
34149
|
+
if (rejection2 === void 0) return Promise.resolve();
|
|
34150
|
+
reportError(/* @__PURE__ */ new Error(`Rejected 2025-era request on a modern-only stdio connection (${rejection2.cell}): ${rejection2.message}`));
|
|
34151
|
+
return writeErrorResponse(request.id, rejection2.code, rejection2.message, rejection2.data);
|
|
34152
|
+
};
|
|
34153
|
+
const onInstanceClosed = (channel) => {
|
|
34154
|
+
if (closing || channel === discarding) return;
|
|
34155
|
+
closeAll();
|
|
34156
|
+
};
|
|
34157
|
+
const connectInstance = async (era, revision) => {
|
|
34158
|
+
const product = await factory({ era });
|
|
34159
|
+
const server = product instanceof McpServer ? product.server : product;
|
|
34160
|
+
if (era === "modern") {
|
|
34161
|
+
setNegotiatedProtocolVersion(server, revision);
|
|
34162
|
+
installModernOnlyHandlers(server, SUPPORTED_MODERN_PROTOCOL_VERSIONS);
|
|
34163
|
+
listenRouter.setServerCapabilities(server.getCapabilities(), serverIdentityOf(server));
|
|
34164
|
+
}
|
|
34165
|
+
const channel = new StdioConnectionChannel(wire, () => onInstanceClosed(channel), era === "modern" ? modernOutboundIntercept : void 0);
|
|
34166
|
+
await product.connect(channel);
|
|
34167
|
+
return {
|
|
34168
|
+
product,
|
|
34169
|
+
channel
|
|
34170
|
+
};
|
|
34171
|
+
};
|
|
34172
|
+
const disposeLateInstance = (instance) => instance.product.close().catch((error62) => reportError(toError(error62)));
|
|
34173
|
+
const discardProbeInstance = async (instance) => {
|
|
34174
|
+
discarding = instance.channel;
|
|
34175
|
+
try {
|
|
34176
|
+
if (!await instance.channel.whenRequestsAnswered(DISCARD_ANSWER_TIMEOUT_MS)) reportError(/* @__PURE__ */ new Error(`Discarded the probe instance with requests still unanswered after ${DISCARD_ANSWER_TIMEOUT_MS}ms; continuing with the fallback`));
|
|
34177
|
+
await instance.product.close();
|
|
34178
|
+
} catch (error62) {
|
|
34179
|
+
reportError(toError(error62));
|
|
34180
|
+
} finally {
|
|
34181
|
+
discarding = void 0;
|
|
34182
|
+
}
|
|
34183
|
+
};
|
|
34184
|
+
const processMessage = async (message) => {
|
|
34185
|
+
if (state.phase === "closed") return;
|
|
34186
|
+
if (state.phase === "pinned") {
|
|
34187
|
+
if (state.era === "modern" && isJSONRPCRequest(message) && message.method === "initialize" && !carriesValidModernEnvelopeClaim(message.params)) {
|
|
34188
|
+
await answerLegacyRejection(message, "initialize", message.params !== null && typeof message.params === "object" && typeof message.params.protocolVersion === "string" ? message.params.protocolVersion : void 0);
|
|
34189
|
+
return;
|
|
34190
|
+
}
|
|
34191
|
+
if (state.era === "modern" && await tryServeListen(message)) return;
|
|
34192
|
+
state.instance.channel.deliver(message);
|
|
34193
|
+
return;
|
|
34194
|
+
}
|
|
34195
|
+
if (!isJSONRPCRequest(message) && !isJSONRPCNotification(message)) {
|
|
34196
|
+
reportError(/* @__PURE__ */ new Error("Discarded a JSON-RPC response received before the connection negotiated an era"));
|
|
34197
|
+
return;
|
|
34198
|
+
}
|
|
34199
|
+
const opening = classifyOpeningMessage(message);
|
|
34200
|
+
switch (opening.kind) {
|
|
34201
|
+
case "invalid-envelope": {
|
|
34202
|
+
const detail = `Invalid _meta envelope for protocol revision 2026-07-28: ${opening.issue.key}: ${opening.issue.problem}`;
|
|
34203
|
+
if (isJSONRPCRequest(message)) await writeErrorResponse(message.id, ProtocolErrorCode.InvalidParams, detail, { envelope: opening.issue });
|
|
34204
|
+
else reportError(/* @__PURE__ */ new Error(`Discarded a notification with a malformed envelope: ${detail}`));
|
|
34205
|
+
return;
|
|
34206
|
+
}
|
|
34207
|
+
case "unsupported-revision":
|
|
34208
|
+
if (isJSONRPCRequest(message)) {
|
|
34209
|
+
const error62 = new UnsupportedProtocolVersionError({
|
|
34210
|
+
supported: [...SUPPORTED_MODERN_PROTOCOL_VERSIONS],
|
|
34211
|
+
requested: opening.requested
|
|
34212
|
+
});
|
|
34213
|
+
reportError(error62);
|
|
34214
|
+
await writeErrorResponse(message.id, error62.code, error62.message, error62.data);
|
|
34215
|
+
} else reportError(/* @__PURE__ */ new Error(`Discarded a notification claiming unsupported protocol revision ${opening.requested}`));
|
|
34216
|
+
return;
|
|
34217
|
+
case "modern":
|
|
34218
|
+
if (isJSONRPCRequest(message) && message.method === "server/discover") {
|
|
34219
|
+
if (state.phase === "probe") {
|
|
34220
|
+
state.instance.channel.deliver(message, { classification: opening.classification });
|
|
34221
|
+
return;
|
|
34222
|
+
}
|
|
34223
|
+
const instance = await connectInstance("modern", opening.revision);
|
|
34224
|
+
if (isTornDown()) {
|
|
34225
|
+
await disposeLateInstance(instance);
|
|
34226
|
+
return;
|
|
34227
|
+
}
|
|
34228
|
+
state = {
|
|
34229
|
+
phase: "probe",
|
|
34230
|
+
instance
|
|
34231
|
+
};
|
|
34232
|
+
instance.channel.deliver(message, { classification: opening.classification });
|
|
34233
|
+
return;
|
|
34234
|
+
}
|
|
34235
|
+
if (state.phase === "probe") {
|
|
34236
|
+
if (isJSONRPCNotification(message)) {
|
|
34237
|
+
state.instance.channel.deliver(message, { classification: opening.classification });
|
|
34238
|
+
return;
|
|
34239
|
+
}
|
|
34240
|
+
state = {
|
|
34241
|
+
phase: "pinned",
|
|
34242
|
+
era: "modern",
|
|
34243
|
+
instance: state.instance
|
|
34244
|
+
};
|
|
34245
|
+
} else {
|
|
34246
|
+
const instance = await connectInstance("modern", opening.revision);
|
|
34247
|
+
if (isTornDown()) {
|
|
34248
|
+
await disposeLateInstance(instance);
|
|
34249
|
+
return;
|
|
34250
|
+
}
|
|
34251
|
+
state = {
|
|
34252
|
+
phase: "pinned",
|
|
34253
|
+
era: "modern",
|
|
34254
|
+
instance
|
|
34255
|
+
};
|
|
34256
|
+
}
|
|
34257
|
+
if (await tryServeListen(message)) return;
|
|
34258
|
+
state.instance.channel.deliver(message, { classification: opening.classification });
|
|
34259
|
+
return;
|
|
34260
|
+
case "legacy": {
|
|
34261
|
+
if (legacyMode === "reject") {
|
|
34262
|
+
if (isJSONRPCRequest(message)) await answerLegacyRejection(message, opening.reason, opening.requestedVersion);
|
|
34263
|
+
return;
|
|
34264
|
+
}
|
|
34265
|
+
if (state.phase === "probe") {
|
|
34266
|
+
await discardProbeInstance(state.instance);
|
|
34267
|
+
if (isTornDown()) return;
|
|
34268
|
+
state = { phase: "opening" };
|
|
34269
|
+
}
|
|
34270
|
+
const instance = await connectInstance("legacy");
|
|
34271
|
+
if (isTornDown()) {
|
|
34272
|
+
await disposeLateInstance(instance);
|
|
34273
|
+
return;
|
|
34274
|
+
}
|
|
34275
|
+
state = {
|
|
34276
|
+
phase: "pinned",
|
|
34277
|
+
era: "legacy",
|
|
34278
|
+
instance
|
|
34279
|
+
};
|
|
34280
|
+
state.instance.channel.deliver(message);
|
|
34281
|
+
return;
|
|
34282
|
+
}
|
|
34283
|
+
}
|
|
34284
|
+
};
|
|
34285
|
+
const queue = [];
|
|
34286
|
+
let pumping = false;
|
|
34287
|
+
const pump = async () => {
|
|
34288
|
+
if (pumping) return;
|
|
34289
|
+
pumping = true;
|
|
34290
|
+
try {
|
|
34291
|
+
while (queue.length > 0) {
|
|
34292
|
+
const message = queue.shift();
|
|
34293
|
+
try {
|
|
34294
|
+
await processMessage(message);
|
|
34295
|
+
} catch (error62) {
|
|
34296
|
+
if (isJSONRPCRequest(message)) await writeErrorResponse(message.id, ProtocolErrorCode.InternalError, "Internal server error");
|
|
34297
|
+
reportError(toError(error62));
|
|
34298
|
+
}
|
|
34299
|
+
}
|
|
34300
|
+
} finally {
|
|
34301
|
+
pumping = false;
|
|
34302
|
+
}
|
|
34303
|
+
};
|
|
34304
|
+
const closeAll = async () => {
|
|
34305
|
+
if (closing || state.phase === "closed") return;
|
|
34306
|
+
closing = true;
|
|
34307
|
+
const current = state;
|
|
34308
|
+
state = { phase: "closed" };
|
|
34309
|
+
for (const result of listenRouter.teardownAll()) await wire.send(result).catch((error62) => reportError(toError(error62)));
|
|
34310
|
+
if (current.phase === "probe" || current.phase === "pinned") await current.instance.product.close().catch((error62) => reportError(toError(error62)));
|
|
34311
|
+
await wire.close().catch((error62) => reportError(toError(error62)));
|
|
34312
|
+
};
|
|
34313
|
+
wire.onmessage = (message) => {
|
|
34314
|
+
queue.push(message);
|
|
34315
|
+
pump();
|
|
34316
|
+
};
|
|
34317
|
+
wire.onerror = (error62) => {
|
|
34318
|
+
reportError(error62);
|
|
34319
|
+
if (state.phase === "probe" || state.phase === "pinned") state.instance.channel.onerror?.(error62);
|
|
34320
|
+
};
|
|
34321
|
+
wire.onclose = () => {
|
|
34322
|
+
if (closing || state.phase === "closed") return;
|
|
34323
|
+
closing = true;
|
|
34324
|
+
const current = state;
|
|
34325
|
+
state = { phase: "closed" };
|
|
34326
|
+
if (current.phase === "probe" || current.phase === "pinned") current.instance.product.close().catch((error62) => reportError(toError(error62)));
|
|
34327
|
+
};
|
|
34328
|
+
const started = wire.start().catch((error62) => {
|
|
34329
|
+
reportError(toError(error62));
|
|
34330
|
+
throw error62;
|
|
34331
|
+
});
|
|
34332
|
+
started.catch(() => {
|
|
34333
|
+
});
|
|
34334
|
+
return { close: async () => {
|
|
34335
|
+
await started.catch(() => {
|
|
34336
|
+
});
|
|
34337
|
+
await closeAll();
|
|
34338
|
+
} };
|
|
34339
|
+
}
|
|
34340
|
+
function toError(value) {
|
|
34341
|
+
return value instanceof Error ? value : new Error(String(value));
|
|
34342
|
+
}
|
|
33671
34343
|
|
|
33672
34344
|
// ../../node_modules/@chrischall/mcp-utils/dist/errors/index.js
|
|
33673
34345
|
var McpToolError = class extends Error {
|
|
@@ -33787,17 +34459,41 @@ Hint: ${err.hint}`);
|
|
|
33787
34459
|
}
|
|
33788
34460
|
throw err;
|
|
33789
34461
|
}
|
|
34462
|
+
function callSignalFrom(args) {
|
|
34463
|
+
const ctx = args.at(-1);
|
|
34464
|
+
if (typeof ctx !== "object" || ctx === null)
|
|
34465
|
+
return void 0;
|
|
34466
|
+
const req = ctx.mcpReq;
|
|
34467
|
+
if (typeof req !== "object" || req === null)
|
|
34468
|
+
return void 0;
|
|
34469
|
+
const signal = req.signal;
|
|
34470
|
+
return signal instanceof AbortSignal ? signal : void 0;
|
|
34471
|
+
}
|
|
33790
34472
|
function surfaceToolHints(server) {
|
|
33791
34473
|
const register2 = server.registerTool.bind(server);
|
|
33792
|
-
server.registerTool = (name, config2, cb) => register2(name, config2, (...args) =>
|
|
33793
|
-
|
|
33794
|
-
|
|
33795
|
-
|
|
33796
|
-
|
|
33797
|
-
|
|
33798
|
-
|
|
33799
|
-
|
|
33800
|
-
|
|
34474
|
+
server.registerTool = (name, config2, cb) => register2(name, config2, (...args) => (
|
|
34475
|
+
// THE CALLER'S CANCELLATION, made ambient for the whole handler
|
|
34476
|
+
// (`cancel/index.ts`). The SDK delivers it and the fleet ignored it:
|
|
34477
|
+
// measured against @modelcontextprotocol/server 2.0.0, a cancelled
|
|
34478
|
+
// call aborts `ctx.mcpReq.signal` with the caller's reason and the
|
|
34479
|
+
// handler runs to completion regardless — so the HTTP request stays
|
|
34480
|
+
// in flight, the child keeps burning metered CPU, and the upstream
|
|
34481
|
+
// keeps being hit for somebody who has gone. claude.ai sent 101
|
|
34482
|
+
// cancellations in the week to 2026-09-20.
|
|
34483
|
+
//
|
|
34484
|
+
// Here because this is the one wrapper every tool already passes
|
|
34485
|
+
// through: threading the signal by hand would mean editing several
|
|
34486
|
+
// hundred handlers and missing exactly the ones nobody edits.
|
|
34487
|
+
withCallSignal(callSignalFrom(args), () => {
|
|
34488
|
+
let result;
|
|
34489
|
+
try {
|
|
34490
|
+
result = cb(...args);
|
|
34491
|
+
} catch (err) {
|
|
34492
|
+
return hintResultOrRethrow(err);
|
|
34493
|
+
}
|
|
34494
|
+
return result instanceof Promise ? result.catch(hintResultOrRethrow) : result;
|
|
34495
|
+
})
|
|
34496
|
+
));
|
|
33801
34497
|
}
|
|
33802
34498
|
async function createMcpServer(opts) {
|
|
33803
34499
|
const server = new McpServer({ name: opts.name, version: opts.version }, { supportedProtocolVersions: [...SERVER_PROTOCOL_VERSIONS] });
|
|
@@ -33812,7 +34508,7 @@ async function createMcpServer(opts) {
|
|
|
33812
34508
|
}
|
|
33813
34509
|
return server;
|
|
33814
34510
|
}
|
|
33815
|
-
function withGracefulShutdown(
|
|
34511
|
+
function withGracefulShutdown(target, opts = {}) {
|
|
33816
34512
|
const shouldExit = opts.exit ?? true;
|
|
33817
34513
|
let shuttingDown = false;
|
|
33818
34514
|
const handler = (signal) => {
|
|
@@ -33823,7 +34519,7 @@ function withGracefulShutdown(server, opts = {}) {
|
|
|
33823
34519
|
try {
|
|
33824
34520
|
if (opts.onSignal)
|
|
33825
34521
|
await opts.onSignal(signal);
|
|
33826
|
-
await
|
|
34522
|
+
await target.close();
|
|
33827
34523
|
} catch (err) {
|
|
33828
34524
|
console.error(`[mcp-utils] error during graceful shutdown on ${signal}: ${err instanceof Error ? err.message : String(err)}`);
|
|
33829
34525
|
} finally {
|
|
@@ -33835,16 +34531,26 @@ function withGracefulShutdown(server, opts = {}) {
|
|
|
33835
34531
|
process.on("SIGINT", () => handler("SIGINT"));
|
|
33836
34532
|
process.on("SIGTERM", () => handler("SIGTERM"));
|
|
33837
34533
|
}
|
|
33838
|
-
|
|
33839
|
-
|
|
34534
|
+
function runMcp(opts) {
|
|
34535
|
+
if (opts.banner !== void 0) {
|
|
34536
|
+
console.error(opts.banner);
|
|
34537
|
+
}
|
|
34538
|
+
const spec = opts.transport ?? "stdio";
|
|
34539
|
+
const handle = serveStdio(() => createMcpServer({ ...opts, banner: void 0 }), {
|
|
34540
|
+
legacy: opts.legacy ?? "serve",
|
|
34541
|
+
onerror: opts.onerror ?? ((error62) => {
|
|
34542
|
+
console.error(`[mcp-utils] stdio server error: ${redactSecrets(error62.message)}`);
|
|
34543
|
+
}),
|
|
34544
|
+
// `'stdio'` means "let the entry make its own StdioServerTransport over
|
|
34545
|
+
// this process"; anything else is the caller's transport, which the entry
|
|
34546
|
+
// then owns (it starts it, pumps it, and closes it with the handle).
|
|
34547
|
+
...spec === "stdio" ? {} : { transport: spec }
|
|
34548
|
+
});
|
|
33840
34549
|
const shutdown = opts.shutdown ?? true;
|
|
33841
34550
|
if (shutdown !== false) {
|
|
33842
|
-
withGracefulShutdown(
|
|
34551
|
+
withGracefulShutdown(handle, shutdown === true ? {} : shutdown);
|
|
33843
34552
|
}
|
|
33844
|
-
|
|
33845
|
-
const transport = spec === "stdio" ? new StdioServerTransport() : spec;
|
|
33846
|
-
await server.connect(transport);
|
|
33847
|
-
return server;
|
|
34553
|
+
return handle;
|
|
33848
34554
|
}
|
|
33849
34555
|
|
|
33850
34556
|
// ../../node_modules/@chrischall/mcp-utils/dist/config/index.js
|
|
@@ -34222,8 +34928,15 @@ async function spawnGog(fullArgs, opts) {
|
|
|
34222
34928
|
const stdoutChunks = [];
|
|
34223
34929
|
const stderrChunks = [];
|
|
34224
34930
|
let settled = false;
|
|
34931
|
+
const cancelled = currentCallSignal();
|
|
34932
|
+
const stopWatchingCancel = killOnCancel(child);
|
|
34933
|
+
const stopWatching = () => {
|
|
34934
|
+
clearTimeout(timer);
|
|
34935
|
+
stopWatchingCancel();
|
|
34936
|
+
};
|
|
34225
34937
|
const timer = setTimeout(() => {
|
|
34226
34938
|
settled = true;
|
|
34939
|
+
stopWatchingCancel();
|
|
34227
34940
|
child.kill();
|
|
34228
34941
|
reject(new Error(`gog timed out after ${formatTimeout(effectiveTimeout)}`));
|
|
34229
34942
|
}, effectiveTimeout);
|
|
@@ -34234,9 +34947,13 @@ async function spawnGog(fullArgs, opts) {
|
|
|
34234
34947
|
stderrChunks.push(chunk);
|
|
34235
34948
|
});
|
|
34236
34949
|
child.on("close", (code) => {
|
|
34237
|
-
|
|
34950
|
+
stopWatching();
|
|
34238
34951
|
if (settled) return;
|
|
34239
34952
|
settled = true;
|
|
34953
|
+
if (cancelled?.aborted) {
|
|
34954
|
+
reject(cancelled.reason instanceof Error ? cancelled.reason : new Error("the caller cancelled this call"));
|
|
34955
|
+
return;
|
|
34956
|
+
}
|
|
34240
34957
|
const stderr = Buffer.concat(stderrChunks).toString().trim();
|
|
34241
34958
|
if (code === 0) {
|
|
34242
34959
|
if (binary) {
|
|
@@ -34254,7 +34971,7 @@ async function spawnGog(fullArgs, opts) {
|
|
|
34254
34971
|
}
|
|
34255
34972
|
});
|
|
34256
34973
|
child.on("error", (err) => {
|
|
34257
|
-
|
|
34974
|
+
stopWatching();
|
|
34258
34975
|
if (settled) return;
|
|
34259
34976
|
settled = true;
|
|
34260
34977
|
if (err.code === "ENOENT") {
|
|
@@ -34744,7 +35461,7 @@ var failIfNotEmptyParam = external_exports.boolean().optional().describe(
|
|
|
34744
35461
|
);
|
|
34745
35462
|
|
|
34746
35463
|
// ../gogcli-mcp/src/server.ts
|
|
34747
|
-
var VERSION = true ? "4.0
|
|
35464
|
+
var VERSION = true ? "4.2.0" : "0.0.0";
|
|
34748
35465
|
|
|
34749
35466
|
// ../gogcli-mcp/src/bootstrap-auth.ts
|
|
34750
35467
|
import { join as join2 } from "node:path";
|
package/manifest.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"manifest_version": "0.3",
|
|
4
4
|
"name": "gogcli-mcp-contacts",
|
|
5
5
|
"display_name": "gogcli (Contacts)",
|
|
6
|
-
"version": "4.0
|
|
6
|
+
"version": "4.2.0",
|
|
7
7
|
"description": "Extended Google Contacts for Claude via gogcli — auth + Contacts + Workspace directory (People API)",
|
|
8
8
|
"author": {
|
|
9
9
|
"name": "Chris Hall",
|
|
@@ -162,7 +162,7 @@
|
|
|
162
162
|
"win32"
|
|
163
163
|
],
|
|
164
164
|
"runtimes": {
|
|
165
|
-
"node": ">=
|
|
165
|
+
"node": ">=22.0.0"
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gogcli-mcp-contacts",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.2.0",
|
|
4
4
|
"mcpName": "io.github.chrischall/gogcli-mcp-contacts",
|
|
5
5
|
"description": "Extended Google Contacts + People MCP server via gogcli — auth + Contacts + Workspace directory (People API)",
|
|
6
6
|
"author": "Claude Code (AI) <https://www.anthropic.com/claude>",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"test:coverage": "vitest run --coverage"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@chrischall/mcp-utils": "^0.
|
|
27
|
+
"@chrischall/mcp-utils": "^2.0.0",
|
|
28
28
|
"@modelcontextprotocol/server": "^2.0.0",
|
|
29
29
|
"zod": "^4.6.1"
|
|
30
30
|
},
|