@adapt-toolkit/a2adapt 0.2.0 → 0.3.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/index.js CHANGED
@@ -1317,11 +1317,11 @@ var require_errors = __commonJS({
1317
1317
  gen.code((0, codegen_1._)`${names_1.default.errors}++`);
1318
1318
  }
1319
1319
  function returnErrors(it, errs) {
1320
- const { gen, validateName, schemaEnv } = it;
1320
+ const { gen, validateName: validateName2, schemaEnv } = it;
1321
1321
  if (schemaEnv.$async) {
1322
1322
  gen.throw((0, codegen_1._)`new ${it.ValidationError}(${errs})`);
1323
1323
  } else {
1324
- gen.assign((0, codegen_1._)`${validateName}.errors`, errs);
1324
+ gen.assign((0, codegen_1._)`${validateName2}.errors`, errs);
1325
1325
  gen.return(false);
1326
1326
  }
1327
1327
  }
@@ -1390,13 +1390,13 @@ var require_boolSchema = __commonJS({
1390
1390
  message: "boolean schema is false"
1391
1391
  };
1392
1392
  function topBoolOrEmptySchema(it) {
1393
- const { gen, schema, validateName } = it;
1393
+ const { gen, schema, validateName: validateName2 } = it;
1394
1394
  if (schema === false) {
1395
1395
  falseSchemaError(it, false);
1396
1396
  } else if (typeof schema == "object" && schema.$async === true) {
1397
1397
  gen.return(names_1.default.data);
1398
1398
  } else {
1399
- gen.assign((0, codegen_1._)`${validateName}.errors`, null);
1399
+ gen.assign((0, codegen_1._)`${validateName2}.errors`, null);
1400
1400
  gen.return(true);
1401
1401
  }
1402
1402
  }
@@ -2345,15 +2345,15 @@ var require_validate = __commonJS({
2345
2345
  validateFunction(it, () => (0, boolSchema_1.topBoolOrEmptySchema)(it));
2346
2346
  }
2347
2347
  exports.validateFunctionCode = validateFunctionCode;
2348
- function validateFunction({ gen, validateName, schema, schemaEnv, opts }, body) {
2348
+ function validateFunction({ gen, validateName: validateName2, schema, schemaEnv, opts }, body) {
2349
2349
  if (opts.code.es5) {
2350
- gen.func(validateName, (0, codegen_1._)`${names_1.default.data}, ${names_1.default.valCxt}`, schemaEnv.$async, () => {
2350
+ gen.func(validateName2, (0, codegen_1._)`${names_1.default.data}, ${names_1.default.valCxt}`, schemaEnv.$async, () => {
2351
2351
  gen.code((0, codegen_1._)`"use strict"; ${funcSourceUrl(schema, opts)}`);
2352
2352
  destructureValCxtES5(gen, opts);
2353
2353
  gen.code(body);
2354
2354
  });
2355
2355
  } else {
2356
- gen.func(validateName, (0, codegen_1._)`${names_1.default.data}, ${destructureValCxt(opts)}`, schemaEnv.$async, () => gen.code(funcSourceUrl(schema, opts)).code(body));
2356
+ gen.func(validateName2, (0, codegen_1._)`${names_1.default.data}, ${destructureValCxt(opts)}`, schemaEnv.$async, () => gen.code(funcSourceUrl(schema, opts)).code(body));
2357
2357
  }
2358
2358
  }
2359
2359
  function destructureValCxt(opts) {
@@ -2392,8 +2392,8 @@ var require_validate = __commonJS({
2392
2392
  return;
2393
2393
  }
2394
2394
  function resetEvaluated(it) {
2395
- const { gen, validateName } = it;
2396
- it.evaluated = gen.const("evaluated", (0, codegen_1._)`${validateName}.evaluated`);
2395
+ const { gen, validateName: validateName2 } = it;
2396
+ it.evaluated = gen.const("evaluated", (0, codegen_1._)`${validateName2}.evaluated`);
2397
2397
  gen.if((0, codegen_1._)`${it.evaluated}.dynamicProps`, () => gen.assign((0, codegen_1._)`${it.evaluated}.props`, (0, codegen_1._)`undefined`));
2398
2398
  gen.if((0, codegen_1._)`${it.evaluated}.dynamicItems`, () => gen.assign((0, codegen_1._)`${it.evaluated}.items`, (0, codegen_1._)`undefined`));
2399
2399
  }
@@ -2475,11 +2475,11 @@ var require_validate = __commonJS({
2475
2475
  }
2476
2476
  }
2477
2477
  function returnResults(it) {
2478
- const { gen, schemaEnv, validateName, ValidationError, opts } = it;
2478
+ const { gen, schemaEnv, validateName: validateName2, ValidationError, opts } = it;
2479
2479
  if (schemaEnv.$async) {
2480
2480
  gen.if((0, codegen_1._)`${names_1.default.errors} === 0`, () => gen.return(names_1.default.data), () => gen.throw((0, codegen_1._)`new ${ValidationError}(${names_1.default.vErrors})`));
2481
2481
  } else {
2482
- gen.assign((0, codegen_1._)`${validateName}.errors`, names_1.default.vErrors);
2482
+ gen.assign((0, codegen_1._)`${validateName2}.errors`, names_1.default.vErrors);
2483
2483
  if (opts.unevaluated)
2484
2484
  assignEvaluated(it);
2485
2485
  gen.return((0, codegen_1._)`${names_1.default.errors} === 0`);
@@ -2904,8 +2904,8 @@ var require_compile = __commonJS({
2904
2904
  code: (0, codegen_1._)`require("ajv/dist/runtime/validation_error").default`
2905
2905
  });
2906
2906
  }
2907
- const validateName = gen.scopeName("validate");
2908
- sch.validateName = validateName;
2907
+ const validateName2 = gen.scopeName("validate");
2908
+ sch.validateName = validateName2;
2909
2909
  const schemaCxt = {
2910
2910
  gen,
2911
2911
  allErrors: this.opts.allErrors,
@@ -2919,7 +2919,7 @@ var require_compile = __commonJS({
2919
2919
  dataTypes: [],
2920
2920
  definedProperties: /* @__PURE__ */ new Set(),
2921
2921
  topSchemaRef: gen.scopeValue("schema", this.opts.code.source === true ? { ref: sch.schema, code: (0, codegen_1.stringify)(sch.schema) } : { ref: sch.schema }),
2922
- validateName,
2922
+ validateName: validateName2,
2923
2923
  ValidationError: _ValidationError,
2924
2924
  schema: sch.schema,
2925
2925
  schemaEnv: sch,
@@ -2942,14 +2942,14 @@ var require_compile = __commonJS({
2942
2942
  sourceCode = this.opts.code.process(sourceCode, sch);
2943
2943
  const makeValidate = new Function(`${names_1.default.self}`, `${names_1.default.scope}`, sourceCode);
2944
2944
  const validate = makeValidate(this, this.scope.get());
2945
- this.scope.value(validateName, { ref: validate });
2945
+ this.scope.value(validateName2, { ref: validate });
2946
2946
  validate.errors = null;
2947
2947
  validate.schema = sch.schema;
2948
2948
  validate.schemaEnv = sch;
2949
2949
  if (sch.$async)
2950
2950
  validate.$async = true;
2951
2951
  if (this.opts.code.source === true) {
2952
- validate.source = { validateName, validateCode, scopeValues: gen._values };
2952
+ validate.source = { validateName: validateName2, validateCode, scopeValues: gen._values };
2953
2953
  }
2954
2954
  if (this.opts.unevaluated) {
2955
2955
  const { props, items } = schemaCxt;
@@ -4235,8 +4235,8 @@ var require_core = __commonJS({
4235
4235
  return this;
4236
4236
  }
4237
4237
  case "object": {
4238
- const cacheKey = schemaKeyRef;
4239
- this._cache.delete(cacheKey);
4238
+ const cacheKey2 = schemaKeyRef;
4239
+ this._cache.delete(cacheKey2);
4240
4240
  let id = schemaKeyRef[this.opts.schemaId];
4241
4241
  if (id) {
4242
4242
  id = (0, resolve_1.normalizeId)(id);
@@ -4401,11 +4401,11 @@ var require_core = __commonJS({
4401
4401
  Ajv2.ValidationError = validation_error_1.default;
4402
4402
  Ajv2.MissingRefError = ref_error_1.default;
4403
4403
  exports.default = Ajv2;
4404
- function checkOptions(checkOpts, options, msg, log = "error") {
4404
+ function checkOptions(checkOpts, options, msg, log2 = "error") {
4405
4405
  for (const key in checkOpts) {
4406
4406
  const opt = key;
4407
4407
  if (opt in options)
4408
- this.logger[log](`${msg}: option ${key}. ${checkOpts[opt]}`);
4408
+ this.logger[log2](`${msg}: option ${key}. ${checkOpts[opt]}`);
4409
4409
  }
4410
4410
  }
4411
4411
  function getSchEnv(keyRef) {
@@ -4563,7 +4563,7 @@ var require_ref = __commonJS({
4563
4563
  schemaType: "string",
4564
4564
  code(cxt) {
4565
4565
  const { gen, schema: $ref, it } = cxt;
4566
- const { baseId, schemaEnv: env, validateName, opts, self } = it;
4566
+ const { baseId, schemaEnv: env, validateName: validateName2, opts, self } = it;
4567
4567
  const { root } = env;
4568
4568
  if (($ref === "#" || $ref === "#/") && baseId === root.baseId)
4569
4569
  return callRootRef();
@@ -4575,7 +4575,7 @@ var require_ref = __commonJS({
4575
4575
  return inlineRefSchema(schOrEnv);
4576
4576
  function callRootRef() {
4577
4577
  if (env === root)
4578
- return callRef(cxt, validateName, env, env.$async);
4578
+ return callRef(cxt, validateName2, env, env.$async);
4579
4579
  const rootName = gen.scopeValue("root", { ref: root });
4580
4580
  return callRef(cxt, (0, codegen_1._)`${rootName}.validate`, root, root.$async);
4581
4581
  }
@@ -6873,12 +6873,12 @@ var require_dist = __commonJS({
6873
6873
  throw new Error(`Unknown format "${name}"`);
6874
6874
  return f;
6875
6875
  };
6876
- function addFormats(ajv, list, fs, exportName) {
6876
+ function addFormats(ajv, list, fs2, exportName) {
6877
6877
  var _a;
6878
6878
  var _b;
6879
6879
  (_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
6880
6880
  for (const f of list)
6881
- ajv.addFormat(f, fs[f]);
6881
+ ajv.addFormat(f, fs2[f]);
6882
6882
  }
6883
6883
  module.exports = exports = formatsPlugin;
6884
6884
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -15620,6 +15620,7 @@ config(en_default2());
15620
15620
 
15621
15621
  // ../node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
15622
15622
  var LATEST_PROTOCOL_VERSION = "2025-11-25";
15623
+ var DEFAULT_NEGOTIATED_PROTOCOL_VERSION = "2025-03-26";
15623
15624
  var SUPPORTED_PROTOCOL_VERSIONS = [LATEST_PROTOCOL_VERSION, "2025-06-18", "2025-03-26", "2024-11-05", "2024-10-07"];
15624
15625
  var RELATED_TASK_META_KEY = "io.modelcontextprotocol/related-task";
15625
15626
  var JSONRPC_VERSION = "2.0";
@@ -15948,6 +15949,7 @@ var InitializeRequestSchema = RequestSchema.extend({
15948
15949
  method: literal("initialize"),
15949
15950
  params: InitializeRequestParamsSchema
15950
15951
  });
15952
+ var isInitializeRequest = (value) => InitializeRequestSchema.safeParse(value).success;
15951
15953
  var ServerCapabilitiesSchema = object2({
15952
15954
  /**
15953
15955
  * Experimental, non-standard capabilities that the server supports.
@@ -21099,81 +21101,2040 @@ var StdioServerTransport = class {
21099
21101
  }
21100
21102
  };
21101
21103
 
21104
+ // ../node_modules/@hono/node-server/dist/index.mjs
21105
+ import { Http2ServerRequest as Http2ServerRequest2, constants as h2constants } from "http2";
21106
+ import { Http2ServerRequest } from "http2";
21107
+ import { Readable } from "stream";
21108
+ import crypto2 from "crypto";
21109
+ var RequestError = class extends Error {
21110
+ constructor(message, options) {
21111
+ super(message, options);
21112
+ this.name = "RequestError";
21113
+ }
21114
+ };
21115
+ var toRequestError = (e) => {
21116
+ if (e instanceof RequestError) {
21117
+ return e;
21118
+ }
21119
+ return new RequestError(e.message, { cause: e });
21120
+ };
21121
+ var GlobalRequest = global.Request;
21122
+ var Request = class extends GlobalRequest {
21123
+ constructor(input, options) {
21124
+ if (typeof input === "object" && getRequestCache in input) {
21125
+ input = input[getRequestCache]();
21126
+ }
21127
+ if (typeof options?.body?.getReader !== "undefined") {
21128
+ ;
21129
+ options.duplex ??= "half";
21130
+ }
21131
+ super(input, options);
21132
+ }
21133
+ };
21134
+ var newHeadersFromIncoming = (incoming) => {
21135
+ const headerRecord = [];
21136
+ const rawHeaders = incoming.rawHeaders;
21137
+ for (let i = 0; i < rawHeaders.length; i += 2) {
21138
+ const { [i]: key, [i + 1]: value } = rawHeaders;
21139
+ if (key.charCodeAt(0) !== /*:*/
21140
+ 58) {
21141
+ headerRecord.push([key, value]);
21142
+ }
21143
+ }
21144
+ return new Headers(headerRecord);
21145
+ };
21146
+ var wrapBodyStream = Symbol("wrapBodyStream");
21147
+ var newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
21148
+ const init = {
21149
+ method,
21150
+ headers,
21151
+ signal: abortController.signal
21152
+ };
21153
+ if (method === "TRACE") {
21154
+ init.method = "GET";
21155
+ const req = new Request(url, init);
21156
+ Object.defineProperty(req, "method", {
21157
+ get() {
21158
+ return "TRACE";
21159
+ }
21160
+ });
21161
+ return req;
21162
+ }
21163
+ if (!(method === "GET" || method === "HEAD")) {
21164
+ if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) {
21165
+ init.body = new ReadableStream({
21166
+ start(controller) {
21167
+ controller.enqueue(incoming.rawBody);
21168
+ controller.close();
21169
+ }
21170
+ });
21171
+ } else if (incoming[wrapBodyStream]) {
21172
+ let reader;
21173
+ init.body = new ReadableStream({
21174
+ async pull(controller) {
21175
+ try {
21176
+ reader ||= Readable.toWeb(incoming).getReader();
21177
+ const { done, value } = await reader.read();
21178
+ if (done) {
21179
+ controller.close();
21180
+ } else {
21181
+ controller.enqueue(value);
21182
+ }
21183
+ } catch (error2) {
21184
+ controller.error(error2);
21185
+ }
21186
+ }
21187
+ });
21188
+ } else {
21189
+ init.body = Readable.toWeb(incoming);
21190
+ }
21191
+ }
21192
+ return new Request(url, init);
21193
+ };
21194
+ var getRequestCache = Symbol("getRequestCache");
21195
+ var requestCache = Symbol("requestCache");
21196
+ var incomingKey = Symbol("incomingKey");
21197
+ var urlKey = Symbol("urlKey");
21198
+ var headersKey = Symbol("headersKey");
21199
+ var abortControllerKey = Symbol("abortControllerKey");
21200
+ var getAbortController = Symbol("getAbortController");
21201
+ var requestPrototype = {
21202
+ get method() {
21203
+ return this[incomingKey].method || "GET";
21204
+ },
21205
+ get url() {
21206
+ return this[urlKey];
21207
+ },
21208
+ get headers() {
21209
+ return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
21210
+ },
21211
+ [getAbortController]() {
21212
+ this[getRequestCache]();
21213
+ return this[abortControllerKey];
21214
+ },
21215
+ [getRequestCache]() {
21216
+ this[abortControllerKey] ||= new AbortController();
21217
+ return this[requestCache] ||= newRequestFromIncoming(
21218
+ this.method,
21219
+ this[urlKey],
21220
+ this.headers,
21221
+ this[incomingKey],
21222
+ this[abortControllerKey]
21223
+ );
21224
+ }
21225
+ };
21226
+ [
21227
+ "body",
21228
+ "bodyUsed",
21229
+ "cache",
21230
+ "credentials",
21231
+ "destination",
21232
+ "integrity",
21233
+ "mode",
21234
+ "redirect",
21235
+ "referrer",
21236
+ "referrerPolicy",
21237
+ "signal",
21238
+ "keepalive"
21239
+ ].forEach((k) => {
21240
+ Object.defineProperty(requestPrototype, k, {
21241
+ get() {
21242
+ return this[getRequestCache]()[k];
21243
+ }
21244
+ });
21245
+ });
21246
+ ["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
21247
+ Object.defineProperty(requestPrototype, k, {
21248
+ value: function() {
21249
+ return this[getRequestCache]()[k]();
21250
+ }
21251
+ });
21252
+ });
21253
+ Object.defineProperty(requestPrototype, Symbol.for("nodejs.util.inspect.custom"), {
21254
+ value: function(depth, options, inspectFn) {
21255
+ const props = {
21256
+ method: this.method,
21257
+ url: this.url,
21258
+ headers: this.headers,
21259
+ nativeRequest: this[requestCache]
21260
+ };
21261
+ return `Request (lightweight) ${inspectFn(props, { ...options, depth: depth == null ? null : depth - 1 })}`;
21262
+ }
21263
+ });
21264
+ Object.setPrototypeOf(requestPrototype, Request.prototype);
21265
+ var newRequest = (incoming, defaultHostname) => {
21266
+ const req = Object.create(requestPrototype);
21267
+ req[incomingKey] = incoming;
21268
+ const incomingUrl = incoming.url || "";
21269
+ if (incomingUrl[0] !== "/" && // short-circuit for performance. most requests are relative URL.
21270
+ (incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) {
21271
+ if (incoming instanceof Http2ServerRequest) {
21272
+ throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
21273
+ }
21274
+ try {
21275
+ const url2 = new URL(incomingUrl);
21276
+ req[urlKey] = url2.href;
21277
+ } catch (e) {
21278
+ throw new RequestError("Invalid absolute URL", { cause: e });
21279
+ }
21280
+ return req;
21281
+ }
21282
+ const host = (incoming instanceof Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;
21283
+ if (!host) {
21284
+ throw new RequestError("Missing host header");
21285
+ }
21286
+ let scheme;
21287
+ if (incoming instanceof Http2ServerRequest) {
21288
+ scheme = incoming.scheme;
21289
+ if (!(scheme === "http" || scheme === "https")) {
21290
+ throw new RequestError("Unsupported scheme");
21291
+ }
21292
+ } else {
21293
+ scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
21294
+ }
21295
+ const url = new URL(`${scheme}://${host}${incomingUrl}`);
21296
+ if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
21297
+ throw new RequestError("Invalid host header");
21298
+ }
21299
+ req[urlKey] = url.href;
21300
+ return req;
21301
+ };
21302
+ var responseCache = Symbol("responseCache");
21303
+ var getResponseCache = Symbol("getResponseCache");
21304
+ var cacheKey = Symbol("cache");
21305
+ var GlobalResponse = global.Response;
21306
+ var Response2 = class _Response {
21307
+ #body;
21308
+ #init;
21309
+ [getResponseCache]() {
21310
+ delete this[cacheKey];
21311
+ return this[responseCache] ||= new GlobalResponse(this.#body, this.#init);
21312
+ }
21313
+ constructor(body, init) {
21314
+ let headers;
21315
+ this.#body = body;
21316
+ if (init instanceof _Response) {
21317
+ const cachedGlobalResponse = init[responseCache];
21318
+ if (cachedGlobalResponse) {
21319
+ this.#init = cachedGlobalResponse;
21320
+ this[getResponseCache]();
21321
+ return;
21322
+ } else {
21323
+ this.#init = init.#init;
21324
+ headers = new Headers(init.#init.headers);
21325
+ }
21326
+ } else {
21327
+ this.#init = init;
21328
+ }
21329
+ if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) {
21330
+ ;
21331
+ this[cacheKey] = [init?.status || 200, body, headers || init?.headers];
21332
+ }
21333
+ }
21334
+ get headers() {
21335
+ const cache = this[cacheKey];
21336
+ if (cache) {
21337
+ if (!(cache[2] instanceof Headers)) {
21338
+ cache[2] = new Headers(
21339
+ cache[2] || { "content-type": "text/plain; charset=UTF-8" }
21340
+ );
21341
+ }
21342
+ return cache[2];
21343
+ }
21344
+ return this[getResponseCache]().headers;
21345
+ }
21346
+ get status() {
21347
+ return this[cacheKey]?.[0] ?? this[getResponseCache]().status;
21348
+ }
21349
+ get ok() {
21350
+ const status = this.status;
21351
+ return status >= 200 && status < 300;
21352
+ }
21353
+ };
21354
+ ["body", "bodyUsed", "redirected", "statusText", "trailers", "type", "url"].forEach((k) => {
21355
+ Object.defineProperty(Response2.prototype, k, {
21356
+ get() {
21357
+ return this[getResponseCache]()[k];
21358
+ }
21359
+ });
21360
+ });
21361
+ ["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
21362
+ Object.defineProperty(Response2.prototype, k, {
21363
+ value: function() {
21364
+ return this[getResponseCache]()[k]();
21365
+ }
21366
+ });
21367
+ });
21368
+ Object.defineProperty(Response2.prototype, Symbol.for("nodejs.util.inspect.custom"), {
21369
+ value: function(depth, options, inspectFn) {
21370
+ const props = {
21371
+ status: this.status,
21372
+ headers: this.headers,
21373
+ ok: this.ok,
21374
+ nativeResponse: this[responseCache]
21375
+ };
21376
+ return `Response (lightweight) ${inspectFn(props, { ...options, depth: depth == null ? null : depth - 1 })}`;
21377
+ }
21378
+ });
21379
+ Object.setPrototypeOf(Response2, GlobalResponse);
21380
+ Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
21381
+ async function readWithoutBlocking(readPromise) {
21382
+ return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
21383
+ }
21384
+ function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
21385
+ const cancel = (error2) => {
21386
+ reader.cancel(error2).catch(() => {
21387
+ });
21388
+ };
21389
+ writable.on("close", cancel);
21390
+ writable.on("error", cancel);
21391
+ (currentReadPromise ?? reader.read()).then(flow, handleStreamError);
21392
+ return reader.closed.finally(() => {
21393
+ writable.off("close", cancel);
21394
+ writable.off("error", cancel);
21395
+ });
21396
+ function handleStreamError(error2) {
21397
+ if (error2) {
21398
+ writable.destroy(error2);
21399
+ }
21400
+ }
21401
+ function onDrain() {
21402
+ reader.read().then(flow, handleStreamError);
21403
+ }
21404
+ function flow({ done, value }) {
21405
+ try {
21406
+ if (done) {
21407
+ writable.end();
21408
+ } else if (!writable.write(value)) {
21409
+ writable.once("drain", onDrain);
21410
+ } else {
21411
+ return reader.read().then(flow, handleStreamError);
21412
+ }
21413
+ } catch (e) {
21414
+ handleStreamError(e);
21415
+ }
21416
+ }
21417
+ }
21418
+ function writeFromReadableStream(stream, writable) {
21419
+ if (stream.locked) {
21420
+ throw new TypeError("ReadableStream is locked.");
21421
+ } else if (writable.destroyed) {
21422
+ return;
21423
+ }
21424
+ return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
21425
+ }
21426
+ var buildOutgoingHttpHeaders = (headers) => {
21427
+ const res = {};
21428
+ if (!(headers instanceof Headers)) {
21429
+ headers = new Headers(headers ?? void 0);
21430
+ }
21431
+ const cookies = [];
21432
+ for (const [k, v] of headers) {
21433
+ if (k === "set-cookie") {
21434
+ cookies.push(v);
21435
+ } else {
21436
+ res[k] = v;
21437
+ }
21438
+ }
21439
+ if (cookies.length > 0) {
21440
+ res["set-cookie"] = cookies;
21441
+ }
21442
+ res["content-type"] ??= "text/plain; charset=UTF-8";
21443
+ return res;
21444
+ };
21445
+ var X_ALREADY_SENT = "x-hono-already-sent";
21446
+ if (typeof global.crypto === "undefined") {
21447
+ global.crypto = crypto2;
21448
+ }
21449
+ var outgoingEnded = Symbol("outgoingEnded");
21450
+ var incomingDraining = Symbol("incomingDraining");
21451
+ var DRAIN_TIMEOUT_MS = 500;
21452
+ var MAX_DRAIN_BYTES = 64 * 1024 * 1024;
21453
+ var drainIncoming = (incoming) => {
21454
+ const incomingWithDrainState = incoming;
21455
+ if (incoming.destroyed || incomingWithDrainState[incomingDraining]) {
21456
+ return;
21457
+ }
21458
+ incomingWithDrainState[incomingDraining] = true;
21459
+ if (incoming instanceof Http2ServerRequest2) {
21460
+ try {
21461
+ ;
21462
+ incoming.stream?.close?.(h2constants.NGHTTP2_NO_ERROR);
21463
+ } catch {
21464
+ }
21465
+ return;
21466
+ }
21467
+ let bytesRead = 0;
21468
+ const cleanup = () => {
21469
+ clearTimeout(timer);
21470
+ incoming.off("data", onData);
21471
+ incoming.off("end", cleanup);
21472
+ incoming.off("error", cleanup);
21473
+ };
21474
+ const forceClose = () => {
21475
+ cleanup();
21476
+ const socket = incoming.socket;
21477
+ if (socket && !socket.destroyed) {
21478
+ socket.destroySoon();
21479
+ }
21480
+ };
21481
+ const timer = setTimeout(forceClose, DRAIN_TIMEOUT_MS);
21482
+ timer.unref?.();
21483
+ const onData = (chunk) => {
21484
+ bytesRead += chunk.length;
21485
+ if (bytesRead > MAX_DRAIN_BYTES) {
21486
+ forceClose();
21487
+ }
21488
+ };
21489
+ incoming.on("data", onData);
21490
+ incoming.on("end", cleanup);
21491
+ incoming.on("error", cleanup);
21492
+ incoming.resume();
21493
+ };
21494
+ var handleRequestError = () => new Response(null, {
21495
+ status: 400
21496
+ });
21497
+ var handleFetchError = (e) => new Response(null, {
21498
+ status: e instanceof Error && (e.name === "TimeoutError" || e.constructor.name === "TimeoutError") ? 504 : 500
21499
+ });
21500
+ var handleResponseError = (e, outgoing) => {
21501
+ const err = e instanceof Error ? e : new Error("unknown error", { cause: e });
21502
+ if (err.code === "ERR_STREAM_PREMATURE_CLOSE") {
21503
+ console.info("The user aborted a request.");
21504
+ } else {
21505
+ console.error(e);
21506
+ if (!outgoing.headersSent) {
21507
+ outgoing.writeHead(500, { "Content-Type": "text/plain" });
21508
+ }
21509
+ outgoing.end(`Error: ${err.message}`);
21510
+ outgoing.destroy(err);
21511
+ }
21512
+ };
21513
+ var flushHeaders = (outgoing) => {
21514
+ if ("flushHeaders" in outgoing && outgoing.writable) {
21515
+ outgoing.flushHeaders();
21516
+ }
21517
+ };
21518
+ var responseViaCache = async (res, outgoing) => {
21519
+ let [status, body, header] = res[cacheKey];
21520
+ let hasContentLength = false;
21521
+ if (!header) {
21522
+ header = { "content-type": "text/plain; charset=UTF-8" };
21523
+ } else if (header instanceof Headers) {
21524
+ hasContentLength = header.has("content-length");
21525
+ header = buildOutgoingHttpHeaders(header);
21526
+ } else if (Array.isArray(header)) {
21527
+ const headerObj = new Headers(header);
21528
+ hasContentLength = headerObj.has("content-length");
21529
+ header = buildOutgoingHttpHeaders(headerObj);
21530
+ } else {
21531
+ for (const key in header) {
21532
+ if (key.length === 14 && key.toLowerCase() === "content-length") {
21533
+ hasContentLength = true;
21534
+ break;
21535
+ }
21536
+ }
21537
+ }
21538
+ if (!hasContentLength) {
21539
+ if (typeof body === "string") {
21540
+ header["Content-Length"] = Buffer.byteLength(body);
21541
+ } else if (body instanceof Uint8Array) {
21542
+ header["Content-Length"] = body.byteLength;
21543
+ } else if (body instanceof Blob) {
21544
+ header["Content-Length"] = body.size;
21545
+ }
21546
+ }
21547
+ outgoing.writeHead(status, header);
21548
+ if (typeof body === "string" || body instanceof Uint8Array) {
21549
+ outgoing.end(body);
21550
+ } else if (body instanceof Blob) {
21551
+ outgoing.end(new Uint8Array(await body.arrayBuffer()));
21552
+ } else {
21553
+ flushHeaders(outgoing);
21554
+ await writeFromReadableStream(body, outgoing)?.catch(
21555
+ (e) => handleResponseError(e, outgoing)
21556
+ );
21557
+ }
21558
+ ;
21559
+ outgoing[outgoingEnded]?.();
21560
+ };
21561
+ var isPromise = (res) => typeof res.then === "function";
21562
+ var responseViaResponseObject = async (res, outgoing, options = {}) => {
21563
+ if (isPromise(res)) {
21564
+ if (options.errorHandler) {
21565
+ try {
21566
+ res = await res;
21567
+ } catch (err) {
21568
+ const errRes = await options.errorHandler(err);
21569
+ if (!errRes) {
21570
+ return;
21571
+ }
21572
+ res = errRes;
21573
+ }
21574
+ } else {
21575
+ res = await res.catch(handleFetchError);
21576
+ }
21577
+ }
21578
+ if (cacheKey in res) {
21579
+ return responseViaCache(res, outgoing);
21580
+ }
21581
+ const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);
21582
+ if (res.body) {
21583
+ const reader = res.body.getReader();
21584
+ const values = [];
21585
+ let done = false;
21586
+ let currentReadPromise = void 0;
21587
+ if (resHeaderRecord["transfer-encoding"] !== "chunked") {
21588
+ let maxReadCount = 2;
21589
+ for (let i = 0; i < maxReadCount; i++) {
21590
+ currentReadPromise ||= reader.read();
21591
+ const chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {
21592
+ console.error(e);
21593
+ done = true;
21594
+ });
21595
+ if (!chunk) {
21596
+ if (i === 1) {
21597
+ await new Promise((resolve2) => setTimeout(resolve2));
21598
+ maxReadCount = 3;
21599
+ continue;
21600
+ }
21601
+ break;
21602
+ }
21603
+ currentReadPromise = void 0;
21604
+ if (chunk.value) {
21605
+ values.push(chunk.value);
21606
+ }
21607
+ if (chunk.done) {
21608
+ done = true;
21609
+ break;
21610
+ }
21611
+ }
21612
+ if (done && !("content-length" in resHeaderRecord)) {
21613
+ resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0);
21614
+ }
21615
+ }
21616
+ outgoing.writeHead(res.status, resHeaderRecord);
21617
+ values.forEach((value) => {
21618
+ ;
21619
+ outgoing.write(value);
21620
+ });
21621
+ if (done) {
21622
+ outgoing.end();
21623
+ } else {
21624
+ if (values.length === 0) {
21625
+ flushHeaders(outgoing);
21626
+ }
21627
+ await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
21628
+ }
21629
+ } else if (resHeaderRecord[X_ALREADY_SENT]) {
21630
+ } else {
21631
+ outgoing.writeHead(res.status, resHeaderRecord);
21632
+ outgoing.end();
21633
+ }
21634
+ ;
21635
+ outgoing[outgoingEnded]?.();
21636
+ };
21637
+ var getRequestListener = (fetchCallback, options = {}) => {
21638
+ const autoCleanupIncoming = options.autoCleanupIncoming ?? true;
21639
+ if (options.overrideGlobalObjects !== false && global.Request !== Request) {
21640
+ Object.defineProperty(global, "Request", {
21641
+ value: Request
21642
+ });
21643
+ Object.defineProperty(global, "Response", {
21644
+ value: Response2
21645
+ });
21646
+ }
21647
+ return async (incoming, outgoing) => {
21648
+ let res, req;
21649
+ try {
21650
+ req = newRequest(incoming, options.hostname);
21651
+ let incomingEnded = !autoCleanupIncoming || incoming.method === "GET" || incoming.method === "HEAD";
21652
+ if (!incomingEnded) {
21653
+ ;
21654
+ incoming[wrapBodyStream] = true;
21655
+ incoming.on("end", () => {
21656
+ incomingEnded = true;
21657
+ });
21658
+ if (incoming instanceof Http2ServerRequest2) {
21659
+ ;
21660
+ outgoing[outgoingEnded] = () => {
21661
+ if (!incomingEnded) {
21662
+ setTimeout(() => {
21663
+ if (!incomingEnded) {
21664
+ setTimeout(() => {
21665
+ drainIncoming(incoming);
21666
+ });
21667
+ }
21668
+ });
21669
+ }
21670
+ };
21671
+ }
21672
+ outgoing.on("finish", () => {
21673
+ if (!incomingEnded) {
21674
+ drainIncoming(incoming);
21675
+ }
21676
+ });
21677
+ }
21678
+ outgoing.on("close", () => {
21679
+ const abortController = req[abortControllerKey];
21680
+ if (abortController) {
21681
+ if (incoming.errored) {
21682
+ req[abortControllerKey].abort(incoming.errored.toString());
21683
+ } else if (!outgoing.writableFinished) {
21684
+ req[abortControllerKey].abort("Client connection prematurely closed.");
21685
+ }
21686
+ }
21687
+ if (!incomingEnded) {
21688
+ setTimeout(() => {
21689
+ if (!incomingEnded) {
21690
+ setTimeout(() => {
21691
+ drainIncoming(incoming);
21692
+ });
21693
+ }
21694
+ });
21695
+ }
21696
+ });
21697
+ res = fetchCallback(req, { incoming, outgoing });
21698
+ if (cacheKey in res) {
21699
+ return responseViaCache(res, outgoing);
21700
+ }
21701
+ } catch (e) {
21702
+ if (!res) {
21703
+ if (options.errorHandler) {
21704
+ res = await options.errorHandler(req ? e : toRequestError(e));
21705
+ if (!res) {
21706
+ return;
21707
+ }
21708
+ } else if (!req) {
21709
+ res = handleRequestError();
21710
+ } else {
21711
+ res = handleFetchError(e);
21712
+ }
21713
+ } else {
21714
+ return handleResponseError(e, outgoing);
21715
+ }
21716
+ }
21717
+ try {
21718
+ return await responseViaResponseObject(res, outgoing, options);
21719
+ } catch (e) {
21720
+ return handleResponseError(e, outgoing);
21721
+ }
21722
+ };
21723
+ };
21724
+
21725
+ // ../node_modules/@modelcontextprotocol/sdk/dist/esm/server/webStandardStreamableHttp.js
21726
+ var WebStandardStreamableHTTPServerTransport = class {
21727
+ constructor(options = {}) {
21728
+ this._started = false;
21729
+ this._hasHandledRequest = false;
21730
+ this._streamMapping = /* @__PURE__ */ new Map();
21731
+ this._requestToStreamMapping = /* @__PURE__ */ new Map();
21732
+ this._requestResponseMap = /* @__PURE__ */ new Map();
21733
+ this._initialized = false;
21734
+ this._enableJsonResponse = false;
21735
+ this._standaloneSseStreamId = "_GET_stream";
21736
+ this.sessionIdGenerator = options.sessionIdGenerator;
21737
+ this._enableJsonResponse = options.enableJsonResponse ?? false;
21738
+ this._eventStore = options.eventStore;
21739
+ this._onsessioninitialized = options.onsessioninitialized;
21740
+ this._onsessionclosed = options.onsessionclosed;
21741
+ this._allowedHosts = options.allowedHosts;
21742
+ this._allowedOrigins = options.allowedOrigins;
21743
+ this._enableDnsRebindingProtection = options.enableDnsRebindingProtection ?? false;
21744
+ this._retryInterval = options.retryInterval;
21745
+ }
21746
+ /**
21747
+ * Starts the transport. This is required by the Transport interface but is a no-op
21748
+ * for the Streamable HTTP transport as connections are managed per-request.
21749
+ */
21750
+ async start() {
21751
+ if (this._started) {
21752
+ throw new Error("Transport already started");
21753
+ }
21754
+ this._started = true;
21755
+ }
21756
+ /**
21757
+ * Helper to create a JSON error response
21758
+ */
21759
+ createJsonErrorResponse(status, code, message, options) {
21760
+ const error2 = { code, message };
21761
+ if (options?.data !== void 0) {
21762
+ error2.data = options.data;
21763
+ }
21764
+ return new Response(JSON.stringify({
21765
+ jsonrpc: "2.0",
21766
+ error: error2,
21767
+ id: null
21768
+ }), {
21769
+ status,
21770
+ headers: {
21771
+ "Content-Type": "application/json",
21772
+ ...options?.headers
21773
+ }
21774
+ });
21775
+ }
21776
+ /**
21777
+ * Validates request headers for DNS rebinding protection.
21778
+ * @returns Error response if validation fails, undefined if validation passes.
21779
+ */
21780
+ validateRequestHeaders(req) {
21781
+ if (!this._enableDnsRebindingProtection) {
21782
+ return void 0;
21783
+ }
21784
+ if (this._allowedHosts && this._allowedHosts.length > 0) {
21785
+ const hostHeader = req.headers.get("host");
21786
+ if (!hostHeader || !this._allowedHosts.includes(hostHeader)) {
21787
+ const error2 = `Invalid Host header: ${hostHeader}`;
21788
+ this.onerror?.(new Error(error2));
21789
+ return this.createJsonErrorResponse(403, -32e3, error2);
21790
+ }
21791
+ }
21792
+ if (this._allowedOrigins && this._allowedOrigins.length > 0) {
21793
+ const originHeader = req.headers.get("origin");
21794
+ if (originHeader && !this._allowedOrigins.includes(originHeader)) {
21795
+ const error2 = `Invalid Origin header: ${originHeader}`;
21796
+ this.onerror?.(new Error(error2));
21797
+ return this.createJsonErrorResponse(403, -32e3, error2);
21798
+ }
21799
+ }
21800
+ return void 0;
21801
+ }
21802
+ /**
21803
+ * Handles an incoming HTTP request, whether GET, POST, or DELETE
21804
+ * Returns a Response object (Web Standard)
21805
+ */
21806
+ async handleRequest(req, options) {
21807
+ if (!this.sessionIdGenerator && this._hasHandledRequest) {
21808
+ throw new Error("Stateless transport cannot be reused across requests. Create a new transport per request.");
21809
+ }
21810
+ this._hasHandledRequest = true;
21811
+ const validationError = this.validateRequestHeaders(req);
21812
+ if (validationError) {
21813
+ return validationError;
21814
+ }
21815
+ switch (req.method) {
21816
+ case "POST":
21817
+ return this.handlePostRequest(req, options);
21818
+ case "GET":
21819
+ return this.handleGetRequest(req);
21820
+ case "DELETE":
21821
+ return this.handleDeleteRequest(req);
21822
+ default:
21823
+ return this.handleUnsupportedRequest();
21824
+ }
21825
+ }
21826
+ /**
21827
+ * Writes a priming event to establish resumption capability.
21828
+ * Only sends if eventStore is configured (opt-in for resumability) and
21829
+ * the client's protocol version supports empty SSE data (>= 2025-11-25).
21830
+ */
21831
+ async writePrimingEvent(controller, encoder, streamId, protocolVersion) {
21832
+ if (!this._eventStore) {
21833
+ return;
21834
+ }
21835
+ if (protocolVersion < "2025-11-25") {
21836
+ return;
21837
+ }
21838
+ const primingEventId = await this._eventStore.storeEvent(streamId, {});
21839
+ let primingEvent = `id: ${primingEventId}
21840
+ data:
21841
+
21842
+ `;
21843
+ if (this._retryInterval !== void 0) {
21844
+ primingEvent = `id: ${primingEventId}
21845
+ retry: ${this._retryInterval}
21846
+ data:
21847
+
21848
+ `;
21849
+ }
21850
+ controller.enqueue(encoder.encode(primingEvent));
21851
+ }
21852
+ /**
21853
+ * Handles GET requests for SSE stream
21854
+ */
21855
+ async handleGetRequest(req) {
21856
+ const acceptHeader = req.headers.get("accept");
21857
+ if (!acceptHeader?.includes("text/event-stream")) {
21858
+ this.onerror?.(new Error("Not Acceptable: Client must accept text/event-stream"));
21859
+ return this.createJsonErrorResponse(406, -32e3, "Not Acceptable: Client must accept text/event-stream");
21860
+ }
21861
+ const sessionError = this.validateSession(req);
21862
+ if (sessionError) {
21863
+ return sessionError;
21864
+ }
21865
+ const protocolError = this.validateProtocolVersion(req);
21866
+ if (protocolError) {
21867
+ return protocolError;
21868
+ }
21869
+ if (this._eventStore) {
21870
+ const lastEventId = req.headers.get("last-event-id");
21871
+ if (lastEventId) {
21872
+ return this.replayEvents(lastEventId);
21873
+ }
21874
+ }
21875
+ if (this._streamMapping.get(this._standaloneSseStreamId) !== void 0) {
21876
+ this.onerror?.(new Error("Conflict: Only one SSE stream is allowed per session"));
21877
+ return this.createJsonErrorResponse(409, -32e3, "Conflict: Only one SSE stream is allowed per session");
21878
+ }
21879
+ const encoder = new TextEncoder();
21880
+ let streamController;
21881
+ const readable = new ReadableStream({
21882
+ start: (controller) => {
21883
+ streamController = controller;
21884
+ },
21885
+ cancel: () => {
21886
+ this._streamMapping.delete(this._standaloneSseStreamId);
21887
+ }
21888
+ });
21889
+ const headers = {
21890
+ "Content-Type": "text/event-stream",
21891
+ "Cache-Control": "no-cache, no-transform",
21892
+ Connection: "keep-alive"
21893
+ };
21894
+ if (this.sessionId !== void 0) {
21895
+ headers["mcp-session-id"] = this.sessionId;
21896
+ }
21897
+ this._streamMapping.set(this._standaloneSseStreamId, {
21898
+ controller: streamController,
21899
+ encoder,
21900
+ cleanup: () => {
21901
+ this._streamMapping.delete(this._standaloneSseStreamId);
21902
+ try {
21903
+ streamController.close();
21904
+ } catch {
21905
+ }
21906
+ }
21907
+ });
21908
+ return new Response(readable, { headers });
21909
+ }
21910
+ /**
21911
+ * Replays events that would have been sent after the specified event ID
21912
+ * Only used when resumability is enabled
21913
+ */
21914
+ async replayEvents(lastEventId) {
21915
+ if (!this._eventStore) {
21916
+ this.onerror?.(new Error("Event store not configured"));
21917
+ return this.createJsonErrorResponse(400, -32e3, "Event store not configured");
21918
+ }
21919
+ try {
21920
+ let streamId;
21921
+ if (this._eventStore.getStreamIdForEventId) {
21922
+ streamId = await this._eventStore.getStreamIdForEventId(lastEventId);
21923
+ if (!streamId) {
21924
+ this.onerror?.(new Error("Invalid event ID format"));
21925
+ return this.createJsonErrorResponse(400, -32e3, "Invalid event ID format");
21926
+ }
21927
+ if (this._streamMapping.get(streamId) !== void 0) {
21928
+ this.onerror?.(new Error("Conflict: Stream already has an active connection"));
21929
+ return this.createJsonErrorResponse(409, -32e3, "Conflict: Stream already has an active connection");
21930
+ }
21931
+ }
21932
+ const headers = {
21933
+ "Content-Type": "text/event-stream",
21934
+ "Cache-Control": "no-cache, no-transform",
21935
+ Connection: "keep-alive"
21936
+ };
21937
+ if (this.sessionId !== void 0) {
21938
+ headers["mcp-session-id"] = this.sessionId;
21939
+ }
21940
+ const encoder = new TextEncoder();
21941
+ let streamController;
21942
+ const readable = new ReadableStream({
21943
+ start: (controller) => {
21944
+ streamController = controller;
21945
+ },
21946
+ cancel: () => {
21947
+ }
21948
+ });
21949
+ const replayedStreamId = await this._eventStore.replayEventsAfter(lastEventId, {
21950
+ send: async (eventId, message) => {
21951
+ const success = this.writeSSEEvent(streamController, encoder, message, eventId);
21952
+ if (!success) {
21953
+ this.onerror?.(new Error("Failed replay events"));
21954
+ try {
21955
+ streamController.close();
21956
+ } catch {
21957
+ }
21958
+ }
21959
+ }
21960
+ });
21961
+ this._streamMapping.set(replayedStreamId, {
21962
+ controller: streamController,
21963
+ encoder,
21964
+ cleanup: () => {
21965
+ this._streamMapping.delete(replayedStreamId);
21966
+ try {
21967
+ streamController.close();
21968
+ } catch {
21969
+ }
21970
+ }
21971
+ });
21972
+ return new Response(readable, { headers });
21973
+ } catch (error2) {
21974
+ this.onerror?.(error2);
21975
+ return this.createJsonErrorResponse(500, -32e3, "Error replaying events");
21976
+ }
21977
+ }
21978
+ /**
21979
+ * Writes an event to an SSE stream via controller with proper formatting
21980
+ */
21981
+ writeSSEEvent(controller, encoder, message, eventId) {
21982
+ try {
21983
+ let eventData = `event: message
21984
+ `;
21985
+ if (eventId) {
21986
+ eventData += `id: ${eventId}
21987
+ `;
21988
+ }
21989
+ eventData += `data: ${JSON.stringify(message)}
21990
+
21991
+ `;
21992
+ controller.enqueue(encoder.encode(eventData));
21993
+ return true;
21994
+ } catch (error2) {
21995
+ this.onerror?.(error2);
21996
+ return false;
21997
+ }
21998
+ }
21999
+ /**
22000
+ * Handles unsupported requests (PUT, PATCH, etc.)
22001
+ */
22002
+ handleUnsupportedRequest() {
22003
+ this.onerror?.(new Error("Method not allowed."));
22004
+ return new Response(JSON.stringify({
22005
+ jsonrpc: "2.0",
22006
+ error: {
22007
+ code: -32e3,
22008
+ message: "Method not allowed."
22009
+ },
22010
+ id: null
22011
+ }), {
22012
+ status: 405,
22013
+ headers: {
22014
+ Allow: "GET, POST, DELETE",
22015
+ "Content-Type": "application/json"
22016
+ }
22017
+ });
22018
+ }
22019
+ /**
22020
+ * Handles POST requests containing JSON-RPC messages
22021
+ */
22022
+ async handlePostRequest(req, options) {
22023
+ try {
22024
+ const acceptHeader = req.headers.get("accept");
22025
+ if (!acceptHeader?.includes("application/json") || !acceptHeader.includes("text/event-stream")) {
22026
+ this.onerror?.(new Error("Not Acceptable: Client must accept both application/json and text/event-stream"));
22027
+ return this.createJsonErrorResponse(406, -32e3, "Not Acceptable: Client must accept both application/json and text/event-stream");
22028
+ }
22029
+ const ct = req.headers.get("content-type");
22030
+ if (!ct || !ct.includes("application/json")) {
22031
+ this.onerror?.(new Error("Unsupported Media Type: Content-Type must be application/json"));
22032
+ return this.createJsonErrorResponse(415, -32e3, "Unsupported Media Type: Content-Type must be application/json");
22033
+ }
22034
+ const requestInfo = {
22035
+ headers: Object.fromEntries(req.headers.entries()),
22036
+ url: new URL(req.url)
22037
+ };
22038
+ let rawMessage;
22039
+ if (options?.parsedBody !== void 0) {
22040
+ rawMessage = options.parsedBody;
22041
+ } else {
22042
+ try {
22043
+ rawMessage = await req.json();
22044
+ } catch {
22045
+ this.onerror?.(new Error("Parse error: Invalid JSON"));
22046
+ return this.createJsonErrorResponse(400, -32700, "Parse error: Invalid JSON");
22047
+ }
22048
+ }
22049
+ let messages;
22050
+ try {
22051
+ if (Array.isArray(rawMessage)) {
22052
+ messages = rawMessage.map((msg) => JSONRPCMessageSchema.parse(msg));
22053
+ } else {
22054
+ messages = [JSONRPCMessageSchema.parse(rawMessage)];
22055
+ }
22056
+ } catch {
22057
+ this.onerror?.(new Error("Parse error: Invalid JSON-RPC message"));
22058
+ return this.createJsonErrorResponse(400, -32700, "Parse error: Invalid JSON-RPC message");
22059
+ }
22060
+ const isInitializationRequest = messages.some(isInitializeRequest);
22061
+ if (isInitializationRequest) {
22062
+ if (this._initialized && this.sessionId !== void 0) {
22063
+ this.onerror?.(new Error("Invalid Request: Server already initialized"));
22064
+ return this.createJsonErrorResponse(400, -32600, "Invalid Request: Server already initialized");
22065
+ }
22066
+ if (messages.length > 1) {
22067
+ this.onerror?.(new Error("Invalid Request: Only one initialization request is allowed"));
22068
+ return this.createJsonErrorResponse(400, -32600, "Invalid Request: Only one initialization request is allowed");
22069
+ }
22070
+ this.sessionId = this.sessionIdGenerator?.();
22071
+ this._initialized = true;
22072
+ if (this.sessionId && this._onsessioninitialized) {
22073
+ await Promise.resolve(this._onsessioninitialized(this.sessionId));
22074
+ }
22075
+ }
22076
+ if (!isInitializationRequest) {
22077
+ const sessionError = this.validateSession(req);
22078
+ if (sessionError) {
22079
+ return sessionError;
22080
+ }
22081
+ const protocolError = this.validateProtocolVersion(req);
22082
+ if (protocolError) {
22083
+ return protocolError;
22084
+ }
22085
+ }
22086
+ const hasRequests = messages.some(isJSONRPCRequest);
22087
+ if (!hasRequests) {
22088
+ for (const message of messages) {
22089
+ this.onmessage?.(message, { authInfo: options?.authInfo, requestInfo });
22090
+ }
22091
+ return new Response(null, { status: 202 });
22092
+ }
22093
+ const streamId = crypto.randomUUID();
22094
+ const initRequest = messages.find((m) => isInitializeRequest(m));
22095
+ const clientProtocolVersion = initRequest ? initRequest.params.protocolVersion : req.headers.get("mcp-protocol-version") ?? DEFAULT_NEGOTIATED_PROTOCOL_VERSION;
22096
+ if (this._enableJsonResponse) {
22097
+ return new Promise((resolve2) => {
22098
+ this._streamMapping.set(streamId, {
22099
+ resolveJson: resolve2,
22100
+ cleanup: () => {
22101
+ this._streamMapping.delete(streamId);
22102
+ }
22103
+ });
22104
+ for (const message of messages) {
22105
+ if (isJSONRPCRequest(message)) {
22106
+ this._requestToStreamMapping.set(message.id, streamId);
22107
+ }
22108
+ }
22109
+ for (const message of messages) {
22110
+ this.onmessage?.(message, { authInfo: options?.authInfo, requestInfo });
22111
+ }
22112
+ });
22113
+ }
22114
+ const encoder = new TextEncoder();
22115
+ let streamController;
22116
+ const readable = new ReadableStream({
22117
+ start: (controller) => {
22118
+ streamController = controller;
22119
+ },
22120
+ cancel: () => {
22121
+ this._streamMapping.delete(streamId);
22122
+ }
22123
+ });
22124
+ const headers = {
22125
+ "Content-Type": "text/event-stream",
22126
+ "Cache-Control": "no-cache",
22127
+ Connection: "keep-alive"
22128
+ };
22129
+ if (this.sessionId !== void 0) {
22130
+ headers["mcp-session-id"] = this.sessionId;
22131
+ }
22132
+ for (const message of messages) {
22133
+ if (isJSONRPCRequest(message)) {
22134
+ this._streamMapping.set(streamId, {
22135
+ controller: streamController,
22136
+ encoder,
22137
+ cleanup: () => {
22138
+ this._streamMapping.delete(streamId);
22139
+ try {
22140
+ streamController.close();
22141
+ } catch {
22142
+ }
22143
+ }
22144
+ });
22145
+ this._requestToStreamMapping.set(message.id, streamId);
22146
+ }
22147
+ }
22148
+ await this.writePrimingEvent(streamController, encoder, streamId, clientProtocolVersion);
22149
+ for (const message of messages) {
22150
+ let closeSSEStream;
22151
+ let closeStandaloneSSEStream;
22152
+ if (isJSONRPCRequest(message) && this._eventStore && clientProtocolVersion >= "2025-11-25") {
22153
+ closeSSEStream = () => {
22154
+ this.closeSSEStream(message.id);
22155
+ };
22156
+ closeStandaloneSSEStream = () => {
22157
+ this.closeStandaloneSSEStream();
22158
+ };
22159
+ }
22160
+ this.onmessage?.(message, { authInfo: options?.authInfo, requestInfo, closeSSEStream, closeStandaloneSSEStream });
22161
+ }
22162
+ return new Response(readable, { status: 200, headers });
22163
+ } catch (error2) {
22164
+ this.onerror?.(error2);
22165
+ return this.createJsonErrorResponse(400, -32700, "Parse error", { data: String(error2) });
22166
+ }
22167
+ }
22168
+ /**
22169
+ * Handles DELETE requests to terminate sessions
22170
+ */
22171
+ async handleDeleteRequest(req) {
22172
+ const sessionError = this.validateSession(req);
22173
+ if (sessionError) {
22174
+ return sessionError;
22175
+ }
22176
+ const protocolError = this.validateProtocolVersion(req);
22177
+ if (protocolError) {
22178
+ return protocolError;
22179
+ }
22180
+ await Promise.resolve(this._onsessionclosed?.(this.sessionId));
22181
+ await this.close();
22182
+ return new Response(null, { status: 200 });
22183
+ }
22184
+ /**
22185
+ * Validates session ID for non-initialization requests.
22186
+ * Returns Response error if invalid, undefined otherwise
22187
+ */
22188
+ validateSession(req) {
22189
+ if (this.sessionIdGenerator === void 0) {
22190
+ return void 0;
22191
+ }
22192
+ if (!this._initialized) {
22193
+ this.onerror?.(new Error("Bad Request: Server not initialized"));
22194
+ return this.createJsonErrorResponse(400, -32e3, "Bad Request: Server not initialized");
22195
+ }
22196
+ const sessionId = req.headers.get("mcp-session-id");
22197
+ if (!sessionId) {
22198
+ this.onerror?.(new Error("Bad Request: Mcp-Session-Id header is required"));
22199
+ return this.createJsonErrorResponse(400, -32e3, "Bad Request: Mcp-Session-Id header is required");
22200
+ }
22201
+ if (sessionId !== this.sessionId) {
22202
+ this.onerror?.(new Error("Session not found"));
22203
+ return this.createJsonErrorResponse(404, -32001, "Session not found");
22204
+ }
22205
+ return void 0;
22206
+ }
22207
+ /**
22208
+ * Validates the MCP-Protocol-Version header on incoming requests.
22209
+ *
22210
+ * For initialization: Version negotiation handles unknown versions gracefully
22211
+ * (server responds with its supported version).
22212
+ *
22213
+ * For subsequent requests with MCP-Protocol-Version header:
22214
+ * - Accept if in supported list
22215
+ * - 400 if unsupported
22216
+ *
22217
+ * For HTTP requests without the MCP-Protocol-Version header:
22218
+ * - Accept and default to the version negotiated at initialization
22219
+ */
22220
+ validateProtocolVersion(req) {
22221
+ const protocolVersion = req.headers.get("mcp-protocol-version");
22222
+ if (protocolVersion !== null && !SUPPORTED_PROTOCOL_VERSIONS.includes(protocolVersion)) {
22223
+ this.onerror?.(new Error(`Bad Request: Unsupported protocol version: ${protocolVersion} (supported versions: ${SUPPORTED_PROTOCOL_VERSIONS.join(", ")})`));
22224
+ return this.createJsonErrorResponse(400, -32e3, `Bad Request: Unsupported protocol version: ${protocolVersion} (supported versions: ${SUPPORTED_PROTOCOL_VERSIONS.join(", ")})`);
22225
+ }
22226
+ return void 0;
22227
+ }
22228
+ async close() {
22229
+ this._streamMapping.forEach(({ cleanup }) => {
22230
+ cleanup();
22231
+ });
22232
+ this._streamMapping.clear();
22233
+ this._requestResponseMap.clear();
22234
+ this.onclose?.();
22235
+ }
22236
+ /**
22237
+ * Close an SSE stream for a specific request, triggering client reconnection.
22238
+ * Use this to implement polling behavior during long-running operations -
22239
+ * client will reconnect after the retry interval specified in the priming event.
22240
+ */
22241
+ closeSSEStream(requestId) {
22242
+ const streamId = this._requestToStreamMapping.get(requestId);
22243
+ if (!streamId)
22244
+ return;
22245
+ const stream = this._streamMapping.get(streamId);
22246
+ if (stream) {
22247
+ stream.cleanup();
22248
+ }
22249
+ }
22250
+ /**
22251
+ * Close the standalone GET SSE stream, triggering client reconnection.
22252
+ * Use this to implement polling behavior for server-initiated notifications.
22253
+ */
22254
+ closeStandaloneSSEStream() {
22255
+ const stream = this._streamMapping.get(this._standaloneSseStreamId);
22256
+ if (stream) {
22257
+ stream.cleanup();
22258
+ }
22259
+ }
22260
+ async send(message, options) {
22261
+ let requestId = options?.relatedRequestId;
22262
+ if (isJSONRPCResultResponse(message) || isJSONRPCErrorResponse(message)) {
22263
+ requestId = message.id;
22264
+ }
22265
+ if (requestId === void 0) {
22266
+ if (isJSONRPCResultResponse(message) || isJSONRPCErrorResponse(message)) {
22267
+ throw new Error("Cannot send a response on a standalone SSE stream unless resuming a previous client request");
22268
+ }
22269
+ let eventId;
22270
+ if (this._eventStore) {
22271
+ eventId = await this._eventStore.storeEvent(this._standaloneSseStreamId, message);
22272
+ }
22273
+ const standaloneSse = this._streamMapping.get(this._standaloneSseStreamId);
22274
+ if (standaloneSse === void 0) {
22275
+ return;
22276
+ }
22277
+ if (standaloneSse.controller && standaloneSse.encoder) {
22278
+ this.writeSSEEvent(standaloneSse.controller, standaloneSse.encoder, message, eventId);
22279
+ }
22280
+ return;
22281
+ }
22282
+ const streamId = this._requestToStreamMapping.get(requestId);
22283
+ if (!streamId) {
22284
+ throw new Error(`No connection established for request ID: ${String(requestId)}`);
22285
+ }
22286
+ const stream = this._streamMapping.get(streamId);
22287
+ if (!this._enableJsonResponse && stream?.controller && stream?.encoder) {
22288
+ let eventId;
22289
+ if (this._eventStore) {
22290
+ eventId = await this._eventStore.storeEvent(streamId, message);
22291
+ }
22292
+ this.writeSSEEvent(stream.controller, stream.encoder, message, eventId);
22293
+ }
22294
+ if (isJSONRPCResultResponse(message) || isJSONRPCErrorResponse(message)) {
22295
+ this._requestResponseMap.set(requestId, message);
22296
+ const relatedIds = Array.from(this._requestToStreamMapping.entries()).filter(([_, sid]) => sid === streamId).map(([id]) => id);
22297
+ const allResponsesReady = relatedIds.every((id) => this._requestResponseMap.has(id));
22298
+ if (allResponsesReady) {
22299
+ if (!stream) {
22300
+ throw new Error(`No connection established for request ID: ${String(requestId)}`);
22301
+ }
22302
+ if (this._enableJsonResponse && stream.resolveJson) {
22303
+ const headers = {
22304
+ "Content-Type": "application/json"
22305
+ };
22306
+ if (this.sessionId !== void 0) {
22307
+ headers["mcp-session-id"] = this.sessionId;
22308
+ }
22309
+ const responses = relatedIds.map((id) => this._requestResponseMap.get(id));
22310
+ if (responses.length === 1) {
22311
+ stream.resolveJson(new Response(JSON.stringify(responses[0]), { status: 200, headers }));
22312
+ } else {
22313
+ stream.resolveJson(new Response(JSON.stringify(responses), { status: 200, headers }));
22314
+ }
22315
+ } else {
22316
+ stream.cleanup();
22317
+ }
22318
+ for (const id of relatedIds) {
22319
+ this._requestResponseMap.delete(id);
22320
+ this._requestToStreamMapping.delete(id);
22321
+ }
22322
+ }
22323
+ }
22324
+ }
22325
+ };
22326
+
22327
+ // ../node_modules/@modelcontextprotocol/sdk/dist/esm/server/streamableHttp.js
22328
+ var StreamableHTTPServerTransport = class {
22329
+ constructor(options = {}) {
22330
+ this._requestContext = /* @__PURE__ */ new WeakMap();
22331
+ this._webStandardTransport = new WebStandardStreamableHTTPServerTransport(options);
22332
+ this._requestListener = getRequestListener(async (webRequest) => {
22333
+ const context = this._requestContext.get(webRequest);
22334
+ return this._webStandardTransport.handleRequest(webRequest, {
22335
+ authInfo: context?.authInfo,
22336
+ parsedBody: context?.parsedBody
22337
+ });
22338
+ }, { overrideGlobalObjects: false });
22339
+ }
22340
+ /**
22341
+ * Gets the session ID for this transport instance.
22342
+ */
22343
+ get sessionId() {
22344
+ return this._webStandardTransport.sessionId;
22345
+ }
22346
+ /**
22347
+ * Sets callback for when the transport is closed.
22348
+ */
22349
+ set onclose(handler) {
22350
+ this._webStandardTransport.onclose = handler;
22351
+ }
22352
+ get onclose() {
22353
+ return this._webStandardTransport.onclose;
22354
+ }
22355
+ /**
22356
+ * Sets callback for transport errors.
22357
+ */
22358
+ set onerror(handler) {
22359
+ this._webStandardTransport.onerror = handler;
22360
+ }
22361
+ get onerror() {
22362
+ return this._webStandardTransport.onerror;
22363
+ }
22364
+ /**
22365
+ * Sets callback for incoming messages.
22366
+ */
22367
+ set onmessage(handler) {
22368
+ this._webStandardTransport.onmessage = handler;
22369
+ }
22370
+ get onmessage() {
22371
+ return this._webStandardTransport.onmessage;
22372
+ }
22373
+ /**
22374
+ * Starts the transport. This is required by the Transport interface but is a no-op
22375
+ * for the Streamable HTTP transport as connections are managed per-request.
22376
+ */
22377
+ async start() {
22378
+ return this._webStandardTransport.start();
22379
+ }
22380
+ /**
22381
+ * Closes the transport and all active connections.
22382
+ */
22383
+ async close() {
22384
+ return this._webStandardTransport.close();
22385
+ }
22386
+ /**
22387
+ * Sends a JSON-RPC message through the transport.
22388
+ */
22389
+ async send(message, options) {
22390
+ return this._webStandardTransport.send(message, options);
22391
+ }
22392
+ /**
22393
+ * Handles an incoming HTTP request, whether GET or POST.
22394
+ *
22395
+ * This method converts Node.js HTTP objects to Web Standard Request/Response
22396
+ * and delegates to the underlying WebStandardStreamableHTTPServerTransport.
22397
+ *
22398
+ * @param req - Node.js IncomingMessage, optionally with auth property from middleware
22399
+ * @param res - Node.js ServerResponse
22400
+ * @param parsedBody - Optional pre-parsed body from body-parser middleware
22401
+ */
22402
+ async handleRequest(req, res, parsedBody) {
22403
+ const authInfo = req.auth;
22404
+ const handler = getRequestListener(async (webRequest) => {
22405
+ return this._webStandardTransport.handleRequest(webRequest, {
22406
+ authInfo,
22407
+ parsedBody
22408
+ });
22409
+ }, { overrideGlobalObjects: false });
22410
+ await handler(req, res);
22411
+ }
22412
+ /**
22413
+ * Close an SSE stream for a specific request, triggering client reconnection.
22414
+ * Use this to implement polling behavior during long-running operations -
22415
+ * client will reconnect after the retry interval specified in the priming event.
22416
+ */
22417
+ closeSSEStream(requestId) {
22418
+ this._webStandardTransport.closeSSEStream(requestId);
22419
+ }
22420
+ /**
22421
+ * Close the standalone GET SSE stream, triggering client reconnection.
22422
+ * Use this to implement polling behavior for server-initiated notifications.
22423
+ */
22424
+ closeStandaloneSSEStream() {
22425
+ this._webStandardTransport.closeStandaloneSSEStream();
22426
+ }
22427
+ };
22428
+
21102
22429
  // src/index.ts
21103
22430
  import { homedir } from "node:os";
21104
- import { resolve } from "node:path";
21105
- var VERSION = true ? "0.2.0" : "0.0.0-dev";
21106
- var STATE_DIR = resolve(process.env.A2ADAPT_STATE_DIR ?? resolve(homedir(), ".a2adapt"));
21107
- var BROKER_URL = process.env.A2ADAPT_BROKER_URL ?? "ws://localhost:9000";
22431
+ import { resolve, join, dirname } from "node:path";
22432
+ import { fileURLToPath } from "node:url";
22433
+ import { randomBytes, randomUUID } from "node:crypto";
22434
+ import { createServer as createHttpServer } from "node:http";
22435
+ import * as fs from "node:fs";
22436
+ import { adapt_wrapper } from "@adapt-toolkit/sdk/executables";
22437
+ import { PacketWrapperConfigurator } from "@adapt-toolkit/sdk/wrappers";
22438
+ import { object_to_adapt_value } from "@adapt-toolkit/sdk/wrapper";
22439
+ var VERSION = true ? "0.3.0" : "0.0.0-dev";
22440
+ var STATE_DIR = resolve(
22441
+ process.env.A2ADAPT_STATE_DIR ?? resolve(homedir(), ".a2adapt")
22442
+ );
22443
+ var BROKER_URL = process.env.A2ADAPT_BROKER_URL ?? "wss://a2adapt.adaptframework.solutions/broker";
22444
+ var TRANSPORT = process.env.A2ADAPT_TRANSPORT ?? "http";
22445
+ var PORT = parseInt(process.env.A2ADAPT_PORT ?? "3030", 10);
22446
+ var log = (...parts) => process.stderr.write(`a2adapt: ${parts.join(" ")}
22447
+ `);
22448
+ var NAME_RE = /^[A-Za-z0-9 _.-]{1,64}$/;
22449
+ function validateName(name) {
22450
+ if (!NAME_RE.test(name)) {
22451
+ return "name must be 1-64 chars of letters, digits, space, _ . or -";
22452
+ }
22453
+ if (name === "." || name === ".." || name.includes("/") || name.includes("\\")) {
22454
+ return "invalid name";
22455
+ }
22456
+ return null;
22457
+ }
22458
+ function locateUnit() {
22459
+ const here = dirname(fileURLToPath(import.meta.url));
22460
+ const override = process.env.A2ADAPT_UNIT_DIR;
22461
+ const candidates = override ? [resolve(override)] : [join(here, "mufl_code"), join(here, "..", "mufl_code")];
22462
+ for (const dir of candidates) {
22463
+ if (!fs.existsSync(dir)) continue;
22464
+ const muflo = fs.readdirSync(dir).find((f) => f.endsWith(".muflo"));
22465
+ if (muflo) {
22466
+ const hash = muflo.slice(0, -".muflo".length);
22467
+ const contents = new Uint8Array(fs.readFileSync(join(dir, muflo)));
22468
+ return { dir, hash, contents };
22469
+ }
22470
+ }
22471
+ throw new Error(
22472
+ `no compiled .muflo packet found (looked in: ${candidates.join(", ")})`
22473
+ );
22474
+ }
22475
+ var UNIT;
22476
+ var wrapper;
22477
+ var identities = /* @__PURE__ */ new Map();
22478
+ var sessionBinding = /* @__PURE__ */ new Map();
22479
+ var bindingOwner = /* @__PURE__ */ new Map();
22480
+ var evictedSessions = /* @__PURE__ */ new Set();
22481
+ var identityDir = (name) => join(STATE_DIR, name);
22482
+ var seedPath = (dir) => join(dir, "identity.seed");
22483
+ var dataPath = (dir) => join(dir, "state_data.bin");
22484
+ var cursorPath = (dir) => join(dir, "inbox_cursor");
22485
+ var inboxLogPath = (dir) => join(dir, "inbox.log");
22486
+ function listPersistedNames() {
22487
+ if (!fs.existsSync(STATE_DIR)) return [];
22488
+ return fs.readdirSync(STATE_DIR, { withFileTypes: true }).filter((d) => d.isDirectory() && fs.existsSync(seedPath(join(STATE_DIR, d.name)))).map((d) => d.name);
22489
+ }
22490
+ function hasSavedState(dir) {
22491
+ try {
22492
+ return fs.existsSync(dataPath(dir)) && fs.statSync(dataPath(dir)).size > 0;
22493
+ } catch {
22494
+ return false;
22495
+ }
22496
+ }
22497
+ function saveState(id) {
22498
+ try {
22499
+ const exported = id.pw.packet.ExecuteTransaction(
22500
+ object_to_adapt_value({ name: "::actor::export_state", targ: void 0 })
22501
+ );
22502
+ const bytes = Buffer.from(exported.Serialize());
22503
+ fs.mkdirSync(id.dir, { recursive: true });
22504
+ const tmp = `${dataPath(id.dir)}.tmp`;
22505
+ fs.writeFileSync(tmp, bytes);
22506
+ fs.renameSync(tmp, dataPath(id.dir));
22507
+ } catch (err) {
22508
+ log(`[${id.name}] failed to save state:`, String(err));
22509
+ }
22510
+ }
22511
+ function readCursor(dir) {
22512
+ try {
22513
+ return parseInt(fs.readFileSync(cursorPath(dir), "utf8").trim(), 10) || 0;
22514
+ } catch {
22515
+ return 0;
22516
+ }
22517
+ }
22518
+ function writeCursor(dir, n) {
22519
+ try {
22520
+ fs.mkdirSync(dir, { recursive: true });
22521
+ fs.writeFileSync(cursorPath(dir), String(n));
22522
+ } catch {
22523
+ }
22524
+ }
22525
+ function appendInboxLog(id, sender, text, date3) {
22526
+ try {
22527
+ fs.mkdirSync(id.dir, { recursive: true });
22528
+ const line = JSON.stringify({ sender, text, date: date3 }) + "\n";
22529
+ fs.appendFileSync(inboxLogPath(id.dir), line);
22530
+ } catch (err) {
22531
+ log(`[${id.name}] failed to append inbox.log:`, String(err));
22532
+ }
22533
+ }
22534
+ var activeMcpServers = /* @__PURE__ */ new Set();
22535
+ var inboxResourceUri = (name) => `a2adapt://inbox/${encodeURIComponent(name)}`;
22536
+ function pushNotification(identityName, summary) {
22537
+ log(`[${identityName}] notify:`, summary);
22538
+ for (const server of activeMcpServers) {
22539
+ try {
22540
+ server.sendLoggingMessage({ level: "info", logger: "a2adapt", data: summary });
22541
+ } catch (e) {
22542
+ log("sendLoggingMessage failed:", String(e));
22543
+ }
22544
+ try {
22545
+ server.server.sendResourceUpdated({ uri: inboxResourceUri(identityName) });
22546
+ } catch {
22547
+ }
22548
+ }
22549
+ }
22550
+ function readonlyTx(id, name) {
22551
+ return id.pw.packet.ExecuteTransaction(
22552
+ object_to_adapt_value({ name, targ: void 0 })
22553
+ );
22554
+ }
22555
+ async function withLock(id, fn) {
22556
+ const prev = id.lock;
22557
+ let release;
22558
+ id.lock = new Promise((r) => release = r);
22559
+ await prev;
22560
+ try {
22561
+ return await fn();
22562
+ } finally {
22563
+ release();
22564
+ }
22565
+ }
22566
+ function enqueueMutation(id, envelope, timeoutMs = 25e3) {
22567
+ return new Promise((res, rej) => {
22568
+ const timer = setTimeout(() => {
22569
+ const i = id.pending.findIndex((p) => p.timer === timer);
22570
+ if (i >= 0) id.pending.splice(i, 1);
22571
+ rej(new Error("timed out waiting for the transaction result"));
22572
+ }, timeoutMs);
22573
+ id.pending.push({ resolve: res, reject: rej, timer });
22574
+ id.pw.add_client_message(envelope);
22575
+ });
22576
+ }
22577
+ function mutatingTx(id, name, targ, timeoutMs) {
22578
+ const envelope = object_to_adapt_value({ name, targ });
22579
+ return withLock(id, () => enqueueMutation(id, envelope, timeoutMs));
22580
+ }
22581
+ function wireHandlers(id) {
22582
+ id.pw.on_return_data = (data) => {
22583
+ const kind = data.Reduce("kind").Visualize();
22584
+ if (kind === "save_state") {
22585
+ saveState(id);
22586
+ return;
22587
+ }
22588
+ if (kind === "notify_agent") {
22589
+ const payload = data.Reduce("payload");
22590
+ const event = payload.Reduce("event").Visualize();
22591
+ if (event === "message_received") {
22592
+ const sender = payload.Reduce("sender_name").Visualize();
22593
+ const text = payload.Reduce("text").Visualize();
22594
+ const date3 = payload.Reduce("date").Visualize();
22595
+ appendInboxLog(id, sender, text, date3);
22596
+ process.nextTick(
22597
+ () => pushNotification(id.name, `[${id.name}] new message from ${sender}: ${text} (${date3})`)
22598
+ );
22599
+ } else if (event === "contact_accepted") {
22600
+ const name = payload.Reduce("name").Visualize();
22601
+ const cid = payload.Reduce("container_id").Visualize();
22602
+ process.nextTick(
22603
+ () => pushNotification(id.name, `[${id.name}] contact "${name}" (${cid}) accepted your invite.`)
22604
+ );
22605
+ }
22606
+ return;
22607
+ }
22608
+ const p = id.pending.shift();
22609
+ if (!p) return;
22610
+ clearTimeout(p.timer);
22611
+ p.resolve(data.Reduce("payload"));
22612
+ };
22613
+ id.pw.on_transaction_failure = (message) => {
22614
+ const p = id.pending.shift();
22615
+ if (p) {
22616
+ clearTimeout(p.timer);
22617
+ p.reject(new Error(message));
22618
+ } else {
22619
+ log(`[${id.name}] inbound transaction rejected:`, message);
22620
+ }
22621
+ };
22622
+ }
22623
+ function createPacket(name, seed, dir) {
22624
+ const config2 = new PacketWrapperConfigurator();
22625
+ config2.process_arguments([
22626
+ "--unit_hash",
22627
+ UNIT.hash,
22628
+ "--seed_phrase",
22629
+ seed,
22630
+ "--unit_dir_path",
22631
+ UNIT.dir
22632
+ ]);
22633
+ return new Promise((resolveCreate, rejectCreate) => {
22634
+ const timer = setTimeout(
22635
+ () => rejectCreate(new Error(`packet creation for "${name}" timed out`)),
22636
+ 3e4
22637
+ );
22638
+ wrapper.packet_manager.create_packet(
22639
+ config2,
22640
+ (pw) => {
22641
+ clearTimeout(timer);
22642
+ const id = {
22643
+ name,
22644
+ seed,
22645
+ cid: pw.packet.GetContainerID().Visualize(),
22646
+ pw,
22647
+ dir,
22648
+ pending: [],
22649
+ lock: Promise.resolve()
22650
+ };
22651
+ wireHandlers(id);
22652
+ identities.set(name, id);
22653
+ log(`[${name}] packet created \u2014 container id ${id.cid}`);
22654
+ resolveCreate(id);
22655
+ },
22656
+ UNIT.contents
22657
+ );
22658
+ });
22659
+ }
22660
+ async function provisionIdentity(name) {
22661
+ const dir = identityDir(name);
22662
+ fs.mkdirSync(dir, { recursive: true });
22663
+ const seed = randomBytes(24).toString("hex");
22664
+ fs.writeFileSync(seedPath(dir), seed, { mode: 384 });
22665
+ const id = await createPacket(name, seed, dir);
22666
+ await mutatingTx(id, "::actor::set_my_name", { name });
22667
+ saveState(id);
22668
+ return id;
22669
+ }
22670
+ async function restoreIdentity(name) {
22671
+ const dir = identityDir(name);
22672
+ const seed = fs.readFileSync(seedPath(dir), "utf8").trim();
22673
+ const id = await createPacket(name, seed, dir);
22674
+ if (hasSavedState(dir)) {
22675
+ try {
22676
+ const buf = fs.readFileSync(dataPath(dir));
22677
+ const adaptData = id.pw.packet.ParseValue(new Uint8Array(buf));
22678
+ await mutatingTx(id, "::actor::import_state", adaptData);
22679
+ } catch (err) {
22680
+ log(`[${name}] failed to import saved state (continuing fresh):`, String(err));
22681
+ }
22682
+ }
22683
+ return id;
22684
+ }
22685
+ async function bootWrapper() {
22686
+ UNIT = locateUnit();
22687
+ const argv = [
22688
+ "--broker_address",
22689
+ BROKER_URL,
22690
+ "--test_mode",
22691
+ "--logger_config",
22692
+ "--level",
22693
+ "INFO",
22694
+ "--stdout",
22695
+ "stderr",
22696
+ "--logger_config_end"
22697
+ ];
22698
+ log(`booting wrapper (unit ${UNIT.hash.slice(0, 12)}\u2026, broker ${BROKER_URL})`);
22699
+ wrapper = await adapt_wrapper.start(argv);
22700
+ wrapper.on_packet_created_cb = (cid) => log(`wrapper: packet ready ${cid.slice(0, 12)}\u2026`);
22701
+ wrapper.start();
22702
+ const names = listPersistedNames();
22703
+ if (names.length === 0) {
22704
+ log("no persisted identities \u2014 start with create_identity");
22705
+ } else {
22706
+ log(`restoring ${names.length} identit${names.length === 1 ? "y" : "ies"}: ${names.join(", ")}`);
22707
+ for (const name of names) {
22708
+ try {
22709
+ await restoreIdentity(name);
22710
+ } catch (err) {
22711
+ log(`failed to restore "${name}":`, String(err));
22712
+ }
22713
+ }
22714
+ }
22715
+ }
22716
+ function resolveBound(sessionId) {
22717
+ if (evictedSessions.has(sessionId)) {
22718
+ return { error: "Your identity binding was reassigned to another session. Call choose_identity again to continue." };
22719
+ }
22720
+ const name = sessionBinding.get(sessionId);
22721
+ if (!name) {
22722
+ return { error: "No identity bound to this session. Call choose_identity (or create_identity) first." };
22723
+ }
22724
+ const id = identities.get(name);
22725
+ if (!id) {
22726
+ sessionBinding.delete(sessionId);
22727
+ bindingOwner.delete(name);
22728
+ return { error: `The bound identity "${name}" no longer exists. Choose another with choose_identity.` };
22729
+ }
22730
+ return { id };
22731
+ }
22732
+ function bindSession(sessionId, name) {
22733
+ const prev = sessionBinding.get(sessionId);
22734
+ if (prev && prev !== name && bindingOwner.get(prev) === sessionId) {
22735
+ bindingOwner.delete(prev);
22736
+ }
22737
+ sessionBinding.set(sessionId, name);
22738
+ bindingOwner.set(name, sessionId);
22739
+ evictedSessions.delete(sessionId);
22740
+ }
22741
+ function renderContacts(v) {
22742
+ const out = [];
22743
+ if (v.IsNil()) return out;
22744
+ for (const key of v.GetKeys()) {
22745
+ const c = v.Reduce(key);
22746
+ if (c.IsNil()) continue;
22747
+ out.push({
22748
+ name: c.Reduce("name").Visualize(),
22749
+ container_id: c.Reduce("container_id").Visualize()
22750
+ });
22751
+ }
22752
+ return out;
22753
+ }
22754
+ function renderInbox(v) {
22755
+ const out = [];
22756
+ if (v.IsNil()) return out;
22757
+ for (let i = 0; ; i++) {
22758
+ const m = v.Reduce(i);
22759
+ if (m.IsNil()) break;
22760
+ out.push({
22761
+ sender_id: m.Reduce("sender_id").Visualize(),
22762
+ sender_name: m.Reduce("sender_name").Visualize(),
22763
+ text: m.Reduce("text").Visualize(),
22764
+ date: m.Reduce("date").Visualize()
22765
+ });
22766
+ }
22767
+ return out;
22768
+ }
21108
22769
  function textResult(text, isError = false) {
21109
22770
  return { content: [{ type: "text", text }], isError };
21110
22771
  }
21111
- function nodeNotWiredYet(tool) {
21112
- return textResult(
21113
- `a2adapt: the ADAPT node is not wired up yet, so \`${tool}\` cannot run.
21114
-
21115
- This is the v0 scaffold \u2014 the tool surface is registered but the native
21116
- ADAPT wrapper (packet bootstrap + state persistence + broker transport)
21117
- is implemented in workspace task "4. MCP server = native ADAPT wrapper".
22772
+ function createMcpServer(getSessionId) {
22773
+ const server = new McpServer(
22774
+ { name: "a2adapt", version: VERSION },
22775
+ { capabilities: { logging: {}, resources: {} } }
22776
+ );
22777
+ activeMcpServers.add(server);
22778
+ const boundOr = () => {
22779
+ const b = resolveBound(getSessionId());
22780
+ return "error" in b ? { err: textResult(b.error, true) } : { id: b.id };
22781
+ };
22782
+ server.tool(
22783
+ "create_identity",
22784
+ "Create a new self-sovereign identity (an ADAPT node) with the given display name and bind it to this session. The name is what peers see for you in invites. Persisted permanently; reject if the name already exists.",
22785
+ { name: external_exports.string().min(1).describe('Display name for the new identity, e.g. "Alice".') },
22786
+ async ({ name }) => {
22787
+ const bad = validateName(name);
22788
+ if (bad) return textResult(`create_identity failed: ${bad}`, true);
22789
+ if (identities.has(name)) return textResult(`create_identity failed: an identity named "${name}" already exists.`, true);
22790
+ try {
22791
+ const id = await provisionIdentity(name);
22792
+ bindSession(getSessionId(), name);
22793
+ return textResult(`Created identity "${name}" (${id.cid}) and bound it to this session.`);
22794
+ } catch (err) {
22795
+ return textResult(`create_identity failed: ${String(err)}`, true);
22796
+ }
22797
+ }
22798
+ );
22799
+ server.tool(
22800
+ "choose_identity",
22801
+ "Bind an existing identity to this session so the messaging tools act as it. Binding is exclusive: if the identity is already in use by another session, this is declined unless force=true, which evicts the other session.",
22802
+ {
22803
+ name: external_exports.string().min(1).describe("Name of the identity to bind."),
22804
+ force: external_exports.boolean().default(false).describe("Evict another session that holds this identity.")
22805
+ },
22806
+ async ({ name, force }) => {
22807
+ if (!identities.has(name)) {
22808
+ return textResult(`choose_identity failed: no identity named "${name}". Create it with create_identity.`, true);
22809
+ }
22810
+ const sid = getSessionId();
22811
+ const holder = bindingOwner.get(name);
22812
+ if (holder && holder !== sid) {
22813
+ if (!force) {
22814
+ return textResult(`choose_identity failed: "${name}" is currently bound to another session. Retry with force=true to take it over.`, true);
22815
+ }
22816
+ evictedSessions.add(holder);
22817
+ sessionBinding.delete(holder);
22818
+ bindingOwner.delete(name);
22819
+ }
22820
+ bindSession(sid, name);
22821
+ const id = identities.get(name);
22822
+ return textResult(`Bound to identity "${name}" (${id.cid}).`);
22823
+ }
22824
+ );
22825
+ server.tool(
22826
+ "list_identities",
22827
+ "List all identities hosted by this node (name + container id), marking which one is bound to this session and which are in use elsewhere.",
22828
+ {},
22829
+ async () => {
22830
+ if (identities.size === 0) return textResult("No identities yet. Create one with create_identity.");
22831
+ const sid = getSessionId();
22832
+ const mine = sessionBinding.get(sid);
22833
+ const lines = [...identities.values()].map((id) => {
22834
+ const holder = bindingOwner.get(id.name);
22835
+ const tag = id.name === mine ? " \u2190 this session" : holder ? " (in use by another session)" : "";
22836
+ return `\u2022 ${id.name} \u2014 ${id.cid}${tag}`;
22837
+ });
22838
+ return textResult(`Identities (${identities.size}):
22839
+ ${lines.join("\n")}`);
22840
+ }
22841
+ );
22842
+ server.tool(
22843
+ "current_identity",
22844
+ "Report the identity currently bound to this session (if any).",
22845
+ {},
22846
+ async () => {
22847
+ const b = resolveBound(getSessionId());
22848
+ if ("error" in b) return textResult(b.error);
22849
+ return textResult(`Bound to "${b.id.name}" (${b.id.cid}).`);
22850
+ }
22851
+ );
22852
+ server.tool(
22853
+ "remove_identity",
22854
+ "Permanently delete a persisted identity \u2014 its packet and all on-disk state. This cannot be undone.",
22855
+ { name: external_exports.string().min(1).describe("Name of the identity to delete.") },
22856
+ async ({ name }) => {
22857
+ const id = identities.get(name);
22858
+ if (!id) return textResult(`remove_identity failed: no identity named "${name}".`, true);
22859
+ try {
22860
+ wrapper.remove_packet(id.cid);
22861
+ } catch (err) {
22862
+ log(`remove_packet(${id.cid}) failed:`, String(err));
22863
+ }
22864
+ identities.delete(name);
22865
+ const holder = bindingOwner.get(name);
22866
+ if (holder) {
22867
+ bindingOwner.delete(name);
22868
+ sessionBinding.delete(holder);
22869
+ }
22870
+ try {
22871
+ fs.rmSync(id.dir, { recursive: true, force: true });
22872
+ } catch (err) {
22873
+ return textResult(`Identity "${name}" removed from memory, but deleting ${id.dir} failed: ${String(err)}`, true);
22874
+ }
22875
+ return textResult(`Removed identity "${name}" and its state.`);
22876
+ }
22877
+ );
22878
+ server.resource(
22879
+ "inbox",
22880
+ "a2adapt://inbox",
22881
+ { description: "Decrypted incoming messages for the bound identity \u2014 auto-notifies on new arrivals." },
22882
+ async () => {
22883
+ const { id, err } = boundOr();
22884
+ const uri = id ? inboxResourceUri(id.name) : "a2adapt://inbox";
22885
+ if (err || !id) return { contents: [{ uri, mimeType: "text/plain", text: "No identity bound to this session." }] };
22886
+ const inbox = renderInbox(readonlyTx(id, "::actor::list_incoming_messages"));
22887
+ const text = inbox.length === 0 ? "Inbox is empty." : `Inbox (${inbox.length}):
22888
+ ${inbox.map((m, i) => `${i + 1}. [${m.sender_name}] ${m.text} (${m.date})`).join("\n")}`;
22889
+ return { contents: [{ uri, mimeType: "text/plain", text }] };
22890
+ }
22891
+ );
22892
+ server.tool(
22893
+ "generate_invite",
22894
+ "Generate a named invite to share out-of-band with another agent. The invite carries your identity and display name; whoever redeems it is registered under the name you pass here. Requires a bound identity.",
22895
+ { name: external_exports.string().min(1).describe('Name to register the peer who redeems this invite, e.g. "Bob".') },
22896
+ async ({ name }) => {
22897
+ const { id, err } = boundOr();
22898
+ if (err) return err;
22899
+ try {
22900
+ const data = await mutatingTx(id, "::actor::generate_invite", { name });
22901
+ const blob = Buffer.from(data.Reduce("invite").GetBinary()).toString("base64");
22902
+ return textResult(
22903
+ `Invite for "${name}" created. Share this blob out-of-band (they paste it into add_contact):
21118
22904
 
21119
- State dir: ${STATE_DIR}
21120
- Broker URL: ${BROKER_URL}`,
21121
- true
22905
+ ${blob}`
22906
+ );
22907
+ } catch (e) {
22908
+ return textResult(`generate_invite failed: ${String(e)}`, true);
22909
+ }
22910
+ }
22911
+ );
22912
+ server.tool(
22913
+ "add_contact",
22914
+ "Add a contact from an invite blob produced by another agent's generate_invite. If no name is given, the inviter's embedded display name is used. Also replies to the inviter so they register you back. Requires a bound identity.",
22915
+ {
22916
+ invite: external_exports.string().min(1).describe("The base64 invite blob to redeem."),
22917
+ name: external_exports.string().min(1).optional().describe("Optional custom name for the inviter; defaults to their own name.")
22918
+ },
22919
+ async ({ invite, name }) => {
22920
+ const { id, err } = boundOr();
22921
+ if (err) return err;
22922
+ let buf;
22923
+ try {
22924
+ buf = Buffer.from(invite.trim(), "base64");
22925
+ if (buf.length === 0) throw new Error("empty");
22926
+ } catch {
22927
+ return textResult("add_contact failed: the invite blob is not valid base64.", true);
22928
+ }
22929
+ try {
22930
+ const blobValue = id.pw.packet.NewBinaryFromBuffer(buf);
22931
+ const targ = { invite: blobValue };
22932
+ if (name) targ.name = name;
22933
+ const data = await mutatingTx(id, "::actor::add_contact", targ);
22934
+ const added = data.Reduce("added").Visualize();
22935
+ const cid = data.Reduce("container_id").Visualize();
22936
+ return textResult(`Added contact "${added}" (${cid}).`);
22937
+ } catch (e) {
22938
+ return textResult(`add_contact failed: ${String(e)}`, true);
22939
+ }
22940
+ }
21122
22941
  );
22942
+ server.tool(
22943
+ "list_contacts",
22944
+ "List the contacts the bound identity knows about (name + container id).",
22945
+ {},
22946
+ async () => {
22947
+ const { id, err } = boundOr();
22948
+ if (err) return err;
22949
+ try {
22950
+ const contacts = renderContacts(readonlyTx(id, "::actor::list_contacts"));
22951
+ if (contacts.length === 0) return textResult("No contacts yet.");
22952
+ return textResult(`Contacts (${contacts.length}):
22953
+ ${contacts.map((c) => `\u2022 ${c.name} \u2014 ${c.container_id}`).join("\n")}`);
22954
+ } catch (e) {
22955
+ return textResult(`list_contacts failed: ${String(e)}`, true);
22956
+ }
22957
+ }
22958
+ );
22959
+ server.tool(
22960
+ "send_message",
22961
+ "Send an end-to-end-encrypted message to a known contact (by name or container id). Requires a bound identity.",
22962
+ {
22963
+ contact: external_exports.string().min(1).describe("Contact name or container id to send to."),
22964
+ text: external_exports.string().min(1).describe("The message text.")
22965
+ },
22966
+ async ({ contact, text }) => {
22967
+ const { id, err } = boundOr();
22968
+ if (err) return err;
22969
+ try {
22970
+ await mutatingTx(id, "::actor::send_message", { contact, text });
22971
+ return textResult(`Message sent to "${contact}".`);
22972
+ } catch (e) {
22973
+ return textResult(`send_message failed: ${String(e)}`, true);
22974
+ }
22975
+ }
22976
+ );
22977
+ server.tool(
22978
+ "list_incoming_messages",
22979
+ "List all received messages in the bound identity's inbox (decrypted, with sender).",
22980
+ {},
22981
+ async () => {
22982
+ const { id, err } = boundOr();
22983
+ if (err) return err;
22984
+ try {
22985
+ const inbox = renderInbox(readonlyTx(id, "::actor::list_incoming_messages"));
22986
+ if (inbox.length === 0) return textResult("Inbox is empty.");
22987
+ return textResult(`Inbox (${inbox.length}):
22988
+ ${inbox.map((m, i) => `${i + 1}. [${m.sender_name}] ${m.text} (${m.date})`).join("\n")}`);
22989
+ } catch (e) {
22990
+ return textResult(`list_incoming_messages failed: ${String(e)}`, true);
22991
+ }
22992
+ }
22993
+ );
22994
+ server.tool(
22995
+ "process_incoming_message",
22996
+ "Surface messages that have arrived for the bound identity since the last check, and mark them processed (non-blocking \u2014 use to poll for new mail).",
22997
+ {},
22998
+ async () => {
22999
+ const { id, err } = boundOr();
23000
+ if (err) return err;
23001
+ try {
23002
+ const inbox = renderInbox(readonlyTx(id, "::actor::list_incoming_messages"));
23003
+ const cursor = readCursor(id.dir);
23004
+ const fresh = inbox.slice(cursor);
23005
+ writeCursor(id.dir, inbox.length);
23006
+ if (fresh.length === 0) return textResult("No new messages.");
23007
+ return textResult(`${fresh.length} new message(s):
23008
+ ${fresh.map((m) => `\u2022 [${m.sender_name}] ${m.text} (${m.date})`).join("\n")}`);
23009
+ } catch (e) {
23010
+ return textResult(`process_incoming_message failed: ${String(e)}`, true);
23011
+ }
23012
+ }
23013
+ );
23014
+ return server;
23015
+ }
23016
+ function readBody(req) {
23017
+ return new Promise((resolve2, reject) => {
23018
+ let data = "";
23019
+ req.on("data", (chunk) => data += chunk);
23020
+ req.on("end", () => {
23021
+ try {
23022
+ resolve2(JSON.parse(data));
23023
+ } catch (e) {
23024
+ reject(e);
23025
+ }
23026
+ });
23027
+ req.on("error", reject);
23028
+ });
21123
23029
  }
21124
- var server = new McpServer({ name: "a2adapt", version: VERSION });
21125
- server.tool(
21126
- "generate_invite",
21127
- "Generate a named invite to share with another agent out-of-band. The invite carries your public identity and a default display name; the receiver adds it with add_contact and may keep that name or set their own.",
21128
- {
21129
- name: external_exports.string().min(1).describe('The contact name to associate with this invite, e.g. "Alex".')
21130
- },
21131
- async (_args) => nodeNotWiredYet("generate_invite")
21132
- );
21133
- server.tool(
21134
- "add_contact",
21135
- "Add a contact from an invite blob produced by another agent's generate_invite. If no name is given, the invite's embedded default name is used.",
21136
- {
21137
- invite: external_exports.string().min(1).describe("The invite blob (copy-pasted string) to add."),
21138
- name: external_exports.string().min(1).optional().describe("Optional custom name; defaults to the name embedded in the invite.")
21139
- },
21140
- async (_args) => nodeNotWiredYet("add_contact")
21141
- );
21142
- server.tool(
21143
- "list_contacts",
21144
- "List the contacts this node knows about (name + container id).",
21145
- {},
21146
- async () => nodeNotWiredYet("list_contacts")
21147
- );
21148
- server.tool(
21149
- "send_message",
21150
- "Send an end-to-end-encrypted message to a known contact.",
21151
- {
21152
- contact: external_exports.string().min(1).describe("Contact name or container id to send to."),
21153
- text: external_exports.string().min(1).describe("The message text.")
21154
- },
21155
- async (_args) => nodeNotWiredYet("send_message")
21156
- );
21157
- server.tool(
21158
- "process_incoming_message",
21159
- "Drain newly-arrived inbound messages from the broker, apply them to the node, and surface the decrypted contents with sender attribution.",
21160
- {},
21161
- async () => nodeNotWiredYet("process_incoming_message")
21162
- );
21163
- server.tool(
21164
- "list_incoming_messages",
21165
- "List received messages currently held in the node inbox (decrypted, with sender).",
21166
- {},
21167
- async () => nodeNotWiredYet("list_incoming_messages")
21168
- );
21169
23030
  async function main() {
21170
- const transport = new StdioServerTransport();
21171
- await server.connect(transport);
21172
- process.stderr.write(`a2adapt MCP server v${VERSION} ready (state=${STATE_DIR}, broker=${BROKER_URL})
21173
- `);
23031
+ if (TRANSPORT === "stdio") {
23032
+ const server = createMcpServer(() => "stdio");
23033
+ const transport = new StdioServerTransport();
23034
+ await server.connect(transport);
23035
+ log("MCP stdio transport connected, booting wrapper\u2026");
23036
+ await bootWrapper();
23037
+ log(`MCP server v${VERSION} ready (transport=stdio, identities=${identities.size}, state=${STATE_DIR}, broker=${BROKER_URL})`);
23038
+ const flush = () => {
23039
+ for (const id of identities.values()) saveState(id);
23040
+ process.exit(0);
23041
+ };
23042
+ process.on("SIGINT", flush);
23043
+ process.on("SIGTERM", flush);
23044
+ return;
23045
+ }
23046
+ log("booting wrapper\u2026");
23047
+ await bootWrapper();
23048
+ log(`wrapper ready (identities=${identities.size}), starting HTTP server\u2026`);
23049
+ const transports = {};
23050
+ const httpServer = createHttpServer(async (req, res) => {
23051
+ const url = new URL(req.url, `http://localhost:${PORT}`);
23052
+ if (url.pathname !== "/mcp") {
23053
+ res.writeHead(404, { "Content-Type": "text/plain" });
23054
+ res.end("Not found");
23055
+ return;
23056
+ }
23057
+ try {
23058
+ if (req.method === "POST") {
23059
+ const body = await readBody(req);
23060
+ const sessionId = req.headers["mcp-session-id"];
23061
+ if (sessionId && transports[sessionId]) {
23062
+ await transports[sessionId].handleRequest(req, res, body);
23063
+ } else if (!sessionId && isInitializeRequest(body)) {
23064
+ const transport = new StreamableHTTPServerTransport({
23065
+ sessionIdGenerator: () => randomUUID(),
23066
+ onsessioninitialized: (sid) => {
23067
+ transports[sid] = transport;
23068
+ log(`session ${sid.slice(0, 8)}\u2026 initialized`);
23069
+ }
23070
+ });
23071
+ const server = createMcpServer(() => transport.sessionId ?? "pending");
23072
+ transport.onclose = () => {
23073
+ const sid = transport.sessionId;
23074
+ if (sid) {
23075
+ delete transports[sid];
23076
+ const name = sessionBinding.get(sid);
23077
+ if (name && bindingOwner.get(name) === sid) bindingOwner.delete(name);
23078
+ sessionBinding.delete(sid);
23079
+ evictedSessions.delete(sid);
23080
+ log(`session ${sid.slice(0, 8)}\u2026 closed`);
23081
+ }
23082
+ activeMcpServers.delete(server);
23083
+ };
23084
+ await server.connect(transport);
23085
+ await transport.handleRequest(req, res, body);
23086
+ } else {
23087
+ res.writeHead(400, { "Content-Type": "application/json" });
23088
+ res.end(JSON.stringify({ jsonrpc: "2.0", error: { code: -32e3, message: "Bad Request: No valid session ID" }, id: null }));
23089
+ }
23090
+ } else if (req.method === "GET") {
23091
+ const sessionId = req.headers["mcp-session-id"];
23092
+ if (!sessionId || !transports[sessionId]) {
23093
+ res.writeHead(400, { "Content-Type": "text/plain" });
23094
+ res.end("Invalid or missing session ID");
23095
+ return;
23096
+ }
23097
+ await transports[sessionId].handleRequest(req, res);
23098
+ } else if (req.method === "DELETE") {
23099
+ const sessionId = req.headers["mcp-session-id"];
23100
+ if (!sessionId || !transports[sessionId]) {
23101
+ res.writeHead(400, { "Content-Type": "text/plain" });
23102
+ res.end("Invalid or missing session ID");
23103
+ return;
23104
+ }
23105
+ await transports[sessionId].handleRequest(req, res);
23106
+ } else {
23107
+ res.writeHead(405, { "Content-Type": "text/plain" });
23108
+ res.end("Method not allowed");
23109
+ }
23110
+ } catch (err) {
23111
+ log("HTTP handler error:", String(err));
23112
+ if (!res.headersSent) {
23113
+ res.writeHead(500, { "Content-Type": "application/json" });
23114
+ res.end(JSON.stringify({ jsonrpc: "2.0", error: { code: -32603, message: "Internal server error" }, id: null }));
23115
+ }
23116
+ }
23117
+ });
23118
+ httpServer.listen(PORT, () => {
23119
+ log(`MCP server v${VERSION} ready (transport=http, port=${PORT}, identities=${identities.size}, state=${STATE_DIR}, broker=${BROKER_URL})`);
23120
+ });
23121
+ const shutdown = async () => {
23122
+ log("shutting down\u2026");
23123
+ for (const sid of Object.keys(transports)) {
23124
+ try {
23125
+ await transports[sid].close();
23126
+ } catch {
23127
+ }
23128
+ delete transports[sid];
23129
+ }
23130
+ for (const id of identities.values()) saveState(id);
23131
+ httpServer.close();
23132
+ process.exit(0);
23133
+ };
23134
+ process.on("SIGINT", shutdown);
23135
+ process.on("SIGTERM", shutdown);
21174
23136
  }
21175
23137
  main().catch((err) => {
21176
- process.stderr.write(`a2adapt: fatal startup error: ${err?.stack ?? err}
21177
- `);
23138
+ log(`fatal startup error: ${err?.stack ?? err}`);
21178
23139
  process.exit(1);
21179
23140
  });