@toon-protocol/client-mcp 0.1.0 → 0.2.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/daemon.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  ClientRunner,
5
5
  registerRoutes,
6
6
  scaffoldFirstRun
7
- } from "./chunk-3NAWISI5.js";
7
+ } from "./chunk-L6F2B3GX.js";
8
8
  import {
9
9
  ControlClient,
10
10
  ToonClient,
@@ -17,9 +17,9 @@ import {
17
17
  resolveConfig,
18
18
  spawnDaemonDetached,
19
19
  waitForReady
20
- } from "./chunk-5KFXUT5Q.js";
20
+ } from "./chunk-NP35YO5O.js";
21
21
  import "./chunk-32QD72IL.js";
22
- import "./chunk-FSS45ZX3.js";
22
+ import "./chunk-DLYE6U2Z.js";
23
23
  import "./chunk-LR7W2ISE.js";
24
24
  import "./chunk-VA7XC4FD.js";
25
25
  import "./chunk-SKQTKZIH.js";
@@ -3,25 +3,29 @@ import {
3
3
  ED25519_TORSION_SUBGROUP,
4
4
  _map_to_curve_elligator2_curve25519,
5
5
  ed25519,
6
+ ed25519_FROST,
6
7
  ed25519_hasher,
7
8
  ed25519ctx,
8
9
  ed25519ph,
9
10
  ristretto255,
11
+ ristretto255_FROST,
10
12
  ristretto255_hasher,
11
13
  ristretto255_oprf,
12
14
  x25519
13
- } from "./chunk-FSS45ZX3.js";
15
+ } from "./chunk-DLYE6U2Z.js";
14
16
  import "./chunk-F22GNSF6.js";
15
17
  export {
16
18
  ED25519_TORSION_SUBGROUP,
17
19
  _map_to_curve_elligator2_curve25519,
18
20
  ed25519,
21
+ ed25519_FROST,
19
22
  ed25519_hasher,
20
23
  ed25519ctx,
21
24
  ed25519ph,
22
25
  ristretto255,
26
+ ristretto255_FROST,
23
27
  ristretto255_hasher,
24
28
  ristretto255_oprf,
25
29
  x25519
26
30
  };
27
- //# sourceMappingURL=ed25519-2QVPINLS.js.map
31
+ //# sourceMappingURL=ed25519-2LFQXLYS.js.map
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- import { NostrEvent } from 'nostr-tools/pure';
1
+ import { NostrEvent, EventTemplate } from 'nostr-tools/pure';
2
2
  import { SwapPair } from '@toon-protocol/core';
3
3
  import { ToonClientConfig } from '@toon-protocol/client';
4
4
  import { FastifyInstance } from 'fastify';
5
+ import { ViewSpec } from '@toon-protocol/views';
5
6
 
6
7
  /**
7
8
  * Shared request/response contract for the `toon-clientd` localhost control
@@ -90,6 +91,58 @@ interface PublishResponse {
90
91
  /** Channel nonce after this publish (advances by one per paid write). */
91
92
  nonce: number;
92
93
  }
94
+ /**
95
+ * `POST /publish-unsigned` — build, SIGN (with the daemon-held key), and
96
+ * pay-to-write a Nostr event. The caller (a UI/agent) supplies only the event
97
+ * shell — it never holds the private key. For replaceable kinds (0 profile,
98
+ * 3 follow list) the daemon merges the latest known event's tags before signing.
99
+ */
100
+ interface PublishUnsignedRequest {
101
+ /** Event kind to publish (integer, 0–65535). */
102
+ kind: number;
103
+ /** Event content (default ''). */
104
+ content?: string;
105
+ /** Event tags (array of string arrays). */
106
+ tags?: string[][];
107
+ /** ILP destination override (default: the configured apex/town address). */
108
+ destination?: string;
109
+ /** Fee override in base units. Defaults to the daemon's configured fee. */
110
+ fee?: string;
111
+ /** Which apex (BTP write target) to publish through (default: config-seeded). */
112
+ btpUrl?: string;
113
+ }
114
+ /**
115
+ * `POST /upload-media` — two-step spendy write: upload bytes to Arweave via the
116
+ * kind:5094 blob-storage DVM, then sign+publish a media event referencing the
117
+ * resulting Arweave URL. Single-packet only (large media is out of scope; see
118
+ * `requestBlobStorage`).
119
+ */
120
+ interface UploadMediaRequest {
121
+ /** Base64-encoded media bytes. */
122
+ dataBase64: string;
123
+ /** MIME type (default 'application/octet-stream'). */
124
+ mime?: string;
125
+ /**
126
+ * Kind of the media event to publish referencing the upload. Default 1063
127
+ * (NIP-94 file metadata). 20 = NIP-68 picture, 21/22 = NIP-71 video, 1 = note
128
+ * with a NIP-92 `imeta` attachment.
129
+ */
130
+ kind?: number;
131
+ /** Caption / content for the published media event. */
132
+ caption?: string;
133
+ /** Extra tags merged into the published media event. */
134
+ tags?: string[][];
135
+ /** Fee override in base units (applies to the upload + the publish). */
136
+ fee?: string;
137
+ /** Which apex to publish through (default: config-seeded). */
138
+ btpUrl?: string;
139
+ }
140
+ interface UploadMediaResponse extends PublishResponse {
141
+ /** Arweave URL the media event references. */
142
+ url: string;
143
+ /** Arweave transaction id of the uploaded blob. */
144
+ txId: string;
145
+ }
93
146
  /** `POST /subscribe` — register a persistent free-read subscription. */
94
147
  interface SubscribeRequest {
95
148
  /** NIP-01 filter(s). A single object or an array of OR-ed filters. */
@@ -108,6 +161,18 @@ interface SubscribeResponse {
108
161
  /** The relays the subscription was registered on. */
109
162
  relays: string[];
110
163
  }
164
+ /**
165
+ * `POST /query` — one-shot free read: subscribe the filter(s), wait briefly, and
166
+ * return every buffered event matching them. Used by the apps `toon_query` tool.
167
+ */
168
+ interface QueryRequest {
169
+ filters: NostrFilter | NostrFilter[];
170
+ /** Bounded wait for relay delivery, ms (default 1200). */
171
+ timeoutMs?: number;
172
+ }
173
+ interface QueryResponse {
174
+ events: NostrEvent[];
175
+ }
111
176
  /** `GET /events` — drain buffered events for a subscription (free read). */
112
177
  interface EventsQuery {
113
178
  /** Restrict to a single subscription id. */
@@ -211,6 +276,36 @@ interface SwapResponse {
211
276
  /** First rejection message, if any. */
212
277
  message?: string;
213
278
  }
279
+ /**
280
+ * `POST /http-fetch-paid` — payment-aware HTTP GET/POST. The daemon issues the
281
+ * request via `ToonClient.h402Fetch`; if the origin answers `402 Payment
282
+ * Required` the client transparently pays over TOON and retries, returning the
283
+ * settled resource. The caller never holds chain keys — settlement happens
284
+ * inside the daemon against the open apex channel.
285
+ */
286
+ interface HttpFetchPaidRequest {
287
+ /** Absolute URL of the resource to fetch (the origin may gate it behind 402). */
288
+ url: string;
289
+ /** HTTP method (default GET). */
290
+ method?: string;
291
+ /** Request headers as a flat string→string map. */
292
+ headers?: Record<string, string>;
293
+ /** Request body (string; sent verbatim). Typically used with POST. */
294
+ body?: string;
295
+ /** Per-request timeout, ms (passed through to the client). */
296
+ timeout?: number;
297
+ }
298
+ interface HttpFetchPaidResponse {
299
+ /** Final HTTP status after any 402-pay-and-retry round trip. */
300
+ status: number;
301
+ /** Response headers as a flat string→string map. */
302
+ headers: Record<string, string>;
303
+ /**
304
+ * Response body decoded as text. Binary bodies are returned as their decoded
305
+ * text for v1 (acceptable; a base64 path can be added later if needed).
306
+ */
307
+ body: string;
308
+ }
214
309
  /** `POST /relays` — add a relay READ target (fans into all fan-out reads). */
215
310
  interface AddRelayRequest {
216
311
  /** Relay WS URL, e.g. `ws://host:7100` or a `.anyone` hidden service. */
@@ -337,13 +432,17 @@ declare class ControlClient {
337
432
  ping(): Promise<boolean>;
338
433
  status(): Promise<StatusResponse>;
339
434
  publish(body: PublishRequest): Promise<PublishResponse>;
435
+ publishUnsigned(body: PublishUnsignedRequest): Promise<PublishResponse>;
436
+ uploadMedia(body: UploadMediaRequest): Promise<UploadMediaResponse>;
340
437
  subscribe(body: SubscribeRequest): Promise<SubscribeResponse>;
438
+ query(body: QueryRequest): Promise<QueryResponse>;
341
439
  events(query?: EventsQuery): Promise<EventsResponse>;
342
440
  openChannel(body?: OpenChannelRequest): Promise<{
343
441
  channelId: string;
344
442
  }>;
345
443
  channels(): Promise<ChannelsResponse>;
346
444
  swap(body: SwapRequest): Promise<SwapResponse>;
445
+ httpFetchPaid(body: HttpFetchPaidRequest): Promise<HttpFetchPaidResponse>;
347
446
  targets(): Promise<TargetsResponse>;
348
447
  addRelay(body: AddRelayRequest): Promise<TargetsResponse>;
349
448
  removeRelay(body: RemoveRelayRequest): Promise<TargetsResponse>;
@@ -674,6 +773,28 @@ interface ToonClientLike {
674
773
  error?: string;
675
774
  }>;
676
775
  signBalanceProof(channelId: string, amount: bigint): Promise<unknown>;
776
+ /**
777
+ * Sign an unsigned event template with the daemon-held Nostr key (the key
778
+ * never leaves the daemon). Backs the `publish-unsigned` / `upload-media`
779
+ * paths so a UI/agent supplies only the event shell.
780
+ */
781
+ signEvent(template: EventTemplate): NostrEvent | Promise<NostrEvent>;
782
+ /**
783
+ * Upload bytes to Arweave via the kind:5094 blob-storage DVM (single-packet),
784
+ * returning the Arweave tx id. Reuses the client's claim/channel plumbing.
785
+ */
786
+ uploadBlob(params: {
787
+ blobData: Uint8Array;
788
+ contentType?: string;
789
+ bid?: string;
790
+ destination?: string;
791
+ ilpAmount?: bigint;
792
+ }): Promise<{
793
+ success: boolean;
794
+ txId?: string;
795
+ eventId?: string;
796
+ error?: string;
797
+ }>;
677
798
  openChannel(destination?: string): Promise<string>;
678
799
  getTrackedChannels(): string[];
679
800
  getChannelNonce(channelId: string): number;
@@ -689,6 +810,18 @@ interface ToonClientLike {
689
810
  code?: string;
690
811
  message?: string;
691
812
  }>;
813
+ /**
814
+ * Payment-aware HTTP fetch: issue the request and, on a `402 Payment
815
+ * Required`, transparently pay over TOON and retry, returning the settled Web
816
+ * `Response`. Pinned to the `ToonClient.h402Fetch` shape (issue #50).
817
+ */
818
+ h402Fetch(url: string, opts?: {
819
+ method?: string;
820
+ headers?: Record<string, string>;
821
+ body?: string | Uint8Array;
822
+ timeout?: number;
823
+ destination?: string;
824
+ }): Promise<Response>;
692
825
  }
693
826
  /** A started managed proxy: just the teardown handle the runner needs. */
694
827
  interface ManagedProxyHandle {
@@ -781,6 +914,16 @@ declare class ClientRunner {
781
914
  * every relay (and onto relays added later); with one it targets that relay.
782
915
  */
783
916
  subscribe(req: SubscribeRequest): SubscribeResponse;
917
+ /**
918
+ * One-shot free read: subscribe the given filter(s) across all relays, wait a
919
+ * bounded window for the relay(s) to deliver, then return every buffered event
920
+ * matching the filter (matched by content, not subId — so events already
921
+ * buffered by other subscriptions are included despite the global dedup).
922
+ *
923
+ * Backs the apps `toon_query` tool the generative-UI runtime calls to resolve
924
+ * a ViewSpec node's data bind.
925
+ */
926
+ query(filters: NostrFilter | NostrFilter[], timeoutMs?: number): Promise<NostrEvent[]>;
784
927
  /** Drain merged events newer than the cursor (free read), optionally scoped. */
785
928
  getEvents(query: EventsQuery): EventsResponse;
786
929
  private makeApex;
@@ -821,6 +964,26 @@ declare class ClientRunner {
821
964
  getTargets(): TargetsResponse;
822
965
  /** Pay-to-write a single event through the selected (or default) apex. */
823
966
  publish(req: PublishRequest): Promise<PublishResponse>;
967
+ /**
968
+ * Build, sign (with the daemon-held key), and pay-to-write an event. The
969
+ * caller supplies only the event shell; the private key never leaves the
970
+ * daemon. Payloads are MODEL-AUTHORED → validated server-side here (the model
971
+ * is not a security boundary). Replaceable kinds (0/3) merge the latest known
972
+ * event's tags before signing.
973
+ */
974
+ publishUnsigned(req: PublishUnsignedRequest): Promise<PublishResponse>;
975
+ /**
976
+ * Upload media to Arweave (kind:5094 blob DVM, single-packet) then sign+publish
977
+ * a media event referencing the resulting URL. One spendy operation, two steps,
978
+ * entirely server-side.
979
+ */
980
+ uploadMedia(req: UploadMediaRequest): Promise<UploadMediaResponse>;
981
+ /** Validate + assemble a signable event template (with replaceable merge). */
982
+ private buildTemplate;
983
+ /** Latest self-authored event of `kind` currently in the merged read buffer. */
984
+ private latestSelfReplaceable;
985
+ /** Tags for a published media event referencing an Arweave URL. */
986
+ private buildMediaTags;
824
987
  /** Open (or return) a payment channel on the selected (or default) apex. */
825
988
  openChannel(destination?: string, btpUrl?: string): Promise<{
826
989
  channelId: string;
@@ -829,6 +992,12 @@ declare class ClientRunner {
829
992
  getChannels(): ChannelsResponse;
830
993
  /** Swap source→target asset against a mill peer via the selected apex. */
831
994
  swap(req: SwapRequest): Promise<SwapResponse>;
995
+ /**
996
+ * Payment-aware HTTP fetch through an apex's client. The client issues the
997
+ * request and, on `402 Payment Required`, pays over TOON and retries; we
998
+ * translate the resulting Web `Response` into the wire envelope.
999
+ */
1000
+ httpFetchPaid(req: HttpFetchPaidRequest): Promise<HttpFetchPaidResponse>;
832
1001
  /** Graceful teardown: close every relay + stop every apex client + read proxy. */
833
1002
  stop(): Promise<void>;
834
1003
  private selectApex;
@@ -944,6 +1113,8 @@ interface ToolDefinition {
944
1113
  name: string;
945
1114
  description: string;
946
1115
  inputSchema: Record<string, unknown>;
1116
+ /** MCP-apps metadata, e.g. `{ ui: { resourceUri } }` linking a UI resource. */
1117
+ _meta?: Record<string, unknown>;
947
1118
  }
948
1119
  /** MCP tool-call result shape (subset of the SDK's CallToolResult). */
949
1120
  interface ToolResult {
@@ -951,6 +1122,8 @@ interface ToolResult {
951
1122
  type: 'text';
952
1123
  text: string;
953
1124
  }[];
1125
+ /** Machine-readable payload the MCP-app iframe reads (events, ViewSpec, …). */
1126
+ structuredContent?: Record<string, unknown>;
954
1127
  isError?: boolean;
955
1128
  }
956
1129
  declare const TOOL_DEFINITIONS: ToolDefinition[];
@@ -962,4 +1135,51 @@ declare const TOOL_DEFINITIONS: ToolDefinition[];
962
1135
  */
963
1136
  declare function dispatchTool(client: ControlClient, name: string, args: Record<string, unknown>): Promise<ToolResult>;
964
1137
 
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 };
1138
+ /** Accumulated per-step results keyed by step id. */
1139
+ type JourneyState = Record<string, unknown>;
1140
+ /** One step in a journey: a tool call with a ViewSpec renderer. */
1141
+ interface JourneyStep {
1142
+ /** Unique identifier for this step within the plan. */
1143
+ id: string;
1144
+ /** MCP tool name to call (e.g. `toon_status`, `toon_publish_unsigned`). */
1145
+ toolName: string;
1146
+ /** Build the tool input from accumulated prior-step state. */
1147
+ buildInput: (state: JourneyState) => Record<string, unknown>;
1148
+ /** Render the step's result data as a ViewSpec panel. */
1149
+ renderPanel: (data: unknown) => ViewSpec;
1150
+ }
1151
+ /** Ordered sequence of steps with plan metadata. */
1152
+ interface JourneyPlan {
1153
+ id: string;
1154
+ title: string;
1155
+ steps: JourneyStep[];
1156
+ }
1157
+ /** Result for one executed step. */
1158
+ interface JourneyStepResult {
1159
+ stepId: string;
1160
+ /** Raw ToolResult from the tool call. */
1161
+ toolResult: ToolResult;
1162
+ /** ToolResult carrying the step's ViewSpec panel as structuredContent. */
1163
+ panel: ToolResult;
1164
+ }
1165
+ /** Final result of a runJourney call. */
1166
+ interface JourneyResult {
1167
+ /** True when all steps completed without error. */
1168
+ completed: boolean;
1169
+ /** Results for every step that ran (may be partial on error). */
1170
+ steps: JourneyStepResult[];
1171
+ /** Present when the run halted due to a tool error. */
1172
+ error?: {
1173
+ stepId: string;
1174
+ message: string;
1175
+ };
1176
+ }
1177
+
1178
+ /**
1179
+ * Run all steps in the plan sequentially against the given ControlClient.
1180
+ * Each step's result is threaded forward into the next step's buildInput via
1181
+ * JourneyState. Halts on the first tool error and returns a partial result.
1182
+ */
1183
+ declare function runJourney(plan: JourneyPlan, client: ControlClient): Promise<JourneyResult>;
1184
+
1185
+ 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 HttpFetchPaidRequest, type HttpFetchPaidResponse, type JourneyPlan, type JourneyResult, type JourneyState, type JourneyStep, type JourneyStepResult, type MinimalWebSocket, type NostrFilter, NotReadyError, type OpenChannelRequest, PublishRejectedError, type PublishRequest, type PublishResponse, type PublishUnsignedRequest, type QueryRequest, type QueryResponse, 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 UploadMediaRequest, type UploadMediaResponse, type WebSocketFactory, acquireLock, configDir, defaultConfigPath, defaultKeystorePath, dispatchTool, hasConfiguredIdentity, isDaemonRunning, isProcessAlive, readConfigFile, readPid, registerRoutes, releaseLock, resolveConfig, resolveMnemonic, runJourney, 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-3NAWISI5.js";
11
+ } from "./chunk-L6F2B3GX.js";
12
12
  import {
13
13
  TOOL_DEFINITIONS,
14
14
  dispatchTool
15
- } from "./chunk-ZQKYZJWT.js";
15
+ } from "./chunk-KNQ2DKNN.js";
16
16
  import {
17
17
  ControlApiError,
18
18
  ControlClient,
@@ -30,13 +30,48 @@ import {
30
30
  resolveMnemonic,
31
31
  spawnDaemonDetached,
32
32
  waitForReady
33
- } from "./chunk-5KFXUT5Q.js";
33
+ } from "./chunk-NP35YO5O.js";
34
34
  import "./chunk-32QD72IL.js";
35
- import "./chunk-FSS45ZX3.js";
35
+ import "./chunk-DLYE6U2Z.js";
36
36
  import "./chunk-LR7W2ISE.js";
37
37
  import "./chunk-VA7XC4FD.js";
38
38
  import "./chunk-SKQTKZIH.js";
39
39
  import "./chunk-F22GNSF6.js";
40
+
41
+ // src/journey/runner.ts
42
+ async function runJourney(plan, client) {
43
+ const state = {};
44
+ const completedSteps = [];
45
+ for (const step of plan.steps) {
46
+ const toolResult = await dispatchTool(client, step.toolName, step.buildInput(state));
47
+ if (toolResult.isError) {
48
+ return {
49
+ completed: false,
50
+ steps: completedSteps,
51
+ error: { stepId: step.id, message: toolResult.content[0]?.text ?? "Tool error" }
52
+ };
53
+ }
54
+ const data = extractData(toolResult);
55
+ state[step.id] = data;
56
+ const viewSpec = step.renderPanel(data);
57
+ const panel = {
58
+ content: [{ type: "text", text: `Journey step: ${step.id}` }],
59
+ structuredContent: { viewSpec }
60
+ };
61
+ completedSteps.push({ stepId: step.id, toolResult, panel });
62
+ }
63
+ return { completed: true, steps: completedSteps };
64
+ }
65
+ function extractData(result) {
66
+ if (result.structuredContent !== void 0) return result.structuredContent;
67
+ const text = result.content[0]?.text;
68
+ if (!text) return null;
69
+ try {
70
+ return JSON.parse(text);
71
+ } catch {
72
+ return text;
73
+ }
74
+ }
40
75
  export {
41
76
  ClientRunner,
42
77
  ControlApiError,
@@ -61,6 +96,7 @@ export {
61
96
  releaseLock,
62
97
  resolveConfig,
63
98
  resolveMnemonic,
99
+ runJourney,
64
100
  scaffoldFirstRun,
65
101
  spawnDaemonDetached,
66
102
  waitForReady
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
1
+ {"version":3,"sources":["../src/journey/runner.ts"],"sourcesContent":["import { dispatchTool, type ToolResult } from '../mcp-tools.js';\nimport type { ControlClient } from '../control-client.js';\nimport type { JourneyPlan, JourneyResult, JourneyState } from './types.js';\n\n/**\n * Run all steps in the plan sequentially against the given ControlClient.\n * Each step's result is threaded forward into the next step's buildInput via\n * JourneyState. Halts on the first tool error and returns a partial result.\n */\nexport async function runJourney(\n plan: JourneyPlan,\n client: ControlClient\n): Promise<JourneyResult> {\n const state: JourneyState = {};\n const completedSteps: JourneyResult['steps'] = [];\n\n for (const step of plan.steps) {\n const toolResult = await dispatchTool(client, step.toolName, step.buildInput(state));\n\n if (toolResult.isError) {\n return {\n completed: false,\n steps: completedSteps,\n error: { stepId: step.id, message: toolResult.content[0]?.text ?? 'Tool error' },\n };\n }\n\n const data = extractData(toolResult);\n state[step.id] = data;\n\n const viewSpec = step.renderPanel(data);\n const panel: ToolResult = {\n content: [{ type: 'text', text: `Journey step: ${step.id}` }],\n structuredContent: { viewSpec },\n };\n\n completedSteps.push({ stepId: step.id, toolResult, panel });\n }\n\n return { completed: true, steps: completedSteps };\n}\n\n/** Extract the data payload from a successful ToolResult for state threading. */\nfunction extractData(result: ToolResult): unknown {\n if (result.structuredContent !== undefined) return result.structuredContent;\n const text = result.content[0]?.text;\n if (!text) return null;\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AASA,eAAsB,WACpB,MACA,QACwB;AACxB,QAAM,QAAsB,CAAC;AAC7B,QAAM,iBAAyC,CAAC;AAEhD,aAAW,QAAQ,KAAK,OAAO;AAC7B,UAAM,aAAa,MAAM,aAAa,QAAQ,KAAK,UAAU,KAAK,WAAW,KAAK,CAAC;AAEnF,QAAI,WAAW,SAAS;AACtB,aAAO;AAAA,QACL,WAAW;AAAA,QACX,OAAO;AAAA,QACP,OAAO,EAAE,QAAQ,KAAK,IAAI,SAAS,WAAW,QAAQ,CAAC,GAAG,QAAQ,aAAa;AAAA,MACjF;AAAA,IACF;AAEA,UAAM,OAAO,YAAY,UAAU;AACnC,UAAM,KAAK,EAAE,IAAI;AAEjB,UAAM,WAAW,KAAK,YAAY,IAAI;AACtC,UAAM,QAAoB;AAAA,MACxB,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,iBAAiB,KAAK,EAAE,GAAG,CAAC;AAAA,MAC5D,mBAAmB,EAAE,SAAS;AAAA,IAChC;AAEA,mBAAe,KAAK,EAAE,QAAQ,KAAK,IAAI,YAAY,MAAM,CAAC;AAAA,EAC5D;AAEA,SAAO,EAAE,WAAW,MAAM,OAAO,eAAe;AAClD;AAGA,SAAS,YAAY,QAA6B;AAChD,MAAI,OAAO,sBAAsB,OAAW,QAAO,OAAO;AAC1D,QAAM,OAAO,OAAO,QAAQ,CAAC,GAAG;AAChC,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI;AACF,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
package/dist/mcp.js CHANGED
@@ -1,9 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire as __cr } from 'module'; const require = __cr(import.meta.url);
3
3
  import {
4
+ APP_RESOURCE_URI,
4
5
  TOOL_DEFINITIONS,
5
6
  dispatchTool
6
- } from "./chunk-ZQKYZJWT.js";
7
+ } from "./chunk-KNQ2DKNN.js";
7
8
  import {
8
9
  ControlClient,
9
10
  defaultConfigPath,
@@ -11,21 +12,40 @@ import {
11
12
  readConfigFile,
12
13
  spawnDaemonDetached,
13
14
  waitForReady
14
- } from "./chunk-5KFXUT5Q.js";
15
+ } from "./chunk-NP35YO5O.js";
15
16
  import "./chunk-32QD72IL.js";
16
- import "./chunk-FSS45ZX3.js";
17
+ import "./chunk-DLYE6U2Z.js";
17
18
  import "./chunk-LR7W2ISE.js";
18
19
  import "./chunk-VA7XC4FD.js";
19
20
  import "./chunk-SKQTKZIH.js";
20
21
  import "./chunk-F22GNSF6.js";
21
22
 
22
23
  // src/mcp.ts
24
+ import { createRequire } from "module";
25
+ import { readFileSync } from "fs";
26
+ import { dirname, join } from "path";
23
27
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
24
28
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
25
29
  import {
26
30
  CallToolRequestSchema,
27
- ListToolsRequestSchema
31
+ ListResourcesRequestSchema,
32
+ ListToolsRequestSchema,
33
+ ReadResourceRequestSchema
28
34
  } from "@modelcontextprotocol/sdk/types.js";
35
+ var APP_MIME = "text/html;profile=mcp-app";
36
+ function loadAppHtml() {
37
+ try {
38
+ return readFileSync(new URL("./app/index.html", import.meta.url), "utf8");
39
+ } catch {
40
+ }
41
+ try {
42
+ const req = createRequire(import.meta.url);
43
+ const entry = req.resolve("@toon-protocol/views");
44
+ return readFileSync(join(dirname(entry), "app", "index.html"), "utf8");
45
+ } catch {
46
+ return '<!doctype html><html><body><div id="root">toon app bundle missing \u2014 run `pnpm --filter @toon-protocol/views build`</div></body></html>';
47
+ }
48
+ }
29
49
  function log(msg) {
30
50
  console.error(`[toon-mcp] ${msg}`);
31
51
  }
@@ -59,11 +79,25 @@ async function main() {
59
79
  void ensureDaemon(url);
60
80
  const server = new Server(
61
81
  { name: "toon-client", version: "0.1.0" },
62
- { capabilities: { tools: {} } }
82
+ { capabilities: { tools: {}, resources: {} } }
63
83
  );
84
+ const appHtml = loadAppHtml();
64
85
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
65
86
  tools: TOOL_DEFINITIONS
66
87
  }));
88
+ server.setRequestHandler(ListResourcesRequestSchema, async () => ({
89
+ resources: [
90
+ { uri: APP_RESOURCE_URI, name: "TOON", mimeType: APP_MIME }
91
+ ]
92
+ }));
93
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
94
+ if (request.params.uri !== APP_RESOURCE_URI) {
95
+ throw new Error(`Unknown resource: ${request.params.uri}`);
96
+ }
97
+ return {
98
+ contents: [{ uri: APP_RESOURCE_URI, mimeType: APP_MIME, text: appHtml }]
99
+ };
100
+ });
67
101
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
68
102
  const name = request.params.name;
69
103
  const args = request.params.arguments ?? {};
package/dist/mcp.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/mcp.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `toon-mcp` — a thin MCP stdio server exposing the TOON client to a Claude\n * agent (Desktop or Code). It holds NO chain keys and NO long-lived\n * connections: every tool maps to an HTTP call against the always-on\n * `toon-clientd` daemon, which it auto-spawns (detached) if it is not running.\n *\n * Works on both surfaces:\n * • Claude Desktop — `claude_desktop_config.json` mcpServers entry.\n * • Claude Code — `claude mcp add toon -- toon-mcp` (or `.mcp.json`).\n */\n\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n type CallToolResult,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { ControlClient } from './control-client.js';\nimport { dispatchTool, TOOL_DEFINITIONS } from './mcp-tools.js';\nimport { defaultConfigPath, readConfigFile } from './daemon/config.js';\nimport {\n isDaemonRunning,\n spawnDaemonDetached,\n waitForReady,\n} from './daemon/lifecycle.js';\n\n/** stdout carries the MCP protocol — all logging must go to stderr. */\nfunction log(msg: string): void {\n console.error(`[toon-mcp] ${msg}`);\n}\n\n/** Resolve the daemon control-plane URL without needing the mnemonic. */\nfunction controlPlaneUrl(): string {\n const file = readConfigFile(\n process.env['TOON_CLIENT_CONFIG'] ?? defaultConfigPath()\n );\n const port = Number(\n process.env['TOON_CLIENT_HTTP_PORT'] ?? file.httpPort ?? 8787\n );\n return `http://127.0.0.1:${port}`;\n}\n\n/**\n * Make sure the daemon is up: if the lock shows it running, return; otherwise\n * spawn it detached and wait until the control plane is reachable. Best-effort\n * — failures surface as readable tool errors rather than crashing the server.\n */\nasync function ensureDaemon(url: string): Promise<void> {\n if (isDaemonRunning()) return;\n const client = new ControlClient({ baseUrl: url });\n if (await client.ping()) return;\n log('daemon not running — spawning detached');\n try {\n const pid = spawnDaemonDetached();\n log(`spawned toon-clientd (pid ${pid}); waiting for control plane`);\n await waitForReady(url, 20_000);\n } catch (err) {\n log(\n `failed to spawn daemon: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n}\n\nasync function main(): Promise<void> {\n const url = controlPlaneUrl();\n const control = new ControlClient({ baseUrl: url });\n\n // Kick off daemon startup; don't block server init on it (anon bootstrap is\n // slow). Tools report \"bootstrapping — retry\" until it is ready.\n void ensureDaemon(url);\n\n const server = new Server(\n { name: 'toon-client', version: '0.1.0' },\n { capabilities: { tools: {} } }\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: TOOL_DEFINITIONS,\n }));\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const name = request.params.name;\n const args = (request.params.arguments ?? {}) as Record<string, unknown>;\n // If the daemon went away, try once to bring it back before dispatching.\n if (!(await control.ping())) await ensureDaemon(url);\n // Our ToolResult is a structural subset of CallToolResult (content + isError);\n // the SDK's handler union also carries a task-augmented variant we never use.\n return (await dispatchTool(control, name, args)) as CallToolResult;\n });\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n log(`ready; proxying to ${url}`);\n}\n\nmain().catch((err) => {\n log(err instanceof Error ? (err.stack ?? err.message) : String(err));\n process.exitCode = 1;\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAYA,SAAS,cAAc;AACvB,SAAS,4BAA4B;AACrC;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AAWP,SAAS,IAAI,KAAmB;AAC9B,UAAQ,MAAM,cAAc,GAAG,EAAE;AACnC;AAGA,SAAS,kBAA0B;AACjC,QAAM,OAAO;AAAA,IACX,QAAQ,IAAI,oBAAoB,KAAK,kBAAkB;AAAA,EACzD;AACA,QAAM,OAAO;AAAA,IACX,QAAQ,IAAI,uBAAuB,KAAK,KAAK,YAAY;AAAA,EAC3D;AACA,SAAO,oBAAoB,IAAI;AACjC;AAOA,eAAe,aAAa,KAA4B;AACtD,MAAI,gBAAgB,EAAG;AACvB,QAAM,SAAS,IAAI,cAAc,EAAE,SAAS,IAAI,CAAC;AACjD,MAAI,MAAM,OAAO,KAAK,EAAG;AACzB,MAAI,6CAAwC;AAC5C,MAAI;AACF,UAAM,MAAM,oBAAoB;AAChC,QAAI,6BAA6B,GAAG,8BAA8B;AAClE,UAAM,aAAa,KAAK,GAAM;AAAA,EAChC,SAAS,KAAK;AACZ;AAAA,MACE,2BAA2B,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IAC7E;AAAA,EACF;AACF;AAEA,eAAe,OAAsB;AACnC,QAAM,MAAM,gBAAgB;AAC5B,QAAM,UAAU,IAAI,cAAc,EAAE,SAAS,IAAI,CAAC;AAIlD,OAAK,aAAa,GAAG;AAErB,QAAM,SAAS,IAAI;AAAA,IACjB,EAAE,MAAM,eAAe,SAAS,QAAQ;AAAA,IACxC,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,EAAE;AAAA,EAChC;AAEA,SAAO,kBAAkB,wBAAwB,aAAa;AAAA,IAC5D,OAAO;AAAA,EACT,EAAE;AAEF,SAAO,kBAAkB,uBAAuB,OAAO,YAAY;AACjE,UAAM,OAAO,QAAQ,OAAO;AAC5B,UAAM,OAAQ,QAAQ,OAAO,aAAa,CAAC;AAE3C,QAAI,CAAE,MAAM,QAAQ,KAAK,EAAI,OAAM,aAAa,GAAG;AAGnD,WAAQ,MAAM,aAAa,SAAS,MAAM,IAAI;AAAA,EAChD,CAAC;AAED,QAAM,YAAY,IAAI,qBAAqB;AAC3C,QAAM,OAAO,QAAQ,SAAS;AAC9B,MAAI,sBAAsB,GAAG,EAAE;AACjC;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,MAAI,eAAe,QAAS,IAAI,SAAS,IAAI,UAAW,OAAO,GAAG,CAAC;AACnE,UAAQ,WAAW;AACrB,CAAC;","names":[]}
1
+ {"version":3,"sources":["../src/mcp.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `toon-mcp` — a thin MCP stdio server exposing the TOON client to a Claude\n * agent (Desktop or Code). It holds NO chain keys and NO long-lived\n * connections: every tool maps to an HTTP call against the always-on\n * `toon-clientd` daemon, which it auto-spawns (detached) if it is not running.\n *\n * Works on both surfaces:\n * • Claude Desktop — `claude_desktop_config.json` mcpServers entry.\n * • Claude Code — `claude mcp add toon -- toon-mcp` (or `.mcp.json`).\n */\n\nimport { createRequire } from 'node:module';\nimport { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { Server } from '@modelcontextprotocol/sdk/server/index.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport {\n CallToolRequestSchema,\n ListResourcesRequestSchema,\n ListToolsRequestSchema,\n ReadResourceRequestSchema,\n type CallToolResult,\n} from '@modelcontextprotocol/sdk/types.js';\nimport { APP_RESOURCE_URI } from '@toon-protocol/views';\nimport { ControlClient } from './control-client.js';\nimport { dispatchTool, TOOL_DEFINITIONS } from './mcp-tools.js';\n\n/** MIME marking the bundle as an MCP-app UI resource (ext-apps profile). */\nconst APP_MIME = 'text/html;profile=mcp-app';\n\n/** Load the prebuilt single-file MCP-app bundle served as `ui://toon/app`. */\nfunction loadAppHtml(): string {\n // 1. Prefer the copy shipped next to the built server (tsup onSuccess copies\n // it into dist/app). This is what a published client-mcp serves — no\n // dependency on the unpublished @toon-protocol/views package at runtime.\n try {\n return readFileSync(new URL('./app/index.html', import.meta.url), 'utf8');\n } catch {\n /* running from source / not yet copied — fall through to the dev resolve */\n }\n // 2. Dev fallback: resolve the bundle from the @toon-protocol/views workspace.\n try {\n const req = createRequire(import.meta.url);\n const entry = req.resolve('@toon-protocol/views'); // …/views/dist/index.js\n return readFileSync(join(dirname(entry), 'app', 'index.html'), 'utf8');\n } catch {\n return '<!doctype html><html><body><div id=\"root\">toon app bundle missing — run `pnpm --filter @toon-protocol/views build`</div></body></html>';\n }\n}\nimport { defaultConfigPath, readConfigFile } from './daemon/config.js';\nimport {\n isDaemonRunning,\n spawnDaemonDetached,\n waitForReady,\n} from './daemon/lifecycle.js';\n\n/** stdout carries the MCP protocol — all logging must go to stderr. */\nfunction log(msg: string): void {\n console.error(`[toon-mcp] ${msg}`);\n}\n\n/** Resolve the daemon control-plane URL without needing the mnemonic. */\nfunction controlPlaneUrl(): string {\n const file = readConfigFile(\n process.env['TOON_CLIENT_CONFIG'] ?? defaultConfigPath()\n );\n const port = Number(\n process.env['TOON_CLIENT_HTTP_PORT'] ?? file.httpPort ?? 8787\n );\n return `http://127.0.0.1:${port}`;\n}\n\n/**\n * Make sure the daemon is up: if the lock shows it running, return; otherwise\n * spawn it detached and wait until the control plane is reachable. Best-effort\n * — failures surface as readable tool errors rather than crashing the server.\n */\nasync function ensureDaemon(url: string): Promise<void> {\n if (isDaemonRunning()) return;\n const client = new ControlClient({ baseUrl: url });\n if (await client.ping()) return;\n log('daemon not running — spawning detached');\n try {\n const pid = spawnDaemonDetached();\n log(`spawned toon-clientd (pid ${pid}); waiting for control plane`);\n await waitForReady(url, 20_000);\n } catch (err) {\n log(\n `failed to spawn daemon: ${err instanceof Error ? err.message : String(err)}`\n );\n }\n}\n\nasync function main(): Promise<void> {\n const url = controlPlaneUrl();\n const control = new ControlClient({ baseUrl: url });\n\n // Kick off daemon startup; don't block server init on it (anon bootstrap is\n // slow). Tools report \"bootstrapping — retry\" until it is ready.\n void ensureDaemon(url);\n\n const server = new Server(\n { name: 'toon-client', version: '0.1.0' },\n { capabilities: { tools: {}, resources: {} } }\n );\n\n const appHtml = loadAppHtml();\n\n server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: TOOL_DEFINITIONS,\n }));\n\n // The MCP-app UI resource the host renders for toon_render results.\n server.setRequestHandler(ListResourcesRequestSchema, async () => ({\n resources: [\n { uri: APP_RESOURCE_URI, name: 'TOON', mimeType: APP_MIME },\n ],\n }));\n\n server.setRequestHandler(ReadResourceRequestSchema, async (request) => {\n if (request.params.uri !== APP_RESOURCE_URI) {\n throw new Error(`Unknown resource: ${request.params.uri}`);\n }\n return {\n contents: [{ uri: APP_RESOURCE_URI, mimeType: APP_MIME, text: appHtml }],\n };\n });\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const name = request.params.name;\n const args = (request.params.arguments ?? {}) as Record<string, unknown>;\n // If the daemon went away, try once to bring it back before dispatching.\n if (!(await control.ping())) await ensureDaemon(url);\n // Our ToolResult is a structural subset of CallToolResult (content + isError);\n // the SDK's handler union also carries a task-augmented variant we never use.\n return (await dispatchTool(control, name, args)) as CallToolResult;\n });\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n log(`ready; proxying to ${url}`);\n}\n\nmain().catch((err) => {\n log(err instanceof Error ? (err.stack ?? err.message) : String(err));\n process.exitCode = 1;\n});\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@toon-protocol/client-mcp",
3
- "version": "0.1.0",
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.",
3
+ "version": "0.2.0",
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 swaps.",
5
5
  "license": "MIT",
6
6
  "author": "Jonathan Green",
7
7
  "type": "module",
@@ -46,7 +46,8 @@
46
46
  "tsup": "^8.0.0",
47
47
  "typescript": "^5.3.0",
48
48
  "vitest": "^1.0.0",
49
- "@toon-protocol/client": "0.9.2"
49
+ "@toon-protocol/client": "0.11.0",
50
+ "@toon-protocol/views": "0.1.0"
50
51
  },
51
52
  "engines": {
52
53
  "node": ">=20"