tiny-http-mcp-server 0.1.37 → 0.1.39
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/composition.json +1 -1
- package/node_modules/mcp-oauth/dist/client/resource-bound-store.js +13 -3
- package/node_modules/tiny-mcp-client/README.md +4 -1
- package/node_modules/tiny-mcp-client/dist/index.d.ts +11 -1
- package/node_modules/tiny-mcp-client/dist/index.js +37 -8
- package/package.json +1 -1
package/dist/composition.json
CHANGED
|
@@ -65,12 +65,22 @@ export function createResourceBoundOAuthStores(options, namespace, identity) {
|
|
|
65
65
|
return record;
|
|
66
66
|
}
|
|
67
67
|
result.sessionStore = {
|
|
68
|
-
async withLock(
|
|
68
|
+
async withLock(resource, operation, options) {
|
|
69
69
|
if (store.withLock === undefined)
|
|
70
70
|
throw new Error("OAuth resource identity backend must support transaction locks");
|
|
71
|
-
return store.withLock(
|
|
71
|
+
return store.withLock(async () => {
|
|
72
|
+
options.signal?.throwIfAborted();
|
|
73
|
+
await reconcile(resource);
|
|
74
|
+
options.signal?.throwIfAborted();
|
|
75
|
+
return operation();
|
|
76
|
+
}, options);
|
|
77
|
+
},
|
|
78
|
+
async load(resource) {
|
|
79
|
+
// Unauthorized provenance may peek before acquiring the transaction lock.
|
|
80
|
+
// Only the lock owner may adopt a URL or retire the previous credentials.
|
|
81
|
+
const record = await read();
|
|
82
|
+
return record?.resource === canonicalizeResourceIndicator(resource) ? record.session : null;
|
|
72
83
|
},
|
|
73
|
-
async load(resource) { return (await reconcile(resource)).session; },
|
|
74
84
|
async save(resource, session) {
|
|
75
85
|
const record = await reconcile(resource);
|
|
76
86
|
if (canonicalizeResourceIndicator(session.resource) !== record.resource)
|
|
@@ -37,7 +37,10 @@ by the server. Announced endpoints must remain on the original origin without
|
|
|
37
37
|
embedded credentials or fragments; endpoint changes close the connection.
|
|
38
38
|
Both transports accept the same headers, OAuth provider and response limits.
|
|
39
39
|
HTTP failures expose `HttpTransportError.status` and `.method`, so callers can
|
|
40
|
-
make transport decisions without parsing error messages.
|
|
40
|
+
make transport decisions without parsing error messages. Legacy HTTP/SSE
|
|
41
|
+
`connect()` also waits for the initialized notification POST to complete before
|
|
42
|
+
reporting ready. Completion failures reject the connection and expose
|
|
43
|
+
`rpcMethod: "notifications/initialized"`; they are not setup transport mismatches.
|
|
41
44
|
|
|
42
45
|
## OAuth HTTP support
|
|
43
46
|
|
|
@@ -641,6 +641,11 @@ interface McpTransport {
|
|
|
641
641
|
closed: Promise<McpTransportClosedEvent>;
|
|
642
642
|
dispose(reason?: Error): void;
|
|
643
643
|
filterTools?(tools: Tool[], reset?: boolean): Tool[];
|
|
644
|
+
/** Complete a legacy initialization handshake before the client reports ready. */
|
|
645
|
+
completeInitialization?(options: {
|
|
646
|
+
signal?: AbortSignal;
|
|
647
|
+
timeoutMs: number;
|
|
648
|
+
}): Promise<void>;
|
|
644
649
|
}
|
|
645
650
|
interface InMemoryServerTransport {
|
|
646
651
|
readable: Readable;
|
|
@@ -676,7 +681,8 @@ type HttpTransportFetch = (input: string | URL, init?: RequestInit) => Promise<R
|
|
|
676
681
|
declare class HttpTransportError extends Error {
|
|
677
682
|
readonly status: number;
|
|
678
683
|
readonly method: "GET" | "POST" | "DELETE";
|
|
679
|
-
|
|
684
|
+
readonly rpcMethod?: string | undefined;
|
|
685
|
+
constructor(message: string, status: number, method: "GET" | "POST" | "DELETE", rpcMethod?: string | undefined);
|
|
680
686
|
}
|
|
681
687
|
interface HttpTransportOptions {
|
|
682
688
|
url: string;
|
|
@@ -733,6 +739,10 @@ declare class HttpTransport implements McpTransport {
|
|
|
733
739
|
private readonly toolParameterHeaders;
|
|
734
740
|
private readonly onWarning;
|
|
735
741
|
constructor({ url, mode, headers, fetch: fetchImpl, oauth, oauthDiscoveryCache, onWarning, maxResponseBytes, }: HttpTransportOptions);
|
|
742
|
+
completeInitialization(options: {
|
|
743
|
+
signal?: AbortSignal;
|
|
744
|
+
timeoutMs: number;
|
|
745
|
+
}): Promise<void>;
|
|
736
746
|
filterTools(tools: Tool[], reset?: boolean): Tool[];
|
|
737
747
|
dispose(reason?: Error): void;
|
|
738
748
|
private closeWithSessionTermination;
|
|
@@ -4771,13 +4771,19 @@ function createResourceBoundOAuthStores(options, namespace, identity) {
|
|
|
4771
4771
|
return record2;
|
|
4772
4772
|
}
|
|
4773
4773
|
result.sessionStore = {
|
|
4774
|
-
async withLock(
|
|
4774
|
+
async withLock(resource, operation, options2) {
|
|
4775
4775
|
if (store.withLock === void 0)
|
|
4776
4776
|
throw new Error("OAuth resource identity backend must support transaction locks");
|
|
4777
|
-
return store.withLock(
|
|
4777
|
+
return store.withLock(async () => {
|
|
4778
|
+
options2.signal?.throwIfAborted();
|
|
4779
|
+
await reconcile(resource);
|
|
4780
|
+
options2.signal?.throwIfAborted();
|
|
4781
|
+
return operation();
|
|
4782
|
+
}, options2);
|
|
4778
4783
|
},
|
|
4779
4784
|
async load(resource) {
|
|
4780
|
-
|
|
4785
|
+
const record2 = await read();
|
|
4786
|
+
return record2?.resource === canonicalizeResourceIndicator(resource) ? record2.session : null;
|
|
4781
4787
|
},
|
|
4782
4788
|
async save(resource, session) {
|
|
4783
4789
|
const record2 = await reconcile(resource);
|
|
@@ -6782,7 +6788,8 @@ var McpClient = class {
|
|
|
6782
6788
|
async (params, context) => this.options.onElicitationRequest(params, context)
|
|
6783
6789
|
);
|
|
6784
6790
|
}
|
|
6785
|
-
messageLayer.sendNotification("notifications/initialized");
|
|
6791
|
+
if (transport.completeInitialization === void 0) messageLayer.sendNotification("notifications/initialized");
|
|
6792
|
+
else await transport.completeInitialization({ signal: options.signal, timeoutMs: this.options.requestTimeoutMs ?? 3e4 });
|
|
6786
6793
|
this.currentState = "ready";
|
|
6787
6794
|
return initializeResult;
|
|
6788
6795
|
} catch (error) {
|
|
@@ -7282,14 +7289,16 @@ async function createTestPair(server, createClient) {
|
|
|
7282
7289
|
return { client, cleanup };
|
|
7283
7290
|
}
|
|
7284
7291
|
var HttpTransportError = class extends Error {
|
|
7285
|
-
constructor(message, status, method) {
|
|
7292
|
+
constructor(message, status, method, rpcMethod) {
|
|
7286
7293
|
super(message);
|
|
7287
7294
|
this.status = status;
|
|
7288
7295
|
this.method = method;
|
|
7296
|
+
this.rpcMethod = rpcMethod;
|
|
7289
7297
|
this.name = "HttpTransportError";
|
|
7290
7298
|
}
|
|
7291
7299
|
status;
|
|
7292
7300
|
method;
|
|
7301
|
+
rpcMethod;
|
|
7293
7302
|
};
|
|
7294
7303
|
function defaultStdioSpawn(command, args, options) {
|
|
7295
7304
|
return spawn2(command, args, options);
|
|
@@ -7464,6 +7473,21 @@ var HttpTransport = class {
|
|
|
7464
7473
|
this.dispose(error instanceof Error ? error : new Error(String(error)));
|
|
7465
7474
|
});
|
|
7466
7475
|
}
|
|
7476
|
+
async completeInitialization(options) {
|
|
7477
|
+
const deadline = options.timeoutMs > 0 ? AbortSignal.timeout(Math.ceil(options.timeoutMs)) : void 0;
|
|
7478
|
+
const signals = [options.signal, deadline].filter((signal2) => signal2 !== void 0);
|
|
7479
|
+
const signal = signals.length === 0 ? new AbortController().signal : AbortSignal.any(signals);
|
|
7480
|
+
signal.throwIfAborted();
|
|
7481
|
+
try {
|
|
7482
|
+
await this.sendPost(serializeJsonRpcMessage({ jsonrpc: "2.0", method: "notifications/initialized" }), signal);
|
|
7483
|
+
signal.throwIfAborted();
|
|
7484
|
+
if (this.disposed) throw (await this.closed).reason;
|
|
7485
|
+
} catch (error) {
|
|
7486
|
+
if (error instanceof HttpTransportError)
|
|
7487
|
+
throw new HttpTransportError(error.message, error.status, error.method, "notifications/initialized");
|
|
7488
|
+
throw error;
|
|
7489
|
+
}
|
|
7490
|
+
}
|
|
7467
7491
|
filterTools(tools, reset = true) {
|
|
7468
7492
|
if (reset) this.toolParameterHeaders.clear();
|
|
7469
7493
|
const accepted = [];
|
|
@@ -7575,7 +7599,8 @@ var HttpTransport = class {
|
|
|
7575
7599
|
}
|
|
7576
7600
|
}
|
|
7577
7601
|
}
|
|
7578
|
-
async sendPost(line) {
|
|
7602
|
+
async sendPost(line, signal) {
|
|
7603
|
+
signal?.throwIfAborted();
|
|
7579
7604
|
const parsed = parseJsonRpcMessage(line);
|
|
7580
7605
|
const message = parsed.type === "request" || parsed.type === "notification" ? parsed.message : void 0;
|
|
7581
7606
|
const metadata = isObjectRecord5(message?.params) ? message.params._meta : void 0;
|
|
@@ -7589,7 +7614,10 @@ var HttpTransport = class {
|
|
|
7589
7614
|
this.modernRequests.get(requestId)?.abort();
|
|
7590
7615
|
return;
|
|
7591
7616
|
}
|
|
7592
|
-
const controller = modern && parsed.type === "request" ? new AbortController() : void 0;
|
|
7617
|
+
const controller = modern && parsed.type === "request" || signal !== void 0 ? new AbortController() : void 0;
|
|
7618
|
+
const aborted = () => controller?.abort(signal?.reason);
|
|
7619
|
+
signal?.addEventListener("abort", aborted, { once: true });
|
|
7620
|
+
if (signal?.aborted) aborted();
|
|
7593
7621
|
const id = parsed.type === "request" ? parsed.message.id : void 0;
|
|
7594
7622
|
if (controller !== void 0 && id !== void 0) this.modernRequests.set(id, controller);
|
|
7595
7623
|
try {
|
|
@@ -7598,7 +7626,7 @@ var HttpTransport = class {
|
|
|
7598
7626
|
const response = await this.fetchWithOAuthRetry({
|
|
7599
7627
|
url: postUrl,
|
|
7600
7628
|
method: "POST",
|
|
7601
|
-
createHeaders: (
|
|
7629
|
+
createHeaders: (signal2) => this.createPostHeaders(message, modern, signal2),
|
|
7602
7630
|
body: line,
|
|
7603
7631
|
controller
|
|
7604
7632
|
});
|
|
@@ -7634,6 +7662,7 @@ var HttpTransport = class {
|
|
|
7634
7662
|
} catch (error) {
|
|
7635
7663
|
if (!controller?.signal.aborted) throw error;
|
|
7636
7664
|
} finally {
|
|
7665
|
+
signal?.removeEventListener("abort", aborted);
|
|
7637
7666
|
if (id !== void 0 && this.modernRequests.get(id) === controller)
|
|
7638
7667
|
this.modernRequests.delete(id);
|
|
7639
7668
|
}
|