@zktx.io/sui-mcp 0.5.0 → 0.6.1

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 (138) hide show
  1. package/README.md +21 -21
  2. package/dist/adapters/adapterPromptSurfaces.js +0 -20
  3. package/dist/adapters/deepbook/deepbookQuotePolicy.js +0 -4
  4. package/dist/adapters/deepbook/deepbookReviewEvidence.js +0 -9
  5. package/dist/adapters/deepbook/deepbookTransactionMaterialProducer.js +0 -9
  6. package/dist/adapters/intentPlanFactories.js +0 -6
  7. package/dist/core/action/contractNameRegistry.js +0 -53
  8. package/dist/core/action/forbiddenFields.js +0 -4
  9. package/dist/core/action/ptbVisualizationProducer.js +0 -3
  10. package/dist/core/action/receiptPtbGraph.js +0 -17
  11. package/dist/core/action/reviewTimeSimulationEvidence.js +0 -4
  12. package/dist/core/action/signableAdapterContract.js +0 -5
  13. package/dist/core/action/suiChainReceiptMapping.js +0 -18
  14. package/dist/core/action/suiChainReceiptReader.js +1 -21
  15. package/dist/core/action/suiChainReceiptVerifier.js +0 -10
  16. package/dist/core/action/transactionFunding.js +0 -7
  17. package/dist/core/action/types.js +0 -1
  18. package/dist/core/action/walletReviewContractAssembler.js +0 -2
  19. package/dist/core/activity/localDataService.js +65 -52
  20. package/dist/core/activity/localDataValidation.js +1 -3
  21. package/dist/core/activity/sqliteActivityStore.js +24 -24
  22. package/dist/core/activity/sqliteActivityStoreRows.js +0 -2
  23. package/dist/core/activity/sqliteActivityStoreSchema.js +81 -14
  24. package/dist/core/preferences/sqlitePreferencesRepository.js +5 -3
  25. package/dist/core/read/deepbookReadHelpers.js +0 -2
  26. package/dist/core/read/deepbookRegistry.js +0 -19
  27. package/dist/core/read/deepbookUsdcChartService.js +0 -2
  28. package/dist/core/read/readCardResult.js +0 -2
  29. package/dist/core/read/readService.js +0 -19
  30. package/dist/core/read/readServiceTypes.js +0 -2
  31. package/dist/core/session/cardSession.js +1 -5
  32. package/dist/core/session/cardSessionStore.js +54 -7
  33. package/dist/core/session/reviewValidity.js +0 -3
  34. package/dist/core/session/sessionRecordStore.js +0 -1
  35. package/dist/core/session/sessionStore.js +0 -32
  36. package/dist/core/session/settingsFileIdentity.js +9 -0
  37. package/dist/core/session/settingsFileProtocol.js +20 -0
  38. package/dist/core/session/settingsFileStore.js +337 -0
  39. package/dist/core/session/settingsInputError.js +32 -0
  40. package/dist/core/session/settingsOperation.js +220 -0
  41. package/dist/core/session/settingsPreparationSql.js +13 -0
  42. package/dist/core/session/settingsWorkflow.js +1183 -0
  43. package/dist/core/session/sqliteCardStore.js +0 -2
  44. package/dist/core/session/sqliteSessionStore.js +0 -51
  45. package/dist/core/session/sqliteSettingsWorkflowStore.js +453 -0
  46. package/dist/core/session/sqliteTransactionMaterialStore.js +0 -11
  47. package/dist/core/session/sqliteWalletWorkflowStore.js +160 -66
  48. package/dist/core/session/status.js +2 -4
  49. package/dist/core/session/transactionMaterialStore.js +0 -4
  50. package/dist/core/session/transactionRequest.js +0 -4
  51. package/dist/core/session/walletConnection.js +26 -10
  52. package/dist/core/session/walletWorkflow.js +70 -30
  53. package/dist/core/session/workflowState.js +14 -14
  54. package/dist/core/session/workflowView.js +18 -8
  55. package/dist/core/suiAddress.js +0 -5
  56. package/dist/core/suiEndpoint.js +0 -3
  57. package/dist/mcp/prompts.js +0 -12
  58. package/dist/mcp/responseGuidance.js +10 -5
  59. package/dist/mcp/schemas.js +0 -3
  60. package/dist/mcp/serverInfo.js +3 -4
  61. package/dist/mcp/toolNames.js +2 -2
  62. package/dist/mcp/tools/account/index.js +1 -19
  63. package/dist/mcp/tools/action/prepareSuiActionReview.js +0 -6
  64. package/dist/mcp/tools/read/readToolHelpers.js +5 -4
  65. package/dist/mcp/tools/read/serverStatusTools.js +0 -1
  66. package/dist/mcp/tools/session/executionResultTools.js +2 -2
  67. package/dist/mcp/tools/session/shared.js +1 -2
  68. package/dist/mcp/tools/session/statusTools.js +4 -5
  69. package/dist/mcp/tools/settings/index.js +8 -28
  70. package/dist/mcp-app/account.html +14 -14
  71. package/dist/mcp-app/account.notices.txt +1 -1
  72. package/dist/mcp-app/chart.html +9 -9
  73. package/dist/mcp-app/chart.notices.txt +1 -1
  74. package/dist/mcp-app/connect.html +14 -14
  75. package/dist/mcp-app/connect.notices.txt +1 -1
  76. package/dist/mcp-app/receipt.html +1298 -1463
  77. package/dist/mcp-app/receipt.notices.txt +226 -1204
  78. package/dist/mcp-app/review.html +1298 -1463
  79. package/dist/mcp-app/review.notices.txt +226 -1204
  80. package/dist/mcp-app/settings.html +3133 -0
  81. package/dist/mcp-app/settings.notices.txt +973 -0
  82. package/dist/mcp-ui/contracts.js +8 -2
  83. package/dist/mcp-ui/readCards.js +1 -1
  84. package/dist/mcp-ui/tools.js +34 -4
  85. package/dist/review-server/server.js +3 -51
  86. package/dist/runtime/application.js +41 -14
  87. package/dist/runtime/config.js +0 -2
  88. package/dist/runtime/localSettingsService.js +23 -2
  89. package/dist/runtime/logger.js +0 -2
  90. package/dist/runtime/reviewServerAcquire.js +1 -18
  91. package/dist/runtime/runtimeTermination.js +1 -4
  92. package/dist/runtime/shared/authenticatedFetch.js +2 -4
  93. package/dist/runtime/shared/control.js +4 -7
  94. package/dist/runtime/shared/dataAccess.js +0 -2
  95. package/dist/runtime/shared/http.js +14 -0
  96. package/dist/runtime/shared/mcpHttp.js +6 -6
  97. package/dist/runtime/shared/ownerLease.js +0 -4
  98. package/dist/runtime/shared/server.js +1 -2
  99. package/dist/runtime/shared/stdio.js +2 -5
  100. package/dist/runtime/smokeMainnetRead.js +0 -3
  101. package/dist/runtime/smokeReview.js +0 -4
  102. package/dist/runtime/start.js +0 -2
  103. package/dist/runtime/suiTransactionGraphqlMapping.js +0 -2
  104. package/dist/runtime/suiTransactionGraphqlQueries.js +0 -3
  105. package/dist/runtime/walletConnectConfig.js +0 -2
  106. package/dist/runtime/walletConnectStorage.js +2 -10
  107. package/dist/runtime/walletConnectTransport.js +0 -11
  108. package/dist/runtime/walletSdkChildRuntime.js +2 -6
  109. package/dist/runtime/walletSdkIpc.js +2 -1
  110. package/dist/runtime/walletSdkProcess.js +3 -8
  111. package/docs/AGENT_BEHAVIOR.md +45 -15
  112. package/docs/LOCAL_DB_ARCHITECTURE.md +145 -22
  113. package/docs/MCP_SETUP.md +99 -39
  114. package/docs/MCP_TOOLS.md +288 -24
  115. package/docs/SDK_API.md +63 -10
  116. package/docs/UTILITY_INDEX.md +9 -6
  117. package/docs/WALLET_CONNECTION.md +32 -10
  118. package/package.json +22 -8
  119. package/dist/core/activity/schemaVersion.js +0 -2
  120. package/dist/core/session/keyedRecordStore.js +0 -18
  121. package/dist/core/session/settingsSession.js +0 -1
  122. package/dist/core/session/settingsSessions.js +0 -45
  123. package/dist/review-app/brand-dark.svg +0 -1
  124. package/dist/review-app/brand-light.svg +0 -1
  125. package/dist/review-app/favicon.svg +0 -1
  126. package/dist/review-app/settings.css +0 -1
  127. package/dist/review-app/settings.js +0 -1
  128. package/dist/review-app/ui.css +0 -809
  129. package/dist/review-server/assets.js +0 -48
  130. package/dist/review-server/html.js +0 -45
  131. package/dist/review-server/http.js +0 -47
  132. package/dist/review-server/middleware/reviewToken.js +0 -7
  133. package/dist/review-server/settingsApi.js +0 -158
  134. package/docs/AGENT_DEVELOPMENT_POLICY.md +0 -815
  135. package/docs/FRONTEND_POLICY.md +0 -534
  136. package/docs/golden-scenarios/BEHAVIOR_MATRIX.md +0 -166
  137. package/docs/golden-scenarios/INTENT_EVIDENCE_GOLDEN_ANSWERS.md +0 -161
  138. package/docs/golden-scenarios/INTENT_EVIDENCE_MATRIX.md +0 -259
@@ -1,3 +1,4 @@
1
+ import { workflowConnectionEligibility } from "./workflowState.js";
1
2
  import { SessionStoreError } from "./sessionErrors.js";
2
3
  import { Transaction } from "@mysten/sui/transactions";
3
4
  import { verifyTransactionSignature } from "@mysten/sui/verify";
@@ -18,7 +19,9 @@ export class WalletWorkflow {
18
19
  observing = new Map();
19
20
  preparing = new Set();
20
21
  pendingWrites = new Map();
22
+ parentSignatureWork = new Set();
21
23
  eventListener;
24
+ settingsRecovery;
22
25
  constructor(options) {
23
26
  this.options = options;
24
27
  }
@@ -42,12 +45,13 @@ export class WalletWorkflow {
42
45
  report(stage) { try {
43
46
  this.options.logger.error("Wallet operation failed", { stage });
44
47
  }
45
- catch { /* SQLite owns outcomes. */ } }
48
+ catch { } }
46
49
  async start() {
47
50
  this.assertCurrent();
48
51
  if (this.started)
49
52
  throw new WorkflowConflict("The wallet service has already started.");
50
53
  this.started = true;
54
+ this.options.records.setWalletRunId(this.options.runtime.runId);
51
55
  this.options.records.recover(this.now());
52
56
  this.bindEvents();
53
57
  this.options.runtime.start((event) => this.eventListener?.(event));
@@ -61,9 +65,11 @@ export class WalletWorkflow {
61
65
  return;
62
66
  const runtime = this.options.runtime;
63
67
  if (event.type === "snapshot") {
64
- this.options.records.applyWalletObservation(event.snapshot, event.previous, event.ready);
65
- if (event.ready)
68
+ this.options.records.applyWalletObservation(event.snapshot, event.previous, event.ready, () => this.settingsRecovery?.runtimeEvent(event));
69
+ if (event.ready) {
66
70
  runtime.publishReady(event.runId);
71
+ this.settingsRecovery?.readyPublished(event.runId);
72
+ }
67
73
  }
68
74
  else if (event.type === "stage") {
69
75
  this.options.records.publishWalletState();
@@ -71,8 +77,38 @@ export class WalletWorkflow {
71
77
  else if (event.type === "lost") {
72
78
  this.pairings.clear();
73
79
  this.retainWrite({ kind: "runtime_failure", runId: event.runId, observedAt: this.now().toISOString() });
80
+ this.settingsRecovery?.runtimeEvent(event);
81
+ }
82
+ else if (event.type === "exit") {
83
+ this.retainWrite({ kind: "runtime_exit", runId: event.runId, observedAt: this.now().toISOString(), parentProcessing: [...this.parentSignatureWork] });
74
84
  }
75
85
  }
86
+ attachSettingsRecovery(recovery) {
87
+ if (this.settingsRecovery)
88
+ throw new Error("Settings recovery is already attached.");
89
+ this.settingsRecovery = recovery;
90
+ }
91
+ recoveryContext() {
92
+ this.synchronizeWalletState();
93
+ return this.currentRecoveryFacts();
94
+ }
95
+ currentRecoveryFacts() {
96
+ return { availability: this.walletAvailability(), impact: this.options.records.recoveryImpact(this.options.runtime.runId) };
97
+ }
98
+ blockSettingsAdmissionFailure() {
99
+ const runId = this.options.runtime.runId;
100
+ this.options.runtime.block("wallet_state_unavailable");
101
+ this.retainWrite({ kind: "runtime_failure", runId, observedAt: this.now().toISOString() });
102
+ }
103
+ fenceForSettings(runId) { this.assertCurrent(); this.options.runtime.fence(runId); }
104
+ replaceForSettings(runId, reserve) {
105
+ this.assertCurrent();
106
+ return this.options.runtime.replace(runId, (nextRunId) => {
107
+ this.synchronizeWalletState();
108
+ reserve(nextRunId);
109
+ this.options.records.setWalletRunId(nextRunId);
110
+ });
111
+ }
76
112
  dataReplaced() {
77
113
  this.pairings.clear();
78
114
  this.pendingWrites.clear();
@@ -92,14 +128,13 @@ export class WalletWorkflow {
92
128
  this.retainWrite(completion);
93
129
  }
94
130
  retainWrite(completion) {
95
- // An old data generation cannot add repair work to the replacement data.
96
131
  try {
97
132
  this.assertCurrent();
98
133
  }
99
134
  catch {
100
135
  return;
101
136
  }
102
- const key = completion.kind === "runtime_failure" ? `runtime:${completion.runId}` :
137
+ const key = completion.kind === "runtime_failure" || completion.kind === "runtime_exit" ? `${completion.kind}:${completion.runId}` :
103
138
  completion.kind === "request" ? `request:${completion.id}:${completion.field}` : `connection:${completion.cardId}:${completion.runId}`;
104
139
  if (!this.pendingWrites.has(key))
105
140
  this.pendingWrites.set(key, completion);
@@ -115,7 +150,9 @@ export class WalletWorkflow {
115
150
  this.options.records.settle(completion.id, completion.field, false);
116
151
  else if (completion.kind === "connection")
117
152
  this.options.records.settleConnection(completion.id, completion);
118
- else if (completion.runId === this.options.runtime.runId)
153
+ else if (completion.kind === "runtime_exit")
154
+ this.options.records.recordRunExit(completion.runId, completion.parentProcessing);
155
+ else
119
156
  this.options.records.recordWalletFailure(completion);
120
157
  this.pendingWrites.delete(key);
121
158
  }
@@ -133,10 +170,10 @@ export class WalletWorkflow {
133
170
  failure = error;
134
171
  }
135
172
  }
136
- // A completed callback's pending flag is housekeeping, not authority to
137
- // read recorded facts. Retain failed repairs for the next applicable read.
138
173
  if (failure && walletDependent)
139
174
  throw failure;
175
+ if (walletDependent)
176
+ this.settingsRecovery?.synchronize();
140
177
  if (walletDependent)
141
178
  this.options.runtime.synchronize();
142
179
  }
@@ -159,16 +196,23 @@ export class WalletWorkflow {
159
196
  }
160
197
  return { status: "ready" };
161
198
  }
162
- readConnectionContext() {
199
+ reconcileConnectionContext() {
163
200
  this.assertCurrent();
164
201
  this.synchronizeWalletState();
165
202
  this.recoverDisconnects();
166
- const state = this.options.records.evaluate({ walletAvailability: this.walletAvailability(), walletObservation: this.observation() });
167
- // Current-owner rows are published by the same SDK observation/admission
168
- // transactions that gate availability. Use their evaluated selection in
169
- // every consumer instead of deriving another default from address matches.
170
- return { connections: state.connections, connectionConflict: state.connectionConflict, walletAvailability: state.walletAvailability, walletObservation: this.observation(),
171
- assetReadAccount: state.assetReadAccount ?? { status: "address_required" } };
203
+ const state = this.options.records.reconcileAndEvaluate({ purpose: "current_wallet", walletAvailability: this.walletAvailability(), walletObservation: this.observation() });
204
+ return { connections: state.connections, connectionConflict: state.connectionConflict, walletAvailability: state.walletAvailability,
205
+ walletObservation: state.walletObservation, manageableConnectionIds: state.manageableConnectionIds,
206
+ connectionReconciliationRequired: state.connectionReconciliationRequired, assetReadAccount: state.assetReadAccount ?? { status: "address_required" } };
207
+ }
208
+ currentConnectionContext() {
209
+ this.assertCurrent();
210
+ const facts = this.options.records.readConnectionFacts(this.now()), availability = this.walletAvailability();
211
+ const { selection: _selection, ...eligibility } = workflowConnectionEligibility({ ...facts, walletAvailability: availability });
212
+ return { connections: facts.connections, walletAvailability: availability, walletObservation: facts.walletObservation,
213
+ connectionConflict: eligibility.connectionConflict, manageableConnectionIds: eligibility.manageableConnectionIds,
214
+ connectionReconciliationRequired: eligibility.connectionReconciliationRequired,
215
+ assetReadAccount: eligibility.assetReadAccount ?? { status: "address_required" } };
172
216
  }
173
217
  recoverDisconnects() {
174
218
  const available = this.walletAvailability().status === "available";
@@ -178,7 +222,6 @@ export class WalletWorkflow {
178
222
  const pending = this.options.records.pendingDisconnect(record.connection.connectionId);
179
223
  if (!pending)
180
224
  continue;
181
- // Disabled transports also return undefined; that is not session absence.
182
225
  const absent = available && !!record.topic && this.observed(record.topic)?.status === "absent";
183
226
  this.options.records.recoverDisconnect(pending.state.cardId, record.connection.connectionId, record.connection.revision, absent);
184
227
  }
@@ -194,7 +237,9 @@ export class WalletWorkflow {
194
237
  this.options.records.failPreparation(id, preparation, this.now());
195
238
  const candidate = await this.options.sessions.inspectReview(id, this.now());
196
239
  this.assertCurrent();
197
- const evaluated = this.options.records.evaluate({ reviewSessionId: id, candidate, expectedCard, readTarget,
240
+ if (!candidate)
241
+ throw new SessionStoreError("session_not_found", "The saved review is unavailable.");
242
+ const evaluated = this.options.records.reconcileAndEvaluate({ purpose: "review", reviewSessionId: id, candidate, expectedCard, readTarget,
198
243
  walletAvailability: this.walletAvailability(), walletObservation: this.observation(), uiObservation });
199
244
  this.options.sessions.recordEvaluationEvents(evaluated.events);
200
245
  return evaluated;
@@ -208,23 +253,22 @@ export class WalletWorkflow {
208
253
  if (explicitResult) {
209
254
  await this.observing.get(state.request.attemptId);
210
255
  this.assertCurrent();
211
- // An awaited receipt may have committed new facts. Return one freshly
212
- // evaluated snapshot; ordinary status reads do not await external I/O.
213
256
  state = await this.evaluateReview(id, undefined, false, state.request.attemptId);
214
257
  }
215
258
  }
216
259
  if (!state.session)
217
260
  return undefined;
218
261
  return { session: state.session, request: state.request, hasReviewInput: state.hasReviewInput, connectionConflict: state.connectionConflict, walletAvailability: state.walletAvailability, walletObservation: this.observation(),
262
+ connectionReconciliationRequired: state.connectionReconciliationRequired,
219
263
  progress: reviewProgress(!!state.session.preparationId, state.request, state.walletAvailability, { stopped: state.authority?.observation_stopped === 1, pending: state.authority?.lookup_pending === 1 }) };
220
264
  }
221
265
  async describe(record, uiObservation = false) {
222
266
  this.assertCurrent();
223
267
  if (record.state.kind === "connect")
224
- this.readConnectionContext();
268
+ this.reconcileConnectionContext();
225
269
  const evaluated = record.state.kind === "review"
226
270
  ? await this.evaluateReview(String(record.state.input.reviewSessionId), record, uiObservation)
227
- : this.options.records.evaluate({ expectedCard: record, walletAvailability: this.walletAvailability(), walletObservation: this.observation() });
271
+ : this.options.records.reconcileAndEvaluate({ purpose: "current_wallet", expectedCard: record, walletAvailability: this.walletAvailability(), walletObservation: this.observation() });
228
272
  this.assertCurrent();
229
273
  if (record.state.kind === "connect") {
230
274
  const data = projectConnectionView(evaluated);
@@ -391,8 +435,6 @@ export class WalletWorkflow {
391
435
  catch (error) {
392
436
  displayFailure = error;
393
437
  }
394
- // The approval remains pending even if setup/QR recording fails or the
395
- // wallet dependency is disabled. Settle only after that promise ends.
396
438
  const session = await result.approval;
397
439
  if (displayFailure)
398
440
  throw displayFailure;
@@ -444,6 +486,7 @@ export class WalletWorkflow {
444
486
  await this.performSignature(request, connectionId, bytesBase64, run);
445
487
  }
446
488
  finally {
489
+ this.parentSignatureWork.delete(request.attemptId);
447
490
  this.completeCallback({ kind: "request", id: request.attemptId, field: "sdk_pending" });
448
491
  }
449
492
  }
@@ -458,6 +501,7 @@ export class WalletWorkflow {
458
501
  this.assertWalletAvailable(run);
459
502
  response = await run.sign({ topic: connection.topic, account: request.account, transactionBytesBase64: bytesBase64,
460
503
  sessionVersion: proof.observed.version }, request.attemptId);
504
+ this.parentSignatureWork.add(request.attemptId);
461
505
  this.assertWalletAvailable(run);
462
506
  }
463
507
  catch {
@@ -494,8 +538,6 @@ export class WalletWorkflow {
494
538
  return;
495
539
  }
496
540
  catch (error) {
497
- // SDK verification can itself depend on a remote source. An exception is
498
- // not proof of a mismatched transaction or signer.
499
541
  if (!this.stopped)
500
542
  this.options.records.transitionRequest(request.attemptId, "request_failed", this.now(), {
501
543
  reason: this.walletAvailability().status !== "available" ? "Wallet operations became unavailable before submission. The returned signature will not be submitted."
@@ -506,7 +548,7 @@ export class WalletWorkflow {
506
548
  try {
507
549
  await this.options.submitTransaction(bytes, response.signature);
508
550
  }
509
- catch { /* A lost submit response is not proof of failure. Observe the same digest. */ }
551
+ catch { }
510
552
  finally {
511
553
  this.completeCallback({ kind: "request", id: request.attemptId, field: "submit_pending" });
512
554
  }
@@ -527,8 +569,6 @@ export class WalletWorkflow {
527
569
  const current = this.options.records.request(id);
528
570
  if (!current || !(isInitialChainObservation(current.requestStatus) || explicit && current.requestStatus === "outcome_unknown"))
529
571
  return;
530
- // Starting another lookup needs its own previous callback to be settled.
531
- // Stored terminal facts above never depend on this write succeeding.
532
572
  for (const [key, write] of this.pendingWrites)
533
573
  if (write.kind === "request" && write.id === id && write.field === "lookup_pending") {
534
574
  this.settlePendingWrite(key, write);
@@ -549,7 +589,7 @@ export class WalletWorkflow {
549
589
  if (receipt.status === "found")
550
590
  details = projectReadCardResult("receipt", { digest: request.transactionDigest }, receipt);
551
591
  }
552
- catch { /* Keep verified chain facts if the additional display read is unavailable. */ }
592
+ catch { }
553
593
  }
554
594
  this.assertCurrent();
555
595
  this.options.records.transitionRequest(id, "completed", this.now(), { execution: {
@@ -581,7 +621,7 @@ export class WalletWorkflow {
581
621
  this.recoverDisconnects();
582
622
  const rows = [];
583
623
  for (const card of this.options.records.pendingConnectionCards(this.now())) {
584
- const evaluated = this.options.records.evaluate({ expectedCard: card, walletAvailability: this.walletAvailability(), walletObservation: this.observation() });
624
+ const evaluated = this.options.records.reconcileAndEvaluate({ purpose: "current_wallet", expectedCard: card, walletAvailability: this.walletAvailability(), walletObservation: this.observation() });
585
625
  if (evaluated.record?.state.state === "closed")
586
626
  continue;
587
627
  const data = projectConnectionView(evaluated);
@@ -2,8 +2,6 @@ import { walletConnectionSelection } from "./walletConnection.js";
2
2
  import { isInitialChainObservation } from "./transactionRequest.js";
3
3
  export const workflowActions = ["connect", "disconnect", "use_account", "stop_connection", "prepare_review",
4
4
  "request_signature", "cancel", "stop_waiting", "read_result"];
5
- // Read context may change; an existing review's account binding may not.
6
- // Both evaluated choices and admission consume this relation with current facts.
7
5
  export function reviewPreparationAccount(boundAccount, activeAccount, selectedAccount = activeAccount) {
8
6
  if (!activeAccount)
9
7
  return { allowed: false, message: "No account from a connected wallet is selected for this review." };
@@ -15,24 +13,26 @@ export function reviewPreparationAccount(boundAccount, activeAccount, selectedAc
15
13
  message: "The selected account has changed since this request was made." };
16
14
  return { allowed: true, account: activeAccount };
17
15
  }
18
- // Shared domain eligibility. The DB supplies current facts at its decision
19
- // boundary. Returned choices are advisory; admission still binds concrete input.
16
+ export function workflowConnectionEligibility(facts) {
17
+ const selection = walletConnectionSelection(facts.connections, Date.parse(facts.evaluatedAt), facts.connectionPresence, facts.activeAccount ? { address: facts.activeAccount, walletId: facts.activeAccountConnectionId } : undefined);
18
+ const available = facts.walletAvailability.status === "available", dependent = facts.walletDependent !== false;
19
+ const usableConnectionId = available && dependent ? selection.connection?.connectionId : undefined;
20
+ const assetReadAccount = !dependent ? undefined
21
+ : usableConnectionId ? selection.assetReadAccount : { status: "address_required" };
22
+ return { selection, usableConnectionId, assetReadAccount, connectionConflict: selection.conflict,
23
+ manageableConnectionIds: available ? selection.manageableConnectionIds : [],
24
+ connectionReconciliationRequired: available && dependent ? selection.connectionReconciliationRequired : undefined };
25
+ }
20
26
  export function workflowEligibility(facts) {
21
27
  const { record, session, request, authority, walletAvailability } = facts;
22
28
  const at = Date.parse(facts.evaluatedAt);
23
29
  const cardRemaining = record?.ownerId === facts.ownerId ? Math.max(0, Date.parse(record.state.expiresAt) - at) : 0;
24
- // A later-created input card cannot extend its review session. Admitted
25
- // requests and management cards retain their separate observation authority.
26
30
  const remaining = record?.scope === "review" && session && !request
27
31
  ? Math.min(cardRemaining, Math.max(0, Date.parse(session.expiresAt) - at)) : cardRemaining;
28
32
  const inputAvailable = remaining > 0 && record?.state.state === "ready" && record.acceptedInput === undefined;
29
33
  const allowedActions = [];
30
- const selection = walletConnectionSelection(facts.connections, at, facts.activeAccount
31
- ? { address: facts.activeAccount, walletId: facts.activeAccountConnectionId } : undefined);
32
- const usableConnectionId = walletAvailability.status === "available" && facts.walletDependent !== false
33
- ? selection.connection?.connectionId : undefined;
34
- const assetReadAccount = facts.walletDependent === false ? undefined
35
- : usableConnectionId ? selection.assetReadAccount : { status: "address_required" };
34
+ const { selection, ...connectionEligibility } = workflowConnectionEligibility(facts);
35
+ const { assetReadAccount } = connectionEligibility;
36
36
  let preparationIssue;
37
37
  if (record?.scope === "connect") {
38
38
  if (inputAvailable) {
@@ -40,7 +40,7 @@ export function workflowEligibility(facts) {
40
40
  if (walletAvailability.status === "available") {
41
41
  if (["connect", "manage"].includes(String(record.state.input.intent)) && selection.pairingAllowed)
42
42
  allowedActions.push("connect");
43
- if (facts.connections.some((item) => item.status === "connected" && !item.pendingAction))
43
+ if (selection.manageableConnectionIds.length)
44
44
  allowedActions.push("disconnect");
45
45
  if (selection.connection)
46
46
  allowedActions.push("use_account");
@@ -74,7 +74,7 @@ export function workflowEligibility(facts) {
74
74
  session.status === "ready_for_wallet_review" && (!request || request.reviewRevision !== session.reviewRevision)
75
75
  ? session.reviewState?.humanReadableReview?.freshness.expiresAt : undefined;
76
76
  const nextRead = expiry && session ? Math.min(remaining, Date.parse(session.expiresAt) - at, Date.parse(expiry) - at) : undefined;
77
- return { allowedActions, preparationIssue, usableConnectionId, assetReadAccount, connectionConflict: selection.conflict,
77
+ return { allowedActions, preparationIssue, ...connectionEligibility,
78
78
  actionRemainingMs: remaining, inputRemainingMs: inputAvailable ? remaining : 0,
79
79
  ...(nextRead !== undefined && nextRead > 0 ? { nextStateReadAfterMs: nextRead } : {}) };
80
80
  }
@@ -9,7 +9,6 @@ import { reviewProgress, EXECUTION_POLLING_INTERVAL_SECONDS } from "./status.js"
9
9
  import { walletRunIdSchema, walletRecoverySchema, walletObservationSchema } from "./walletRuntime.js";
10
10
  export const CONNECT_BOUNDARY = "A wallet connection provides account context; it is not a transaction approval or proof of address ownership.";
11
11
  export const REVIEW_BOUNDARY = "Review evidence is not a safety guarantee. Only an explicit card action and wallet approval may authorize this exact transaction.";
12
- // A projection of an admitted card operation, not a new wallet connection state.
13
12
  export const connectionViewSchema = walletConnectionSchema.extend({ pendingAction: z.literal("disconnect").optional() });
14
13
  export { assetReadAccountSchema } from "./walletConnection.js";
15
14
  export const pendingConnectionStatusSchema = z.enum(["input_required", "awaiting_approval", "disconnect_pending"]);
@@ -37,6 +36,8 @@ export const workflowViewSchema = z.object({
37
36
  walletObservation: walletObservationSchema.optional(),
38
37
  runtimeRecovery: walletRecoverySchema.optional(),
39
38
  connectionConflict: connectionConflictSchema.optional(),
39
+ manageableConnectionIds: z.array(z.string().min(1)),
40
+ connectionReconciliationRequired: z.literal(true).optional(),
40
41
  usableConnectionId: z.string().min(1).optional(),
41
42
  assetReadAccount: assetReadAccountSchema.optional(),
42
43
  acceptedWalletRunId: walletRunIdSchema.optional(),
@@ -60,17 +61,24 @@ export const workflowViewSchema = z.object({
60
61
  }).strict().superRefine((view, context) => {
61
62
  const connection = view.connections.find((item) => item.connectionId === view.usableConnectionId);
62
63
  if (view.usableConnectionId && (!connection || connection.status !== "connected" ||
63
- view.walletAvailability.status !== "available" || view.connectionConflict ||
64
+ view.walletAvailability.status !== "available" || view.connectionConflict || view.connectionReconciliationRequired ||
64
65
  view.connections.some((item) => item.pendingAction || item.status === "awaiting_approval"))) {
65
66
  context.addIssue({ code: "custom", path: ["usableConnectionId"], message: "The usable connection must match current connection facts." });
66
67
  }
68
+ if (new Set(view.manageableConnectionIds).size !== view.manageableConnectionIds.length ||
69
+ view.manageableConnectionIds.some((id) => !view.connections.some((item) => item.connectionId === id &&
70
+ !item.pendingAction && item.status !== "awaiting_approval"))) {
71
+ context.addIssue({ code: "custom", path: ["manageableConnectionIds"], message: "Management must name distinct recorded targets without pending operations." });
72
+ }
73
+ if (view.connectionReconciliationRequired && (view.usableConnectionId || view.assetReadAccount?.status === "available" ||
74
+ view.allowedActions.some((action) => ["connect", "use_account", "prepare_review", "request_signature"].includes(action)))) {
75
+ context.addIssue({ code: "custom", path: ["connectionReconciliationRequired"], message: "Unrecorded SDK connections cannot authorize connection or account use." });
76
+ }
67
77
  if (view.assetReadAccount?.status === "available" && (!connection ||
68
78
  !connection.accounts.includes(view.assetReadAccount.account) || view.activeAccount !== view.assetReadAccount.account)) {
69
79
  context.addIssue({ code: "custom", path: ["assetReadAccount"], message: "The default address must belong to the usable connection and stored selection." });
70
80
  }
71
81
  });
72
- // Automatic preparation uses the same current selection and typed admission as
73
- // a deliberate retry. A failed computation is not a reason to compute in a loop.
74
82
  function automaticReviewAction(input) {
75
83
  const { record, session, request } = input;
76
84
  if (!session || record?.scope !== "review" || request || session.preparationError ||
@@ -87,7 +95,6 @@ function automaticReviewAction(input) {
87
95
  return { action: "prepare_review", walletRunId: input.walletAvailability.walletRunId, connectionId: candidates[0].connectionId,
88
96
  account, reviewRevision: session.reviewRevision };
89
97
  }
90
- // Method support filters wallet choices; it does not authorize a signature.
91
98
  export function reviewWalletChoices(selection, account, requireSigningMethod = false) {
92
99
  return selection.connections.filter((item) => item.connectionId === selection.usableConnectionId && item.accounts.includes(account) &&
93
100
  (!requireSigningMethod || item.methods.includes("sui_signTransaction")));
@@ -101,10 +108,11 @@ function nextStateRead(input) {
101
108
  .filter((value) => value !== undefined && value > 0);
102
109
  return delays.length ? Math.min(...delays) : undefined;
103
110
  }
104
- // These projections do not read clocks, storage, or admission rules. The
105
- // evaluated facts and choices were collected together by the database owner.
106
111
  export function projectConnectionView(input) {
107
- const { connection, walletAvailability } = input;
112
+ const { walletAvailability } = input;
113
+ const stored = input.record?.state.data;
114
+ const connection = input.record?.acceptedInput?.action === "disconnect" && stored?.disconnectOutcome
115
+ ? connectionViewSchema.parse(stored.disconnectOutcome) : input.connection;
108
116
  const readAfter = nextStateRead(input);
109
117
  const progress = input.runtimeRecovery ? { status: "phase" in input.runtimeRecovery ? "waiting" : "idle" } :
110
118
  workflowProgress(connection?.status === "awaiting_approval" || connection?.pendingAction === "disconnect", true, walletAvailability);
@@ -114,6 +122,7 @@ export function projectConnectionView(input) {
114
122
  ? { automaticAction: { action: "connect", walletRunId: walletAvailability.walletRunId } } : {}),
115
123
  runtimeRecovery: input.runtimeRecovery, walletObservation: input.walletObservation,
116
124
  connectionConflict: input.connectionConflict, usableConnectionId: input.usableConnectionId, assetReadAccount: input.assetReadAccount,
125
+ manageableConnectionIds: input.manageableConnectionIds, connectionReconciliationRequired: input.connectionReconciliationRequired,
117
126
  connectionAction: ["connect", "disconnect"].includes(String(input.record?.acceptedInput?.action)) ? input.record?.acceptedInput?.action : undefined,
118
127
  acceptedWalletRunId: input.record?.acceptedInput?.walletRunId,
119
128
  ...(readAfter === undefined ? {} : { nextStateReadAfterMs: readAfter }),
@@ -133,6 +142,7 @@ export function projectReviewView(input) {
133
142
  return workflowViewSchema.parse({ kind: "review", mode: record.scope === "review_manage" ? "review_manage" : "review",
134
143
  allowedActions: input.allowedActions, actionRemainingMs: input.actionRemainingMs, observe: progress.status === "waiting", progress, walletAvailability,
135
144
  connections: input.connections, connectionConflict: input.connectionConflict, usableConnectionId: input.usableConnectionId,
145
+ manageableConnectionIds: input.manageableConnectionIds, connectionReconciliationRequired: input.connectionReconciliationRequired,
136
146
  assetReadAccount: input.assetReadAccount, activeAccount: input.activeAccount, boundary: REVIEW_BOUNDARY, receipt: input.receipt,
137
147
  walletObservation: input.walletObservation,
138
148
  acceptedWalletRunId: record.acceptedInput?.walletRunId,
@@ -1,13 +1,8 @@
1
1
  import { isValidSuiAddress, isValidTransactionDigest, normalizeSuiAddress } from "@mysten/sui/utils";
2
2
  import { z } from "zod";
3
- // Use the string-only schema at MCP/HTTP output boundaries because zod transforms
4
- // cannot be represented in MCP JSON Schema. Use the normalized schema for values
5
- // before storing them as local session state.
6
3
  export const suiAddressStringSchema = z
7
4
  .string()
8
5
  .refine(isValidSuiAddress, "Expected a 32-byte Sui address");
9
- // Shared Sui transaction digest schema (pinned SDK source of truth). Used at
10
- // MCP/HTTP boundaries and by the signable-adapter commitment fields.
11
6
  export const suiTransactionDigestSchema = z
12
7
  .string()
13
8
  .refine(isValidTransactionDigest, "Expected a Sui transaction digest");
@@ -35,9 +35,6 @@ export function parseGrpcUrl(value) {
35
35
  }
36
36
  return `${parsed.protocol}//${authority}`;
37
37
  }
38
- // GraphQL endpoints commonly include a path such as /graphql and may omit an
39
- // explicit port. gRPC endpoints stay stricter because the pinned gRPC client
40
- // runtime expects only scheme, host, and explicit port.
41
38
  export function parseGraphqlUrl(value) {
42
39
  let parsed;
43
40
  if (value.length > MAX_SUI_GRAPHQL_URL_LENGTH) {
@@ -24,9 +24,6 @@ export const MCP_PROMPTS = [
24
24
  ].join("\n")
25
25
  }
26
26
  ];
27
- // Platform-owned boundary language appended to every adapter prompt surface.
28
- // Adapters contribute copy about their own action only; they cannot weaken
29
- // or omit these lines.
30
27
  const PLATFORM_PROMPT_BOUNDARY_LINES = [
31
28
  "Present the internal Review card and summarize the returned review checks.",
32
29
  "This MCP response never contains signing data, transaction bytes, or signing readiness; only an explicit UI action and wallet approval authorize the backend request; request status is separate from server-verified chain execution facts."
@@ -76,18 +73,9 @@ export function registerMcpPrompts(server, surfaces = []) {
76
73
  ]
77
74
  }));
78
75
  }
79
- // Adapter prompt surfaces: action-first names (`swap-deep`) with one
80
- // free-text intent argument so clients can pass the whole request in one
81
- // line (Claude Code: /mcp__sui-mcp__swap-deep 10 sui to usdc;
82
- // Claude Desktop shows a single input field). The model parses the
83
- // intent; this server never does.
84
76
  for (const surface of surfaces) {
85
77
  registerSurfacePrompt(server, promptNameFor(surface), surface, surface.description);
86
78
  }
87
- // Bare action prompts are always registered. One protocol: straight to it.
88
- // Several protocols: an optional `protocol` argument (completion suggests
89
- // the slugs) and explicit instructions to ask the user - the venue is the
90
- // user's choice, never the server's.
91
79
  for (const [action, group] of actionGroups(surfaces)) {
92
80
  registerBareActionPrompt(server, action, group);
93
81
  }
@@ -1,6 +1,6 @@
1
1
  import { EXTERNAL_PROPOSAL_SETTLEMENT_TOKEN_SELECTION_UNSUPPORTED_CLAIM_ID } from "../core/proposal/types.js";
2
2
  import { TOOL_NAMES } from "./toolNames.js";
3
- export function interactionStatusUserAnswerUse(hasWalletObservation = false, hasConnectionConflict = false) {
3
+ export function interactionStatusUserAnswerUse(hasWalletObservation = false, hasConnectionConflict = false, reconciliationRequired = false) {
4
4
  return {
5
5
  canAnswer: [
6
6
  "stored_active_account_read_context",
@@ -8,6 +8,7 @@ export function interactionStatusUserAnswerUse(hasWalletObservation = false, has
8
8
  "connection_qualified_default_asset_account",
9
9
  "pending_local_wallet_connection_interactions",
10
10
  ...(hasConnectionConflict ? ["multiple_saved_connections_require_user_targeted_disconnection"] : []),
11
+ ...(reconciliationRequired ? ["unrecorded_service_connection_requires_wallet_removal_and_confirmed_absence"] : []),
11
12
  "pending_local_review_interactions",
12
13
  "wallet_operation_availability_separate_from_stored_transaction_facts"
13
14
  ],
@@ -24,9 +25,11 @@ export function interactionStatusUserAnswerUse(hasWalletObservation = false, has
24
25
  "complete_wallet_history",
25
26
  "profit_or_pnl"
26
27
  ],
27
- preconditionFields: ["walletAvailability", "assetReadAccount", ...(hasConnectionConflict ? ["connectionConflict"] : [])],
28
+ preconditionFields: ["walletAvailability", "assetReadAccount", ...(hasConnectionConflict ? ["connectionConflict"] : []),
29
+ ...(reconciliationRequired ? ["connectionReconciliationRequired"] : [])],
28
30
  answerFields: ["activeAccount", "connections", "assetReadAccount", "pendingWalletConnections", "pendingReviewSessions", "walletAvailability",
29
31
  ...(hasConnectionConflict ? ["connectionConflict"] : []),
32
+ "manageableConnectionIds", ...(reconciliationRequired ? ["connectionReconciliationRequired"] : []),
30
33
  ...(hasWalletObservation ? ["walletObservation"] : [])],
31
34
  diagnosticOnlyFields: [
32
35
  "pendingWalletConnections.truncated",
@@ -66,7 +69,8 @@ export function executionResultUserAnswerUse(fields = {}) {
66
69
  "profit_or_pnl"
67
70
  ],
68
71
  answerFields: [
69
- "walletAvailability", "progress", ...(fields.hasConnectionConflict ? ["connectionConflict"] : []), ...(hasWaitOutcome ? ["waitOutcome"] : []),
72
+ "walletAvailability", "progress", ...(fields.hasConnectionConflict ? ["connectionConflict"] : []),
73
+ ...(fields.reconciliationRequired ? ["connectionReconciliationRequired"] : []), ...(hasWaitOutcome ? ["waitOutcome"] : []),
70
74
  "reviewSessionId",
71
75
  "status",
72
76
  "pollingStatus",
@@ -91,7 +95,7 @@ export function executionResultUserAnswerUse(fields = {}) {
91
95
  }
92
96
  };
93
97
  }
94
- export function reviewStatusUserAnswerUse(hasReviewState, hasAdapterLifecycle = false, hasHumanReadableReview = false, hasSimulation = false, hasConnectionConflict = false) {
98
+ export function reviewStatusUserAnswerUse(hasReviewState, hasAdapterLifecycle = false, hasHumanReadableReview = false, hasSimulation = false, hasConnectionConflict = false, reconciliationRequired = false) {
95
99
  return {
96
100
  canAnswer: [
97
101
  "current_local_review_session_status",
@@ -115,7 +119,8 @@ export function reviewStatusUserAnswerUse(hasReviewState, hasAdapterLifecycle =
115
119
  "profit_or_pnl"
116
120
  ],
117
121
  answerFields: [
118
- "walletAvailability", "progress", ...(hasConnectionConflict ? ["connectionConflict"] : []), "reviewSessionId",
122
+ "walletAvailability", "progress", ...(hasConnectionConflict ? ["connectionConflict"] : []),
123
+ ...(reconciliationRequired ? ["connectionReconciliationRequired"] : []), "reviewSessionId",
119
124
  "status",
120
125
  "pollingStatus",
121
126
  "statusCategory",
@@ -1,7 +1,4 @@
1
1
  import { z } from "zod";
2
- // No-parameter tools. The `.optional()` is load-bearing: it lets the tool be called with
3
- // no arguments at all (undefined args validate). A bare `{}`/`z.object({})` would instead
4
- // REQUIRE an (empty) object and reject an argument-less call, so this is not a no-op.
5
2
  export const noParamsInputSchema = z.object({}).optional();
6
3
  export function successOutputSchema(dataShape) {
7
4
  return {
@@ -50,11 +50,11 @@ export const SERVER_INSTRUCTIONS = [
50
50
  "For USD-denominated payment coverage, balance total, or shortfall questions, call read.get_server_status, then read.list_settlement_asset_groups, then read.preview_intent_evidence. Use toolAvailability.requiredToolsAvailable and responseSummary.doNotCallQuoteToolsForThisQuestion; do not call wallet inventory or quote tools unless user asks a separate inventory or conversion question. For parity, use read.summarize_settlement_asset_group_parity. If toolAvailability cannot be used, say the current MCP server build cannot support the answer.",
51
51
  "The active account context is read-only, not login, custody or signing permission. Implicit asset reads require session.get_interaction_status.assetReadAccount: available. Otherwise ask for an address only if the tool accepts account; connected-only tools require connection/account selection or wallet recovery.",
52
52
  "Unsupported: other chains, autonomous trading, alerts, investment advice, arbitrary Move/package calls, P&L/tax.",
53
- "One wallet connection at a time; guidance: suimcp://docs/agent-behavior."
53
+ "One wallet connection at a time; docs: suimcp://docs/agent-behavior, suimcp://docs/mcp-tools."
54
54
  ].join("\n");
55
55
  export const IMPLEMENTED_TOOLS = [
56
56
  TOOL_NAMES.uiOpenAccount, TOOL_NAMES.uiOpenReceipt, TOOL_NAMES.uiOpenChart,
57
- TOOL_NAMES.uiReadCard, TOOL_NAMES.uiSubmitCard, TOOL_NAMES.uiActCard,
57
+ TOOL_NAMES.uiReadCard, TOOL_NAMES.uiSubmitCard, TOOL_NAMES.uiActCard, TOOL_NAMES.uiReadSettingsFile,
58
58
  TOOL_NAMES.readGetServerStatus,
59
59
  TOOL_NAMES.readListSupportedProtocols,
60
60
  TOOL_NAMES.readListDeepbookPools,
@@ -86,7 +86,6 @@ export const IMPLEMENTED_TOOLS = [
86
86
  TOOL_NAMES.actionPrepareSuiActionReview,
87
87
  TOOL_NAMES.actionPrepareExternalProposalReview,
88
88
  TOOL_NAMES.accountGetActiveAccount,
89
- TOOL_NAMES.accountClearActiveAccount,
90
89
  TOOL_NAMES.sessionCreateWalletConnection,
91
90
  TOOL_NAMES.sessionGetWalletConnection,
92
91
  TOOL_NAMES.sessionWaitWalletConnection,
@@ -127,5 +126,5 @@ export const SERVER_LIMITATIONS = [
127
126
  `DeepBook orderbook, mid-price, and quote outputs are ${DEEPBOOK_SOURCE_OWNER_RUNTIME_WORDING.pinnedSdkSnapshots} at fetchedAt; treat them as stale if the user delays.`,
128
127
  `DeepBook USDC price history and price-at-time reads use ${DEEPBOOK_SOURCE_OWNER_RUNTIME_WORDING.officialIndexerCandleData} for the requested official interval. They are external candle evidence only, not live quotes, historical mid prices, global market prices, fiat USD values, USDC/USD peg guarantees, route recommendations, transaction-building inputs, signing readiness, P&L, cost basis, user-account transaction history, or user-account balance history. Sui MCP does not independently recompute those candle values from chain history for the response.`,
129
128
  `ui.open_chart displays ${DEEPBOOK_SOURCE_OWNER_RUNTIME_WORDING.officialIndexerUsdcDenominatedCandles} in an internal read-only card. ui.open_account displays a public-address asset snapshot; ui.open_receipt displays the executed transaction graph when bound UI metadata is available, followed by on-chain facts and a Details slide. Card inputs end after backend admission, expiry or invalidation; chat navigation and frame recreation do not end valid unsubmitted input. Read the same DB state after a lost reply rather than resubmitting. Saved results do not authorize a new query or transaction. These cards are not live feeds, trading interfaces, route recommendations, fiat USD value, P&L, tax, cost basis, signing data, or signing readiness.`,
130
- "Settings mutations happen through local settings pages on the review server. MCP settings tools create settings sessions or read current settings only."
129
+ "Settings uses an internal card. MCP settings tools create the card or read current settings; only the user's scoped card confirmation applies local changes or restarts the connection service. Backup bytes stay in app-only file transfer. No external Settings URL exists."
131
130
  ];
@@ -5,6 +5,7 @@ export const TOOL_NAMES = {
5
5
  uiReadCard: "ui.read_card",
6
6
  uiSubmitCard: "ui.submit_card",
7
7
  uiActCard: "ui.act_card",
8
+ uiReadSettingsFile: "ui.read_settings_file",
8
9
  sessionOpenReviewManagement: "session.open_review_management",
9
10
  readGetServerStatus: "read.get_server_status",
10
11
  readListSupportedProtocols: "read.list_supported_protocols",
@@ -43,8 +44,7 @@ export const TOOL_NAMES = {
43
44
  sessionGetReviewStatus: "session.get_review_status",
44
45
  sessionGetExecutionResult: "session.get_execution_result",
45
46
  sessionWaitExecutionResult: "session.wait_execution_result",
46
- accountGetActiveAccount: "account.get_active_account",
47
- accountClearActiveAccount: "account.clear_active_account"
47
+ accountGetActiveAccount: "account.get_active_account"
48
48
  };
49
49
  export function assertValidToolName(name) {
50
50
  if (!/^[A-Za-z0-9_.-]{1,128}$/.test(name)) {
@@ -1,8 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { activeAccountResponse, activeAccountResponseSchema } from "../../activeAccountResponse.js";
3
- import { registerSuiMcpTool } from "../../registerTool.js";
4
3
  import { okToolResult } from "../../result.js";
5
- import { noParamsInputSchema, successOutputSchema } from "../../schemas.js";
4
+ import { noParamsInputSchema } from "../../schemas.js";
6
5
  import { activityStoreToolError } from "../../toolErrors.js";
7
6
  import { TOOL_NAMES } from "../../toolNames.js";
8
7
  export function registerAccountTools(server, deps) {
@@ -24,21 +23,4 @@ export function registerAccountTools(server, deps) {
24
23
  return activityStoreToolError(error, deps.logger);
25
24
  }
26
25
  });
27
- registerSuiMcpTool(server, TOOL_NAMES.accountClearActiveAccount, {
28
- title: "Clear active account read context",
29
- description: "Remove the active read context. Does not disconnect a wallet or revoke onchain permission.",
30
- inputSchema: noParamsInputSchema,
31
- outputSchema: successOutputSchema({
32
- status: z.literal("cleared")
33
- }),
34
- annotations: { readOnlyHint: false, openWorldHint: false }
35
- }, async () => {
36
- try {
37
- await deps.activityStore.clearActiveAccount();
38
- return okToolResult({ status: "cleared" });
39
- }
40
- catch (error) {
41
- return activityStoreToolError(error, deps.logger);
42
- }
43
- });
44
26
  }
@@ -32,12 +32,6 @@ export function registerActionTools(server, deps) {
32
32
  if (!supportsCards(server))
33
33
  return errorToolResult({ kind: "ui_unavailable", details: { reason: "An internal review card is required." } });
34
34
  const now = new Date();
35
- // A swap review is account-bound: its evidence (balances, transaction
36
- // material, digest, simulation) is computed for a specific sender, and
37
- // no transaction can be built without that account. Refuse here when no
38
- // wallet account is connected instead of creating a hollow proposal that
39
- // can never be computed or signed. Connect first via
40
- // session.create_wallet_connection.
41
35
  let activeAccount;
42
36
  try {
43
37
  activeAccount = await deps.activityStore.getActiveAccount();