@toon-protocol/client-mcp 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +19 -38
  2. package/dist/app/index.html +166 -0
  3. package/dist/{chunk-5KFXUT5Q.js → chunk-CQ2QIZ6Z.js} +864 -604
  4. package/dist/chunk-CQ2QIZ6Z.js.map +1 -0
  5. package/dist/{chunk-FSS45ZX3.js → chunk-DLYE6U2Z.js} +1516 -316
  6. package/dist/chunk-DLYE6U2Z.js.map +1 -0
  7. package/dist/{chunk-3NAWISI5.js → chunk-QFHCXJ2V.js} +348 -101
  8. package/dist/chunk-QFHCXJ2V.js.map +1 -0
  9. package/dist/chunk-XV52IHVR.js +977 -0
  10. package/dist/chunk-XV52IHVR.js.map +1 -0
  11. package/dist/daemon.js +3 -4
  12. package/dist/daemon.js.map +1 -1
  13. package/dist/e2e/run-journey.d.ts +1 -0
  14. package/dist/e2e/run-journey.js +19953 -0
  15. package/dist/e2e/run-journey.js.map +1 -0
  16. package/dist/{ed25519-2QVPINLS.js → ed25519-2LFQXLYS.js} +6 -2
  17. package/dist/index.d.ts +282 -68
  18. package/dist/index.js +380 -5
  19. package/dist/index.js.map +1 -1
  20. package/dist/mcp.js +39 -6
  21. package/dist/mcp.js.map +1 -1
  22. package/package.json +11 -7
  23. package/dist/anon-proxy-W3KMM7GU-FN7ZJY7P.js +0 -25
  24. package/dist/chunk-3NAWISI5.js.map +0 -1
  25. package/dist/chunk-5KFXUT5Q.js.map +0 -1
  26. package/dist/chunk-FSS45ZX3.js.map +0 -1
  27. package/dist/chunk-SKQTKZIH.js +0 -278
  28. package/dist/chunk-SKQTKZIH.js.map +0 -1
  29. package/dist/chunk-ZQKYZJWT.js +0 -359
  30. package/dist/chunk-ZQKYZJWT.js.map +0 -1
  31. package/dist/ed25519-2QVPINLS.js.map +0 -1
  32. package/dist/gateway-QOK47RKS-SEGTXBR3.js +0 -16
  33. package/dist/gateway-QOK47RKS-SEGTXBR3.js.map +0 -1
  34. package/dist/socks5-WTJBYGME-6COK4LXW.js +0 -139
  35. package/dist/socks5-WTJBYGME-6COK4LXW.js.map +0 -1
  36. /package/dist/{anon-proxy-W3KMM7GU-FN7ZJY7P.js.map → ed25519-2LFQXLYS.js.map} +0 -0
package/dist/index.js CHANGED
@@ -8,11 +8,17 @@ import {
8
8
  hasConfiguredIdentity,
9
9
  registerRoutes,
10
10
  scaffoldFirstRun
11
- } from "./chunk-3NAWISI5.js";
11
+ } from "./chunk-QFHCXJ2V.js";
12
12
  import {
13
+ PUBLISH_TOOL,
13
14
  TOOL_DEFINITIONS,
15
+ UPLOAD_TOOL,
16
+ buildFeedFilter,
17
+ buildFileMetadataFilter,
18
+ buildFollowListFilter,
19
+ buildProfileFilter,
14
20
  dispatchTool
15
- } from "./chunk-ZQKYZJWT.js";
21
+ } from "./chunk-XV52IHVR.js";
16
22
  import {
17
23
  ControlApiError,
18
24
  ControlClient,
@@ -30,13 +36,381 @@ import {
30
36
  resolveMnemonic,
31
37
  spawnDaemonDetached,
32
38
  waitForReady
33
- } from "./chunk-5KFXUT5Q.js";
39
+ } from "./chunk-CQ2QIZ6Z.js";
34
40
  import "./chunk-32QD72IL.js";
35
- import "./chunk-FSS45ZX3.js";
41
+ import "./chunk-DLYE6U2Z.js";
36
42
  import "./chunk-LR7W2ISE.js";
37
43
  import "./chunk-VA7XC4FD.js";
38
- import "./chunk-SKQTKZIH.js";
39
44
  import "./chunk-F22GNSF6.js";
45
+
46
+ // src/journey/runner.ts
47
+ async function runJourney(plan, client) {
48
+ const state = {};
49
+ const completedSteps = [];
50
+ for (const step of plan.steps) {
51
+ const toolResult = await dispatchTool(client, step.toolName, step.buildInput(state));
52
+ if (toolResult.isError) {
53
+ return {
54
+ completed: false,
55
+ steps: completedSteps,
56
+ error: { stepId: step.id, message: toolResult.content[0]?.text ?? "Tool error" }
57
+ };
58
+ }
59
+ const data = extractData(toolResult);
60
+ state[step.id] = data;
61
+ const viewSpec = step.renderPanel(data, state);
62
+ const panel = {
63
+ content: [{ type: "text", text: `Journey step: ${step.id}` }],
64
+ structuredContent: { viewSpec }
65
+ };
66
+ completedSteps.push({ stepId: step.id, toolResult, panel });
67
+ }
68
+ return { completed: true, steps: completedSteps };
69
+ }
70
+ function extractData(result) {
71
+ if (result.structuredContent !== void 0) return result.structuredContent;
72
+ const text = result.content[0]?.text;
73
+ if (!text) return null;
74
+ try {
75
+ return JSON.parse(text);
76
+ } catch {
77
+ return text;
78
+ }
79
+ }
80
+
81
+ // src/journey/socialfi.ts
82
+ function pubkeyFromState(state, fallback) {
83
+ const onboard = state["onboard"];
84
+ return onboard?.identity?.nostrPubkey ?? fallback ?? "";
85
+ }
86
+ function socialFiJourney(opts) {
87
+ return {
88
+ id: "socialfi",
89
+ title: "SocialFi Journey",
90
+ steps: [
91
+ // ── Step 1: onboard ─────────────────────────────────────────────────────
92
+ {
93
+ id: "onboard",
94
+ toolName: "toon_status",
95
+ buildInput: () => ({}),
96
+ renderPanel: (data) => {
97
+ const s = data;
98
+ return {
99
+ title: "Onboard",
100
+ root: {
101
+ atom: "section",
102
+ props: { title: s?.ready ? "Ready to publish" : "Connecting\u2026" },
103
+ children: [{ atom: "card", children: [{ atom: "generic-event" }] }]
104
+ }
105
+ };
106
+ }
107
+ },
108
+ // ── Step 2: publish profile (kind:0) ────────────────────────────────────
109
+ {
110
+ id: "publish-profile",
111
+ toolName: "toon_publish_unsigned",
112
+ buildInput: () => ({
113
+ kind: 0,
114
+ content: JSON.stringify({ name: "TOON User", about: "Published via the SocialFi journey." })
115
+ }),
116
+ renderPanel: (_data, state) => ({
117
+ title: "Profile",
118
+ root: {
119
+ atom: "profile-header",
120
+ bind: { query: buildProfileFilter([pubkeyFromState(state, opts?.pubkey)]) }
121
+ }
122
+ })
123
+ },
124
+ // ── Step 3: publish note (kind:1) ───────────────────────────────────────
125
+ {
126
+ id: "publish-note",
127
+ toolName: "toon_publish_unsigned",
128
+ buildInput: () => ({
129
+ kind: 1,
130
+ content: "Hello from TOON Protocol!"
131
+ }),
132
+ renderPanel: (_data, state) => ({
133
+ title: "Note",
134
+ root: {
135
+ atom: "stack",
136
+ children: [
137
+ {
138
+ atom: "composer",
139
+ props: { placeholder: "What's happening?", label: "Post" },
140
+ actions: { post: { tool: PUBLISH_TOOL, args: { kind: 1 } } }
141
+ },
142
+ {
143
+ atom: "note-card",
144
+ bind: { query: buildFeedFilter([pubkeyFromState(state, opts?.pubkey)], 50), kindAuto: true }
145
+ }
146
+ ]
147
+ }
148
+ })
149
+ },
150
+ // ── Step 4: follow (kind:3) ─────────────────────────────────────────────
151
+ {
152
+ id: "follow",
153
+ toolName: "toon_publish_unsigned",
154
+ buildInput: (state) => {
155
+ const pubkey = pubkeyFromState(state, opts?.pubkey);
156
+ return { kind: 3, tags: [["p", pubkey]] };
157
+ },
158
+ renderPanel: (_data, state) => {
159
+ const pubkey = pubkeyFromState(state, opts?.pubkey);
160
+ return {
161
+ title: "Follow",
162
+ root: {
163
+ atom: "stack",
164
+ children: [
165
+ {
166
+ atom: "follow-button",
167
+ props: { label: "Follow" },
168
+ actions: { follow: { tool: PUBLISH_TOOL, args: { kind: 3, tags: [["p", pubkey]] } } }
169
+ },
170
+ {
171
+ atom: "note-card",
172
+ bind: { query: buildFollowListFilter(pubkey), kindAuto: true }
173
+ }
174
+ ]
175
+ }
176
+ };
177
+ }
178
+ },
179
+ // ── Step 5: DVM upload (kind:1063) + media-embed read-back ──────────────
180
+ // Use toon_status (read-only) for the auto-call; the actual upload is
181
+ // user-initiated via the panel's media-uploader action (spendy, confirmed).
182
+ {
183
+ id: "dvm-upload",
184
+ toolName: "toon_status",
185
+ buildInput: () => ({}),
186
+ renderPanel: (_data, state) => ({
187
+ title: "Media Upload",
188
+ root: {
189
+ atom: "stack",
190
+ children: [
191
+ {
192
+ atom: "media-uploader",
193
+ props: { label: "Upload media" },
194
+ actions: {
195
+ upload: {
196
+ tool: UPLOAD_TOOL,
197
+ args: { kind: 1063 },
198
+ spendy: true,
199
+ confirmLabel: "Upload to Arweave (spendy)"
200
+ }
201
+ }
202
+ },
203
+ {
204
+ atom: "media-embed",
205
+ bind: { query: buildFileMetadataFilter([pubkeyFromState(state, opts?.pubkey)], 30), kindAuto: true }
206
+ }
207
+ ]
208
+ }
209
+ })
210
+ }
211
+ ]
212
+ };
213
+ }
214
+
215
+ // src/journey/defi.ts
216
+ function deFiJourney(opts) {
217
+ let capturedSwap;
218
+ return {
219
+ id: "defi",
220
+ title: "DeFi Journey: Open Channel \u2192 Swap \u2192 Settlement Receipt",
221
+ steps: [
222
+ {
223
+ id: "open-channel",
224
+ toolName: "toon_open_channel",
225
+ buildInput: (_state) => ({ destination: opts.destination }),
226
+ renderPanel: (data) => {
227
+ const { channelId } = data;
228
+ return {
229
+ title: "Payment Channel",
230
+ root: {
231
+ atom: "stack",
232
+ children: [{ atom: "channel-card", props: { channelId } }]
233
+ }
234
+ };
235
+ }
236
+ },
237
+ {
238
+ id: "swap",
239
+ toolName: "toon_swap",
240
+ buildInput: (_state) => {
241
+ const args = {
242
+ destination: opts.destination,
243
+ amount: opts.amount,
244
+ millPubkey: opts.millPubkey,
245
+ pair: opts.pair,
246
+ chainRecipient: opts.chainRecipient
247
+ };
248
+ if (opts.packetCount !== void 0) {
249
+ args["packetCount"] = opts.packetCount;
250
+ }
251
+ return args;
252
+ },
253
+ renderPanel: (data) => {
254
+ capturedSwap = data;
255
+ return {
256
+ title: "Swap",
257
+ root: {
258
+ atom: "stack",
259
+ children: [
260
+ {
261
+ atom: "swap-form",
262
+ props: {
263
+ accepted: capturedSwap.accepted,
264
+ packetsAccepted: capturedSwap.packetsAccepted,
265
+ cumulativeSource: capturedSwap.cumulativeSource,
266
+ cumulativeTarget: capturedSwap.cumulativeTarget,
267
+ state: capturedSwap.state,
268
+ claims: capturedSwap.claims
269
+ }
270
+ }
271
+ ]
272
+ }
273
+ };
274
+ }
275
+ },
276
+ {
277
+ id: "settlement-receipt",
278
+ toolName: "toon_channels",
279
+ buildInput: (_state) => ({}),
280
+ renderPanel: (data) => {
281
+ const { channels } = data;
282
+ const swap = capturedSwap;
283
+ return {
284
+ title: "Settlement Receipt",
285
+ root: {
286
+ atom: "stack",
287
+ children: [
288
+ {
289
+ atom: "settlement-receipt",
290
+ props: {
291
+ accepted: swap?.accepted,
292
+ cumulativeSource: swap?.cumulativeSource,
293
+ cumulativeTarget: swap?.cumulativeTarget,
294
+ claims: swap?.claims ?? [],
295
+ channels
296
+ }
297
+ }
298
+ ]
299
+ }
300
+ };
301
+ }
302
+ }
303
+ ]
304
+ };
305
+ }
306
+
307
+ // src/journey/demo.ts
308
+ function chainJourneys(id, title, ...plans) {
309
+ const steps = plans.flatMap((p) => p.steps);
310
+ const seen = /* @__PURE__ */ new Set();
311
+ for (const step of steps) {
312
+ if (seen.has(step.id)) {
313
+ throw new Error(
314
+ `chainJourneys: duplicate step id "${step.id}" across chained plans \u2014 state threading requires unique step ids`
315
+ );
316
+ }
317
+ seen.add(step.id);
318
+ }
319
+ return { id, title, steps };
320
+ }
321
+ function capstoneJourney(opts) {
322
+ return chainJourneys(
323
+ "capstone",
324
+ "Capstone Journey: SocialFi \u2192 DeFi",
325
+ socialFiJourney(opts.socialFi),
326
+ deFiJourney(opts.deFi)
327
+ );
328
+ }
329
+ function extractReceipt(result) {
330
+ const swapStep = result.steps.find((s) => s.stepId === "swap");
331
+ const channelsStep = result.steps.find((s) => s.stepId === "settlement-receipt");
332
+ if (!swapStep || !channelsStep) return void 0;
333
+ const swap = parseToolText(swapStep.toolResult.content[0]?.text);
334
+ const channelsRes = parseToolText(
335
+ channelsStep.toolResult.content[0]?.text
336
+ );
337
+ if (!swap || !channelsRes) return void 0;
338
+ return {
339
+ accepted: swap.accepted,
340
+ state: swap.state,
341
+ cumulativeSource: swap.cumulativeSource,
342
+ cumulativeTarget: swap.cumulativeTarget,
343
+ claims: swap.claims ?? [],
344
+ channels: channelsRes.channels
345
+ };
346
+ }
347
+ function parseToolText(text) {
348
+ if (!text) return void 0;
349
+ try {
350
+ return JSON.parse(text);
351
+ } catch {
352
+ return void 0;
353
+ }
354
+ }
355
+ async function runCapstoneDemo(client, opts, logger = console) {
356
+ const plan = capstoneJourney(opts);
357
+ logger.log(`
358
+ === ${plan.title} (${plan.steps.length} steps) ===
359
+ `);
360
+ const result = await runJourney(plan, client);
361
+ for (const step of result.steps) {
362
+ const viewSpec = step.panel.structuredContent?.["viewSpec"];
363
+ logger.log(`--- panel: ${step.stepId} ---`);
364
+ logger.log(JSON.stringify(viewSpec, null, 2));
365
+ }
366
+ if (!result.completed) {
367
+ logger.error(
368
+ `
369
+ [capstone] FAILED at step "${result.error?.stepId}": ${result.error?.message}`
370
+ );
371
+ return 1;
372
+ }
373
+ const receipt = extractReceipt(result);
374
+ logger.log("\n=== Settlement Receipt ===");
375
+ logger.log(JSON.stringify(receipt, null, 2));
376
+ logger.log(`
377
+ [capstone] completed all ${result.steps.length} steps.`);
378
+ return 0;
379
+ }
380
+ async function main(env = process.env) {
381
+ const baseUrl = env["TOON_DAEMON_URL"] ?? "http://127.0.0.1:8787";
382
+ const destination = env["TOON_SWAP_DEST"];
383
+ const amount = env["TOON_SWAP_AMOUNT"];
384
+ const millPubkey = env["TOON_MILL_PUBKEY"];
385
+ const chainRecipient = env["TOON_CHAIN_RECIPIENT"];
386
+ const pairRaw = env["TOON_SWAP_PAIR"];
387
+ if (!destination || !amount || !millPubkey || !chainRecipient || !pairRaw) {
388
+ console.error(
389
+ "[capstone] missing required env: TOON_SWAP_DEST, TOON_SWAP_AMOUNT, TOON_MILL_PUBKEY, TOON_CHAIN_RECIPIENT, TOON_SWAP_PAIR are all required for the live DeFi leg. See the module header for the full env contract."
390
+ );
391
+ return 2;
392
+ }
393
+ let pair;
394
+ try {
395
+ pair = JSON.parse(pairRaw);
396
+ } catch (e) {
397
+ console.error(`[capstone] TOON_SWAP_PAIR is not valid JSON: ${String(e)}`);
398
+ return 2;
399
+ }
400
+ const client = new ControlClient({ baseUrl });
401
+ const socialFiPubkey = env["TOON_SOCIALFI_PUBKEY"];
402
+ return runCapstoneDemo(client, {
403
+ ...socialFiPubkey ? { socialFi: { pubkey: socialFiPubkey } } : {},
404
+ deFi: { destination, amount, millPubkey, chainRecipient, pair }
405
+ });
406
+ }
407
+ var invokedDirectly = typeof process !== "undefined" && Array.isArray(process.argv) && /[/\\]journey[/\\]demo\.(ts|js|mjs)$/.test(process.argv[1] ?? "");
408
+ if (invokedDirectly) {
409
+ main().then((code) => process.exit(code)).catch((err) => {
410
+ console.error("[capstone] fatal:", err instanceof Error ? err.message : err);
411
+ process.exit(1);
412
+ });
413
+ }
40
414
  export {
41
415
  ClientRunner,
42
416
  ControlApiError,
@@ -61,6 +435,7 @@ export {
61
435
  releaseLock,
62
436
  resolveConfig,
63
437
  resolveMnemonic,
438
+ runJourney,
64
439
  scaffoldFirstRun,
65
440
  spawnDaemonDetached,
66
441
  waitForReady
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
1
+ {"version":3,"sources":["../src/journey/runner.ts","../src/journey/socialfi.ts","../src/journey/defi.ts","../src/journey/demo.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, state);\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","import {\n buildProfileFilter,\n buildFeedFilter,\n buildFollowListFilter,\n buildFileMetadataFilter,\n PUBLISH_TOOL,\n UPLOAD_TOOL,\n} from '@toon-protocol/views';\nimport type { JourneyPlan, JourneyState } from './types.js';\n\nfunction pubkeyFromState(state: JourneyState, fallback?: string): string {\n const onboard = state['onboard'] as { identity?: { nostrPubkey?: string } } | undefined;\n return onboard?.identity?.nostrPubkey ?? fallback ?? '';\n}\n\n/**\n * The canonical five-step SocialFi journey:\n * onboard → publish profile (kind:0) → publish note (kind:1) → follow (kind:3)\n * → DVM media upload (kind:1063) with media-embed read-back.\n *\n * Pass `opts.pubkey` to seed the panel bind-queries with the user's pubkey\n * without waiting for the onboard step to surface it; the follow step's\n * buildInput also reads it from `state['onboard'].identity.nostrPubkey` so\n * the correct pubkey is used in the kind:3 tags even when opts is omitted.\n */\nexport function socialFiJourney(opts?: { pubkey?: string }): JourneyPlan {\n return {\n id: 'socialfi',\n title: 'SocialFi Journey',\n steps: [\n // ── Step 1: onboard ─────────────────────────────────────────────────────\n {\n id: 'onboard',\n toolName: 'toon_status',\n buildInput: () => ({}),\n renderPanel: (data) => {\n const s = data as { ready?: boolean } | undefined;\n return {\n title: 'Onboard',\n root: {\n atom: 'section',\n props: { title: s?.ready ? 'Ready to publish' : 'Connecting…' },\n children: [{ atom: 'card', children: [{ atom: 'generic-event' }] }],\n },\n };\n },\n },\n\n // ── Step 2: publish profile (kind:0) ────────────────────────────────────\n {\n id: 'publish-profile',\n toolName: 'toon_publish_unsigned',\n buildInput: () => ({\n kind: 0,\n content: JSON.stringify({ name: 'TOON User', about: 'Published via the SocialFi journey.' }),\n }),\n renderPanel: (_data, state) => ({\n title: 'Profile',\n root: {\n atom: 'profile-header',\n bind: { query: buildProfileFilter([pubkeyFromState(state, opts?.pubkey)]) },\n },\n }),\n },\n\n // ── Step 3: publish note (kind:1) ───────────────────────────────────────\n {\n id: 'publish-note',\n toolName: 'toon_publish_unsigned',\n buildInput: () => ({\n kind: 1,\n content: 'Hello from TOON Protocol!',\n }),\n renderPanel: (_data, state) => ({\n title: 'Note',\n root: {\n atom: 'stack',\n children: [\n {\n atom: 'composer',\n props: { placeholder: \"What's happening?\", label: 'Post' },\n actions: { post: { tool: PUBLISH_TOOL, args: { kind: 1 } } },\n },\n {\n atom: 'note-card',\n bind: { query: buildFeedFilter([pubkeyFromState(state, opts?.pubkey)], 50), kindAuto: true },\n },\n ],\n },\n }),\n },\n\n // ── Step 4: follow (kind:3) ─────────────────────────────────────────────\n {\n id: 'follow',\n toolName: 'toon_publish_unsigned',\n buildInput: (state: JourneyState) => {\n const pubkey = pubkeyFromState(state, opts?.pubkey);\n return { kind: 3, tags: [['p', pubkey]] };\n },\n renderPanel: (_data, state) => {\n const pubkey = pubkeyFromState(state, opts?.pubkey);\n return {\n title: 'Follow',\n root: {\n atom: 'stack',\n children: [\n {\n atom: 'follow-button',\n props: { label: 'Follow' },\n actions: { follow: { tool: PUBLISH_TOOL, args: { kind: 3, tags: [['p', pubkey]] } } },\n },\n {\n atom: 'note-card',\n bind: { query: buildFollowListFilter(pubkey), kindAuto: true },\n },\n ],\n },\n };\n },\n },\n\n // ── Step 5: DVM upload (kind:1063) + media-embed read-back ──────────────\n // Use toon_status (read-only) for the auto-call; the actual upload is\n // user-initiated via the panel's media-uploader action (spendy, confirmed).\n {\n id: 'dvm-upload',\n toolName: 'toon_status',\n buildInput: () => ({}),\n renderPanel: (_data, state) => ({\n title: 'Media Upload',\n root: {\n atom: 'stack',\n children: [\n {\n atom: 'media-uploader',\n props: { label: 'Upload media' },\n actions: {\n upload: {\n tool: UPLOAD_TOOL,\n args: { kind: 1063 },\n spendy: true,\n confirmLabel: 'Upload to Arweave (spendy)',\n },\n },\n },\n {\n atom: 'media-embed',\n bind: { query: buildFileMetadataFilter([pubkeyFromState(state, opts?.pubkey)], 30), kindAuto: true },\n },\n ],\n },\n }),\n },\n ],\n };\n}\n","import type { ViewSpec } from '@toon-protocol/views';\nimport type { ChannelsResponse, SwapRequest, SwapResponse } from '../control-api.js';\nimport type { JourneyPlan } from './types.js';\n\nexport interface DeFiJourneyOpts {\n /** ILP destination used for both channel open and the swap (e.g. mill peer). */\n destination: string;\n /** Total source-asset amount to swap, in source micro-units. */\n amount: string;\n /** Mill's 64-char lowercase hex Nostr pubkey (gift-wrap recipient). */\n millPubkey: string;\n /** Swap pair from kind:10032 discovery or operator-supplied. */\n pair: SwapRequest['pair'];\n /** Sender's payout address on the target chain. */\n chainRecipient: string;\n /** Split the swap into N equal packets (default 1). */\n packetCount?: number;\n}\n\n/**\n * DeFi journey: pre-open payment channel → tiny testnet swap → settlement receipt.\n *\n * Step 3's settlement-receipt panel is built by joining the swap result\n * (captured from step 2's renderPanel via closure) with the toon_channels\n * watermark — no non-existent toon_settle tool is involved.\n */\nexport function deFiJourney(opts: DeFiJourneyOpts): JourneyPlan {\n let capturedSwap: SwapResponse | undefined;\n\n return {\n id: 'defi',\n title: 'DeFi Journey: Open Channel → Swap → Settlement Receipt',\n steps: [\n {\n id: 'open-channel',\n toolName: 'toon_open_channel',\n buildInput: (_state) => ({ destination: opts.destination }),\n renderPanel: (data): ViewSpec => {\n const { channelId } = data as { channelId: string };\n return {\n title: 'Payment Channel',\n root: {\n atom: 'stack',\n children: [{ atom: 'channel-card', props: { channelId } }],\n },\n };\n },\n },\n {\n id: 'swap',\n toolName: 'toon_swap',\n buildInput: (_state): Record<string, unknown> => {\n const args: Record<string, unknown> = {\n destination: opts.destination,\n amount: opts.amount,\n millPubkey: opts.millPubkey,\n pair: opts.pair,\n chainRecipient: opts.chainRecipient,\n };\n if (opts.packetCount !== undefined) {\n args['packetCount'] = opts.packetCount;\n }\n return args;\n },\n renderPanel: (data): ViewSpec => {\n capturedSwap = data as SwapResponse;\n return {\n title: 'Swap',\n root: {\n atom: 'stack',\n children: [\n {\n atom: 'swap-form',\n props: {\n accepted: capturedSwap.accepted,\n packetsAccepted: capturedSwap.packetsAccepted,\n cumulativeSource: capturedSwap.cumulativeSource,\n cumulativeTarget: capturedSwap.cumulativeTarget,\n state: capturedSwap.state,\n claims: capturedSwap.claims,\n },\n },\n ],\n },\n };\n },\n },\n {\n id: 'settlement-receipt',\n toolName: 'toon_channels',\n buildInput: (_state) => ({}),\n renderPanel: (data): ViewSpec => {\n const { channels } = data as ChannelsResponse;\n const swap = capturedSwap;\n return {\n title: 'Settlement Receipt',\n root: {\n atom: 'stack',\n children: [\n {\n atom: 'settlement-receipt',\n props: {\n accepted: swap?.accepted,\n cumulativeSource: swap?.cumulativeSource,\n cumulativeTarget: swap?.cumulativeTarget,\n claims: swap?.claims ?? [],\n channels,\n },\n },\n ],\n },\n };\n },\n },\n ],\n };\n}\n","/**\n * Capstone journey demo (#25): chain the merged SocialFi and DeFi journeys into\n * one ordered plan, run it against a `toon-clientd` daemon, print each step's\n * ViewSpec panel, and print the settlement receipt sourced from the `swap`\n * response joined with the `channels()` watermark.\n *\n * There is intentionally NO `settle()`/`toon_settle` step: the receipt is the\n * swap result (cumulative source/target + signed claims) reconciled against the\n * channel nonce watermark, exactly as `deFiJourney`'s `settlement-receipt` panel\n * already does. This module just chains the two existing journeys and renders\n * their output to stdout for the demo.\n *\n * Run from source (root devDep `tsx`):\n * pnpm --filter @toon-protocol/client-mcp demo:journey\n * or against a built dist:\n * node dist/journey/demo.js\n *\n * The daemon must already be running (toon-clientd). Live config + funding is a\n * human prerequisite (Base Sepolia treasury) and is OUT OF SCOPE for CI; the\n * dry-run unit test (`demo.test.ts`) covers the orchestration with a mocked\n * ControlClient and no network/funds.\n */\n\nimport type { ChannelsResponse, SwapResponse } from '../control-api.js';\nimport { ControlClient } from '../control-client.js';\nimport { runJourney } from './runner.js';\nimport { socialFiJourney } from './socialfi.js';\nimport { deFiJourney, type DeFiJourneyOpts } from './defi.js';\nimport type { JourneyPlan, JourneyResult } from './types.js';\n\n/**\n * Concatenate several journey plans into one ordered plan. Step ids are\n * namespaced with the source plan id (`<planId>:<stepId>`) so the combined\n * `JourneyState` keys never collide when two legs reuse a step id.\n *\n * Note: each leg's `buildInput`/`renderPanel` reads its OWN step ids out of\n * `JourneyState`, so re-keying here would break that threading. We therefore\n * keep the original step ids on the steps themselves and only namespace the\n * combined plan's *reported* ids via a wrapper is unnecessary because the two\n * legs (`socialfi`, `defi`) share no step ids. We assert that invariant.\n */\nexport function chainJourneys(\n id: string,\n title: string,\n ...plans: JourneyPlan[]\n): JourneyPlan {\n const steps = plans.flatMap((p) => p.steps);\n const seen = new Set<string>();\n for (const step of steps) {\n if (seen.has(step.id)) {\n throw new Error(\n `chainJourneys: duplicate step id \"${step.id}\" across chained plans — ` +\n `state threading requires unique step ids`\n );\n }\n seen.add(step.id);\n }\n return { id, title, steps };\n}\n\n/** Build the capstone SocialFi → DeFi plan. */\nexport function capstoneJourney(opts: {\n socialFi?: { pubkey?: string };\n deFi: DeFiJourneyOpts;\n}): JourneyPlan {\n return chainJourneys(\n 'capstone',\n 'Capstone Journey: SocialFi → DeFi',\n socialFiJourney(opts.socialFi),\n deFiJourney(opts.deFi)\n );\n}\n\n/** The settlement receipt, derived from the swap response + channel watermark. */\nexport interface SettlementReceipt {\n accepted: boolean;\n state: SwapResponse['state'];\n cumulativeSource: string;\n cumulativeTarget: string;\n claims: SwapResponse['claims'];\n channels: ChannelsResponse['channels'];\n}\n\n/**\n * Reconstruct the settlement receipt from a completed journey result. Sources\n * the swap payload from the `swap` step's raw ToolResult and the channel\n * watermark from the `settlement-receipt` step's raw ToolResult. Returns\n * undefined if either step is missing (e.g. the run halted before DeFi).\n */\nexport function extractReceipt(result: JourneyResult): SettlementReceipt | undefined {\n const swapStep = result.steps.find((s) => s.stepId === 'swap');\n const channelsStep = result.steps.find((s) => s.stepId === 'settlement-receipt');\n if (!swapStep || !channelsStep) return undefined;\n\n const swap = parseToolText<SwapResponse>(swapStep.toolResult.content[0]?.text);\n const channelsRes = parseToolText<ChannelsResponse>(\n channelsStep.toolResult.content[0]?.text\n );\n if (!swap || !channelsRes) return undefined;\n\n return {\n accepted: swap.accepted,\n state: swap.state,\n cumulativeSource: swap.cumulativeSource,\n cumulativeTarget: swap.cumulativeTarget,\n claims: swap.claims ?? [],\n channels: channelsRes.channels,\n };\n}\n\nfunction parseToolText<T>(text: string | undefined): T | undefined {\n if (!text) return undefined;\n try {\n return JSON.parse(text) as T;\n } catch {\n return undefined;\n }\n}\n\n/** Minimal console surface so the runner is testable with a captured logger. */\nexport interface DemoLogger {\n log: (msg: string) => void;\n error: (msg: string) => void;\n}\n\n/**\n * Run the capstone journey against a ControlClient, printing each step's panel\n * JSON and the final settlement receipt. Returns the process exit code: 0 on a\n * fully-completed journey, 1 if any step errored. Does no network I/O itself —\n * the ControlClient does. No funds move in the dry-run test (mocked client).\n */\nexport async function runCapstoneDemo(\n client: ControlClient,\n opts: { socialFi?: { pubkey?: string }; deFi: DeFiJourneyOpts },\n logger: DemoLogger = console\n): Promise<number> {\n const plan = capstoneJourney(opts);\n logger.log(`\\n=== ${plan.title} (${plan.steps.length} steps) ===\\n`);\n\n const result = await runJourney(plan, client);\n\n for (const step of result.steps) {\n const viewSpec = step.panel.structuredContent?.['viewSpec'];\n logger.log(`--- panel: ${step.stepId} ---`);\n logger.log(JSON.stringify(viewSpec, null, 2));\n }\n\n if (!result.completed) {\n logger.error(\n `\\n[capstone] FAILED at step \"${result.error?.stepId}\": ${result.error?.message}`\n );\n return 1;\n }\n\n const receipt = extractReceipt(result);\n logger.log('\\n=== Settlement Receipt ===');\n logger.log(JSON.stringify(receipt, null, 2));\n logger.log(`\\n[capstone] completed all ${result.steps.length} steps.`);\n return 0;\n}\n\n/**\n * CLI entry. Reads connection + DeFi opts from env and runs the demo against a\n * live daemon. See module header for the live-run prerequisites.\n *\n * Env:\n * TOON_DAEMON_URL daemon control-plane base URL (default http://127.0.0.1:8787)\n * TOON_SWAP_DEST mill ILP destination (e.g. g.townhouse.mill)\n * TOON_SWAP_AMOUNT source-asset amount, micro-units (e.g. 1000000)\n * TOON_MILL_PUBKEY mill 64-char hex Nostr pubkey\n * TOON_CHAIN_RECIPIENT payout address on the target chain\n * TOON_SWAP_PAIR JSON SwapPair ({ from, to, rate, ... })\n * TOON_SOCIALFI_PUBKEY optional: seed panel bind-queries before onboard surfaces it\n */\nexport async function main(env: NodeJS.ProcessEnv = process.env): Promise<number> {\n const baseUrl = env['TOON_DAEMON_URL'] ?? 'http://127.0.0.1:8787';\n\n const destination = env['TOON_SWAP_DEST'];\n const amount = env['TOON_SWAP_AMOUNT'];\n const millPubkey = env['TOON_MILL_PUBKEY'];\n const chainRecipient = env['TOON_CHAIN_RECIPIENT'];\n const pairRaw = env['TOON_SWAP_PAIR'];\n\n if (!destination || !amount || !millPubkey || !chainRecipient || !pairRaw) {\n console.error(\n '[capstone] missing required env: TOON_SWAP_DEST, TOON_SWAP_AMOUNT, ' +\n 'TOON_MILL_PUBKEY, TOON_CHAIN_RECIPIENT, TOON_SWAP_PAIR are all required ' +\n 'for the live DeFi leg. See the module header for the full env contract.'\n );\n return 2;\n }\n\n let pair: DeFiJourneyOpts['pair'];\n try {\n pair = JSON.parse(pairRaw) as DeFiJourneyOpts['pair'];\n } catch (e) {\n console.error(`[capstone] TOON_SWAP_PAIR is not valid JSON: ${String(e)}`);\n return 2;\n }\n\n const client = new ControlClient({ baseUrl });\n const socialFiPubkey = env['TOON_SOCIALFI_PUBKEY'];\n\n return runCapstoneDemo(client, {\n ...(socialFiPubkey ? { socialFi: { pubkey: socialFiPubkey } } : {}),\n deFi: { destination, amount, millPubkey, chainRecipient, pair },\n });\n}\n\n// Run when invoked directly (tsx src/journey/demo.ts or node dist/journey/demo.js).\nconst invokedDirectly =\n typeof process !== 'undefined' &&\n Array.isArray(process.argv) &&\n /[/\\\\]journey[/\\\\]demo\\.(ts|js|mjs)$/.test(process.argv[1] ?? '');\n\nif (invokedDirectly) {\n main()\n .then((code) => process.exit(code))\n .catch((err) => {\n console.error('[capstone] fatal:', err instanceof Error ? err.message : err);\n process.exit(1);\n });\n}\n"],"mappings":"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","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-XV52IHVR.js";
7
8
  import {
8
9
  ControlClient,
9
10
  defaultConfigPath,
@@ -11,21 +12,39 @@ import {
11
12
  readConfigFile,
12
13
  spawnDaemonDetached,
13
14
  waitForReady
14
- } from "./chunk-5KFXUT5Q.js";
15
+ } from "./chunk-CQ2QIZ6Z.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
- import "./chunk-SKQTKZIH.js";
20
20
  import "./chunk-F22GNSF6.js";
21
21
 
22
22
  // src/mcp.ts
23
+ import { createRequire } from "module";
24
+ import { readFileSync } from "fs";
25
+ import { dirname, join } from "path";
23
26
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
24
27
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
25
28
  import {
26
29
  CallToolRequestSchema,
27
- ListToolsRequestSchema
30
+ ListResourcesRequestSchema,
31
+ ListToolsRequestSchema,
32
+ ReadResourceRequestSchema
28
33
  } from "@modelcontextprotocol/sdk/types.js";
34
+ var APP_MIME = "text/html;profile=mcp-app";
35
+ function loadAppHtml() {
36
+ try {
37
+ return readFileSync(new URL("./app/index.html", import.meta.url), "utf8");
38
+ } catch {
39
+ }
40
+ try {
41
+ const req = createRequire(import.meta.url);
42
+ const entry = req.resolve("@toon-protocol/views");
43
+ return readFileSync(join(dirname(entry), "app", "index.html"), "utf8");
44
+ } catch {
45
+ return '<!doctype html><html><body><div id="root">toon app bundle missing \u2014 run `pnpm --filter @toon-protocol/views build`</div></body></html>';
46
+ }
47
+ }
29
48
  function log(msg) {
30
49
  console.error(`[toon-mcp] ${msg}`);
31
50
  }
@@ -59,11 +78,25 @@ async function main() {
59
78
  void ensureDaemon(url);
60
79
  const server = new Server(
61
80
  { name: "toon-client", version: "0.1.0" },
62
- { capabilities: { tools: {} } }
81
+ { capabilities: { tools: {}, resources: {} } }
63
82
  );
83
+ const appHtml = loadAppHtml();
64
84
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
65
85
  tools: TOOL_DEFINITIONS
66
86
  }));
87
+ server.setRequestHandler(ListResourcesRequestSchema, async () => ({
88
+ resources: [
89
+ { uri: APP_RESOURCE_URI, name: "TOON", mimeType: APP_MIME }
90
+ ]
91
+ }));
92
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
93
+ if (request.params.uri !== APP_RESOURCE_URI) {
94
+ throw new Error(`Unknown resource: ${request.params.uri}`);
95
+ }
96
+ return {
97
+ contents: [{ uri: APP_RESOURCE_URI, mimeType: APP_MIME, text: appHtml }]
98
+ };
99
+ });
67
100
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
68
101
  const name = request.params.name;
69
102
  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 (BTP bootstrap can\n // take a moment). 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":";;;;;;;;;;;;;;;;;;;;;;AAYA,SAAS,qBAAqB;AAC9B,SAAS,oBAAoB;AAC7B,SAAS,SAAS,YAAY;AAC9B,SAAS,cAAc;AACvB,SAAS,4BAA4B;AACrC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAMP,IAAM,WAAW;AAGjB,SAAS,cAAsB;AAI7B,MAAI;AACF,WAAO,aAAa,IAAI,IAAI,oBAAoB,YAAY,GAAG,GAAG,MAAM;AAAA,EAC1E,QAAQ;AAAA,EAER;AAEA,MAAI;AACF,UAAM,MAAM,cAAc,YAAY,GAAG;AACzC,UAAM,QAAQ,IAAI,QAAQ,sBAAsB;AAChD,WAAO,aAAa,KAAK,QAAQ,KAAK,GAAG,OAAO,YAAY,GAAG,MAAM;AAAA,EACvE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AASA,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,GAAG,WAAW,CAAC,EAAE,EAAE;AAAA,EAC/C;AAEA,QAAM,UAAU,YAAY;AAE5B,SAAO,kBAAkB,wBAAwB,aAAa;AAAA,IAC5D,OAAO;AAAA,EACT,EAAE;AAGF,SAAO,kBAAkB,4BAA4B,aAAa;AAAA,IAChE,WAAW;AAAA,MACT,EAAE,KAAK,kBAAkB,MAAM,QAAQ,UAAU,SAAS;AAAA,IAC5D;AAAA,EACF,EAAE;AAEF,SAAO,kBAAkB,2BAA2B,OAAO,YAAY;AACrE,QAAI,QAAQ,OAAO,QAAQ,kBAAkB;AAC3C,YAAM,IAAI,MAAM,qBAAqB,QAAQ,OAAO,GAAG,EAAE;AAAA,IAC3D;AACA,WAAO;AAAA,MACL,UAAU,CAAC,EAAE,KAAK,kBAAkB,UAAU,UAAU,MAAM,QAAQ,CAAC;AAAA,IACzE;AAAA,EACF,CAAC;AAED,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":[]}
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.3.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",
@@ -9,7 +9,8 @@
9
9
  "types": "./dist/index.d.ts",
10
10
  "bin": {
11
11
  "toon-clientd": "./dist/daemon.js",
12
- "toon-mcp": "./dist/mcp.js"
12
+ "toon-mcp": "./dist/mcp.js",
13
+ "toon-journey": "./dist/e2e/run-journey.js"
13
14
  },
14
15
  "files": [
15
16
  "dist",
@@ -35,18 +36,20 @@
35
36
  "optionalDependencies": {
36
37
  "@solana/web3.js": "^1.90.0",
37
38
  "mina-signer": "^3.0.0",
38
- "o1js": "2.14.0",
39
- "socks-proxy-agent": "^8.0.5"
39
+ "o1js": "2.14.0"
40
40
  },
41
41
  "devDependencies": {
42
+ "@anthropic-ai/claude-agent-sdk": "0.3.186",
42
43
  "@toon-protocol/core": "^1.4.1",
43
44
  "@toon-protocol/sdk": "^0.5.0",
44
45
  "@types/node": "^20.0.0",
45
46
  "@types/ws": "^8.5.10",
46
47
  "tsup": "^8.0.0",
48
+ "tsx": "^4.19.2",
47
49
  "typescript": "^5.3.0",
48
50
  "vitest": "^1.0.0",
49
- "@toon-protocol/client": "0.9.2"
51
+ "@toon-protocol/client": "0.12.0",
52
+ "@toon-protocol/views": "0.1.0"
50
53
  },
51
54
  "engines": {
52
55
  "node": ">=20"
@@ -55,6 +58,7 @@
55
58
  "build": "tsup",
56
59
  "test": "vitest run",
57
60
  "test:integration": "vitest run --config vitest.integration.config.ts",
58
- "test:coverage": "vitest run --coverage"
61
+ "test:coverage": "vitest run --coverage",
62
+ "demo:journey": "tsx src/journey/demo.ts"
59
63
  }
60
64
  }
@@ -1,25 +0,0 @@
1
- import { createRequire as __cr } from 'module'; const require = __cr(import.meta.url);
2
- import {
3
- ANON_ASSETS,
4
- ANON_VERSION,
5
- defaultCacheDir,
6
- ensureAnonBinary,
7
- renderTorrc,
8
- selectAnonAsset,
9
- startManagedAnonProxy,
10
- tcpProbe,
11
- waitForAnonSocks
12
- } from "./chunk-SKQTKZIH.js";
13
- import "./chunk-F22GNSF6.js";
14
- export {
15
- ANON_ASSETS,
16
- ANON_VERSION,
17
- defaultCacheDir,
18
- ensureAnonBinary,
19
- renderTorrc,
20
- selectAnonAsset,
21
- startManagedAnonProxy,
22
- tcpProbe,
23
- waitForAnonSocks
24
- };
25
- //# sourceMappingURL=anon-proxy-W3KMM7GU-FN7ZJY7P.js.map