tiny-http-mcp-server 0.1.38 → 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.
@@ -18,7 +18,7 @@
18
18
  },
19
19
  {
20
20
  "name": "tiny-http-mcp-server",
21
- "version": "0.1.38",
21
+ "version": "0.1.39",
22
22
  "license": "MIT"
23
23
  },
24
24
  {
@@ -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
- constructor(message: string, status: number, method: "GET" | "POST" | "DELETE");
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;
@@ -6788,7 +6788,8 @@ var McpClient = class {
6788
6788
  async (params, context) => this.options.onElicitationRequest(params, context)
6789
6789
  );
6790
6790
  }
6791
- 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 });
6792
6793
  this.currentState = "ready";
6793
6794
  return initializeResult;
6794
6795
  } catch (error) {
@@ -7288,14 +7289,16 @@ async function createTestPair(server, createClient) {
7288
7289
  return { client, cleanup };
7289
7290
  }
7290
7291
  var HttpTransportError = class extends Error {
7291
- constructor(message, status, method) {
7292
+ constructor(message, status, method, rpcMethod) {
7292
7293
  super(message);
7293
7294
  this.status = status;
7294
7295
  this.method = method;
7296
+ this.rpcMethod = rpcMethod;
7295
7297
  this.name = "HttpTransportError";
7296
7298
  }
7297
7299
  status;
7298
7300
  method;
7301
+ rpcMethod;
7299
7302
  };
7300
7303
  function defaultStdioSpawn(command, args, options) {
7301
7304
  return spawn2(command, args, options);
@@ -7470,6 +7473,21 @@ var HttpTransport = class {
7470
7473
  this.dispose(error instanceof Error ? error : new Error(String(error)));
7471
7474
  });
7472
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
+ }
7473
7491
  filterTools(tools, reset = true) {
7474
7492
  if (reset) this.toolParameterHeaders.clear();
7475
7493
  const accepted = [];
@@ -7581,7 +7599,8 @@ var HttpTransport = class {
7581
7599
  }
7582
7600
  }
7583
7601
  }
7584
- async sendPost(line) {
7602
+ async sendPost(line, signal) {
7603
+ signal?.throwIfAborted();
7585
7604
  const parsed = parseJsonRpcMessage(line);
7586
7605
  const message = parsed.type === "request" || parsed.type === "notification" ? parsed.message : void 0;
7587
7606
  const metadata = isObjectRecord5(message?.params) ? message.params._meta : void 0;
@@ -7595,7 +7614,10 @@ var HttpTransport = class {
7595
7614
  this.modernRequests.get(requestId)?.abort();
7596
7615
  return;
7597
7616
  }
7598
- 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();
7599
7621
  const id = parsed.type === "request" ? parsed.message.id : void 0;
7600
7622
  if (controller !== void 0 && id !== void 0) this.modernRequests.set(id, controller);
7601
7623
  try {
@@ -7604,7 +7626,7 @@ var HttpTransport = class {
7604
7626
  const response = await this.fetchWithOAuthRetry({
7605
7627
  url: postUrl,
7606
7628
  method: "POST",
7607
- createHeaders: (signal) => this.createPostHeaders(message, modern, signal),
7629
+ createHeaders: (signal2) => this.createPostHeaders(message, modern, signal2),
7608
7630
  body: line,
7609
7631
  controller
7610
7632
  });
@@ -7640,6 +7662,7 @@ var HttpTransport = class {
7640
7662
  } catch (error) {
7641
7663
  if (!controller?.signal.aborted) throw error;
7642
7664
  } finally {
7665
+ signal?.removeEventListener("abort", aborted);
7643
7666
  if (id !== void 0 && this.modernRequests.get(id) === controller)
7644
7667
  this.modernRequests.delete(id);
7645
7668
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiny-http-mcp-server",
3
- "version": "0.1.38",
3
+ "version": "0.1.39",
4
4
  "description": "Minimal MCP server over HTTP built on tiny-stdio-mcp-server",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",