@toon-protocol/client-mcp 0.31.2 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-ARFPM2PT.js → chunk-ALMTQYYJ.js} +19 -1
- package/dist/{chunk-ARFPM2PT.js.map → chunk-ALMTQYYJ.js.map} +1 -1
- package/dist/{chunk-PRFPAEGG.js → chunk-AYZWVPNQ.js} +712 -196
- package/dist/chunk-AYZWVPNQ.js.map +1 -0
- package/dist/{chunk-I5L5CB4N.js → chunk-CPVOJ7FE.js} +130 -5
- package/dist/chunk-CPVOJ7FE.js.map +1 -0
- package/dist/daemon.js +3 -3
- package/dist/daemon.js.map +1 -1
- package/dist/index.d.ts +216 -76
- package/dist/index.js +3 -3
- package/dist/mcp.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-I5L5CB4N.js.map +0 -1
- package/dist/chunk-PRFPAEGG.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -74,6 +74,12 @@ interface PublishRequest {
|
|
|
74
74
|
destination?: string;
|
|
75
75
|
/** Fee override in base units. Defaults to the daemon's configured fee. */
|
|
76
76
|
fee?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Which apex (BTP write target) to publish through. Defaults to the
|
|
79
|
+
* config-seeded apex. Writes always go through BTP — never to a relay
|
|
80
|
+
* directly — so this selects among the registered apexes, not relays.
|
|
81
|
+
*/
|
|
82
|
+
btpUrl?: string;
|
|
77
83
|
}
|
|
78
84
|
interface PublishResponse {
|
|
79
85
|
eventId: string;
|
|
@@ -90,9 +96,17 @@ interface SubscribeRequest {
|
|
|
90
96
|
filters: NostrFilter | NostrFilter[];
|
|
91
97
|
/** Optional caller-supplied subscription id (else one is generated). */
|
|
92
98
|
subId?: string;
|
|
99
|
+
/**
|
|
100
|
+
* Restrict the subscription to a single relay. Omit to FAN OUT across every
|
|
101
|
+
* registered relay (the same subId is registered on each); reads merge into
|
|
102
|
+
* one ordered stream.
|
|
103
|
+
*/
|
|
104
|
+
relayUrl?: string;
|
|
93
105
|
}
|
|
94
106
|
interface SubscribeResponse {
|
|
95
107
|
subId: string;
|
|
108
|
+
/** The relays the subscription was registered on. */
|
|
109
|
+
relays: string[];
|
|
96
110
|
}
|
|
97
111
|
/** `GET /events` — drain buffered events for a subscription (free read). */
|
|
98
112
|
interface EventsQuery {
|
|
@@ -102,6 +116,8 @@ interface EventsQuery {
|
|
|
102
116
|
cursor?: number;
|
|
103
117
|
/** Max events to return (default 200). */
|
|
104
118
|
limit?: number;
|
|
119
|
+
/** Restrict the drain to events received from a single relay. */
|
|
120
|
+
relayUrl?: string;
|
|
105
121
|
}
|
|
106
122
|
interface EventsResponse {
|
|
107
123
|
events: NostrEvent[];
|
|
@@ -150,6 +166,11 @@ interface SwapRequest {
|
|
|
150
166
|
chainRecipient: string;
|
|
151
167
|
/** Split the swap into N equal packets (default 1). */
|
|
152
168
|
packetCount?: number;
|
|
169
|
+
/**
|
|
170
|
+
* Which apex to settle the source-asset claim through (default: the
|
|
171
|
+
* config-seeded apex). The mill must be a child peer of this apex.
|
|
172
|
+
*/
|
|
173
|
+
btpUrl?: string;
|
|
153
174
|
}
|
|
154
175
|
/** One accumulated, decrypted claim harvested from a single swap packet. */
|
|
155
176
|
interface SwapClaim {
|
|
@@ -190,6 +211,74 @@ interface SwapResponse {
|
|
|
190
211
|
/** First rejection message, if any. */
|
|
191
212
|
message?: string;
|
|
192
213
|
}
|
|
214
|
+
/** `POST /relays` — add a relay READ target (fans into all fan-out reads). */
|
|
215
|
+
interface AddRelayRequest {
|
|
216
|
+
/** Relay WS URL, e.g. `ws://host:7100` or a `.anyone` hidden service. */
|
|
217
|
+
relayUrl: string;
|
|
218
|
+
}
|
|
219
|
+
/** `DELETE /relays` — remove a relay read target. */
|
|
220
|
+
interface RemoveRelayRequest {
|
|
221
|
+
relayUrl: string;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* `POST /apex` — add an apex WRITE target. Settlement params are DISCOVERED by
|
|
225
|
+
* reading the apex's `kind:10032` announcement off a relay, so the caller never
|
|
226
|
+
* hand-supplies chain/settlement details.
|
|
227
|
+
*/
|
|
228
|
+
interface AddApexRequest {
|
|
229
|
+
/** ILP address of the apex to add (e.g. `g.townhouse.town`). */
|
|
230
|
+
ilpAddress: string;
|
|
231
|
+
/**
|
|
232
|
+
* Relay to discover the apex's `kind:10032` on. If it isn't already a read
|
|
233
|
+
* target it is added (and persisted) first.
|
|
234
|
+
*/
|
|
235
|
+
relayUrl: string;
|
|
236
|
+
/** Optional apex Nostr pubkey to narrow the discovery filter (64-char hex). */
|
|
237
|
+
pubkey?: string;
|
|
238
|
+
/** Preferred settlement chain family; defaults to the apex's first chain. */
|
|
239
|
+
chain?: SettlementChain;
|
|
240
|
+
/** Child peers reached via this apex's channel (e.g. `["dvm","mill"]`). */
|
|
241
|
+
childPeers?: string[];
|
|
242
|
+
/** Per-write fee override (base units) for this apex. */
|
|
243
|
+
feePerEvent?: string;
|
|
244
|
+
}
|
|
245
|
+
interface AddApexResponse {
|
|
246
|
+
btpUrl: string;
|
|
247
|
+
destination: string;
|
|
248
|
+
chain: SettlementChain;
|
|
249
|
+
/** Whether the apex bootstrapped + opened a channel by the time we replied. */
|
|
250
|
+
ready: boolean;
|
|
251
|
+
}
|
|
252
|
+
/** `DELETE /apex` — remove an apex write target by its BTP URL. */
|
|
253
|
+
interface RemoveApexRequest {
|
|
254
|
+
btpUrl: string;
|
|
255
|
+
}
|
|
256
|
+
/** Status of one registered relay read target. */
|
|
257
|
+
interface RelayTargetStatus {
|
|
258
|
+
relayUrl: string;
|
|
259
|
+
connected: boolean;
|
|
260
|
+
buffered: number;
|
|
261
|
+
subscriptions: string[];
|
|
262
|
+
/** True for the permanent config-seeded relay (not removable). */
|
|
263
|
+
isDefault: boolean;
|
|
264
|
+
}
|
|
265
|
+
/** Status of one registered apex write target. */
|
|
266
|
+
interface ApexTargetStatus {
|
|
267
|
+
btpUrl: string;
|
|
268
|
+
destination: string;
|
|
269
|
+
chain: SettlementChain;
|
|
270
|
+
ready: boolean;
|
|
271
|
+
bootstrapping: boolean;
|
|
272
|
+
channelId?: string;
|
|
273
|
+
lastError?: string;
|
|
274
|
+
/** True for the permanent config-seeded apex (not removable). */
|
|
275
|
+
isDefault: boolean;
|
|
276
|
+
}
|
|
277
|
+
/** `GET /targets` — list every registered relay + apex target. */
|
|
278
|
+
interface TargetsResponse {
|
|
279
|
+
relays: RelayTargetStatus[];
|
|
280
|
+
apexes: ApexTargetStatus[];
|
|
281
|
+
}
|
|
193
282
|
/** Uniform error envelope returned with non-2xx responses. */
|
|
194
283
|
interface ErrorResponse {
|
|
195
284
|
error: string;
|
|
@@ -255,6 +344,11 @@ declare class ControlClient {
|
|
|
255
344
|
}>;
|
|
256
345
|
channels(): Promise<ChannelsResponse>;
|
|
257
346
|
swap(body: SwapRequest): Promise<SwapResponse>;
|
|
347
|
+
targets(): Promise<TargetsResponse>;
|
|
348
|
+
addRelay(body: AddRelayRequest): Promise<TargetsResponse>;
|
|
349
|
+
removeRelay(body: RemoveRelayRequest): Promise<TargetsResponse>;
|
|
350
|
+
addApex(body: AddApexRequest): Promise<AddApexResponse>;
|
|
351
|
+
removeApex(body: RemoveApexRequest): Promise<TargetsResponse>;
|
|
258
352
|
private request;
|
|
259
353
|
}
|
|
260
354
|
|
|
@@ -303,6 +397,14 @@ interface RelaySubscriptionOptions {
|
|
|
303
397
|
* object it is used directly and this is not called.
|
|
304
398
|
*/
|
|
305
399
|
decodeEvent?: (raw: string) => NostrEvent;
|
|
400
|
+
/**
|
|
401
|
+
* Invoked once per newly-buffered (de-duplicated) event. The daemon uses this
|
|
402
|
+
* to feed a runner-level MERGED buffer across many relays — so a fan-out read
|
|
403
|
+
* (`toon_read` with no relayUrl) draws from one ordered stream with a single
|
|
404
|
+
* scalar cursor. The relay still keeps its own buffer for `bufferedCount` /
|
|
405
|
+
* single-relay drains.
|
|
406
|
+
*/
|
|
407
|
+
onEvent?: (subId: string, event: NostrEvent) => void;
|
|
306
408
|
/** Optional logger. */
|
|
307
409
|
logger?: (msg: string) => void;
|
|
308
410
|
}
|
|
@@ -321,6 +423,7 @@ declare class RelaySubscription {
|
|
|
321
423
|
private readonly log;
|
|
322
424
|
private readonly wsFactory;
|
|
323
425
|
private readonly decodeEvent?;
|
|
426
|
+
private readonly onEvent?;
|
|
324
427
|
/** Active subscriptions: subId -> filters (re-sent on every (re)connect). */
|
|
325
428
|
private readonly subscriptions;
|
|
326
429
|
/** Ring buffer of received events, ordered by ascending `seq`. */
|
|
@@ -525,18 +628,23 @@ declare function resolveMnemonic(file: DaemonConfigFile): string;
|
|
|
525
628
|
declare function resolveConfig(file: DaemonConfigFile): ResolvedDaemonConfig;
|
|
526
629
|
|
|
527
630
|
/**
|
|
528
|
-
* ClientRunner — the daemon's connection owner.
|
|
529
|
-
*
|
|
530
|
-
*
|
|
531
|
-
*
|
|
631
|
+
* ClientRunner — the daemon's connection owner. The TOON client is 1-to-MANY:
|
|
632
|
+
* it can write through several apexes (each a `ToonClient` + BTP session +
|
|
633
|
+
* payment channel) and read from several relays (each a `RelaySubscription`).
|
|
634
|
+
*
|
|
635
|
+
* • Writes go through BTP, never to a relay directly — `publish`/`swap` select
|
|
636
|
+
* an apex (default: the config-seeded one).
|
|
637
|
+
* • Reads FAN OUT — `subscribe`/`getEvents` apply across every relay and merge
|
|
638
|
+
* into one ordered stream with a single scalar cursor (the runner owns the
|
|
639
|
+
* merged buffer; each `RelaySubscription` mirrors new events into it).
|
|
532
640
|
*
|
|
533
|
-
*
|
|
534
|
-
*
|
|
535
|
-
*
|
|
536
|
-
* tools surface "retry" rather than hang.
|
|
641
|
+
* Targets are added at runtime (`addRelay`/`addApex`), persisted to
|
|
642
|
+
* `targets.json`, replayed on the next boot, and removable. The config-seeded
|
|
643
|
+
* relay + apex are the permanent DEFAULT targets and cannot be removed.
|
|
537
644
|
*
|
|
538
|
-
*
|
|
539
|
-
*
|
|
645
|
+
* Each apex bootstraps asynchronously and non-blocking: the connection comes up
|
|
646
|
+
* in the background (the managed anon proxy alone can take 30–90s). Until ready,
|
|
647
|
+
* writes against it report `bootstrapping` so tools surface "retry".
|
|
540
648
|
*/
|
|
541
649
|
|
|
542
650
|
/** The subset of `ToonClient` the runner depends on. */
|
|
@@ -591,110 +699,142 @@ type StartReadProxy = (opts: {
|
|
|
591
699
|
socksPort: number;
|
|
592
700
|
log?: (msg: string) => void;
|
|
593
701
|
}) => Promise<ManagedProxyHandle>;
|
|
702
|
+
/** Builds a `ToonClient` (or a fake) for a given resolved client config. */
|
|
703
|
+
type CreateClient = (config: ToonClientConfig) => ToonClientLike;
|
|
704
|
+
/** Builds a `RelaySubscription` for a given relay URL + optional read proxy. */
|
|
705
|
+
type CreateRelay = (opts: {
|
|
706
|
+
relayUrl: string;
|
|
707
|
+
socksProxy?: string;
|
|
708
|
+
onEvent: (subId: string, event: NostrEvent) => void;
|
|
709
|
+
logger?: (msg: string) => void;
|
|
710
|
+
}) => RelaySubscription;
|
|
594
711
|
interface ClientRunnerDeps {
|
|
595
712
|
config: ResolvedDaemonConfig;
|
|
596
|
-
/** Factory producing the (real or fake) ToonClient. */
|
|
597
|
-
createClient:
|
|
598
|
-
/** Factory producing
|
|
599
|
-
createRelay?:
|
|
713
|
+
/** Factory producing the (real or fake) ToonClient for a client config. */
|
|
714
|
+
createClient: CreateClient;
|
|
715
|
+
/** Factory producing a relay subscription (defaults to the real one). */
|
|
716
|
+
createRelay?: CreateRelay;
|
|
600
717
|
/**
|
|
601
718
|
* Starts the daemon-managed read proxy (defaults to the real
|
|
602
719
|
* `startManagedAnonProxy`). Injected so tests avoid the anon download/spawn.
|
|
603
720
|
*/
|
|
604
721
|
startReadProxy?: StartReadProxy;
|
|
605
722
|
logger?: (msg: string) => void;
|
|
723
|
+
/** Path to the dynamic-targets store (tests override). */
|
|
724
|
+
targetsPath?: string;
|
|
606
725
|
}
|
|
607
726
|
declare class ClientRunner {
|
|
608
727
|
private readonly config;
|
|
609
|
-
private readonly
|
|
610
|
-
private readonly
|
|
728
|
+
private readonly createClient;
|
|
729
|
+
private readonly createRelay;
|
|
611
730
|
private readonly startReadProxy;
|
|
612
731
|
private readonly log;
|
|
732
|
+
private readonly targetsPath?;
|
|
613
733
|
private readonly startedAt;
|
|
614
|
-
|
|
615
|
-
private
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
734
|
+
/** Apex write targets, keyed by btpUrl. */
|
|
735
|
+
private readonly apexes;
|
|
736
|
+
/** Relay read targets, keyed by relayUrl. */
|
|
737
|
+
private readonly relays;
|
|
738
|
+
/** Runner-level merged read buffer across all relays (de-duped by event.id). */
|
|
739
|
+
private merged;
|
|
740
|
+
private readonly mergedSeen;
|
|
741
|
+
private mergedSeq;
|
|
742
|
+
/**
|
|
743
|
+
* Fan-out subscriptions (no relayUrl restriction): replayed onto relays added
|
|
744
|
+
* later so a new relay immediately participates in existing reads.
|
|
745
|
+
*/
|
|
746
|
+
private readonly fanoutSubs;
|
|
747
|
+
private subIdCounter;
|
|
748
|
+
private readonly defaultBtpUrl;
|
|
749
|
+
private readonly defaultRelayUrl;
|
|
750
|
+
/** Teardown for the daemon-managed read proxy (btp-direct + relay-`.anyone`). */
|
|
620
751
|
private stopReadProxy;
|
|
621
|
-
/** Error from the read proxy (kept separate from the paid-path `lastError`). */
|
|
622
752
|
private readProxyError;
|
|
623
753
|
private stopped;
|
|
754
|
+
private started;
|
|
624
755
|
constructor(deps: ClientRunnerDeps);
|
|
625
756
|
/**
|
|
626
|
-
*
|
|
627
|
-
*
|
|
628
|
-
*
|
|
757
|
+
* Start the live connections: the shared read proxy, every relay socket, the
|
|
758
|
+
* default apex bootstrap (non-blocking), then replay persisted dynamic
|
|
759
|
+
* targets. Returns immediately; apexes become ready asynchronously.
|
|
629
760
|
*/
|
|
630
761
|
start(): void;
|
|
631
|
-
/**
|
|
632
|
-
private bringUpReadProxy;
|
|
633
|
-
/** The background bootstrap routine (exposed for awaiting in tests). */
|
|
762
|
+
/** Await the default apex's bootstrap (kicking it off if not already running). */
|
|
634
763
|
bootstrap(): Promise<void>;
|
|
635
764
|
/**
|
|
636
|
-
*
|
|
637
|
-
*
|
|
638
|
-
*
|
|
639
|
-
* peer→channelId mapping, so a naive `openChannel()` after restart re-deposits
|
|
640
|
-
* into a fresh channel and reverts on-chain. We persist the channelId here and,
|
|
641
|
-
* when present, `trackChannel()` the live channel (which rehydrates the nonce
|
|
642
|
-
* from the channel store) — no on-chain write, watermark continues.
|
|
765
|
+
* Build + register a relay (idempotent by URL), wiring its events into the
|
|
766
|
+
* merged buffer and replaying active fan-out subscriptions. Does NOT start the
|
|
767
|
+
* socket — callers start it (so construction stays side-effect-free for tests).
|
|
643
768
|
*/
|
|
644
|
-
private
|
|
769
|
+
private registerRelay;
|
|
645
770
|
/**
|
|
646
|
-
*
|
|
647
|
-
*
|
|
648
|
-
* peers (no relay-based discovery). Mirrors the docker entrypoint's approach.
|
|
771
|
+
* Add a relay read target at runtime. `.anyone` relays reuse the managed read
|
|
772
|
+
* proxy (started here if needed). Persisted unless `persist` is false.
|
|
649
773
|
*/
|
|
650
|
-
|
|
774
|
+
addRelay(relayUrl: string, persist?: boolean): Promise<void>;
|
|
775
|
+
/** Remove a relay read target. The config-seeded default cannot be removed. */
|
|
776
|
+
removeRelay(relayUrl: string): void;
|
|
777
|
+
/** Mirror a newly-buffered relay event into the merged cross-relay buffer. */
|
|
778
|
+
private pushMerged;
|
|
779
|
+
/**
|
|
780
|
+
* Register a free-read subscription. With no `relayUrl` it FANS OUT across
|
|
781
|
+
* every relay (and onto relays added later); with one it targets that relay.
|
|
782
|
+
*/
|
|
783
|
+
subscribe(req: SubscribeRequest): SubscribeResponse;
|
|
784
|
+
/** Drain merged events newer than the cursor (free read), optionally scoped. */
|
|
785
|
+
getEvents(query: EventsQuery): EventsResponse;
|
|
786
|
+
private makeApex;
|
|
787
|
+
/**
|
|
788
|
+
* Bootstrap one apex (memoized): start, inject negotiation, open/resume the
|
|
789
|
+
* channel, route child peers. Concurrent callers await the same in-flight
|
|
790
|
+
* work rather than re-running it.
|
|
791
|
+
*/
|
|
792
|
+
private bootstrapApex;
|
|
793
|
+
private doBootstrapApex;
|
|
651
794
|
/**
|
|
652
|
-
*
|
|
653
|
-
* apex
|
|
654
|
-
* channel with the apex (g.townhouse) and pays via it regardless of which
|
|
655
|
-
* child the ILP destination addresses; but `ToonClient.resolvePeerId` keys off
|
|
656
|
-
* the destination's last segment (`town`/`dvm`/`mill`), so without this each
|
|
657
|
-
* child would (a) fail the "no negotiation for peer" guard and (b) try to open
|
|
658
|
-
* a SECOND on-chain channel to the same apex receive (which reverts —
|
|
659
|
-
* channel-exists). So: inject the same apex negotiation under each child peer
|
|
660
|
-
* AND pre-map its peer→channel to the already-open apex channel so
|
|
661
|
-
* `ensureChannel` reuses it (no second open; one shared nonce sequence).
|
|
795
|
+
* Add an apex write target. Settlement params are discovered by reading the
|
|
796
|
+
* apex's kind:10032 off the given relay (added first if unknown). Persisted.
|
|
662
797
|
*/
|
|
798
|
+
addApex(req: AddApexRequest): Promise<AddApexResponse>;
|
|
799
|
+
/** Build + register + bootstrap an apex from a (persisted) target record. */
|
|
800
|
+
private instantiateApex;
|
|
801
|
+
/** Remove an apex write target. The config-seeded default cannot be removed. */
|
|
802
|
+
removeApex(btpUrl: string): Promise<void>;
|
|
803
|
+
/** Derive a per-apex ToonClientConfig from the default (shared identity/transport). */
|
|
804
|
+
private deriveApexClientConfig;
|
|
805
|
+
private apexChannelStorePathFor;
|
|
806
|
+
private replayPersistedTargets;
|
|
807
|
+
private ensureReadProxy;
|
|
808
|
+
private bringUpReadProxy;
|
|
809
|
+
/** Open the apex channel — or, on a restart, RESUME the existing one. */
|
|
810
|
+
private openOrResumeApexChannel;
|
|
811
|
+
/** Inject the apex settlement negotiation directly into its ToonClient. */
|
|
812
|
+
private injectApexNegotiation;
|
|
813
|
+
/** Route apex CHILD peers (dvm/mill) through the SAME apex payment channel. */
|
|
663
814
|
private routeChildPeersThroughApexChannel;
|
|
815
|
+
private defaultApex;
|
|
816
|
+
/** Whether any apex has finished bootstrapping. */
|
|
664
817
|
isReady(): boolean;
|
|
665
818
|
isBootstrapping(): boolean;
|
|
666
819
|
getStatus(): StatusResponse;
|
|
667
|
-
/**
|
|
820
|
+
/** Full registry of relay + apex targets with per-target status. */
|
|
821
|
+
getTargets(): TargetsResponse;
|
|
822
|
+
/** Pay-to-write a single event through the selected (or default) apex. */
|
|
668
823
|
publish(req: PublishRequest): Promise<PublishResponse>;
|
|
669
|
-
/**
|
|
670
|
-
|
|
671
|
-
/** Drain buffered events newer than the cursor (free read). */
|
|
672
|
-
getEvents(query: EventsQuery): EventsResponse;
|
|
673
|
-
/** Open (or return) a payment channel for a destination. */
|
|
674
|
-
openChannel(destination?: string): Promise<{
|
|
824
|
+
/** Open (or return) a payment channel on the selected (or default) apex. */
|
|
825
|
+
openChannel(destination?: string, btpUrl?: string): Promise<{
|
|
675
826
|
channelId: string;
|
|
676
827
|
}>;
|
|
677
|
-
/** List tracked channels with
|
|
828
|
+
/** List tracked channels across ALL apexes with nonce + cumulative amount. */
|
|
678
829
|
getChannels(): ChannelsResponse;
|
|
679
|
-
/**
|
|
680
|
-
* Swap source asset → target asset against a mill peer.
|
|
681
|
-
*
|
|
682
|
-
* Uses SDK `streamSwap`, which builds a NIP-59 gift-wrapped kind:20032 swap
|
|
683
|
-
* rumor per packet and sends it over the open BTP session. The source-asset
|
|
684
|
-
* balance proof is signed by the ToonClient's ChannelManager against the apex
|
|
685
|
-
* channel — so the mill peer MUST be routed via `apexChildPeers` (otherwise
|
|
686
|
-
* there is no channel to sign against and the mill rejects with F99).
|
|
687
|
-
*
|
|
688
|
-
* A fresh ephemeral gift-wrap key is generated per swap (used for sealing the
|
|
689
|
-
* rumor AND decrypting the FULFILL claims) — independent of the daemon's
|
|
690
|
-
* settlement identity, so callers never need to expose a key.
|
|
691
|
-
*/
|
|
830
|
+
/** Swap source→target asset against a mill peer via the selected apex. */
|
|
692
831
|
swap(req: SwapRequest): Promise<SwapResponse>;
|
|
693
|
-
/** Graceful teardown
|
|
832
|
+
/** Graceful teardown: close every relay + stop every apex client + read proxy. */
|
|
694
833
|
stop(): Promise<void>;
|
|
695
|
-
private
|
|
834
|
+
private selectApex;
|
|
835
|
+
private assertApexReady;
|
|
696
836
|
}
|
|
697
|
-
/** Thrown by paid-write operations while the
|
|
837
|
+
/** Thrown by paid-write operations while the target apex is not yet ready. */
|
|
698
838
|
declare class NotReadyError extends Error {
|
|
699
839
|
readonly retryable = true;
|
|
700
840
|
constructor(message: string);
|
|
@@ -822,4 +962,4 @@ declare const TOOL_DEFINITIONS: ToolDefinition[];
|
|
|
822
962
|
*/
|
|
823
963
|
declare function dispatchTool(client: ControlClient, name: string, args: Record<string, unknown>): Promise<ToolResult>;
|
|
824
964
|
|
|
825
|
-
export { type ApexNegotiationConfig, type ChainStatus, type ChannelInfo, type ChannelsResponse, ClientRunner, type ClientRunnerDeps, ControlApiError, ControlClient, type ControlClientOptions, DEFAULT_KEYSTORE_PASSWORD, type DaemonConfigFile, DaemonUnreachableError, type DrainResult, type ErrorResponse, type EventsQuery, type EventsResponse, type MinimalWebSocket, type NostrFilter, NotReadyError, type OpenChannelRequest, PublishRejectedError, type PublishRequest, type PublishResponse, RelaySubscription, type RelaySubscriptionOptions, type ResolvedDaemonConfig, type SettlementChain, type StatusResponse, type SubscribeRequest, type SubscribeResponse, type SwapClaim, type SwapRequest, type SwapResponse, TOOL_DEFINITIONS, type ToolDefinition, type ToolResult, type ToonClientLike, type WebSocketFactory, acquireLock, configDir, defaultConfigPath, defaultKeystorePath, dispatchTool, hasConfiguredIdentity, isDaemonRunning, isProcessAlive, readConfigFile, readPid, registerRoutes, releaseLock, resolveConfig, resolveMnemonic, scaffoldFirstRun, spawnDaemonDetached, waitForReady };
|
|
965
|
+
export { type AddApexRequest, type AddApexResponse, type AddRelayRequest, type ApexNegotiationConfig, type ApexTargetStatus, type ChainStatus, type ChannelInfo, type ChannelsResponse, ClientRunner, type ClientRunnerDeps, ControlApiError, ControlClient, type ControlClientOptions, DEFAULT_KEYSTORE_PASSWORD, type DaemonConfigFile, DaemonUnreachableError, type DrainResult, type ErrorResponse, type EventsQuery, type EventsResponse, type MinimalWebSocket, type NostrFilter, NotReadyError, type OpenChannelRequest, PublishRejectedError, type PublishRequest, type PublishResponse, RelaySubscription, type RelaySubscriptionOptions, type RelayTargetStatus, type RemoveApexRequest, type RemoveRelayRequest, type ResolvedDaemonConfig, type SettlementChain, type StatusResponse, type SubscribeRequest, type SubscribeResponse, type SwapClaim, type SwapRequest, type SwapResponse, TOOL_DEFINITIONS, type TargetsResponse, type ToolDefinition, type ToolResult, type ToonClientLike, type WebSocketFactory, acquireLock, configDir, defaultConfigPath, defaultKeystorePath, dispatchTool, hasConfiguredIdentity, isDaemonRunning, isProcessAlive, readConfigFile, readPid, registerRoutes, releaseLock, resolveConfig, resolveMnemonic, scaffoldFirstRun, spawnDaemonDetached, waitForReady };
|
package/dist/index.js
CHANGED
|
@@ -8,11 +8,11 @@ import {
|
|
|
8
8
|
hasConfiguredIdentity,
|
|
9
9
|
registerRoutes,
|
|
10
10
|
scaffoldFirstRun
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-AYZWVPNQ.js";
|
|
12
12
|
import {
|
|
13
13
|
TOOL_DEFINITIONS,
|
|
14
14
|
dispatchTool
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-CPVOJ7FE.js";
|
|
16
16
|
import {
|
|
17
17
|
ControlApiError,
|
|
18
18
|
ControlClient,
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
resolveMnemonic,
|
|
31
31
|
spawnDaemonDetached,
|
|
32
32
|
waitForReady
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-ALMTQYYJ.js";
|
|
34
34
|
import "./chunk-32QD72IL.js";
|
|
35
35
|
import "./chunk-QTDCFXPF.js";
|
|
36
36
|
import "./chunk-LR7W2ISE.js";
|
package/dist/mcp.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire as __cr } from 'module'; const require = __cr(import.meta
|
|
|
3
3
|
import {
|
|
4
4
|
TOOL_DEFINITIONS,
|
|
5
5
|
dispatchTool
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-CPVOJ7FE.js";
|
|
7
7
|
import {
|
|
8
8
|
ControlClient,
|
|
9
9
|
defaultConfigPath,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
readConfigFile,
|
|
12
12
|
spawnDaemonDetached,
|
|
13
13
|
waitForReady
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-ALMTQYYJ.js";
|
|
15
15
|
import "./chunk-32QD72IL.js";
|
|
16
16
|
import "./chunk-QTDCFXPF.js";
|
|
17
17
|
import "./chunk-LR7W2ISE.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toon-protocol/client-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.0",
|
|
4
4
|
"description": "Always-on local daemon + MCP server letting a Claude agent (Desktop or Code) act as a TOON Protocol client: pay-to-write publishing, free reads, channel/balance management, and mill swaps.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Jonathan Green",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcp-tools.ts"],"sourcesContent":["/**\n * MCP tool definitions + dispatch. The MCP server is a thin proxy: each tool\n * maps to a `toon-clientd` control-plane call. This module is the testable core\n * (no stdio / SDK transport) so the tool→HTTP mapping and the\n * \"bootstrapping — retry\" handling can be unit-tested directly.\n */\n\nimport { ControlApiError, DaemonUnreachableError } from './control-client.js';\nimport type { ControlClient } from './control-client.js';\nimport type {\n NostrFilter,\n PublishRequest,\n SwapRequest,\n} from './control-api.js';\n\n/** A JSON-Schema-described MCP tool. */\nexport interface ToolDefinition {\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n}\n\n/** MCP tool-call result shape (subset of the SDK's CallToolResult). */\nexport interface ToolResult {\n content: { type: 'text'; text: string }[];\n isError?: boolean;\n}\n\nexport const TOOL_DEFINITIONS: ToolDefinition[] = [\n {\n name: 'toon_status',\n description:\n 'Report TOON client daemon health: bootstrapping/ready state, transport, ' +\n 'relay connection, buffered-event count, and per-chain settlement status.',\n inputSchema: {\n type: 'object',\n properties: {},\n additionalProperties: false,\n },\n },\n {\n name: 'toon_identity',\n description:\n \"Return this client's public identity (Nostr pubkey + EVM/Solana/Mina \" +\n 'addresses). Never returns private keys.',\n inputSchema: {\n type: 'object',\n properties: {},\n additionalProperties: false,\n },\n },\n {\n name: 'toon_publish',\n description:\n 'Pay-to-write: publish a fully-signed Nostr event to the TOON network. ' +\n 'Signs an off-chain payment-channel claim and forwards it over BTP. ' +\n 'Returns the event id, channel id, and the advanced channel nonce.',\n inputSchema: {\n type: 'object',\n properties: {\n event: {\n type: 'object',\n description:\n 'A fully-signed Nostr event (must include id, pubkey, sig, kind, ' +\n 'created_at, tags, content).',\n },\n destination: {\n type: 'string',\n description:\n 'Optional ILP destination override (default: the apex/town).',\n },\n fee: {\n type: 'string',\n description:\n 'Optional fee override in base units (default: daemon config).',\n },\n },\n required: ['event'],\n additionalProperties: false,\n },\n },\n {\n name: 'toon_subscribe',\n description:\n 'Free read: register a persistent town-relay subscription with NIP-01 ' +\n 'filter(s). Returns a subscription id to drain with toon_read.',\n inputSchema: {\n type: 'object',\n properties: {\n filters: {\n description: 'A NIP-01 filter object or an array of OR-ed filters.',\n },\n subId: { type: 'string', description: 'Optional caller-supplied id.' },\n },\n required: ['filters'],\n additionalProperties: false,\n },\n },\n {\n name: 'toon_read',\n description:\n 'Free read: drain buffered events newer than a cursor. Pass back the ' +\n 'returned cursor to fetch only events received since the last read.',\n inputSchema: {\n type: 'object',\n properties: {\n subId: { type: 'string', description: 'Restrict to one subscription.' },\n cursor: {\n type: 'number',\n description: 'Cursor from a prior toon_read.',\n },\n limit: {\n type: 'number',\n description: 'Max events to return (default 200).',\n },\n },\n additionalProperties: false,\n },\n },\n {\n name: 'toon_open_channel',\n description:\n 'Open (or return the existing) payment channel for a destination. ' +\n 'Channels open lazily on first publish; use this to pre-open.',\n inputSchema: {\n type: 'object',\n properties: {\n destination: {\n type: 'string',\n description: 'ILP destination (default: apex).',\n },\n },\n additionalProperties: false,\n },\n },\n {\n name: 'toon_channels',\n description:\n 'List tracked payment channels with their nonce watermark and cumulative ' +\n 'transferred amount.',\n inputSchema: {\n type: 'object',\n properties: {},\n additionalProperties: false,\n },\n },\n {\n name: 'toon_swap',\n description:\n 'Pay a mill peer (asset A) to receive asset B plus a signed target-chain ' +\n 'claim. Builds the NIP-59 gift-wrapped kind:20032 swap rumor and streams ' +\n 'it; the source-asset claim is signed against the open apex channel (the ' +\n 'mill must be routed via apexChildPeers). Returns the accumulated, ' +\n 'decrypted target-chain claim(s) and settlement metadata.',\n inputSchema: {\n type: 'object',\n properties: {\n destination: {\n type: 'string',\n description: 'Mill peer ILP destination (e.g. g.townhouse.mill).',\n },\n amount: {\n type: 'string',\n description: 'Total source-asset amount to swap, source micro-units.',\n },\n millPubkey: {\n type: 'string',\n description:\n \"Mill's 64-char lowercase hex Nostr pubkey (gift-wrap recipient).\",\n },\n pair: {\n type: 'object',\n description:\n 'The swap pair (from kind:10032 discovery or operator-supplied): ' +\n '{ from:{assetCode,assetScale,chain}, to:{...}, rate, minAmount?, maxAmount? }.',\n },\n chainRecipient: {\n type: 'string',\n description:\n \"Sender's payout address on pair.to.chain (EVM 0x-hex / Solana / Mina base58).\",\n },\n packetCount: {\n type: 'number',\n description: 'Split the swap into N equal packets (default 1).',\n },\n },\n required: [\n 'destination',\n 'amount',\n 'millPubkey',\n 'pair',\n 'chainRecipient',\n ],\n additionalProperties: false,\n },\n },\n];\n\n/**\n * Dispatch an MCP tool call to the daemon control plane. Always resolves with a\n * `ToolResult` (errors are encoded as `isError: true` text, not thrown, so the\n * agent sees a readable message). A retryable error (daemon still\n * bootstrapping) yields a clear \"retry shortly\" message.\n */\nexport async function dispatchTool(\n client: ControlClient,\n name: string,\n args: Record<string, unknown>\n): Promise<ToolResult> {\n try {\n switch (name) {\n case 'toon_status':\n return ok(await client.status());\n case 'toon_identity': {\n const s = await client.status();\n return ok({\n identity: s.identity,\n ready: s.ready,\n bootstrapping: s.bootstrapping,\n });\n }\n case 'toon_publish':\n return ok(await client.publish(args as unknown as PublishRequest));\n case 'toon_subscribe':\n return ok(\n await client.subscribe({\n filters: args['filters'] as NostrFilter | NostrFilter[],\n ...(typeof args['subId'] === 'string'\n ? { subId: args['subId'] }\n : {}),\n })\n );\n case 'toon_read':\n return ok(\n await client.events({\n ...(typeof args['subId'] === 'string'\n ? { subId: args['subId'] }\n : {}),\n ...(typeof args['cursor'] === 'number'\n ? { cursor: args['cursor'] }\n : {}),\n ...(typeof args['limit'] === 'number'\n ? { limit: args['limit'] }\n : {}),\n })\n );\n case 'toon_open_channel':\n return ok(\n await client.openChannel(\n typeof args['destination'] === 'string'\n ? { destination: args['destination'] }\n : {}\n )\n );\n case 'toon_channels':\n return ok(await client.channels());\n case 'toon_swap':\n return ok(\n await client.swap({\n destination: String(args['destination']),\n amount: String(args['amount']),\n millPubkey: String(args['millPubkey']),\n pair: args['pair'] as SwapRequest['pair'],\n chainRecipient: String(args['chainRecipient']),\n ...(typeof args['packetCount'] === 'number'\n ? { packetCount: args['packetCount'] }\n : {}),\n })\n );\n default:\n return err(`Unknown tool: ${name}`);\n }\n } catch (e) {\n if (e instanceof ControlApiError && e.retryable) {\n return err(\n `TOON client is still bootstrapping (the anon proxy / BTP session can take ` +\n `30–90s) — retry shortly. (${e.message})`\n );\n }\n if (e instanceof DaemonUnreachableError) {\n return err(\n `TOON client daemon is not reachable at ${e.baseUrl}. It may have failed ` +\n `to start — check ~/.toon-client/daemon.log.`\n );\n }\n if (e instanceof ControlApiError) {\n return err(`${e.message}${e.detail ? `: ${e.detail}` : ''}`);\n }\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\nfunction ok(data: unknown): ToolResult {\n return { content: [{ type: 'text', text: JSON.stringify(data, null, 2) }] };\n}\n\nfunction err(message: string): ToolResult {\n return { content: [{ type: 'text', text: message }], isError: true };\n}\n"],"mappings":"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","names":[]}
|