@contextvm/sdk 0.1.1 → 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/README.md +178 -2
  2. package/dist/esm/core/constants.d.ts +65 -0
  3. package/dist/esm/core/constants.d.ts.map +1 -0
  4. package/dist/esm/core/constants.js +70 -0
  5. package/dist/esm/core/constants.js.map +1 -0
  6. package/dist/esm/core/encryption.d.ts +18 -0
  7. package/dist/esm/core/encryption.d.ts.map +1 -0
  8. package/dist/esm/core/encryption.js +40 -0
  9. package/dist/esm/core/encryption.js.map +1 -0
  10. package/dist/esm/core/index.d.ts +5 -0
  11. package/dist/esm/core/index.d.ts.map +1 -0
  12. package/dist/esm/core/index.js +5 -0
  13. package/dist/esm/core/index.js.map +1 -0
  14. package/dist/esm/core/interfaces.d.ts +39 -0
  15. package/dist/esm/core/interfaces.d.ts.map +1 -0
  16. package/dist/esm/core/interfaces.js +13 -0
  17. package/dist/esm/core/interfaces.js.map +1 -0
  18. package/dist/esm/core/utils/serializers.d.ts +29 -0
  19. package/dist/esm/core/utils/serializers.d.ts.map +1 -0
  20. package/dist/esm/core/utils/serializers.js +46 -0
  21. package/dist/esm/core/utils/serializers.js.map +1 -0
  22. package/dist/esm/gateway/index.d.ts +60 -0
  23. package/dist/esm/gateway/index.d.ts.map +1 -0
  24. package/dist/esm/gateway/index.js +110 -0
  25. package/dist/esm/gateway/index.js.map +1 -0
  26. package/dist/esm/index.d.ts +7 -0
  27. package/dist/esm/index.d.ts.map +1 -0
  28. package/dist/esm/index.js +7 -0
  29. package/dist/esm/index.js.map +1 -0
  30. package/dist/esm/package.json +1 -0
  31. package/dist/esm/proxy/index.d.ts +42 -0
  32. package/dist/esm/proxy/index.d.ts.map +1 -0
  33. package/dist/esm/proxy/index.js +59 -0
  34. package/dist/esm/proxy/index.js.map +1 -0
  35. package/dist/esm/proxy/proxy-server.d.ts +3 -0
  36. package/dist/esm/proxy/proxy-server.d.ts.map +1 -0
  37. package/dist/esm/proxy/proxy-server.js +55 -0
  38. package/dist/esm/proxy/proxy-server.js.map +1 -0
  39. package/dist/esm/relay/index.d.ts +2 -0
  40. package/dist/esm/relay/index.d.ts.map +1 -0
  41. package/dist/esm/relay/index.js +2 -0
  42. package/dist/esm/relay/index.js.map +1 -0
  43. package/dist/esm/relay/simple-relay-pool.d.ts +19 -0
  44. package/dist/esm/relay/simple-relay-pool.d.ts.map +1 -0
  45. package/dist/esm/relay/simple-relay-pool.js +44 -0
  46. package/dist/esm/relay/simple-relay-pool.js.map +1 -0
  47. package/dist/esm/signer/index.d.ts +2 -0
  48. package/dist/esm/signer/index.d.ts.map +1 -0
  49. package/dist/esm/signer/index.js +2 -0
  50. package/dist/esm/signer/index.js.map +1 -0
  51. package/dist/esm/signer/private-key-signer.d.ts +16 -0
  52. package/dist/esm/signer/private-key-signer.d.ts.map +1 -0
  53. package/dist/esm/signer/private-key-signer.js +23 -0
  54. package/dist/esm/signer/private-key-signer.js.map +1 -0
  55. package/dist/esm/transport/base-nostr-transport.d.ts +67 -0
  56. package/dist/esm/transport/base-nostr-transport.d.ts.map +1 -0
  57. package/dist/esm/transport/base-nostr-transport.js +122 -0
  58. package/dist/esm/transport/base-nostr-transport.js.map +1 -0
  59. package/dist/esm/transport/index.d.ts +4 -0
  60. package/dist/esm/transport/index.d.ts.map +1 -0
  61. package/dist/esm/transport/index.js +4 -0
  62. package/dist/esm/transport/index.js.map +1 -0
  63. package/dist/esm/transport/nostr-client-transport.d.ts +60 -0
  64. package/dist/esm/transport/nostr-client-transport.d.ts.map +1 -0
  65. package/dist/esm/transport/nostr-client-transport.js +116 -0
  66. package/dist/esm/transport/nostr-client-transport.js.map +1 -0
  67. package/dist/esm/transport/nostr-server-transport.d.ts +128 -0
  68. package/dist/esm/transport/nostr-server-transport.d.ts.map +1 -0
  69. package/dist/esm/transport/nostr-server-transport.js +383 -0
  70. package/dist/esm/transport/nostr-server-transport.js.map +1 -0
  71. package/package.json +2 -2
package/README.md CHANGED
@@ -1,3 +1,179 @@
1
- # ctxvm-sdk
1
+ # @ctxvm/sdk: CTXVM Protocol SDK
2
2
 
3
- `@ctxvm/sdk` is a TypeScript SDK designed to implement the `ctxvm` protocol, providing modular access to core functionalities, relay interactions, and signing operations.
3
+ A JavaScript/TypeScript SDK that implements the Context Vending Machine (CTXVM) Protocol, bridging Nostr and Model Context Protocol (MCP) to enable decentralized access and exposure of computational services.
4
+
5
+ ## Overview
6
+
7
+ The CTXVM Protocol defines how Nostr and Model Context Machines can be used to expose MCP server capabilities, enabling standardized usage of these resources through a decentralized, cryptographically secure messaging system.
8
+
9
+ This SDK provides the necessary components to interact with the CTXVM Protocol:
10
+
11
+ - **Core Module**: Contains fundamental definitions, constants, interfaces, and utilities (e.g., encryption, serialization).
12
+ - **Transports**: Critical for communication, providing `NostrClientTransport` and `NostrServerTransport` implementations for enabling MCP over Nostr.
13
+ - **Proxy**: A client-side MCP server that connects to other servers through Nostr, exposing server capabilities locally. Particularly useful for clients that don't natively support Nostr transport.
14
+ - **Gateway**: Implements Nostr server transport, binding to another MCP server and exposing its capabilities through the Nostr network.
15
+ - **Relay**: Functionality for managing Nostr relays, abstracting relay interactions.
16
+ - **Signer**: Provides cryptographic signing capabilities required for Nostr events.
17
+
18
+ Both the Proxy and Gateway leverage Nostr transports, allowing existing MCP servers to maintain their conventional transports while gaining Nostr interoperability.
19
+
20
+ ## Installation
21
+
22
+ This project requires [Bun](https://bun.sh/) (version 1.2.0 or higher).
23
+
24
+ 1. **Clone the repository:**
25
+
26
+ ```bash
27
+ git clone https://github.com/ContextVM/ts-sdk.git
28
+ cd ts-sdk
29
+ ```
30
+
31
+ 2. **Install dependencies:**
32
+
33
+ ```bash
34
+ bun install
35
+ ```
36
+
37
+ 3. **Build the project:**
38
+ ```bash
39
+ bun run build
40
+ ```
41
+
42
+ ## Usage
43
+
44
+ The SDK provides methods for bridging MCP and Nostr. At its core, the SDK relies on Nostr transports and utilities to facilitate communication.
45
+
46
+ ### Core Building Blocks: Signers and Relay Pools
47
+
48
+ The SDK provides default implementations: `PrivateKeySigner` implements the `NostrSigner` interface, and `SimpleRelayPool` implements the `RelayHandler` interface. You can extend the SDK's capabilities by creating custom implementations that satisfy these interfaces, allowing you to integrate with different signing mechanisms or relay management logic.ª
49
+
50
+ ### Nostr Transports
51
+
52
+ The SDK provides specialized transports to send and receive MCP messages over the Nostr network.
53
+
54
+ #### `NostrClientTransport`
55
+
56
+ Used by MCP clients to connect to remote MCP servers exposed via Nostr.
57
+
58
+ ```typescript
59
+ import { Client } from '@modelcontextprotocol/sdk/client';
60
+ import { NostrClientTransport } from '@ctxvm/sdk/transport';
61
+ import { EncryptionMode } from '@ctxvm/sdk/core';
62
+
63
+ // Public key of the target MCP server on Nostr
64
+ const REMOTE_SERVER_PUBKEY = 'remote_server_public_key_here';
65
+
66
+ const clientNostrTransport = new NostrClientTransport({
67
+ signer: signer, // Your NostrSigner instance
68
+ relayHandler: relayPool, // Your RelayHandler instance
69
+ serverPubkey: REMOTE_SERVER_PUBKEY, // Public key of the target MCP server
70
+ encryptionMode: EncryptionMode.OPTIONAL, // Optional: REQUIRED, OPTIONAL (default), or DISABLED
71
+ });
72
+
73
+ const mcpClient = new Client();
74
+
75
+ // To connect the MCP client:
76
+ await mcpClient.connect(clientNostrTransport);
77
+ // Subsequent MCP calls (e.g., listTools, callTool) would use this transport.
78
+ await mcpClient.listTools();
79
+ // await mcpClient.close();
80
+ ```
81
+
82
+ #### `NostrServerTransport`
83
+
84
+ Used by MCP servers to expose their capabilities to Nostr clients.
85
+
86
+ ```typescript
87
+ import { McpServer } from '@modelcontextprotocol/sdk/server';
88
+ import { NostrServerTransport } from '@ctxvm/sdk/transport';
89
+ import { EncryptionMode } from '@ctxvm/sdk/core';
90
+ // Assume signer and relayPool are configured as shown above.
91
+
92
+ const server = new McpServer({
93
+ name: 'demo-server',
94
+ version: '1.0.0',
95
+ });
96
+
97
+ // Before connecting, register your MCP server's capabilities.
98
+
99
+ const serverNostrTransport = new NostrServerTransport({
100
+ signer: signer, // Server's NostrSigner instance
101
+ relayHandler: relayPool, // Server's RelayHandler instance
102
+ isPublicServer: true, // Optional: set to true to announce server capabilities via Nostr events
103
+ encryptionMode: EncryptionMode.OPTIONAL, // Optional: REQUIRED, OPTIONAL (default), or DISABLED
104
+ serverInfo: {
105
+ // Optional: Information for public announcements
106
+ name: 'Nostr MCP Example Server',
107
+ website: 'https://example.com/mcp-server',
108
+ },
109
+ });
110
+
111
+ // To connect the MCP server and make it available via Nostr:
112
+ await mcpServer.connect(serverNostrTransport);
113
+ // This will keep the server running and listening for Nostr events.
114
+ // To gracefully shut down: await mcpServer.close();
115
+ ```
116
+
117
+ ### Bridging Components: Proxy and Gateway
118
+
119
+ The SDK also provides higher-level components that leverage these transports to bridge conventional MCP setups with Nostr.
120
+
121
+ #### `NostrMCPProxy` (Client-Side Bridge)
122
+
123
+ Allows an MCP client (e.g., a local application communicating via a mcp transport) to communicate with a remote MCP server over Nostr. The proxy acts as a translation layer, using `NostrClientTransport` internally.
124
+
125
+ ```typescript
126
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/stdio';
127
+ import { NostrMCPProxy } from '@ctxvm/sdk/proxy';
128
+
129
+ // This transport represents the connection between your local MCP client and the proxy.
130
+ const hostTransport = new StdioServerTransport();
131
+
132
+ const proxy = new NostrMCPProxy({
133
+ mcpHostTransport: hostTransport, // Your local client's transport
134
+ nostrTransportOptions: {
135
+ signer: signer,
136
+ relayHandler: relayPool,
137
+ serverPubkey: REMOTE_SERVER_PUBKEY, // Target the remote MCP server public key via Nostr
138
+ },
139
+ });
140
+
141
+ // To start the proxy:
142
+ await proxy.start();
143
+ ```
144
+
145
+ #### `NostrMCPGateway` (Server-Side Bridge)
146
+
147
+ Allows an existing MCP server (e.g., communicating via a mcp transport) to expose its capabilities through Nostr. The gateway uses `NostrServerTransport` internally.
148
+
149
+ ```typescript
150
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/stdio';
151
+ import { NostrMCPGateway } from '@ctxvm/sdk/gateway';
152
+
153
+ // This transport defines how the Gateway connects to your traditional MCP server.
154
+ const serverTransport = new StdioClientTransport({
155
+ command: 'bun',
156
+ args: ['path/to/your/mcp-server.ts'],
157
+ });
158
+
159
+ const gateway = new NostrMCPGateway({
160
+ mcpServerTransport: serverTransport, // Your existing MCP server's transport
161
+ nostrTransportOptions: {
162
+ signer: signer,
163
+ relayHandler: relayPool,
164
+ isPublicServer: true, // Set to true to announce server capabilities to Nostr clients for discovery
165
+ },
166
+ });
167
+
168
+ // To start the gateway and expose your MCP server to Nostr clients:
169
+ await gateway.start();
170
+ // The gateway will run indefinitely, relaying messages between Nostr and your MCP server.
171
+ ```
172
+
173
+ ## Running Tests
174
+
175
+ To run the test suite, use Bun:
176
+
177
+ ```bash
178
+ bun tests
179
+ ```
@@ -0,0 +1,65 @@
1
+ import { AnnouncementMethods } from './interfaces.js';
2
+ /**
3
+ * CTXVM-specific event kinds.
4
+ *
5
+ * All CTXVM messages are ephemeral events.
6
+ * @see https://github.com/nostr-protocol/nips/blob/master/01.md#kinds
7
+ */
8
+ export declare const CTXVM_MESSAGES_KIND = 25910;
9
+ /**
10
+ * Encrypted CTXVM messages using NIP-59 Gift Wrap.
11
+ * @see https://github.com/nostr-protocol/nips/blob/master/59.md
12
+ */
13
+ export declare const GIFT_WRAP_KIND = 1059;
14
+ /**
15
+ * Addressable event for server announcements.
16
+ */
17
+ export declare const SERVER_ANNOUNCEMENT_KIND = 11316;
18
+ /**
19
+ * Addressable event for listing available tools.
20
+ */
21
+ export declare const TOOLS_LIST_KIND = 11317;
22
+ /**
23
+ * Addressable event for listing available resources.
24
+ */
25
+ export declare const RESOURCES_LIST_KIND = 11318;
26
+ /**
27
+ * Addressable event for listing available resources.
28
+ */
29
+ export declare const RESOURCETEMPLATES_LIST_KIND = 11319;
30
+ /**
31
+ * Addressable event for listing available prompts.
32
+ */
33
+ export declare const PROMPTS_LIST_KIND = 11320;
34
+ /**
35
+ * CTXVM-specific Nostr event tags.
36
+ */
37
+ export declare const NOSTR_TAGS: {
38
+ readonly PUBKEY: "p";
39
+ /**
40
+ * Event ID for correlating requests and responses.
41
+ */
42
+ readonly EVENT_ID: "e";
43
+ /**
44
+ * Capability tag for tools, resources, and prompts to provide pricing metadata.
45
+ */
46
+ readonly CAPABILITY: "cap";
47
+ /**
48
+ * Name tag for server announcements.
49
+ */
50
+ readonly NAME: "name";
51
+ /**
52
+ * Website tag for server announcements.
53
+ */
54
+ readonly WEBSITE: "website";
55
+ /**
56
+ * Picture tag for server announcements.
57
+ */
58
+ readonly PICTURE: "picture";
59
+ /**
60
+ * Support encryption tag for server announcements.
61
+ */
62
+ readonly SUPPORT_ENCRYPTION: "support_encryption";
63
+ };
64
+ export declare const announcementMethods: AnnouncementMethods;
65
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/core/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEtD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAEzC;;;GAGG;AACH,eAAO,MAAM,cAAc,OAAO,CAAC;AAEnC;;GAEG;AACH,eAAO,MAAM,wBAAwB,QAAQ,CAAC;AAE9C;;GAEG;AACH,eAAO,MAAM,eAAe,QAAQ,CAAC;AAErC;;GAEG;AACH,eAAO,MAAM,mBAAmB,QAAQ,CAAC;AAEzC;;GAEG;AACH,eAAO,MAAM,2BAA2B,QAAQ,CAAC;AAEjD;;GAEG;AACH,eAAO,MAAM,iBAAiB,QAAQ,CAAC;AAEvC;;GAEG;AACH,eAAO,MAAM,UAAU;;IAErB;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;IAEH;;OAEG;;CAEK,CAAC;AAEX,eAAO,MAAM,mBAAmB,EAAE,mBAMxB,CAAC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * CTXVM-specific event kinds.
3
+ *
4
+ * All CTXVM messages are ephemeral events.
5
+ * @see https://github.com/nostr-protocol/nips/blob/master/01.md#kinds
6
+ */
7
+ export const CTXVM_MESSAGES_KIND = 25910;
8
+ /**
9
+ * Encrypted CTXVM messages using NIP-59 Gift Wrap.
10
+ * @see https://github.com/nostr-protocol/nips/blob/master/59.md
11
+ */
12
+ export const GIFT_WRAP_KIND = 1059;
13
+ /**
14
+ * Addressable event for server announcements.
15
+ */
16
+ export const SERVER_ANNOUNCEMENT_KIND = 11316;
17
+ /**
18
+ * Addressable event for listing available tools.
19
+ */
20
+ export const TOOLS_LIST_KIND = 11317;
21
+ /**
22
+ * Addressable event for listing available resources.
23
+ */
24
+ export const RESOURCES_LIST_KIND = 11318;
25
+ /**
26
+ * Addressable event for listing available resources.
27
+ */
28
+ export const RESOURCETEMPLATES_LIST_KIND = 11319;
29
+ /**
30
+ * Addressable event for listing available prompts.
31
+ */
32
+ export const PROMPTS_LIST_KIND = 11320;
33
+ /**
34
+ * CTXVM-specific Nostr event tags.
35
+ */
36
+ export const NOSTR_TAGS = {
37
+ PUBKEY: 'p',
38
+ /**
39
+ * Event ID for correlating requests and responses.
40
+ */
41
+ EVENT_ID: 'e',
42
+ /**
43
+ * Capability tag for tools, resources, and prompts to provide pricing metadata.
44
+ */
45
+ CAPABILITY: 'cap',
46
+ /**
47
+ * Name tag for server announcements.
48
+ */
49
+ NAME: 'name',
50
+ /**
51
+ * Website tag for server announcements.
52
+ */
53
+ WEBSITE: 'website',
54
+ /**
55
+ * Picture tag for server announcements.
56
+ */
57
+ PICTURE: 'picture',
58
+ /**
59
+ * Support encryption tag for server announcements.
60
+ */
61
+ SUPPORT_ENCRYPTION: 'support_encryption',
62
+ };
63
+ export const announcementMethods = {
64
+ server: 'initialize',
65
+ tools: 'tools/list',
66
+ resources: 'resources/list',
67
+ resourceTemplates: 'resources/templates/list',
68
+ prompts: 'prompts/list',
69
+ };
70
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/core/constants.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,CAAC;AAEzC;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC;AAEnC;;GAEG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,KAAK,CAAC;AAE9C;;GAEG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,CAAC;AAErC;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,CAAC;AAEzC;;GAEG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,KAAK,CAAC;AAEjD;;GAEG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,KAAK,CAAC;AAEvC;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,MAAM,EAAE,GAAG;IACX;;OAEG;IACH,QAAQ,EAAE,GAAG;IACb;;OAEG;IACH,UAAU,EAAE,KAAK;IACjB;;OAEG;IACH,IAAI,EAAE,MAAM;IACZ;;OAEG;IACH,OAAO,EAAE,SAAS;IAClB;;OAEG;IACH,OAAO,EAAE,SAAS;IAClB;;OAEG;IACH,kBAAkB,EAAE,oBAAoB;CAChC,CAAC;AAEX,MAAM,CAAC,MAAM,mBAAmB,GAAwB;IACtD,MAAM,EAAE,YAAY;IACpB,KAAK,EAAE,YAAY;IACnB,SAAS,EAAE,gBAAgB;IAC3B,iBAAiB,EAAE,0BAA0B;IAC7C,OAAO,EAAE,cAAc;CACf,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { type Event as NostrEvent } from 'nostr-tools';
2
+ /**
3
+ * Encrypts a JSON-RPC message using a simplified NIP-17/NIP-59 gift wrap scheme.
4
+ * The message is encrypted with NIP-44 and wrapped in a kind 1059 event.
5
+ * @param message The JSON-RPC message to encrypt.
6
+ * @param recipientPublicKey The public key of the recipient.
7
+ * @returns The encrypted gift wrap event.
8
+ */
9
+ export declare function encryptMessage(message: string, recipientPublicKey: string): NostrEvent;
10
+ /**
11
+ * Decrypts a gift-wrapped Nostr event.
12
+ * @param event The gift wrap event (kind 1059).
13
+ * @param recipientPrivateKey The private key of the recipient.
14
+ * @returns The decrypted message content.
15
+ * @throws If the event is not a valid gift wrap or decryption fails.
16
+ */
17
+ export declare function decryptMessage(event: NostrEvent, recipientPrivateKey: Uint8Array): string;
18
+ //# sourceMappingURL=encryption.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.d.ts","sourceRoot":"","sources":["../../../src/core/encryption.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,KAAK,IAAI,UAAU,EAAE,MAAM,aAAa,CAAC;AAQ9D;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,kBAAkB,EAAE,MAAM,GACzB,UAAU,CAiBZ;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,UAAU,EACjB,mBAAmB,EAAE,UAAU,GAC9B,MAAM,CAWR"}
@@ -0,0 +1,40 @@
1
+ import { nip44 } from 'nostr-tools';
2
+ import { finalizeEvent, generateSecretKey, getPublicKey, } from 'nostr-tools/pure';
3
+ import { GIFT_WRAP_KIND, NOSTR_TAGS } from './constants.js';
4
+ /**
5
+ * Encrypts a JSON-RPC message using a simplified NIP-17/NIP-59 gift wrap scheme.
6
+ * The message is encrypted with NIP-44 and wrapped in a kind 1059 event.
7
+ * @param message The JSON-RPC message to encrypt.
8
+ * @param recipientPublicKey The public key of the recipient.
9
+ * @returns The encrypted gift wrap event.
10
+ */
11
+ export function encryptMessage(message, recipientPublicKey) {
12
+ const giftWrapPrivateKey = generateSecretKey();
13
+ const giftWrapPublicKey = getPublicKey(giftWrapPrivateKey);
14
+ const conversationKey = nip44.v2.utils.getConversationKey(giftWrapPrivateKey, recipientPublicKey);
15
+ const encryptedContent = nip44.v2.encrypt(message, conversationKey);
16
+ const giftWrap = {
17
+ kind: GIFT_WRAP_KIND,
18
+ content: encryptedContent,
19
+ tags: [[NOSTR_TAGS.PUBKEY, recipientPublicKey]],
20
+ created_at: Math.floor(Date.now() / 1000),
21
+ pubkey: giftWrapPublicKey,
22
+ };
23
+ return finalizeEvent(giftWrap, giftWrapPrivateKey);
24
+ }
25
+ /**
26
+ * Decrypts a gift-wrapped Nostr event.
27
+ * @param event The gift wrap event (kind 1059).
28
+ * @param recipientPrivateKey The private key of the recipient.
29
+ * @returns The decrypted message content.
30
+ * @throws If the event is not a valid gift wrap or decryption fails.
31
+ */
32
+ export function decryptMessage(event, recipientPrivateKey) {
33
+ if (event.kind !== GIFT_WRAP_KIND) {
34
+ throw new Error('Event is not a gift wrap.');
35
+ }
36
+ const conversationKey = nip44.v2.utils.getConversationKey(recipientPrivateKey, event.pubkey);
37
+ const decryptedMsg = nip44.v2.decrypt(event.content, conversationKey);
38
+ return decryptedMsg;
39
+ }
40
+ //# sourceMappingURL=encryption.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encryption.js","sourceRoot":"","sources":["../../../src/core/encryption.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAA4B,MAAM,aAAa,CAAC;AAC9D,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,YAAY,GACb,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5D;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,OAAe,EACf,kBAA0B;IAE1B,MAAM,kBAAkB,GAAG,iBAAiB,EAAE,CAAC;IAC/C,MAAM,iBAAiB,GAAG,YAAY,CAAC,kBAAkB,CAAC,CAAC;IAC3D,MAAM,eAAe,GAAG,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,kBAAkB,CACvD,kBAAkB,EAClB,kBAAkB,CACnB,CAAC;IACF,MAAM,gBAAgB,GAAG,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IACpE,MAAM,QAAQ,GAAG;QACf,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE,gBAAgB;QACzB,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;QAC/C,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;QACzC,MAAM,EAAE,iBAAiB;KAC1B,CAAC;IAEF,OAAO,aAAa,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;AACrD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAiB,EACjB,mBAA+B;IAE/B,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IAED,MAAM,eAAe,GAAG,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,kBAAkB,CACvD,mBAAmB,EACnB,KAAK,CAAC,MAAM,CACb,CAAC;IACF,MAAM,YAAY,GAAG,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IACtE,OAAO,YAAY,CAAC;AACtB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from './constants.js';
2
+ export * from './interfaces.js';
3
+ export * from './utils/serializers.js';
4
+ export * from './encryption.js';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from './constants.js';
2
+ export * from './interfaces.js';
3
+ export * from './utils/serializers.js';
4
+ export * from './encryption.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,iBAAiB,CAAC"}
@@ -0,0 +1,39 @@
1
+ import { InitializeRequest, ListPromptsRequest, ListResourcesRequest, ListResourceTemplatesRequest, ListToolsRequest } from '@modelcontextprotocol/sdk/types.js';
2
+ import type { Filter, NostrEvent } from 'nostr-tools';
3
+ /**
4
+ * Defines the encryption mode for the transport.
5
+ * - `optional`: Encrypts messages if the incoming message was encrypted.
6
+ * - `required`: Enforces encryption for all messages.
7
+ * - `disabled`: Disables encryption entirely.
8
+ */
9
+ export declare enum EncryptionMode {
10
+ OPTIONAL = "optional",
11
+ REQUIRED = "required",
12
+ DISABLED = "disabled"
13
+ }
14
+ /**
15
+ * A generic interface for Nostr signers.
16
+ */
17
+ export interface NostrSigner {
18
+ getPublicKey(): Promise<string>;
19
+ signEvent(event: Omit<NostrEvent, 'sig' | 'id'>): Promise<NostrEvent>;
20
+ getSecretKey(): Promise<Uint8Array>;
21
+ }
22
+ /**
23
+ * A generic interface for Nostr relays.
24
+ */
25
+ export interface RelayHandler {
26
+ connect(): Promise<void>;
27
+ disconnect(relayUrls?: string[]): Promise<void>;
28
+ publish(event: NostrEvent): Promise<void>;
29
+ subscribe(filters: Filter[], onEvent: (event: NostrEvent) => void, onEose?: () => void): Promise<void>;
30
+ unsubscribe(): void;
31
+ }
32
+ export interface AnnouncementMethods {
33
+ server: InitializeRequest['method'];
34
+ tools: ListToolsRequest['method'];
35
+ resources: ListResourcesRequest['method'];
36
+ resourceTemplates: ListResourceTemplatesRequest['method'];
37
+ prompts: ListPromptsRequest['method'];
38
+ }
39
+ //# sourceMappingURL=interfaces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../../src/core/interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,4BAA4B,EAC5B,gBAAgB,EACjB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEtD;;;;;GAKG;AACH,oBAAY,cAAc;IACxB,QAAQ,aAAa;IACrB,QAAQ,aAAa;IACrB,QAAQ,aAAa;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAChC,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,KAAK,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACtE,YAAY,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,SAAS,CACP,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,EACpC,MAAM,CAAC,EAAE,MAAM,IAAI,GAClB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,WAAW,IAAI,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACpC,KAAK,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAClC,SAAS,EAAE,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAC1C,iBAAiB,EAAE,4BAA4B,CAAC,QAAQ,CAAC,CAAC;IAC1D,OAAO,EAAE,kBAAkB,CAAC,QAAQ,CAAC,CAAC;CACvC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Defines the encryption mode for the transport.
3
+ * - `optional`: Encrypts messages if the incoming message was encrypted.
4
+ * - `required`: Enforces encryption for all messages.
5
+ * - `disabled`: Disables encryption entirely.
6
+ */
7
+ export var EncryptionMode;
8
+ (function (EncryptionMode) {
9
+ EncryptionMode["OPTIONAL"] = "optional";
10
+ EncryptionMode["REQUIRED"] = "required";
11
+ EncryptionMode["DISABLED"] = "disabled";
12
+ })(EncryptionMode || (EncryptionMode = {}));
13
+ //# sourceMappingURL=interfaces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interfaces.js","sourceRoot":"","sources":["../../../src/core/interfaces.ts"],"names":[],"mappings":"AASA;;;;;GAKG;AACH,MAAM,CAAN,IAAY,cAIX;AAJD,WAAY,cAAc;IACxB,uCAAqB,CAAA;IACrB,uCAAqB,CAAA;IACrB,uCAAqB,CAAA;AACvB,CAAC,EAJW,cAAc,KAAd,cAAc,QAIzB"}
@@ -0,0 +1,29 @@
1
+ import type { Event as NostrEvent, UnsignedEvent } from 'nostr-tools';
2
+ import type { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js';
3
+ /**
4
+ * Serializes an MCP message into a Nostr event object.
5
+ *
6
+ * @param mcpMessage The MCP message (request or response) to serialize.
7
+ * @param pubkey The public key of the sender.
8
+ * @param kind The kind of Nostr event to create.
9
+ * @param tags An array of tags to include in the event.
10
+ * @returns A Nostr event object (without `id` and `sig`).
11
+ */
12
+ export declare function mcpToNostrEvent(mcpMessage: JSONRPCMessage, pubkey: string, kind: number, tags?: string[][]): UnsignedEvent;
13
+ /**
14
+ * Deserializes a Nostr event into an MCP message.
15
+ *
16
+ * @param event The Nostr event to deserialize.
17
+ * @returns An MCP request or response object.
18
+ * @throws Error if the event content is not valid JSON
19
+ */
20
+ export declare function nostrEventToMcpMessage(event: NostrEvent): JSONRPCMessage;
21
+ /**
22
+ * Extracts a specific tag from a Nostr event.
23
+ *
24
+ * @param event The Nostr event.
25
+ * @param tagName The name of the tag to extract (e.g., 'e', 'p', 'd').
26
+ * @returns The value of the tag, or undefined if not found.
27
+ */
28
+ export declare function getNostrEventTag(tags: NostrEvent['tags'], tagName: string): string | undefined;
29
+ //# sourceMappingURL=serializers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serializers.d.ts","sourceRoot":"","sources":["../../../../src/core/utils/serializers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,IAAI,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,UAAU,EAAE,cAAc,EAC1B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,MAAM,EAAE,EAAO,GACpB,aAAa,CAQf;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,UAAU,GAAG,cAAc,CASxE;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,EACxB,OAAO,EAAE,MAAM,GACd,MAAM,GAAG,SAAS,CAGpB"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Serializes an MCP message into a Nostr event object.
3
+ *
4
+ * @param mcpMessage The MCP message (request or response) to serialize.
5
+ * @param pubkey The public key of the sender.
6
+ * @param kind The kind of Nostr event to create.
7
+ * @param tags An array of tags to include in the event.
8
+ * @returns A Nostr event object (without `id` and `sig`).
9
+ */
10
+ export function mcpToNostrEvent(mcpMessage, pubkey, kind, tags = []) {
11
+ return {
12
+ pubkey,
13
+ kind,
14
+ tags,
15
+ content: JSON.stringify(mcpMessage),
16
+ created_at: Math.floor(Date.now() / 1000),
17
+ };
18
+ }
19
+ /**
20
+ * Deserializes a Nostr event into an MCP message.
21
+ *
22
+ * @param event The Nostr event to deserialize.
23
+ * @returns An MCP request or response object.
24
+ * @throws Error if the event content is not valid JSON
25
+ */
26
+ export function nostrEventToMcpMessage(event) {
27
+ try {
28
+ const content = JSON.parse(event.content);
29
+ return content;
30
+ }
31
+ catch (error) {
32
+ throw new Error(`Invalid JSON in Nostr event content: ${error instanceof Error ? error.message : 'Unknown error'}`);
33
+ }
34
+ }
35
+ /**
36
+ * Extracts a specific tag from a Nostr event.
37
+ *
38
+ * @param event The Nostr event.
39
+ * @param tagName The name of the tag to extract (e.g., 'e', 'p', 'd').
40
+ * @returns The value of the tag, or undefined if not found.
41
+ */
42
+ export function getNostrEventTag(tags, tagName) {
43
+ const tag = tags.find((t) => t[0] === tagName);
44
+ return tag ? tag[1] : undefined;
45
+ }
46
+ //# sourceMappingURL=serializers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serializers.js","sourceRoot":"","sources":["../../../../src/core/utils/serializers.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAC7B,UAA0B,EAC1B,MAAc,EACd,IAAY,EACZ,OAAmB,EAAE;IAErB,OAAO;QACL,MAAM;QACN,IAAI;QACJ,IAAI;QACJ,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;QACnC,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;KAC1C,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAiB;IACtD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC1C,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,wCAAwC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CACnG,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAC9B,IAAwB,EACxB,OAAe;IAEf,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC;IAC/C,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAClC,CAAC"}
@@ -0,0 +1,60 @@
1
+ import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
2
+ import { NostrServerTransportOptions } from '../transport/nostr-server-transport.js';
3
+ /**
4
+ * Options for configuring the NostrMCPGateway.
5
+ */
6
+ export interface NostrMCPGatewayOptions {
7
+ /** The MCP server transport (e.g., StdioServerTransport) to connect to the original MCP server */
8
+ mcpServerTransport: Transport;
9
+ /** Options for configuring the Nostr server transport */
10
+ nostrTransportOptions: NostrServerTransportOptions;
11
+ }
12
+ /**
13
+ * The main gateway class that orchestrates communication between Nostr clients
14
+ * and a local MCP server. It acts as a bridge, receiving MCP requests via Nostr
15
+ * events and forwarding them to the local MCP server, then publishing the
16
+ * responses back to Nostr. All request/response correlation is handled by the
17
+ * NostrServerTransport, making this a simple message forwarder.
18
+ */
19
+ export declare class NostrMCPGateway {
20
+ private readonly mcpServerTransport;
21
+ private readonly nostrServerTransport;
22
+ private isRunning;
23
+ constructor(options: NostrMCPGatewayOptions);
24
+ /**
25
+ * Sets up event handlers for both transports.
26
+ */
27
+ private setupEventHandlers;
28
+ /**
29
+ * Starts the gateway, initializing both transports.
30
+ */
31
+ start(): Promise<void>;
32
+ /**
33
+ * Stops the gateway, closing both transports.
34
+ */
35
+ stop(): Promise<void>;
36
+ /**
37
+ * Handles errors from the Nostr transport.
38
+ * @param error The error that occurred.
39
+ */
40
+ private handleNostrError;
41
+ /**
42
+ * Handles the Nostr transport closing.
43
+ */
44
+ private handleNostrClose;
45
+ /**
46
+ * Handles errors from the MCP server transport.
47
+ * @param error The error that occurred.
48
+ */
49
+ private handleServerError;
50
+ /**
51
+ * Handles the MCP server transport closing.
52
+ */
53
+ private handleServerClose;
54
+ /**
55
+ * Gets the current status of the gateway.
56
+ * @returns True if the gateway is running, false otherwise.
57
+ */
58
+ isActive(): boolean;
59
+ }
60
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/gateway/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAC/E,OAAO,EAEL,2BAA2B,EAC5B,MAAM,wCAAwC,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,kGAAkG;IAClG,kBAAkB,EAAE,SAAS,CAAC;IAC9B,yDAAyD;IACzD,qBAAqB,EAAE,2BAA2B,CAAC;CACpD;AAED;;;;;;GAMG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAY;IAC/C,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAuB;IAC5D,OAAO,CAAC,SAAS,CAAS;gBAEd,OAAO,EAAE,sBAAsB;IAS3C;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAoB1B;;OAEG;IACU,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBnC;;OAEG;IACU,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkBlC;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAIxB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAIxB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;;OAGG;IACI,QAAQ,IAAI,OAAO;CAG3B"}