@contextvm/sdk 0.1.0 → 0.1.2

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 (71) hide show
  1. package/dist/esm/core/constants.d.ts +65 -0
  2. package/dist/esm/core/constants.d.ts.map +1 -0
  3. package/dist/esm/core/constants.js +70 -0
  4. package/dist/esm/core/constants.js.map +1 -0
  5. package/dist/esm/core/encryption.d.ts +18 -0
  6. package/dist/esm/core/encryption.d.ts.map +1 -0
  7. package/dist/esm/core/encryption.js +40 -0
  8. package/dist/esm/core/encryption.js.map +1 -0
  9. package/dist/esm/core/index.d.ts +5 -0
  10. package/dist/esm/core/index.d.ts.map +1 -0
  11. package/dist/esm/core/index.js +5 -0
  12. package/dist/esm/core/index.js.map +1 -0
  13. package/dist/esm/core/interfaces.d.ts +39 -0
  14. package/dist/esm/core/interfaces.d.ts.map +1 -0
  15. package/dist/esm/core/interfaces.js +13 -0
  16. package/dist/esm/core/interfaces.js.map +1 -0
  17. package/dist/esm/core/utils/serializers.d.ts +29 -0
  18. package/dist/esm/core/utils/serializers.d.ts.map +1 -0
  19. package/dist/esm/core/utils/serializers.js +46 -0
  20. package/dist/esm/core/utils/serializers.js.map +1 -0
  21. package/dist/esm/gateway/index.d.ts +60 -0
  22. package/dist/esm/gateway/index.d.ts.map +1 -0
  23. package/dist/esm/gateway/index.js +110 -0
  24. package/dist/esm/gateway/index.js.map +1 -0
  25. package/dist/esm/index.d.ts +7 -0
  26. package/dist/esm/index.d.ts.map +1 -0
  27. package/dist/esm/index.js +7 -0
  28. package/dist/esm/index.js.map +1 -0
  29. package/dist/esm/package.json +1 -0
  30. package/dist/esm/proxy/index.d.ts +42 -0
  31. package/dist/esm/proxy/index.d.ts.map +1 -0
  32. package/dist/esm/proxy/index.js +59 -0
  33. package/dist/esm/proxy/index.js.map +1 -0
  34. package/dist/esm/proxy/proxy-server.d.ts +3 -0
  35. package/dist/esm/proxy/proxy-server.d.ts.map +1 -0
  36. package/dist/esm/proxy/proxy-server.js +55 -0
  37. package/dist/esm/proxy/proxy-server.js.map +1 -0
  38. package/dist/esm/relay/index.d.ts +2 -0
  39. package/dist/esm/relay/index.d.ts.map +1 -0
  40. package/dist/esm/relay/index.js +2 -0
  41. package/dist/esm/relay/index.js.map +1 -0
  42. package/dist/esm/relay/simple-relay-pool.d.ts +19 -0
  43. package/dist/esm/relay/simple-relay-pool.d.ts.map +1 -0
  44. package/dist/esm/relay/simple-relay-pool.js +44 -0
  45. package/dist/esm/relay/simple-relay-pool.js.map +1 -0
  46. package/dist/esm/signer/index.d.ts +2 -0
  47. package/dist/esm/signer/index.d.ts.map +1 -0
  48. package/dist/esm/signer/index.js +2 -0
  49. package/dist/esm/signer/index.js.map +1 -0
  50. package/dist/esm/signer/private-key-signer.d.ts +16 -0
  51. package/dist/esm/signer/private-key-signer.d.ts.map +1 -0
  52. package/dist/esm/signer/private-key-signer.js +23 -0
  53. package/dist/esm/signer/private-key-signer.js.map +1 -0
  54. package/dist/esm/transport/base-nostr-transport.d.ts +67 -0
  55. package/dist/esm/transport/base-nostr-transport.d.ts.map +1 -0
  56. package/dist/esm/transport/base-nostr-transport.js +122 -0
  57. package/dist/esm/transport/base-nostr-transport.js.map +1 -0
  58. package/dist/esm/transport/index.d.ts +4 -0
  59. package/dist/esm/transport/index.d.ts.map +1 -0
  60. package/dist/esm/transport/index.js +4 -0
  61. package/dist/esm/transport/index.js.map +1 -0
  62. package/dist/esm/transport/nostr-client-transport.d.ts +60 -0
  63. package/dist/esm/transport/nostr-client-transport.d.ts.map +1 -0
  64. package/dist/esm/transport/nostr-client-transport.js +116 -0
  65. package/dist/esm/transport/nostr-client-transport.js.map +1 -0
  66. package/dist/esm/transport/nostr-server-transport.d.ts +128 -0
  67. package/dist/esm/transport/nostr-server-transport.d.ts.map +1 -0
  68. package/dist/esm/transport/nostr-server-transport.js +383 -0
  69. package/dist/esm/transport/nostr-server-transport.js.map +1 -0
  70. package/package.json +4 -3
  71. package/COPYING.LESSER +0 -165
@@ -0,0 +1,116 @@
1
+ import { NotificationSchema, } from '@modelcontextprotocol/sdk/types.js';
2
+ import { CTXVM_MESSAGES_KIND, GIFT_WRAP_KIND, decryptMessage, } from '../core/index.js';
3
+ import { BaseNostrTransport } from './base-nostr-transport.js';
4
+ import { getNostrEventTag } from '../core/utils/serializers.js';
5
+ /**
6
+ * A transport layer for CTXVM that uses Nostr events for communication.
7
+ * It implements the Transport interface from the @modelcontextprotocol/sdk.
8
+ */
9
+ export class NostrClientTransport extends BaseNostrTransport {
10
+ constructor(options) {
11
+ super(options);
12
+ this.serverPubkey = options.serverPubkey;
13
+ this.pendingRequestIds = new Set();
14
+ }
15
+ /**
16
+ * Starts the transport, connecting to the relay and setting up event listeners.
17
+ */
18
+ async start() {
19
+ await this.connect();
20
+ const pubkey = await this.getPublicKey();
21
+ const filters = this.createSubscriptionFilters(pubkey);
22
+ await this.subscribe(filters, this.processIncomingEvent.bind(this));
23
+ }
24
+ /**
25
+ * Closes the transport, disconnecting from the relay.
26
+ */
27
+ async close() {
28
+ var _a;
29
+ await this.disconnect();
30
+ (_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
31
+ }
32
+ /**
33
+ * Sends a JSON-RPC message over the Nostr transport.
34
+ * @param message The JSON-RPC request or response to send.
35
+ */
36
+ async send(message) {
37
+ const eventId = await this._sendInternal(message);
38
+ if (eventId) {
39
+ this.pendingRequestIds.add(eventId);
40
+ }
41
+ }
42
+ /**
43
+ * Internal method to send a JSON-RPC message and get the resulting event ID.
44
+ * @param message The JSON-RPC message to send.
45
+ * @returns The ID of the published Nostr event.
46
+ */
47
+ async _sendInternal(message) {
48
+ const tags = this.createRecipientTags(this.serverPubkey);
49
+ return this.sendMcpMessage(message, this.serverPubkey, CTXVM_MESSAGES_KIND, tags);
50
+ }
51
+ /**
52
+ * Processes incoming Nostr events, routing them to the correct handler.
53
+ */
54
+ async processIncomingEvent(event) {
55
+ var _a;
56
+ try {
57
+ let nostrEvent = event;
58
+ // Handle encrypted messages
59
+ if (event.kind === GIFT_WRAP_KIND) {
60
+ const secretKey = await this.signer.getSecretKey();
61
+ if (!secretKey) {
62
+ throw new Error('Secret key is not available for decryption.');
63
+ }
64
+ const decryptedContent = decryptMessage(event, secretKey);
65
+ nostrEvent = JSON.parse(decryptedContent);
66
+ }
67
+ // Process the resulting event
68
+ const mcpMessage = this.convertNostrEventToMcpMessage(nostrEvent);
69
+ const eTag = getNostrEventTag(nostrEvent.tags, 'e');
70
+ if (eTag) {
71
+ this.handleResponse(eTag, mcpMessage);
72
+ }
73
+ else {
74
+ this.handleNotification(mcpMessage);
75
+ }
76
+ }
77
+ catch (error) {
78
+ console.error('Error handling incoming Nostr event:', error);
79
+ (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error instanceof Error
80
+ ? error
81
+ : new Error('Failed to handle incoming Nostr event'));
82
+ }
83
+ }
84
+ /**
85
+ * Handles response messages by correlating them with pending requests.
86
+ * @param correlatedEventId The event ID from the 'e' tag.
87
+ * @param mcpMessage The incoming MCP message.
88
+ */
89
+ handleResponse(correlatedEventId, mcpMessage) {
90
+ var _a;
91
+ if (this.pendingRequestIds.has(correlatedEventId)) {
92
+ (_a = this.onmessage) === null || _a === void 0 ? void 0 : _a.call(this, mcpMessage);
93
+ this.pendingRequestIds.delete(correlatedEventId);
94
+ }
95
+ else {
96
+ console.warn(`Received Nostr event with unexpected 'e' tag: ${correlatedEventId}.`);
97
+ }
98
+ }
99
+ /**
100
+ * Handles notification messages.
101
+ * @param mcpMessage The incoming MCP message.
102
+ */
103
+ handleNotification(mcpMessage) {
104
+ var _a, _b;
105
+ try {
106
+ NotificationSchema.parse(mcpMessage);
107
+ (_a = this.onmessage) === null || _a === void 0 ? void 0 : _a.call(this, mcpMessage);
108
+ }
109
+ catch (error) {
110
+ (_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error instanceof Error
111
+ ? error
112
+ : new Error('Failed to handle incoming notification'));
113
+ }
114
+ }
115
+ }
116
+ //# sourceMappingURL=nostr-client-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nostr-client-transport.js","sourceRoot":"","sources":["../../../src/transport/nostr-client-transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,128 @@
1
+ import { type JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
2
+ import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
3
+ import { BaseNostrTransport, BaseNostrTransportOptions } from './base-nostr-transport.js';
4
+ import { EncryptionMode } from '../core/interfaces.js';
5
+ /**
6
+ * Options for configuring the NostrServerTransport.
7
+ */
8
+ export interface NostrServerTransportOptions extends BaseNostrTransportOptions {
9
+ serverInfo?: ServerInfo;
10
+ isPublicServer?: boolean;
11
+ allowedPublicKeys?: string[];
12
+ encryptionMode?: EncryptionMode;
13
+ }
14
+ /**
15
+ * Information about a server.
16
+ */
17
+ export interface ServerInfo {
18
+ name?: string;
19
+ picture?: string;
20
+ website?: string;
21
+ }
22
+ /**
23
+ * A server-side transport layer for CTXVM that uses Nostr events for communication.
24
+ * This transport listens for incoming MCP requests via Nostr events and can send
25
+ * responses back to the originating clients. It handles all request/response correlation
26
+ * internally, making it a standalone MCP transport that works over Nostr.
27
+ */
28
+ export declare class NostrServerTransport extends BaseNostrTransport implements Transport {
29
+ onmessage?: (message: JSONRPCMessage) => void;
30
+ onclose?: () => void;
31
+ onerror?: (error: Error) => void;
32
+ private readonly clientSessions;
33
+ private readonly isPublicServer?;
34
+ private readonly allowedPublicKeys?;
35
+ private readonly serverInfo?;
36
+ constructor(options: NostrServerTransportOptions);
37
+ /**
38
+ * Starts the transport, connecting to the relay and setting up event listeners
39
+ * to receive incoming MCP requests.
40
+ */
41
+ start(): Promise<void>;
42
+ /**
43
+ * Closes the transport, disconnecting from the relay.
44
+ */
45
+ close(): Promise<void>;
46
+ /**
47
+ * Sends JSON-RPC messages over the Nostr transport.
48
+ * @param message The JSON-RPC message to send.
49
+ */
50
+ send(message: JSONRPCMessage): Promise<void>;
51
+ /**
52
+ * Initiates the process of fetching announcement data from the server's internal logic.
53
+ */
54
+ private getAnnouncementData;
55
+ /**
56
+ * Handles the JSON-RPC responses for public server announcements and publishes
57
+ * them as Nostr events to the configured relays.
58
+ * @param message The JSON-RPC response containing the announcement data.
59
+ */
60
+ private announcer;
61
+ /**
62
+ * Gets or creates a client session with proper initialization.
63
+ * @param clientPubkey The client's public key.
64
+ * @param now Current timestamp.
65
+ * @returns The client session.
66
+ */
67
+ private getOrCreateClientSession;
68
+ /**
69
+ * Handles incoming requests with correlation tracking.
70
+ * @param session The client session.
71
+ * @param eventId The Nostr event ID.
72
+ * @param request The request message.
73
+ */
74
+ private handleIncomingRequest;
75
+ /**
76
+ * Handles incoming notifications.
77
+ * @param session The client session.
78
+ * @param notification The notification message.
79
+ */
80
+ private handleIncomingNotification;
81
+ /**
82
+ * Handles response messages by finding the original request and routing back to client.
83
+ * @param response The JSON-RPC response or error to send.
84
+ */
85
+ private handleResponse;
86
+ /**
87
+ * Handles notification messages with routing.
88
+ * @param notification The JSON-RPC notification to send.
89
+ */
90
+ private handleNotification;
91
+ /**
92
+ * Sends a notification to a specific client by their public key.
93
+ * @param clientPubkey The public key of the target client.
94
+ * @param notification The notification message to send.
95
+ * @returns Promise that resolves when the notification is sent.
96
+ */
97
+ sendNotification(clientPubkey: string, notification: JSONRPCMessage, correlatedEventId?: string): Promise<void>;
98
+ /**
99
+ * Processes incoming Nostr events, handling decryption and client authorization.
100
+ * This method centralizes the logic for determining whether to process an event
101
+ * based on encryption mode and allowed public keys.
102
+ * @param event The incoming Nostr event.
103
+ */
104
+ private processIncomingEvent;
105
+ /**
106
+ * Handles encrypted (gift-wrapped) events.
107
+ * @param event The incoming gift-wrapped Nostr event.
108
+ */
109
+ private handleEncryptedEvent;
110
+ /**
111
+ * Handles unencrypted events.
112
+ * @param event The incoming Nostr event.
113
+ */
114
+ private handleUnencryptedEvent;
115
+ /**
116
+ * Common logic for authorizing and processing an event.
117
+ * @param event The event to process.
118
+ * @param isEncrypted Whether the original event was encrypted.
119
+ */
120
+ private authorizeAndProcessEvent;
121
+ /**
122
+ * Cleans up inactive client sessions based on a timeout.
123
+ * @param timeoutMs Timeout in milliseconds for considering a session inactive (default: 5 minutes).
124
+ * @returns The number of sessions that were cleaned up.
125
+ */
126
+ cleanupInactiveSessions(timeoutMs?: number): number;
127
+ }
128
+ //# sourceMappingURL=nostr-server-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nostr-server-transport.d.ts","sourceRoot":"","sources":["../../../src/transport/nostr-server-transport.ts"],"names":[],"mappings":"AAAA,OAAO,EAYL,KAAK,cAAc,EAIpB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAE/E,OAAO,EACL,kBAAkB,EAClB,yBAAyB,EAC1B,MAAM,2BAA2B,CAAC;AAanC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD;;GAEG;AACH,MAAM,WAAW,2BAA4B,SAAQ,yBAAyB;IAC5E,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAYD;;;;;GAKG;AACH,qBAAa,oBACX,SAAQ,kBACR,YAAW,SAAS;IAEb,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;IAC9C,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAExC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAoC;IACnE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAU;IAC1C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAW;IAC9C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAa;gBAE7B,OAAO,EAAE,2BAA2B;IAOhD;;;OAGG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAanC;;OAEG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAMnC;;;OAGG;IACU,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAYzD;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAsB3B;;;;OAIG;YACW,SAAS;IAkDvB;;;;;OAKG;IACH,OAAO,CAAC,wBAAwB;IAoBhC;;;;;OAKG;IACH,OAAO,CAAC,qBAAqB;IAmB7B;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;IAYlC;;;OAGG;YACW,cAAc;IA6E5B;;;OAGG;YACW,kBAAkB;IAiChC;;;;;OAKG;IACU,gBAAgB,CAC3B,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,cAAc,EAC5B,iBAAiB,CAAC,EAAE,MAAM,GACzB,OAAO,CAAC,IAAI,CAAC;IAqBhB;;;;;OAKG;YACW,oBAAoB;IAQlC;;;OAGG;YACW,oBAAoB;IAwBlC;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAU9B;;;;OAIG;IACH,OAAO,CAAC,wBAAwB;IA8BhC;;;;OAIG;IACI,uBAAuB,CAAC,SAAS,GAAE,MAAe,GAAG,MAAM;CAgBnE"}
@@ -0,0 +1,383 @@
1
+ import { InitializeResultSchema, isJSONRPCRequest, isJSONRPCResponse, isJSONRPCNotification, LATEST_PROTOCOL_VERSION, ListPromptsResultSchema, ListResourcesResultSchema, ListResourceTemplatesResultSchema, ListToolsResultSchema, isJSONRPCError, } from '@modelcontextprotocol/sdk/types.js';
2
+ import { BaseNostrTransport, } from './base-nostr-transport.js';
3
+ import { announcementMethods, CTXVM_MESSAGES_KIND, GIFT_WRAP_KIND, NOSTR_TAGS, PROMPTS_LIST_KIND, RESOURCES_LIST_KIND, RESOURCETEMPLATES_LIST_KIND, SERVER_ANNOUNCEMENT_KIND, TOOLS_LIST_KIND, decryptMessage, } from '../core/index.js';
4
+ import { EncryptionMode } from '../core/interfaces.js';
5
+ /**
6
+ * A server-side transport layer for CTXVM that uses Nostr events for communication.
7
+ * This transport listens for incoming MCP requests via Nostr events and can send
8
+ * responses back to the originating clients. It handles all request/response correlation
9
+ * internally, making it a standalone MCP transport that works over Nostr.
10
+ */
11
+ export class NostrServerTransport extends BaseNostrTransport {
12
+ constructor(options) {
13
+ super(options);
14
+ this.clientSessions = new Map();
15
+ this.serverInfo = options.serverInfo;
16
+ this.isPublicServer = options.isPublicServer;
17
+ this.allowedPublicKeys = options.allowedPublicKeys;
18
+ }
19
+ /**
20
+ * Starts the transport, connecting to the relay and setting up event listeners
21
+ * to receive incoming MCP requests.
22
+ */
23
+ async start() {
24
+ await this.connect();
25
+ const pubkey = await this.getPublicKey();
26
+ // Subscribe to events targeting this server's public key
27
+ const filters = this.createSubscriptionFilters(pubkey);
28
+ await this.subscribe(filters, this.processIncomingEvent.bind(this));
29
+ if (this.isPublicServer) {
30
+ this.getAnnouncementData();
31
+ }
32
+ }
33
+ /**
34
+ * Closes the transport, disconnecting from the relay.
35
+ */
36
+ async close() {
37
+ var _a;
38
+ await this.disconnect();
39
+ this.clientSessions.clear();
40
+ (_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
41
+ }
42
+ /**
43
+ * Sends JSON-RPC messages over the Nostr transport.
44
+ * @param message The JSON-RPC message to send.
45
+ */
46
+ async send(message) {
47
+ var _a;
48
+ // Message type detection and routing
49
+ if (isJSONRPCResponse(message) || isJSONRPCError(message)) {
50
+ await this.handleResponse(message);
51
+ }
52
+ else if (isJSONRPCNotification(message)) {
53
+ this.cleanupInactiveSessions();
54
+ await this.handleNotification(message);
55
+ }
56
+ else {
57
+ (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, new Error('Unknown message type in send()'));
58
+ }
59
+ }
60
+ /**
61
+ * Initiates the process of fetching announcement data from the server's internal logic.
62
+ */
63
+ getAnnouncementData() {
64
+ var _a;
65
+ const initializeParams = {
66
+ protocolVersion: LATEST_PROTOCOL_VERSION,
67
+ capabilities: {},
68
+ clientInfo: {
69
+ name: 'DummyClient',
70
+ version: '1.0.0',
71
+ },
72
+ };
73
+ for (const [key, methodValue] of Object.entries(announcementMethods)) {
74
+ const message = {
75
+ jsonrpc: '2.0',
76
+ id: 'announcement',
77
+ method: methodValue,
78
+ params: key === 'server' ? initializeParams : {},
79
+ };
80
+ (_a = this.onmessage) === null || _a === void 0 ? void 0 : _a.call(this, message);
81
+ }
82
+ }
83
+ /**
84
+ * Handles the JSON-RPC responses for public server announcements and publishes
85
+ * them as Nostr events to the configured relays.
86
+ * @param message The JSON-RPC response containing the announcement data.
87
+ */
88
+ async announcer(message) {
89
+ var _a, _b, _c;
90
+ const recipientPubkey = await this.getPublicKey();
91
+ const commonTags = [
92
+ ...(((_a = this.serverInfo) === null || _a === void 0 ? void 0 : _a.name)
93
+ ? [[NOSTR_TAGS.NAME, this.serverInfo.name]]
94
+ : []),
95
+ ...(((_b = this.serverInfo) === null || _b === void 0 ? void 0 : _b.website)
96
+ ? [[NOSTR_TAGS.WEBSITE, this.serverInfo.website]]
97
+ : []),
98
+ ...(((_c = this.serverInfo) === null || _c === void 0 ? void 0 : _c.picture)
99
+ ? [[NOSTR_TAGS.PICTURE, this.serverInfo.picture]]
100
+ : []),
101
+ ...(this.encryptionMode !== EncryptionMode.DISABLED
102
+ ? [[NOSTR_TAGS.SUPPORT_ENCRYPTION]]
103
+ : []),
104
+ ];
105
+ const announcementMapping = [
106
+ {
107
+ schema: InitializeResultSchema,
108
+ kind: SERVER_ANNOUNCEMENT_KIND,
109
+ tags: commonTags,
110
+ },
111
+ { schema: ListToolsResultSchema, kind: TOOLS_LIST_KIND, tags: [] },
112
+ {
113
+ schema: ListResourcesResultSchema,
114
+ kind: RESOURCES_LIST_KIND,
115
+ tags: [],
116
+ },
117
+ {
118
+ schema: ListResourceTemplatesResultSchema,
119
+ kind: RESOURCETEMPLATES_LIST_KIND,
120
+ tags: [],
121
+ },
122
+ { schema: ListPromptsResultSchema, kind: PROMPTS_LIST_KIND, tags: [] },
123
+ ];
124
+ for (const mapping of announcementMapping) {
125
+ if (mapping.schema.safeParse(message.result).success) {
126
+ await this.sendMcpMessage(message.result, recipientPubkey, mapping.kind, mapping.tags);
127
+ break;
128
+ }
129
+ }
130
+ }
131
+ /**
132
+ * Gets or creates a client session with proper initialization.
133
+ * @param clientPubkey The client's public key.
134
+ * @param now Current timestamp.
135
+ * @returns The client session.
136
+ */
137
+ getOrCreateClientSession(clientPubkey, now, isEncrypted) {
138
+ const session = this.clientSessions.get(clientPubkey);
139
+ if (!session) {
140
+ const newSession = {
141
+ isInitialized: false,
142
+ isEncrypted,
143
+ lastActivity: now,
144
+ pendingRequests: new Map(),
145
+ };
146
+ this.clientSessions.set(clientPubkey, newSession);
147
+ return newSession;
148
+ }
149
+ session.isEncrypted = isEncrypted;
150
+ return session;
151
+ }
152
+ /**
153
+ * Handles incoming requests with correlation tracking.
154
+ * @param session The client session.
155
+ * @param eventId The Nostr event ID.
156
+ * @param request The request message.
157
+ */
158
+ handleIncomingRequest(session, eventId, request) {
159
+ var _a, _b;
160
+ // Store the original request ID for later restoration
161
+ const originalRequestId = request.id;
162
+ // Use the unique Nostr event ID as the MCP request ID to avoid collisions
163
+ request.id = eventId;
164
+ // Store in client session
165
+ session.pendingRequests.set(eventId, originalRequestId);
166
+ // Track progress tokens if provided
167
+ const progressToken = (_b = (_a = request.params) === null || _a === void 0 ? void 0 : _a._meta) === null || _b === void 0 ? void 0 : _b.progressToken;
168
+ if (progressToken) {
169
+ session.pendingRequests.set(String(progressToken), eventId);
170
+ }
171
+ }
172
+ /**
173
+ * Handles incoming notifications.
174
+ * @param session The client session.
175
+ * @param notification The notification message.
176
+ */
177
+ handleIncomingNotification(session, notification) {
178
+ if (isJSONRPCNotification(notification) &&
179
+ notification.method === 'notifications/initialized') {
180
+ session.isInitialized = true;
181
+ }
182
+ }
183
+ /**
184
+ * Handles response messages by finding the original request and routing back to client.
185
+ * @param response The JSON-RPC response or error to send.
186
+ */
187
+ async handleResponse(response) {
188
+ var _a, _b;
189
+ // Handle special announcement responses
190
+ if (response.id === 'announcement') {
191
+ if (isJSONRPCResponse(response)) {
192
+ await this.announcer(response);
193
+ }
194
+ return;
195
+ }
196
+ // Find the client session with this pending request
197
+ const nostrEventId = response.id;
198
+ let targetClientPubkey;
199
+ let originalRequestId;
200
+ for (const [clientPubkey, session] of this.clientSessions.entries()) {
201
+ const originalId = session.pendingRequests.get(nostrEventId);
202
+ if (originalId !== undefined) {
203
+ targetClientPubkey = clientPubkey;
204
+ originalRequestId = originalId;
205
+ break;
206
+ }
207
+ }
208
+ if (!targetClientPubkey || originalRequestId === undefined) {
209
+ (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, new Error(`No pending request found for response ID: ${response.id}`));
210
+ return;
211
+ }
212
+ // Restore the original request ID in the response
213
+ response.id = originalRequestId;
214
+ // Send the response back to the original requester
215
+ const session = this.clientSessions.get(targetClientPubkey);
216
+ if (!session) {
217
+ (_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, new Error(`No session found for client: ${targetClientPubkey}`));
218
+ return;
219
+ }
220
+ const tags = this.createResponseTags(targetClientPubkey, nostrEventId);
221
+ if (isJSONRPCResponse(response) &&
222
+ InitializeResultSchema.safeParse(response.result).success &&
223
+ session.isEncrypted) {
224
+ tags.push([NOSTR_TAGS.SUPPORT_ENCRYPTION]);
225
+ }
226
+ await this.sendMcpMessage(response, targetClientPubkey, CTXVM_MESSAGES_KIND, tags, session.isEncrypted);
227
+ // Clean up the pending request and any associated progress token
228
+ if (session) {
229
+ session.pendingRequests.delete(nostrEventId);
230
+ // Find and delete the corresponding progress token if it exists
231
+ let progressTokenToDelete;
232
+ for (const [key, value] of session.pendingRequests.entries()) {
233
+ if (value === nostrEventId) {
234
+ progressTokenToDelete = key;
235
+ break;
236
+ }
237
+ }
238
+ if (progressTokenToDelete !== undefined) {
239
+ session.pendingRequests.delete(String(progressTokenToDelete));
240
+ }
241
+ }
242
+ }
243
+ /**
244
+ * Handles notification messages with routing.
245
+ * @param notification The JSON-RPC notification to send.
246
+ */
247
+ async handleNotification(notification) {
248
+ var _a, _b, _c;
249
+ // Special handling for progress notifications
250
+ if (isJSONRPCNotification(notification) &&
251
+ notification.method === 'notifications/progress' &&
252
+ ((_b = (_a = notification.params) === null || _a === void 0 ? void 0 : _a._meta) === null || _b === void 0 ? void 0 : _b.progressToken)) {
253
+ const token = String(notification.params._meta.progressToken);
254
+ for (const [clientPubkey, session] of this.clientSessions.entries()) {
255
+ if (session.pendingRequests.has(token)) {
256
+ const nostrEventId = session.pendingRequests.get(token);
257
+ await this.sendNotification(clientPubkey, notification, nostrEventId);
258
+ return;
259
+ }
260
+ }
261
+ (_c = this.onerror) === null || _c === void 0 ? void 0 : _c.call(this, new Error(`No client found for progress token: ${token}`));
262
+ return;
263
+ }
264
+ const promises = [];
265
+ for (const [clientPubkey, session] of this.clientSessions.entries()) {
266
+ if (session.isInitialized) {
267
+ promises.push(this.sendNotification(clientPubkey, notification));
268
+ }
269
+ }
270
+ await Promise.all(promises);
271
+ }
272
+ /**
273
+ * Sends a notification to a specific client by their public key.
274
+ * @param clientPubkey The public key of the target client.
275
+ * @param notification The notification message to send.
276
+ * @returns Promise that resolves when the notification is sent.
277
+ */
278
+ async sendNotification(clientPubkey, notification, correlatedEventId) {
279
+ const session = this.clientSessions.get(clientPubkey);
280
+ if (!session) {
281
+ throw new Error(`No active session found for client: ${clientPubkey}`);
282
+ }
283
+ // Create tags for targeting the specific client
284
+ const tags = this.createRecipientTags(clientPubkey);
285
+ if (correlatedEventId) {
286
+ tags.push([NOSTR_TAGS.EVENT_ID, correlatedEventId]);
287
+ }
288
+ await this.sendMcpMessage(notification, clientPubkey, CTXVM_MESSAGES_KIND, tags, session.isEncrypted);
289
+ }
290
+ /**
291
+ * Processes incoming Nostr events, handling decryption and client authorization.
292
+ * This method centralizes the logic for determining whether to process an event
293
+ * based on encryption mode and allowed public keys.
294
+ * @param event The incoming Nostr event.
295
+ */
296
+ async processIncomingEvent(event) {
297
+ if (event.kind === GIFT_WRAP_KIND) {
298
+ await this.handleEncryptedEvent(event);
299
+ }
300
+ else {
301
+ this.handleUnencryptedEvent(event);
302
+ }
303
+ }
304
+ /**
305
+ * Handles encrypted (gift-wrapped) events.
306
+ * @param event The incoming gift-wrapped Nostr event.
307
+ */
308
+ async handleEncryptedEvent(event) {
309
+ var _a;
310
+ if (this.encryptionMode === EncryptionMode.DISABLED) {
311
+ console.warn(`Received encrypted message from ${event.pubkey} but encryption is disabled. Ignoring.`);
312
+ return;
313
+ }
314
+ try {
315
+ const secretKey = await this.signer.getSecretKey();
316
+ if (!secretKey) {
317
+ throw new Error('Server secret key is unavailable for decryption.');
318
+ }
319
+ const decryptedJson = decryptMessage(event, secretKey);
320
+ const currentEvent = JSON.parse(decryptedJson);
321
+ this.authorizeAndProcessEvent(currentEvent, true);
322
+ }
323
+ catch (error) {
324
+ (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error instanceof Error
325
+ ? error
326
+ : new Error('Failed to handle encrypted Nostr event'));
327
+ }
328
+ }
329
+ /**
330
+ * Handles unencrypted events.
331
+ * @param event The incoming Nostr event.
332
+ */
333
+ handleUnencryptedEvent(event) {
334
+ if (this.encryptionMode === EncryptionMode.REQUIRED) {
335
+ console.warn(`Received unencrypted message from ${event.pubkey} but encryption is required. Ignoring.`);
336
+ return;
337
+ }
338
+ this.authorizeAndProcessEvent(event, false);
339
+ }
340
+ /**
341
+ * Common logic for authorizing and processing an event.
342
+ * @param event The event to process.
343
+ * @param isEncrypted Whether the original event was encrypted.
344
+ */
345
+ authorizeAndProcessEvent(event, isEncrypted) {
346
+ var _a, _b;
347
+ if (((_a = this.allowedPublicKeys) === null || _a === void 0 ? void 0 : _a.length) &&
348
+ !this.allowedPublicKeys.includes(event.pubkey)) {
349
+ console.warn(`Unauthorized message from ${event.pubkey}. Ignoring.`);
350
+ return;
351
+ }
352
+ const mcpMessage = this.convertNostrEventToMcpMessage(event);
353
+ const now = Date.now();
354
+ const session = this.getOrCreateClientSession(event.pubkey, now, isEncrypted);
355
+ session.lastActivity = now;
356
+ if (isJSONRPCRequest(mcpMessage)) {
357
+ this.handleIncomingRequest(session, event.id, mcpMessage);
358
+ }
359
+ else if (isJSONRPCNotification(mcpMessage)) {
360
+ this.handleIncomingNotification(session, mcpMessage);
361
+ }
362
+ (_b = this.onmessage) === null || _b === void 0 ? void 0 : _b.call(this, mcpMessage);
363
+ }
364
+ /**
365
+ * Cleans up inactive client sessions based on a timeout.
366
+ * @param timeoutMs Timeout in milliseconds for considering a session inactive (default: 5 minutes).
367
+ * @returns The number of sessions that were cleaned up.
368
+ */
369
+ cleanupInactiveSessions(timeoutMs = 300000) {
370
+ const now = Date.now();
371
+ const keysToDelete = [];
372
+ for (const [clientPubkey, session] of this.clientSessions.entries()) {
373
+ if (now - session.lastActivity > timeoutMs) {
374
+ keysToDelete.push(clientPubkey);
375
+ }
376
+ }
377
+ for (const key of keysToDelete) {
378
+ this.clientSessions.delete(key);
379
+ }
380
+ return keysToDelete.length;
381
+ }
382
+ }
383
+ //# sourceMappingURL=nostr-server-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nostr-server-transport.js","sourceRoot":"","sources":["../../../src/transport/nostr-server-transport.ts"],"names":[],"mappings":"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"}