@contextvm/sdk 0.9.1 → 0.11.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.
Files changed (88) hide show
  1. package/dist/esm/core/constants.d.ts +8 -0
  2. package/dist/esm/core/constants.d.ts.map +1 -1
  3. package/dist/esm/core/constants.js +8 -0
  4. package/dist/esm/core/constants.js.map +1 -1
  5. package/dist/esm/core/index.d.ts +1 -0
  6. package/dist/esm/core/index.d.ts.map +1 -1
  7. package/dist/esm/core/index.js +1 -0
  8. package/dist/esm/core/index.js.map +1 -1
  9. package/dist/esm/core/utils/common-schema.d.ts +25 -0
  10. package/dist/esm/core/utils/common-schema.d.ts.map +1 -0
  11. package/dist/esm/core/utils/common-schema.js +66 -0
  12. package/dist/esm/core/utils/common-schema.js.map +1 -0
  13. package/dist/esm/relay/applesauce-relay-pool.d.ts.map +1 -1
  14. package/dist/esm/relay/applesauce-relay-pool.js +14 -14
  15. package/dist/esm/relay/applesauce-relay-pool.js.map +1 -1
  16. package/dist/esm/transport/call-tool-stream.d.ts +22 -0
  17. package/dist/esm/transport/call-tool-stream.d.ts.map +1 -0
  18. package/dist/esm/transport/call-tool-stream.js +26 -0
  19. package/dist/esm/transport/call-tool-stream.js.map +1 -0
  20. package/dist/esm/transport/discovery-tags.d.ts +2 -0
  21. package/dist/esm/transport/discovery-tags.d.ts.map +1 -1
  22. package/dist/esm/transport/discovery-tags.js +1 -0
  23. package/dist/esm/transport/discovery-tags.js.map +1 -1
  24. package/dist/esm/transport/index.d.ts +4 -0
  25. package/dist/esm/transport/index.d.ts.map +1 -1
  26. package/dist/esm/transport/index.js +4 -0
  27. package/dist/esm/transport/index.js.map +1 -1
  28. package/dist/esm/transport/nostr-client-transport.d.ts +31 -1
  29. package/dist/esm/transport/nostr-client-transport.d.ts.map +1 -1
  30. package/dist/esm/transport/nostr-client-transport.js +168 -1
  31. package/dist/esm/transport/nostr-client-transport.js.map +1 -1
  32. package/dist/esm/transport/nostr-server/announcement-manager.d.ts +7 -1
  33. package/dist/esm/transport/nostr-server/announcement-manager.d.ts.map +1 -1
  34. package/dist/esm/transport/nostr-server/announcement-manager.js +18 -3
  35. package/dist/esm/transport/nostr-server/announcement-manager.js.map +1 -1
  36. package/dist/esm/transport/nostr-server/session-store.d.ts +2 -0
  37. package/dist/esm/transport/nostr-server/session-store.d.ts.map +1 -1
  38. package/dist/esm/transport/nostr-server/session-store.js +1 -0
  39. package/dist/esm/transport/nostr-server/session-store.js.map +1 -1
  40. package/dist/esm/transport/nostr-server-transport.d.ts +37 -2
  41. package/dist/esm/transport/nostr-server-transport.d.ts.map +1 -1
  42. package/dist/esm/transport/nostr-server-transport.js +254 -24
  43. package/dist/esm/transport/nostr-server-transport.js.map +1 -1
  44. package/dist/esm/transport/open-stream/constants.d.ts +8 -0
  45. package/dist/esm/transport/open-stream/constants.d.ts.map +1 -0
  46. package/dist/esm/transport/open-stream/constants.js +8 -0
  47. package/dist/esm/transport/open-stream/constants.js.map +1 -0
  48. package/dist/esm/transport/open-stream/errors.d.ts +19 -0
  49. package/dist/esm/transport/open-stream/errors.d.ts.map +1 -0
  50. package/dist/esm/transport/open-stream/errors.js +31 -0
  51. package/dist/esm/transport/open-stream/errors.js.map +1 -0
  52. package/dist/esm/transport/open-stream/frames.d.ts +37 -0
  53. package/dist/esm/transport/open-stream/frames.d.ts.map +1 -0
  54. package/dist/esm/transport/open-stream/frames.js +91 -0
  55. package/dist/esm/transport/open-stream/frames.js.map +1 -0
  56. package/dist/esm/transport/open-stream/index.d.ts +9 -0
  57. package/dist/esm/transport/open-stream/index.d.ts.map +1 -0
  58. package/dist/esm/transport/open-stream/index.js +9 -0
  59. package/dist/esm/transport/open-stream/index.js.map +1 -0
  60. package/dist/esm/transport/open-stream/receiver.d.ts +18 -0
  61. package/dist/esm/transport/open-stream/receiver.d.ts.map +1 -0
  62. package/dist/esm/transport/open-stream/receiver.js +31 -0
  63. package/dist/esm/transport/open-stream/receiver.js.map +1 -0
  64. package/dist/esm/transport/open-stream/registry.d.ts +37 -0
  65. package/dist/esm/transport/open-stream/registry.d.ts.map +1 -0
  66. package/dist/esm/transport/open-stream/registry.js +115 -0
  67. package/dist/esm/transport/open-stream/registry.js.map +1 -0
  68. package/dist/esm/transport/open-stream/session.d.ts +80 -0
  69. package/dist/esm/transport/open-stream/session.d.ts.map +1 -0
  70. package/dist/esm/transport/open-stream/session.js +343 -0
  71. package/dist/esm/transport/open-stream/session.js.map +1 -0
  72. package/dist/esm/transport/open-stream/types.d.ts +52 -0
  73. package/dist/esm/transport/open-stream/types.d.ts.map +1 -0
  74. package/dist/esm/transport/open-stream/types.js +2 -0
  75. package/dist/esm/transport/open-stream/types.js.map +1 -0
  76. package/dist/esm/transport/open-stream/writer.d.ts +38 -0
  77. package/dist/esm/transport/open-stream/writer.d.ts.map +1 -0
  78. package/dist/esm/transport/open-stream/writer.js +123 -0
  79. package/dist/esm/transport/open-stream/writer.js.map +1 -0
  80. package/dist/esm/transport/open-stream-policy.d.ts +12 -0
  81. package/dist/esm/transport/open-stream-policy.d.ts.map +1 -0
  82. package/dist/esm/transport/open-stream-policy.js +2 -0
  83. package/dist/esm/transport/open-stream-policy.js.map +1 -0
  84. package/dist/esm/transport/server-transport-common-schemas.d.ts +23 -0
  85. package/dist/esm/transport/server-transport-common-schemas.d.ts.map +1 -0
  86. package/dist/esm/transport/server-transport-common-schemas.js +119 -0
  87. package/dist/esm/transport/server-transport-common-schemas.js.map +1 -0
  88. package/package.json +2 -1
@@ -1,4 +1,4 @@
1
- import { type JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
1
+ import { type ListToolsResult, type JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
2
2
  import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
3
3
  import { BaseNostrTransport, BaseNostrTransportOptions } from './base-nostr-transport.js';
4
4
  import { NostrEvent } from 'nostr-tools';
@@ -7,7 +7,9 @@ import { CorrelationStore } from './nostr-server/correlation-store.js';
7
7
  import { ClientSession, SessionStore } from './nostr-server/session-store.js';
8
8
  import { CapabilityExclusion } from './nostr-server/authorization-policy.js';
9
9
  import { type ProfileMetadata, type ServerInfo } from './nostr-server/announcement-manager.js';
10
- import { type TransferPolicy } from './oversized-transfer/index.js';
10
+ import { OversizedTransferReceiver, type TransferPolicy } from './oversized-transfer/index.js';
11
+ import { OpenStreamReceiver } from './open-stream/index.js';
12
+ import type { OpenStreamTransportPolicy } from './open-stream-policy.js';
11
13
  /**
12
14
  * Options for configuring the NostrServerTransport.
13
15
  */
@@ -83,7 +85,16 @@ export interface NostrServerTransportOptions extends BaseNostrTransportOptions {
83
85
  /** Receiver-side admission policy. */
84
86
  policy?: TransferPolicy;
85
87
  };
88
+ /** Options controlling CEP-41 open-ended stream transfer. */
89
+ openStream?: {
90
+ /** Whether open stream transfer is enabled. @default false */
91
+ enabled?: boolean;
92
+ /** Receiver/session policy reserved for CEP-41 stream lifecycle limits. */
93
+ policy?: OpenStreamTransportPolicy;
94
+ };
86
95
  }
96
+ export type ListToolsResultTransformer = (result: ListToolsResult) => ListToolsResult;
97
+ export type ListToolsAnnouncementTagsProducer = (result: ListToolsResult) => string[][];
87
98
  export type InboundMiddlewareFn = (message: JSONRPCMessage, ctx: {
88
99
  clientPubkey: string;
89
100
  clientPmis?: readonly string[];
@@ -109,6 +120,8 @@ export declare class NostrServerTransport extends BaseNostrTransport implements
109
120
  private readonly shouldInjectRequestEventId;
110
121
  private readonly onClientSessionEvicted;
111
122
  private readonly inboundMiddlewares;
123
+ private readonly listToolsResultTransformers;
124
+ private readonly listToolsAnnouncementTagsProducers;
112
125
  /**
113
126
  * Deduplicate inbound events to avoid redundant work.
114
127
  *
@@ -117,9 +130,16 @@ export declare class NostrServerTransport extends BaseNostrTransport implements
117
130
  private readonly seenEventIds;
118
131
  /** Receives inbound oversized-transfer frames from clients (client→server requests). */
119
132
  private readonly oversizedReceiver;
133
+ /** Receives inbound open-stream frames from clients (client→server notifications). */
134
+ private readonly openStreamReceiver;
135
+ /** Pending final responses held until their CEP-41 stream terminates. */
136
+ private readonly pendingOpenStreamResponses;
137
+ /** Active server-side CEP-41 writers keyed by inbound request event id. */
138
+ private readonly openStreamWriters;
120
139
  private readonly oversizedEnabled;
121
140
  private readonly oversizedThreshold;
122
141
  private readonly oversizedChunkSize;
142
+ private readonly openStreamEnabled;
123
143
  constructor(options: NostrServerTransportOptions);
124
144
  /**
125
145
  * Sets extra tags to include in server announcement + initialize response events.
@@ -139,6 +159,16 @@ export declare class NostrServerTransport extends BaseNostrTransport implements
139
159
  * Middleware runs in the order it is added.
140
160
  */
141
161
  addInboundMiddleware(middleware: InboundMiddlewareFn): void;
162
+ /**
163
+ * Adds a transformer for `tools/list` results emitted by the server.
164
+ *
165
+ * Transformers are applied to direct responses and public announcement payloads.
166
+ */
167
+ addListToolsResultTransformer(transformer: ListToolsResultTransformer): void;
168
+ /**
169
+ * Adds a provider for extra tags on public tools/list announcement events.
170
+ */
171
+ addListToolsAnnouncementTagsProducer(producer: ListToolsAnnouncementTagsProducer): void;
142
172
  /**
143
173
  * Starts the transport, connecting to the relay and setting up event listeners
144
174
  * to receive incoming MCP requests.
@@ -187,6 +217,7 @@ export declare class NostrServerTransport extends BaseNostrTransport implements
187
217
  * @param clientPubkey The client's public key.
188
218
  */
189
219
  private handleIncomingRequest;
220
+ private flushPendingOpenStreamResponse;
190
221
  /**
191
222
  * Cleans up request correlation for a request that was dropped by middleware.
192
223
  */
@@ -201,6 +232,8 @@ export declare class NostrServerTransport extends BaseNostrTransport implements
201
232
  * Handles response messages by finding the original request and routing back to client.
202
233
  * @param response The JSON-RPC response or error to send.
203
234
  */
235
+ private applyListToolsResultTransformers;
236
+ private buildListToolsAnnouncementTags;
204
237
  private handleResponse;
205
238
  /**
206
239
  * Handles notification messages with routing.
@@ -245,6 +278,8 @@ export declare class NostrServerTransport extends BaseNostrTransport implements
245
278
  getInternalStateForTesting(): {
246
279
  sessionStore: SessionStore;
247
280
  correlationStore: CorrelationStore;
281
+ oversizedReceiver: OversizedTransferReceiver;
282
+ openStreamReceiver: OpenStreamReceiver;
248
283
  };
249
284
  }
250
285
  //# sourceMappingURL=nostr-server-transport.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"nostr-server-transport.d.ts","sourceRoot":"","sources":["../../../src/transport/nostr-server-transport.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"nostr-server-transport.d.ts","sourceRoot":"","sources":["../../../src/transport/nostr-server-transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,eAAe,EAGpB,KAAK,cAAc,EAMpB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAC/E,OAAO,EACL,kBAAkB,EAClB,yBAAyB,EAC1B,MAAM,2BAA2B,CAAC;AAYnC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAMnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAG9E,OAAO,EAEL,mBAAmB,EACpB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,UAAU,EAChB,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EACL,yBAAyB,EACzB,KAAK,cAAc,EACpB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACL,kBAAkB,EAMnB,MAAM,wBAAwB,CAAC;AAUhC,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAEzE;;GAEG;AACH,MAAM,WAAW,2BAA4B,SAAQ,yBAAyB;IAC5E,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,oFAAoF;IACpF,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC;;OAEG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,uEAAuE;IACvE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,8GAA8G;IAC9G,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,0EAA0E;IAC1E,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,gGAAgG;IAChG,eAAe,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvE,uFAAuF;IACvF,oBAAoB,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAC7C,wGAAwG;IACxG,oBAAoB,CAAC,EAAE,CACrB,SAAS,EAAE,mBAAmB,KAC3B,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAChC,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAE7B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B;;;OAGG;IACH,sBAAsB,CAAC,EAAE,CAAC,GAAG,EAAE;QAC7B,YAAY,EAAE,MAAM,CAAC;QACrB,OAAO,EAAE,aAAa,CAAC;KACxB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3B;;;OAGG;IACH,iBAAiB,CAAC,EAAE,CAClB,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,EAC7B,OAAO,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,KAChD,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB,6DAA6D;IAC7D,iBAAiB,CAAC,EAAE;QAClB,2DAA2D;QAC3D,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB;;;WAGG;QACH,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,yEAAyE;QACzE,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,sCAAsC;QACtC,MAAM,CAAC,EAAE,cAAc,CAAC;KACzB,CAAC;IACF,6DAA6D;IAC7D,UAAU,CAAC,EAAE;QACX,8DAA8D;QAC9D,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,2EAA2E;QAC3E,MAAM,CAAC,EAAE,yBAAyB,CAAC;KACpC,CAAC;CACH;AAED,MAAM,MAAM,0BAA0B,GAAG,CACvC,MAAM,EAAE,eAAe,KACpB,eAAe,CAAC;AAErB,MAAM,MAAM,iCAAiC,GAAG,CAC9C,MAAM,EAAE,eAAe,KACpB,MAAM,EAAE,EAAE,CAAC;AAEhB,MAAM,MAAM,mBAAmB,GAAG,CAChC,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE;IAAE,YAAY,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,EAC7D,OAAO,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,IAAI,CAAC,KAChD,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB;;;;;GAKG;AACH,qBAAa,oBACX,SAAQ,kBACR,YAAW,SAAS;IAEb,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;IAC9C,oBAAoB,CAAC,EAAE,CAC5B,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,KAC1B,IAAI,CAAC;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAExC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAmB;IACpD,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsB;IAC1D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsB;IAC1D,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAU;IAC7C,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAAU;IACrD,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAKzB;IACd,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA6B;IAChE,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CACvC;IACL,OAAO,CAAC,QAAQ,CAAC,kCAAkC,CAC9C;IAEL;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAwC;IAErE,wFAAwF;IACxF,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA4B;IAE9D,sFAAsF;IACtF,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAqB;IAExD,yEAAyE;IACzE,OAAO,CAAC,QAAQ,CAAC,0BAA0B,CAGvC;IAEJ,2EAA2E;IAC3E,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAuC;IAGzE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAU;IAC3C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAS;IAC5C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAU;gBAEhC,OAAO,EAAE,2BAA2B;IA4KhD;;;;OAIG;IACI,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,IAAI;IAIvD;;;;OAIG;IACI,0BAA0B,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,IAAI;IAIzD;;;;OAIG;IACI,oBAAoB,CAAC,UAAU,EAAE,mBAAmB,GAAG,IAAI;IAIlE;;;;OAIG;IACI,6BAA6B,CAClC,WAAW,EAAE,0BAA0B,GACtC,IAAI;IAIP;;OAEG;IACI,oCAAoC,CACzC,QAAQ,EAAE,iCAAiC,GAC1C,IAAI;IAIP;;;OAGG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAuCnC;;OAEG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAsBnC;;;OAGG;IACU,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAazD;;;;;;OAMG;IACU,kBAAkB,CAC7B,MAAM,GAAE,MAA0B,GACjC,OAAO,CAAC,UAAU,EAAE,CAAC;IAIxB;;;;;OAKG;IACI,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI3E;;;;;OAKG;IACH,OAAO,CAAC,wBAAwB;IAchC,OAAO,CAAC,8BAA8B;IAStC,OAAO,CAAC,uBAAuB;IAsB/B,OAAO,CAAC,gCAAgC;IAyBxC,OAAO,CAAC,YAAY;YAIN,uBAAuB;IAkCrC;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;YA8Cf,8BAA8B;IAY5C;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAQ7B;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;IAYlC;;;OAGG;IACH,OAAO,CAAC,gCAAgC;IASxC,OAAO,CAAC,8BAA8B;YAMxB,cAAc;IAmJ5B;;;OAGG;YACW,kBAAkB;IAiEhC;;;;;OAKG;IACU,gBAAgB,CAC3B,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,cAAc,EAC5B,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC,IAAI,CAAC;IA+BhB;;;;;OAKG;YACW,oBAAoB;IAsClC;;;OAGG;YACW,oBAAoB;IAwDlC;;;OAGG;YACW,sBAAsB;IAiBpC;;;;;OAKG;YACW,wBAAwB;IA0WtC;;;OAGG;IACH,0BAA0B;;;;;;CAQ3B"}
@@ -2,6 +2,7 @@ import { InitializeResultSchema, ListPromptsResultSchema, ListResourcesResultSch
2
2
  import { BaseNostrTransport, } from './base-nostr-transport.js';
3
3
  import { CTXVM_MESSAGES_KIND, DEFAULT_TIMEOUT_MS, EPHEMERAL_GIFT_WRAP_KIND, GIFT_WRAP_KIND, NOSTR_TAGS, NOTIFICATIONS_INITIALIZED_METHOD, decryptMessage, DEFAULT_LRU_SIZE, } from '../core/index.js';
4
4
  import { EncryptionMode, GiftWrapMode } from '../core/interfaces.js';
5
+ import { verifyEvent } from 'nostr-tools/pure';
5
6
  import { injectClientPubkey, injectRequestEventId, withTimeout, } from '../core/utils/utils.js';
6
7
  import { CorrelationStore } from './nostr-server/correlation-store.js';
7
8
  import { SessionStore } from './nostr-server/session-store.js';
@@ -10,6 +11,7 @@ import { ApplesauceRelayPool } from '../relay/applesauce-relay-pool.js';
10
11
  import { AuthorizationPolicy, } from './nostr-server/authorization-policy.js';
11
12
  import { AnnouncementManager, } from './nostr-server/announcement-manager.js';
12
13
  import { OversizedTransferReceiver, } from './oversized-transfer/index.js';
14
+ import { OpenStreamReceiver, OpenStreamWriter, buildOpenStreamAcceptFrame, buildOpenStreamAbortFrame, buildOpenStreamPingFrame, buildOpenStreamPongFrame, } from './open-stream/index.js';
13
15
  import { DEFAULT_CHUNK_SIZE, DEFAULT_OVERSIZED_THRESHOLD, } from './oversized-transfer/constants.js';
14
16
  import { learnPeerCapabilities } from './discovery-tags.js';
15
17
  import { sendAcceptFrame, sendOversizedServerResponse, } from './nostr-server/oversized-server-handler.js';
@@ -21,15 +23,21 @@ import { sendAcceptFrame, sendOversizedServerResponse, } from './nostr-server/ov
21
23
  */
22
24
  export class NostrServerTransport extends BaseNostrTransport {
23
25
  constructor(options) {
24
- var _a, _b, _c, _d, _e, _f, _g, _h;
26
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
25
27
  super('nostr-server-transport', options);
26
28
  this.inboundMiddlewares = [];
29
+ this.listToolsResultTransformers = [];
30
+ this.listToolsAnnouncementTagsProducers = [];
27
31
  /**
28
32
  * Deduplicate inbound events to avoid redundant work.
29
33
  *
30
34
  * Used for gift-wrap envelopes (outer event ids) and decrypted inner events.
31
35
  */
32
36
  this.seenEventIds = new LruCache(DEFAULT_LRU_SIZE);
37
+ /** Pending final responses held until their CEP-41 stream terminates. */
38
+ this.pendingOpenStreamResponses = new Map();
39
+ /** Active server-side CEP-41 writers keyed by inbound request event id. */
40
+ this.openStreamWriters = new Map();
33
41
  this.injectClientPubkey = (_a = options.injectClientPubkey) !== null && _a !== void 0 ? _a : false;
34
42
  this.shouldInjectRequestEventId = (_b = options.injectRequestEventId) !== null && _b !== void 0 ? _b : false;
35
43
  this.onClientSessionEvicted = options.onClientSessionEvicted;
@@ -91,6 +99,8 @@ export class NostrServerTransport extends BaseNostrTransport {
91
99
  publishRelayList: options.publishRelayList,
92
100
  relayListUrls: options.relayListUrls,
93
101
  bootstrapRelayUrls: options.bootstrapRelayUrls,
102
+ transformListToolsResult: (result) => this.applyListToolsResultTransformers(result),
103
+ getListToolsAnnouncementTags: (result) => this.buildListToolsAnnouncementTags(result),
94
104
  onDispatchMessage: (message) => { var _a; return (_a = this.onmessage) === null || _a === void 0 ? void 0 : _a.call(this, message); },
95
105
  onPublishEvent: (event) => this.publishEvent(event),
96
106
  onPublishEventToRelays: (event, relayUrls) => this.publishEventToRelayUrls(event, relayUrls),
@@ -105,12 +115,66 @@ export class NostrServerTransport extends BaseNostrTransport {
105
115
  this.oversizedThreshold = (_f = ot === null || ot === void 0 ? void 0 : ot.thresholdBytes) !== null && _f !== void 0 ? _f : DEFAULT_OVERSIZED_THRESHOLD;
106
116
  this.oversizedChunkSize = (_g = ot === null || ot === void 0 ? void 0 : ot.chunkSizeBytes) !== null && _g !== void 0 ? _g : DEFAULT_CHUNK_SIZE;
107
117
  this.oversizedReceiver = new OversizedTransferReceiver((_h = ot === null || ot === void 0 ? void 0 : ot.policy) !== null && _h !== void 0 ? _h : {}, this.logger);
118
+ this.openStreamEnabled = (_k = (_j = options.openStream) === null || _j === void 0 ? void 0 : _j.enabled) !== null && _k !== void 0 ? _k : false;
119
+ this.openStreamReceiver = new OpenStreamReceiver({
120
+ maxConcurrentStreams: (_m = (_l = options.openStream) === null || _l === void 0 ? void 0 : _l.policy) === null || _m === void 0 ? void 0 : _m.maxConcurrentStreams,
121
+ maxBufferedChunksPerStream: (_p = (_o = options.openStream) === null || _o === void 0 ? void 0 : _o.policy) === null || _p === void 0 ? void 0 : _p.maxBufferedChunksPerStream,
122
+ maxBufferedBytesPerStream: (_r = (_q = options.openStream) === null || _q === void 0 ? void 0 : _q.policy) === null || _r === void 0 ? void 0 : _r.maxBufferedBytesPerStream,
123
+ idleTimeoutMs: (_t = (_s = options.openStream) === null || _s === void 0 ? void 0 : _s.policy) === null || _t === void 0 ? void 0 : _t.idleTimeoutMs,
124
+ probeTimeoutMs: (_v = (_u = options.openStream) === null || _u === void 0 ? void 0 : _u.policy) === null || _v === void 0 ? void 0 : _v.probeTimeoutMs,
125
+ closeGracePeriodMs: (_x = (_w = options.openStream) === null || _w === void 0 ? void 0 : _w.policy) === null || _x === void 0 ? void 0 : _x.closeGracePeriodMs,
126
+ getSessionOptions: (progressToken) => {
127
+ let progress = 0;
128
+ return {
129
+ sendPing: async (nonce) => {
130
+ progress += 1;
131
+ await this.sendNotification(progressToken, {
132
+ jsonrpc: '2.0',
133
+ method: 'notifications/progress',
134
+ params: buildOpenStreamPingFrame({
135
+ progressToken,
136
+ progress,
137
+ nonce,
138
+ }),
139
+ });
140
+ },
141
+ sendPong: async (nonce) => {
142
+ progress += 1;
143
+ await this.sendNotification(progressToken, {
144
+ jsonrpc: '2.0',
145
+ method: 'notifications/progress',
146
+ params: buildOpenStreamPongFrame({
147
+ progressToken,
148
+ progress,
149
+ nonce,
150
+ }),
151
+ });
152
+ },
153
+ sendAbort: async (reason) => {
154
+ progress += 1;
155
+ await this.sendNotification(progressToken, {
156
+ jsonrpc: '2.0',
157
+ method: 'notifications/progress',
158
+ params: buildOpenStreamAbortFrame({
159
+ progressToken,
160
+ progress,
161
+ reason,
162
+ }),
163
+ });
164
+ },
165
+ };
166
+ },
167
+ logger: this.logger,
168
+ });
108
169
  // Advertise CEP-22 support so clients can skip the accept handshake.
170
+ const internalCommonTags = [];
109
171
  if (this.oversizedEnabled) {
110
- this.announcementManager.setInternalCommonTags([
111
- [NOSTR_TAGS.SUPPORT_OVERSIZED_TRANSFER],
112
- ]);
172
+ internalCommonTags.push([NOSTR_TAGS.SUPPORT_OVERSIZED_TRANSFER]);
173
+ }
174
+ if (this.openStreamEnabled) {
175
+ internalCommonTags.push([NOSTR_TAGS.SUPPORT_OPEN_STREAM]);
113
176
  }
177
+ this.announcementManager.setInternalCommonTags(internalCommonTags);
114
178
  }
115
179
  /**
116
180
  * Sets extra tags to include in server announcement + initialize response events.
@@ -136,6 +200,20 @@ export class NostrServerTransport extends BaseNostrTransport {
136
200
  addInboundMiddleware(middleware) {
137
201
  this.inboundMiddlewares.push(middleware);
138
202
  }
203
+ /**
204
+ * Adds a transformer for `tools/list` results emitted by the server.
205
+ *
206
+ * Transformers are applied to direct responses and public announcement payloads.
207
+ */
208
+ addListToolsResultTransformer(transformer) {
209
+ this.listToolsResultTransformers.push(transformer);
210
+ }
211
+ /**
212
+ * Adds a provider for extra tags on public tools/list announcement events.
213
+ */
214
+ addListToolsAnnouncementTagsProducer(producer) {
215
+ this.listToolsAnnouncementTagsProducers.push(producer);
216
+ }
139
217
  /**
140
218
  * Starts the transport, connecting to the relay and setting up event listeners
141
219
  * to receive incoming MCP requests.
@@ -191,6 +269,9 @@ export class NostrServerTransport extends BaseNostrTransport {
191
269
  this.correlationStore.clear();
192
270
  this.seenEventIds.clear();
193
271
  this.oversizedReceiver.clear();
272
+ this.openStreamReceiver.clear();
273
+ this.pendingOpenStreamResponses.clear();
274
+ this.openStreamWriters.clear();
194
275
  (_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
195
276
  }
196
277
  catch (error) {
@@ -321,6 +402,35 @@ export class NostrServerTransport extends BaseNostrTransport {
321
402
  // Register the event route in the correlation store
322
403
  const progressToken = (_b = (_a = request.params) === null || _a === void 0 ? void 0 : _a._meta) === null || _b === void 0 ? void 0 : _b.progressToken;
323
404
  this.correlationStore.registerEventRoute(eventId, clientPubkey, originalRequestId, progressToken ? String(progressToken) : undefined, wrapKind, this.shouldInjectRequestEventId ? event : undefined);
405
+ if (this.openStreamEnabled && progressToken) {
406
+ const writer = new OpenStreamWriter({
407
+ progressToken: String(progressToken),
408
+ publishFrame: async (frame) => {
409
+ await this.sendNotification(clientPubkey, {
410
+ jsonrpc: '2.0',
411
+ method: 'notifications/progress',
412
+ params: frame,
413
+ });
414
+ return undefined;
415
+ },
416
+ onClose: async () => {
417
+ await this.flushPendingOpenStreamResponse(eventId);
418
+ },
419
+ onAbort: async () => {
420
+ await this.flushPendingOpenStreamResponse(eventId);
421
+ },
422
+ });
423
+ this.openStreamWriters.set(eventId, writer);
424
+ }
425
+ }
426
+ async flushPendingOpenStreamResponse(eventId) {
427
+ const pendingResponse = this.pendingOpenStreamResponses.get(eventId);
428
+ this.pendingOpenStreamResponses.delete(eventId);
429
+ this.openStreamWriters.delete(eventId);
430
+ if (!pendingResponse) {
431
+ return;
432
+ }
433
+ await this.handleResponse(pendingResponse);
324
434
  }
325
435
  /**
326
436
  * Cleans up request correlation for a request that was dropped by middleware.
@@ -346,6 +456,12 @@ export class NostrServerTransport extends BaseNostrTransport {
346
456
  * Handles response messages by finding the original request and routing back to client.
347
457
  * @param response The JSON-RPC response or error to send.
348
458
  */
459
+ applyListToolsResultTransformers(result) {
460
+ return this.listToolsResultTransformers.reduce((currentResult, transformer) => transformer(currentResult), result);
461
+ }
462
+ buildListToolsAnnouncementTags(result) {
463
+ return this.listToolsAnnouncementTagsProducers.flatMap((producer) => producer(result));
464
+ }
349
465
  async handleResponse(response) {
350
466
  var _a, _b;
351
467
  // Handle special announcement responses
@@ -360,6 +476,11 @@ export class NostrServerTransport extends BaseNostrTransport {
360
476
  }
361
477
  // Find the event route using O(1) lookup
362
478
  const nostrEventId = response.id;
479
+ const existingOpenStreamWriter = this.openStreamWriters.get(nostrEventId);
480
+ if (existingOpenStreamWriter && existingOpenStreamWriter.isActive) {
481
+ this.pendingOpenStreamResponses.set(nostrEventId, response);
482
+ return;
483
+ }
363
484
  const route = this.correlationStore.popEventRoute(nostrEventId);
364
485
  if (!route) {
365
486
  (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, new Error(`No pending request found for response ID: ${response.id}`));
@@ -370,14 +491,23 @@ export class NostrServerTransport extends BaseNostrTransport {
370
491
  (_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, new Error(`No session found for client: ${route.clientPubkey}`));
371
492
  return;
372
493
  }
494
+ const parsedListToolsResult = isJSONRPCResultResponse(response)
495
+ ? ListToolsResultSchema.safeParse(response.result)
496
+ : null;
497
+ const responseToSend = (parsedListToolsResult === null || parsedListToolsResult === void 0 ? void 0 : parsedListToolsResult.success)
498
+ ? {
499
+ ...response,
500
+ result: this.applyListToolsResultTransformers(parsedListToolsResult.data),
501
+ }
502
+ : response;
373
503
  // Restore the original request ID in the response
374
- response.id = route.originalRequestId;
504
+ responseToSend.id = route.originalRequestId;
375
505
  // CEP-22 Oversized Transfer (proactive path for server responses)
376
506
  if (this.oversizedEnabled &&
377
507
  route.progressToken &&
378
508
  session.supportsOversizedTransfer) {
379
509
  // Serialize before restoring id so the client receives the correct id.
380
- const serialized = JSON.stringify(response);
510
+ const serialized = JSON.stringify(responseToSend);
381
511
  const byteLength = new TextEncoder().encode(serialized).byteLength;
382
512
  if (byteLength > this.oversizedThreshold) {
383
513
  const continuationFrameTags = this.createResponseTags(route.clientPubkey, nostrEventId);
@@ -416,8 +546,8 @@ export class NostrServerTransport extends BaseNostrTransport {
416
546
  fallbackWrapKind: route.wrapKind,
417
547
  });
418
548
  // Attach pricing tags to capability list responses so clients can access CEP-8 pricing
419
- if (isJSONRPCResultResponse(response)) {
420
- const result = response.result;
549
+ if (isJSONRPCResultResponse(responseToSend)) {
550
+ const result = responseToSend.result;
421
551
  if (ListToolsResultSchema.safeParse(result).success ||
422
552
  ListResourcesResultSchema.safeParse(result).success ||
423
553
  ListResourceTemplatesResultSchema.safeParse(result).success ||
@@ -426,7 +556,7 @@ export class NostrServerTransport extends BaseNostrTransport {
426
556
  }
427
557
  }
428
558
  try {
429
- await this.sendMcpMessage(response, route.clientPubkey, CTXVM_MESSAGES_KIND, tags, session.isEncrypted, undefined, giftWrapKind);
559
+ await this.sendMcpMessage(responseToSend, route.clientPubkey, CTXVM_MESSAGES_KIND, tags, session.isEncrypted, undefined, giftWrapKind);
430
560
  }
431
561
  catch (error) {
432
562
  this.correlationStore.registerEventRoute(nostrEventId, route.clientPubkey, route.originalRequestId, route.progressToken, route.wrapKind);
@@ -567,6 +697,17 @@ export class NostrServerTransport extends BaseNostrTransport {
567
697
  try {
568
698
  const decryptedJson = await withTimeout(decryptMessage(event, this.signer), DEFAULT_TIMEOUT_MS, 'Decrypt message timed out');
569
699
  const currentEvent = JSON.parse(decryptedJson);
700
+ // Verify the inner event's cryptographic signature to prevent identity
701
+ // forgery. Without this check an attacker can place any pubkey inside
702
+ // the plaintext and bypass allowlists. (Fixes #64)
703
+ if (!verifyEvent(currentEvent)) {
704
+ this.logger.error('Rejecting decrypted inner event with invalid signature', {
705
+ innerEventId: currentEvent.id,
706
+ innerPubkey: currentEvent.pubkey,
707
+ outerEventId: event.id,
708
+ });
709
+ return;
710
+ }
570
711
  // Deduplicate decrypted inner events before authorization and dispatch.
571
712
  if (this.seenEventIds.has(currentEvent.id)) {
572
713
  this.logger.debug('Skipping duplicate decrypted inner event', {
@@ -599,6 +740,13 @@ export class NostrServerTransport extends BaseNostrTransport {
599
740
  this.logger.error(`Received unencrypted message from ${event.pubkey} but encryption is required. Ignoring.`);
600
741
  return;
601
742
  }
743
+ if (!verifyEvent(event)) {
744
+ this.logger.error('Rejecting unencrypted event with invalid signature', {
745
+ eventId: event.id,
746
+ pubkey: event.pubkey,
747
+ });
748
+ return;
749
+ }
602
750
  await this.authorizeAndProcessEvent(event, false);
603
751
  }
604
752
  /**
@@ -608,7 +756,7 @@ export class NostrServerTransport extends BaseNostrTransport {
608
756
  * @param isEncrypted Whether the original event was encrypted.
609
757
  */
610
758
  async authorizeAndProcessEvent(event, isEncrypted, wrapKind) {
611
- var _a;
759
+ var _a, _b, _c, _d, _e, _f, _g, _h;
612
760
  try {
613
761
  const mcpMessage = this.convertNostrEventToMcpMessage(event);
614
762
  if (!mcpMessage) {
@@ -619,6 +767,7 @@ export class NostrServerTransport extends BaseNostrTransport {
619
767
  });
620
768
  return;
621
769
  }
770
+ const inboundMessage = mcpMessage;
622
771
  // Check authorization using the authorization policy
623
772
  const authDecision = await this.authorizationPolicy.authorize(event.pubkey, mcpMessage);
624
773
  if (!authDecision.allowed) {
@@ -660,6 +809,7 @@ export class NostrServerTransport extends BaseNostrTransport {
660
809
  session.supportsEphemeralEncryption || (session.supportsEphemeralEncryption = discoveredCapabilities.supportsEphemeralEncryption);
661
810
  session.supportsOversizedTransfer || (session.supportsOversizedTransfer = this.oversizedEnabled &&
662
811
  discoveredCapabilities.supportsOversizedTransfer);
812
+ session.supportsOpenStream || (session.supportsOpenStream = this.openStreamEnabled && discoveredCapabilities.supportsOpenStream);
663
813
  const shouldSendAccept = !hadLearnedOversizedSupport;
664
814
  const forward = async (msg) => {
665
815
  var _a, _b;
@@ -688,29 +838,107 @@ export class NostrServerTransport extends BaseNostrTransport {
688
838
  });
689
839
  return forwarded;
690
840
  };
691
- if (isJSONRPCRequest(mcpMessage)) {
692
- this.handleIncomingRequest(event, event.id, mcpMessage, event.pubkey, wrapKind);
841
+ if (isJSONRPCRequest(inboundMessage)) {
842
+ this.handleIncomingRequest(event, event.id, inboundMessage, event.pubkey, wrapKind);
693
843
  if (this.shouldInjectRequestEventId) {
694
- injectRequestEventId(mcpMessage, event.id);
844
+ injectRequestEventId(inboundMessage, event.id);
695
845
  }
696
846
  if (this.injectClientPubkey) {
697
- injectClientPubkey(mcpMessage, event.pubkey);
847
+ injectClientPubkey(inboundMessage, event.pubkey);
848
+ }
849
+ const openStreamWriter = this.openStreamWriters.get(event.id);
850
+ if (openStreamWriter) {
851
+ const params = (_a = inboundMessage.params) !== null && _a !== void 0 ? _a : {};
852
+ inboundMessage.params = params;
853
+ const meta = (_b = params._meta) !== null && _b !== void 0 ? _b : {};
854
+ params._meta = meta;
855
+ meta.stream = openStreamWriter;
698
856
  }
699
857
  }
700
- else if (isJSONRPCNotification(mcpMessage)) {
701
- this.handleIncomingNotification(event.pubkey, mcpMessage);
702
- if (mcpMessage.method === 'notifications/progress' &&
703
- OversizedTransferReceiver.isOversizedFrame(mcpMessage)) {
858
+ else if (isJSONRPCNotification(inboundMessage)) {
859
+ this.handleIncomingNotification(event.pubkey, inboundMessage);
860
+ if (inboundMessage.method === 'notifications/progress' &&
861
+ OpenStreamReceiver.isOpenStreamFrame(inboundMessage)) {
862
+ const frame = (_c = inboundMessage.params) === null || _c === void 0 ? void 0 : _c.cvm;
863
+ if ((frame === null || frame === void 0 ? void 0 : frame.frameType) === 'abort') {
864
+ const progressToken = String((_e = (_d = inboundMessage.params) === null || _d === void 0 ? void 0 : _d.progressToken) !== null && _e !== void 0 ? _e : '');
865
+ const eventId = this.correlationStore.getEventIdByProgressToken(progressToken);
866
+ const writer = eventId
867
+ ? this.openStreamWriters.get(eventId)
868
+ : undefined;
869
+ if (writer) {
870
+ void writer.abort(frame.reason).catch((err) => {
871
+ var _a;
872
+ this.logger.error('Open stream abort propagation failed (server)', {
873
+ error: err instanceof Error ? err.message : String(err),
874
+ pubkey: event.pubkey,
875
+ progressToken,
876
+ });
877
+ (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, err instanceof Error ? err : new Error(String(err)));
878
+ });
879
+ }
880
+ return;
881
+ }
882
+ if ((frame === null || frame === void 0 ? void 0 : frame.frameType) === 'ping') {
883
+ const progressToken = String((_g = (_f = inboundMessage.params) === null || _f === void 0 ? void 0 : _f.progressToken) !== null && _g !== void 0 ? _g : '');
884
+ const nonce = 'nonce' in frame && typeof frame.nonce === 'string'
885
+ ? frame.nonce
886
+ : '';
887
+ const eventId = this.correlationStore.getEventIdByProgressToken(progressToken);
888
+ const writer = eventId
889
+ ? this.openStreamWriters.get(eventId)
890
+ : undefined;
891
+ if (writer) {
892
+ void writer.pong(nonce).catch((err) => {
893
+ var _a;
894
+ this.logger.error('Open stream ping handling failed (server)', {
895
+ error: err instanceof Error ? err.message : String(err),
896
+ pubkey: event.pubkey,
897
+ progressToken,
898
+ });
899
+ (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, err instanceof Error ? err : new Error(String(err)));
900
+ });
901
+ return;
902
+ }
903
+ }
904
+ this.openStreamReceiver
905
+ .processFrame(inboundMessage)
906
+ .then(async () => {
907
+ var _a, _b, _c, _d;
908
+ const frameType = frame === null || frame === void 0 ? void 0 : frame.frameType;
909
+ if (frameType === 'start' && session.supportsOpenStream) {
910
+ await this.sendNotification(event.pubkey, {
911
+ jsonrpc: '2.0',
912
+ method: 'notifications/progress',
913
+ params: buildOpenStreamAcceptFrame({
914
+ progressToken: String((_b = (_a = inboundMessage.params) === null || _a === void 0 ? void 0 : _a.progressToken) !== null && _b !== void 0 ? _b : ''),
915
+ progress: Number((_d = (_c = inboundMessage.params) === null || _c === void 0 ? void 0 : _c.progress) !== null && _d !== void 0 ? _d : 0) + 1,
916
+ }),
917
+ });
918
+ }
919
+ })
920
+ .catch((err) => {
921
+ var _a;
922
+ this.logger.error('Open stream error (server)', {
923
+ error: err instanceof Error ? err.message : String(err),
924
+ pubkey: event.pubkey,
925
+ });
926
+ (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, err instanceof Error ? err : new Error(String(err)));
927
+ });
928
+ return;
929
+ }
930
+ if (inboundMessage.method === 'notifications/progress' &&
931
+ OversizedTransferReceiver.isOversizedFrame(inboundMessage)) {
704
932
  this.oversizedReceiver
705
- .processFrame(mcpMessage)
933
+ .processFrame(inboundMessage)
706
934
  .then(async (synthetic) => {
707
935
  var _a, _b, _c, _d;
708
936
  if (synthetic === null) {
709
- if (((_b = (_a = mcpMessage.params) === null || _a === void 0 ? void 0 : _a.cvm) === null || _b === void 0 ? void 0 : _b.frameType) === 'start' &&
937
+ if (((_b = (_a = inboundMessage.params) === null || _a === void 0 ? void 0 : _a.cvm) === null || _b === void 0 ? void 0 : _b.frameType) === 'start' &&
710
938
  shouldSendAccept) {
711
939
  await sendAcceptFrame({
712
940
  clientPubkey: event.pubkey,
713
- progressToken: String((_d = (_c = mcpMessage.params) === null || _c === void 0 ? void 0 : _c.progressToken) !== null && _d !== void 0 ? _d : ''),
941
+ progressToken: String((_d = (_c = inboundMessage.params) === null || _c === void 0 ? void 0 : _c.progressToken) !== null && _d !== void 0 ? _d : ''),
714
942
  }, {
715
943
  sendNotification: this.sendNotification.bind(this),
716
944
  }).catch((err) => {
@@ -760,10 +988,10 @@ export class NostrServerTransport extends BaseNostrTransport {
760
988
  return;
761
989
  }
762
990
  }
763
- void dispatch(0, mcpMessage)
991
+ void dispatch(0, inboundMessage)
764
992
  .then((forwarded) => {
765
993
  if (!forwarded) {
766
- this.cleanupDroppedRequest(mcpMessage);
994
+ this.cleanupDroppedRequest(inboundMessage);
767
995
  }
768
996
  })
769
997
  .catch((err) => {
@@ -783,7 +1011,7 @@ export class NostrServerTransport extends BaseNostrTransport {
783
1011
  eventId: event.id,
784
1012
  pubkey: event.pubkey,
785
1013
  });
786
- (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error instanceof Error ? error : new Error(String(error)));
1014
+ (_h = this.onerror) === null || _h === void 0 ? void 0 : _h.call(this, error instanceof Error ? error : new Error(String(error)));
787
1015
  }
788
1016
  }
789
1017
  /**
@@ -794,6 +1022,8 @@ export class NostrServerTransport extends BaseNostrTransport {
794
1022
  return {
795
1023
  sessionStore: this.sessionStore,
796
1024
  correlationStore: this.correlationStore,
1025
+ oversizedReceiver: this.oversizedReceiver,
1026
+ openStreamReceiver: this.openStreamReceiver,
797
1027
  };
798
1028
  }
799
1029
  }