@wrongstack/mcp 0.303.0 → 0.305.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/dist/authorization-manager.d.ts +2 -0
- package/dist/authorization.d.ts +4 -1
- package/dist/client.d.ts +1 -1
- package/dist/index.js +183 -101
- package/package.json +2 -2
|
@@ -49,6 +49,7 @@ export interface MCPAuthorizationStatus {
|
|
|
49
49
|
export declare class MCPAuthorizationManager {
|
|
50
50
|
private readonly options;
|
|
51
51
|
private readonly pending;
|
|
52
|
+
private readonly starting;
|
|
52
53
|
private readonly pendingTtlMs;
|
|
53
54
|
private readonly discover;
|
|
54
55
|
private readonly exchange;
|
|
@@ -59,6 +60,7 @@ export declare class MCPAuthorizationManager {
|
|
|
59
60
|
status(serverName: string, resource: string): Promise<MCPAuthorizationStatus>;
|
|
60
61
|
disconnect(serverName: string, resource: string): Promise<boolean>;
|
|
61
62
|
private pruneExpired;
|
|
63
|
+
private activeAuthorizationCount;
|
|
62
64
|
private emit;
|
|
63
65
|
}
|
|
64
66
|
export {};
|
package/dist/authorization.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ export interface MCPAuthorizationServerMetadata {
|
|
|
28
28
|
authorizationEndpoint: string;
|
|
29
29
|
tokenEndpoint: string;
|
|
30
30
|
registrationEndpoint?: string | undefined;
|
|
31
|
+
authorizationResponseIssuerParameterSupported?: boolean | undefined;
|
|
31
32
|
scopesSupported: string[];
|
|
32
33
|
}
|
|
33
34
|
export interface MCPAuthorizationDiscoveryResult {
|
|
@@ -53,6 +54,8 @@ export interface MCPAuthorizationSession {
|
|
|
53
54
|
redirectUri: string;
|
|
54
55
|
clientId: string;
|
|
55
56
|
resource: string;
|
|
57
|
+
issuer: string;
|
|
58
|
+
requireIssuerParameter: boolean;
|
|
56
59
|
}
|
|
57
60
|
export interface MCPTokenSet extends MCPAccessToken {
|
|
58
61
|
refreshToken?: string | undefined;
|
|
@@ -121,7 +124,7 @@ export declare function validateMcpAuthorizationServerMetadata(value: unknown):
|
|
|
121
124
|
*/
|
|
122
125
|
export declare function discoverMcpAuthorization(resource: string, options?: MCPAuthorizationDiscoveryOptions): Promise<MCPAuthorizationDiscoveryResult>;
|
|
123
126
|
export declare function createMcpAuthorizationRequest(options: MCPAuthorizationRequestOptions): MCPAuthorizationSession;
|
|
124
|
-
export declare function parseMcpAuthorizationCallback(callbackUrl: string, session: Pick<MCPAuthorizationSession, 'redirectUri' | 'state'>): string;
|
|
127
|
+
export declare function parseMcpAuthorizationCallback(callbackUrl: string, session: Pick<MCPAuthorizationSession, 'redirectUri' | 'state' | 'issuer' | 'requireIssuerParameter'>): string;
|
|
125
128
|
export declare function exchangeMcpAuthorizationCode(options: MCPTokenExchangeOptions): Promise<MCPTokenSet>;
|
|
126
129
|
export declare function refreshMcpAccessToken(options: MCPTokenRefreshOptions): Promise<MCPTokenSet>;
|
|
127
130
|
export {};
|
package/dist/client.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { MCPAuthorizationProvider } from './authorization.js';
|
|
2
2
|
import { type MCPGetPromptResult, type MCPListPromptsResult, type MCPListResourcesResult, type MCPListResourceTemplatesResult, type MCPReadResourceResult, type MCPServerMetadata } from './protocol.js';
|
|
3
|
-
export { quoteWindowsArg } from './client-protocol-helpers.js';
|
|
4
3
|
export { forceKillTree } from './client-process.js';
|
|
4
|
+
export { quoteWindowsArg } from './client-protocol-helpers.js';
|
|
5
5
|
export type Transport = 'stdio' | 'sse' | 'streamable-http';
|
|
6
6
|
export interface MCPClientOptions {
|
|
7
7
|
name: string;
|
package/dist/index.js
CHANGED
|
@@ -120,34 +120,59 @@ function parseAuthorizationServerMetadata(value, expectedIssuer) {
|
|
|
120
120
|
throw new Error("MCP authorization server does not advertise required PKCE S256 support");
|
|
121
121
|
}
|
|
122
122
|
const registration = optionalString(metadata["registration_endpoint"], "registration_endpoint");
|
|
123
|
+
const authorizationEndpoint = secureOAuthUrl(
|
|
124
|
+
requiredString(metadata["authorization_endpoint"], "authorization_endpoint"),
|
|
125
|
+
"authorization endpoint"
|
|
126
|
+
).toString();
|
|
127
|
+
const tokenEndpoint = secureOAuthUrl(
|
|
128
|
+
requiredString(metadata["token_endpoint"], "token_endpoint"),
|
|
129
|
+
"token endpoint"
|
|
130
|
+
).toString();
|
|
131
|
+
const issuerParameterSupported = optionalBoolean(
|
|
132
|
+
metadata["authorization_response_iss_parameter_supported"],
|
|
133
|
+
"authorization_response_iss_parameter_supported"
|
|
134
|
+
);
|
|
135
|
+
if (issuerParameterSupported !== true && (new URL(authorizationEndpoint).origin !== new URL(issuer).origin || new URL(tokenEndpoint).origin !== new URL(issuer).origin)) {
|
|
136
|
+
throw new Error(
|
|
137
|
+
"MCP authorization server with cross-origin endpoints must support the authorization response issuer parameter"
|
|
138
|
+
);
|
|
139
|
+
}
|
|
123
140
|
return {
|
|
124
141
|
issuer,
|
|
125
|
-
authorizationEndpoint
|
|
126
|
-
|
|
127
|
-
"authorization endpoint"
|
|
128
|
-
).toString(),
|
|
129
|
-
tokenEndpoint: secureOAuthUrl(
|
|
130
|
-
requiredString(metadata["token_endpoint"], "token_endpoint"),
|
|
131
|
-
"token endpoint"
|
|
132
|
-
).toString(),
|
|
142
|
+
authorizationEndpoint,
|
|
143
|
+
tokenEndpoint,
|
|
133
144
|
registrationEndpoint: registration ? secureOAuthUrl(registration, "registration endpoint").toString() : void 0,
|
|
145
|
+
authorizationResponseIssuerParameterSupported: issuerParameterSupported,
|
|
134
146
|
scopesSupported: optionalStringArray(metadata["scopes_supported"], "scopes_supported", 128)
|
|
135
147
|
};
|
|
136
148
|
}
|
|
137
149
|
function validateMcpAuthorizationServerMetadata(value) {
|
|
138
150
|
const metadata = record(value, "stored authorization server metadata");
|
|
139
151
|
const registration = optionalString(metadata["registrationEndpoint"], "registrationEndpoint");
|
|
152
|
+
const issuer = secureOAuthUrl(requiredString(metadata["issuer"], "issuer"), "issuer").toString();
|
|
153
|
+
const authorizationEndpoint = secureOAuthUrl(
|
|
154
|
+
requiredString(metadata["authorizationEndpoint"], "authorizationEndpoint"),
|
|
155
|
+
"authorization endpoint"
|
|
156
|
+
).toString();
|
|
157
|
+
const tokenEndpoint = secureOAuthUrl(
|
|
158
|
+
requiredString(metadata["tokenEndpoint"], "tokenEndpoint"),
|
|
159
|
+
"token endpoint"
|
|
160
|
+
).toString();
|
|
161
|
+
const issuerParameterSupported = optionalBoolean(
|
|
162
|
+
metadata["authorizationResponseIssuerParameterSupported"],
|
|
163
|
+
"authorizationResponseIssuerParameterSupported"
|
|
164
|
+
);
|
|
165
|
+
if (issuerParameterSupported !== true && (new URL(authorizationEndpoint).origin !== new URL(issuer).origin || new URL(tokenEndpoint).origin !== new URL(issuer).origin)) {
|
|
166
|
+
throw new Error(
|
|
167
|
+
"MCP authorization server with cross-origin endpoints must support the authorization response issuer parameter"
|
|
168
|
+
);
|
|
169
|
+
}
|
|
140
170
|
return {
|
|
141
|
-
issuer
|
|
142
|
-
authorizationEndpoint
|
|
143
|
-
|
|
144
|
-
"authorization endpoint"
|
|
145
|
-
).toString(),
|
|
146
|
-
tokenEndpoint: secureOAuthUrl(
|
|
147
|
-
requiredString(metadata["tokenEndpoint"], "tokenEndpoint"),
|
|
148
|
-
"token endpoint"
|
|
149
|
-
).toString(),
|
|
171
|
+
issuer,
|
|
172
|
+
authorizationEndpoint,
|
|
173
|
+
tokenEndpoint,
|
|
150
174
|
registrationEndpoint: registration ? secureOAuthUrl(registration, "registration endpoint").toString() : void 0,
|
|
175
|
+
authorizationResponseIssuerParameterSupported: issuerParameterSupported,
|
|
151
176
|
scopesSupported: optionalStringArray(metadata["scopesSupported"], "scopesSupported", 128)
|
|
152
177
|
};
|
|
153
178
|
}
|
|
@@ -212,7 +237,9 @@ function createMcpAuthorizationRequest(options) {
|
|
|
212
237
|
codeVerifier,
|
|
213
238
|
redirectUri,
|
|
214
239
|
clientId,
|
|
215
|
-
resource
|
|
240
|
+
resource,
|
|
241
|
+
issuer: options.authorizationServer.issuer,
|
|
242
|
+
requireIssuerParameter: options.authorizationServer.authorizationResponseIssuerParameterSupported === true
|
|
216
243
|
};
|
|
217
244
|
}
|
|
218
245
|
function parseMcpAuthorizationCallback(callbackUrl, session) {
|
|
@@ -226,14 +253,33 @@ function parseMcpAuthorizationCallback(callbackUrl, session) {
|
|
|
226
253
|
if (callback.protocol !== expected.protocol || callback.hostname !== expected.hostname || callback.port !== expected.port || callback.pathname !== expected.pathname) {
|
|
227
254
|
throw new Error("MCP OAuth callback redirect URI does not match the authorization session");
|
|
228
255
|
}
|
|
229
|
-
const
|
|
256
|
+
const returnedStates = callback.searchParams.getAll("state");
|
|
257
|
+
if (returnedStates.length !== 1) {
|
|
258
|
+
throw new Error("MCP OAuth callback must contain exactly one state parameter");
|
|
259
|
+
}
|
|
260
|
+
const returnedState = returnedStates[0];
|
|
230
261
|
if (!constantTimeEqual(returnedState, session.state)) {
|
|
231
262
|
throw new Error("MCP OAuth callback state mismatch");
|
|
232
263
|
}
|
|
233
|
-
const
|
|
234
|
-
if (
|
|
235
|
-
throw new Error(
|
|
236
|
-
|
|
264
|
+
const returnedIssuers = callback.searchParams.getAll("iss");
|
|
265
|
+
if (session.requireIssuerParameter && returnedIssuers.length !== 1) {
|
|
266
|
+
throw new Error("MCP OAuth callback must contain exactly one issuer parameter");
|
|
267
|
+
}
|
|
268
|
+
if (returnedIssuers.length > 0 && returnedIssuers.some((issuer) => issuer !== session.issuer)) {
|
|
269
|
+
throw new Error("MCP OAuth callback issuer mismatch");
|
|
270
|
+
}
|
|
271
|
+
const oauthErrors = callback.searchParams.getAll("error");
|
|
272
|
+
const codes = callback.searchParams.getAll("code");
|
|
273
|
+
if (oauthErrors.length > 1 || codes.length > 1 || oauthErrors.length === 1 && codes.length > 0) {
|
|
274
|
+
throw new Error("MCP OAuth callback contains ambiguous response parameters");
|
|
275
|
+
}
|
|
276
|
+
if (oauthErrors.length === 1) {
|
|
277
|
+
throw new Error(`MCP OAuth authorization failed: ${boundedErrorCode(oauthErrors[0])}`);
|
|
278
|
+
}
|
|
279
|
+
if (codes.length !== 1) {
|
|
280
|
+
throw new Error("MCP OAuth callback must contain exactly one authorization code");
|
|
281
|
+
}
|
|
282
|
+
return boundedCredential(codes[0], "authorization code");
|
|
237
283
|
}
|
|
238
284
|
async function exchangeMcpAuthorizationCode(options) {
|
|
239
285
|
const resource = canonicalMcpResource(options.resource);
|
|
@@ -315,6 +361,13 @@ function requiredString(value, field) {
|
|
|
315
361
|
function optionalString(value, field) {
|
|
316
362
|
return value === void 0 ? void 0 : requiredString(value, field);
|
|
317
363
|
}
|
|
364
|
+
function optionalBoolean(value, field) {
|
|
365
|
+
if (value === void 0) return void 0;
|
|
366
|
+
if (typeof value !== "boolean") {
|
|
367
|
+
throw new Error(`MCP authorization field "${field}" must be a boolean`);
|
|
368
|
+
}
|
|
369
|
+
return value;
|
|
370
|
+
}
|
|
318
371
|
function boundedStringArray(value, field, maxItems) {
|
|
319
372
|
if (!Array.isArray(value) || value.length > maxItems) {
|
|
320
373
|
throw new Error(`MCP authorization field "${field}" must be an array of at most ${maxItems}`);
|
|
@@ -595,6 +648,7 @@ var MCPAuthorizationManager = class {
|
|
|
595
648
|
}
|
|
596
649
|
options;
|
|
597
650
|
pending = /* @__PURE__ */ new Map();
|
|
651
|
+
starting = /* @__PURE__ */ new Map();
|
|
598
652
|
pendingTtlMs;
|
|
599
653
|
discover;
|
|
600
654
|
exchange;
|
|
@@ -603,33 +657,48 @@ var MCPAuthorizationManager = class {
|
|
|
603
657
|
const resource = canonicalMcpResource(input.resource);
|
|
604
658
|
const key = authorizationKey(input.serverName, resource);
|
|
605
659
|
this.pruneExpired();
|
|
606
|
-
if (
|
|
660
|
+
if (this.starting.has(key)) {
|
|
661
|
+
throw new Error("MCP authorization discovery is already in progress for this server");
|
|
662
|
+
}
|
|
663
|
+
if (!this.pending.has(key) && this.activeAuthorizationCount() >= MAX_PENDING_AUTHORIZATIONS) {
|
|
607
664
|
throw new Error("Too many pending MCP authorization sessions");
|
|
608
665
|
}
|
|
609
|
-
const
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
666
|
+
const attempt = Symbol(key);
|
|
667
|
+
this.starting.set(key, attempt);
|
|
668
|
+
try {
|
|
669
|
+
const discovery = await this.discover(resource, {
|
|
670
|
+
challengeHeader: input.challengeHeader,
|
|
671
|
+
signal: input.signal
|
|
672
|
+
});
|
|
673
|
+
if (this.starting.get(key) !== attempt) {
|
|
674
|
+
throw new Error("MCP authorization discovery was cancelled");
|
|
675
|
+
}
|
|
676
|
+
const challengeScopes = parseMcpBearerChallenge(
|
|
677
|
+
input.challengeHeader ?? null,
|
|
678
|
+
resource
|
|
679
|
+
).scopes;
|
|
680
|
+
const scopes = input.scopes ? [...input.scopes] : challengeScopes;
|
|
681
|
+
const session = createMcpAuthorizationRequest({
|
|
682
|
+
authorizationServer: discovery.authorizationServer,
|
|
683
|
+
clientId: input.clientId,
|
|
684
|
+
redirectUri: input.redirectUri,
|
|
685
|
+
resource,
|
|
686
|
+
scopes
|
|
687
|
+
});
|
|
688
|
+
const normalizedScopes = new URL(session.authorizationUrl).searchParams.get("scope")?.split(" ").filter(Boolean) ?? [];
|
|
689
|
+
const expiresAt = this.now() + this.pendingTtlMs;
|
|
690
|
+
this.pending.set(key, { session, discovery, scopes: normalizedScopes, expiresAt });
|
|
691
|
+
return {
|
|
692
|
+
serverName: boundedServerName(input.serverName),
|
|
693
|
+
resource,
|
|
694
|
+
authorizationUrl: session.authorizationUrl,
|
|
695
|
+
redirectUri: session.redirectUri,
|
|
696
|
+
scopes: [...normalizedScopes],
|
|
697
|
+
expiresAt
|
|
698
|
+
};
|
|
699
|
+
} finally {
|
|
700
|
+
if (this.starting.get(key) === attempt) this.starting.delete(key);
|
|
701
|
+
}
|
|
633
702
|
}
|
|
634
703
|
async complete(input) {
|
|
635
704
|
const serverName = boundedServerName(input.serverName);
|
|
@@ -690,7 +759,9 @@ var MCPAuthorizationManager = class {
|
|
|
690
759
|
async disconnect(serverName, resource) {
|
|
691
760
|
const normalizedName = boundedServerName(serverName);
|
|
692
761
|
const normalizedResource = canonicalMcpResource(resource);
|
|
693
|
-
|
|
762
|
+
const key = authorizationKey(normalizedName, normalizedResource);
|
|
763
|
+
this.starting.delete(key);
|
|
764
|
+
this.pending.delete(key);
|
|
694
765
|
const removed = await this.options.store.remove(normalizedName, normalizedResource);
|
|
695
766
|
if (removed) {
|
|
696
767
|
this.options.onStateChange?.({
|
|
@@ -707,6 +778,13 @@ var MCPAuthorizationManager = class {
|
|
|
707
778
|
if (value.expiresAt <= now) this.pending.delete(key);
|
|
708
779
|
}
|
|
709
780
|
}
|
|
781
|
+
activeAuthorizationCount() {
|
|
782
|
+
let count = this.pending.size;
|
|
783
|
+
for (const key of this.starting.keys()) {
|
|
784
|
+
if (!this.pending.has(key)) count++;
|
|
785
|
+
}
|
|
786
|
+
return count;
|
|
787
|
+
}
|
|
710
788
|
emit(state, value) {
|
|
711
789
|
this.options.onStateChange?.({
|
|
712
790
|
serverName: value.serverName,
|
|
@@ -741,6 +819,57 @@ function boundedServerName(value) {
|
|
|
741
819
|
import { spawn as spawn2 } from "node:child_process";
|
|
742
820
|
import { buildChildEnv, buildWin32CmdShimInvocation, toErrorMessage } from "@wrongstack/core/utils";
|
|
743
821
|
|
|
822
|
+
// src/client-process.ts
|
|
823
|
+
import { spawn } from "node:child_process";
|
|
824
|
+
function forceKillTree(child) {
|
|
825
|
+
if (child.pid === void 0) {
|
|
826
|
+
try {
|
|
827
|
+
child.kill("SIGKILL");
|
|
828
|
+
} catch {
|
|
829
|
+
}
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
if (process.platform === "win32") {
|
|
833
|
+
const killer = spawn("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
|
|
834
|
+
stdio: "ignore",
|
|
835
|
+
windowsHide: true
|
|
836
|
+
});
|
|
837
|
+
killer.once("error", () => {
|
|
838
|
+
try {
|
|
839
|
+
child.kill("SIGKILL");
|
|
840
|
+
} catch {
|
|
841
|
+
}
|
|
842
|
+
});
|
|
843
|
+
killer.unref();
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
try {
|
|
847
|
+
child.kill("SIGKILL");
|
|
848
|
+
} catch {
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
// src/client-protocol-helpers.ts
|
|
853
|
+
var MAX_PROTOCOL_INPUT_CHARS = 8192;
|
|
854
|
+
function validateProtocolString(value, label, allowEmpty = false) {
|
|
855
|
+
if (typeof value !== "string" || !allowEmpty && value.length === 0) {
|
|
856
|
+
throw new Error(`MCP ${label} must be ${allowEmpty ? "a string" : "a non-empty string"}`);
|
|
857
|
+
}
|
|
858
|
+
if (value.length > MAX_PROTOCOL_INPUT_CHARS) {
|
|
859
|
+
throw new Error(`MCP ${label} exceeds ${MAX_PROTOCOL_INPUT_CHARS} characters`);
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
function pageParams(cursor, label) {
|
|
863
|
+
if (cursor === void 0) return {};
|
|
864
|
+
validateProtocolString(cursor, label);
|
|
865
|
+
return { cursor };
|
|
866
|
+
}
|
|
867
|
+
function parseEmptyResult(value) {
|
|
868
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
869
|
+
throw new Error("Malformed MCP empty result: expected object");
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
|
|
744
873
|
// src/constants.ts
|
|
745
874
|
var MCP_CONSTANTS = Object.freeze({
|
|
746
875
|
/** MCP protocol version advertised during handshake. */
|
|
@@ -2040,57 +2169,6 @@ var StreamableHTTPTransport = class extends BaseHTTPTransport {
|
|
|
2040
2169
|
}
|
|
2041
2170
|
};
|
|
2042
2171
|
|
|
2043
|
-
// src/client-protocol-helpers.ts
|
|
2044
|
-
var MAX_PROTOCOL_INPUT_CHARS = 8192;
|
|
2045
|
-
function validateProtocolString(value, label, allowEmpty = false) {
|
|
2046
|
-
if (typeof value !== "string" || !allowEmpty && value.length === 0) {
|
|
2047
|
-
throw new Error(`MCP ${label} must be ${allowEmpty ? "a string" : "a non-empty string"}`);
|
|
2048
|
-
}
|
|
2049
|
-
if (value.length > MAX_PROTOCOL_INPUT_CHARS) {
|
|
2050
|
-
throw new Error(`MCP ${label} exceeds ${MAX_PROTOCOL_INPUT_CHARS} characters`);
|
|
2051
|
-
}
|
|
2052
|
-
}
|
|
2053
|
-
function pageParams(cursor, label) {
|
|
2054
|
-
if (cursor === void 0) return {};
|
|
2055
|
-
validateProtocolString(cursor, label);
|
|
2056
|
-
return { cursor };
|
|
2057
|
-
}
|
|
2058
|
-
function parseEmptyResult(value) {
|
|
2059
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
2060
|
-
throw new Error("Malformed MCP empty result: expected object");
|
|
2061
|
-
}
|
|
2062
|
-
}
|
|
2063
|
-
|
|
2064
|
-
// src/client-process.ts
|
|
2065
|
-
import { spawn } from "node:child_process";
|
|
2066
|
-
function forceKillTree(child) {
|
|
2067
|
-
if (child.pid === void 0) {
|
|
2068
|
-
try {
|
|
2069
|
-
child.kill("SIGKILL");
|
|
2070
|
-
} catch {
|
|
2071
|
-
}
|
|
2072
|
-
return;
|
|
2073
|
-
}
|
|
2074
|
-
if (process.platform === "win32") {
|
|
2075
|
-
const killer = spawn("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
|
|
2076
|
-
stdio: "ignore",
|
|
2077
|
-
windowsHide: true
|
|
2078
|
-
});
|
|
2079
|
-
killer.once("error", () => {
|
|
2080
|
-
try {
|
|
2081
|
-
child.kill("SIGKILL");
|
|
2082
|
-
} catch {
|
|
2083
|
-
}
|
|
2084
|
-
});
|
|
2085
|
-
killer.unref();
|
|
2086
|
-
return;
|
|
2087
|
-
}
|
|
2088
|
-
try {
|
|
2089
|
-
child.kill("SIGKILL");
|
|
2090
|
-
} catch {
|
|
2091
|
-
}
|
|
2092
|
-
}
|
|
2093
|
-
|
|
2094
2172
|
// src/client.ts
|
|
2095
2173
|
var MCPClient = class _MCPClient {
|
|
2096
2174
|
constructor(opts) {
|
|
@@ -2477,7 +2555,11 @@ var MCPClient = class _MCPClient {
|
|
|
2477
2555
|
if (child.exitCode !== null || child.signalCode !== null) resolve();
|
|
2478
2556
|
});
|
|
2479
2557
|
try {
|
|
2480
|
-
child.
|
|
2558
|
+
if (process.platform === "win32" && child.stdin && !child.stdin.destroyed && child.stdin.writable) {
|
|
2559
|
+
child.stdin.end();
|
|
2560
|
+
} else {
|
|
2561
|
+
child.kill();
|
|
2562
|
+
}
|
|
2481
2563
|
} catch {
|
|
2482
2564
|
}
|
|
2483
2565
|
const GRACEFUL_MS = 800;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.305.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "WrongStack Model Context Protocol client and registry: stdio, SSE, and streamable HTTP transports.",
|
|
6
6
|
"repository": {
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"!dist/**/*.map"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@wrongstack/core": "0.
|
|
29
|
+
"@wrongstack/core": "0.305.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@types/node": "^26.1.2",
|