@zktx.io/sui-mcp 0.6.2 → 0.8.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 (87) hide show
  1. package/README.md +94 -52
  2. package/dist/adapters/adapterPromptSurfaces.js +1 -1
  3. package/dist/core/activity/localDataService.js +8 -21
  4. package/dist/core/activity/localDataValidation.js +22 -46
  5. package/dist/core/activity/sqliteAccountStore.js +46 -0
  6. package/dist/core/activity/sqliteActivityStore.js +65 -147
  7. package/dist/core/activity/sqliteActivityStoreSchema.js +42 -26
  8. package/dist/core/activity/transactionActivityService.js +2 -2
  9. package/dist/core/preferences/preferencesStore.js +2 -2
  10. package/dist/core/preferences/sqlitePreferencesRepository.js +10 -0
  11. package/dist/core/read/deepbookReadHelpers.js +1 -1
  12. package/dist/core/read/readResponseGuidance.js +6 -6
  13. package/dist/core/session/cardResult.js +41 -0
  14. package/dist/core/session/cardSession.js +1 -1
  15. package/dist/core/session/cardSessionStore.js +51 -19
  16. package/dist/core/session/chainAccounts.js +120 -0
  17. package/dist/core/session/sessionStore.js +4 -8
  18. package/dist/core/session/settingsFileProtocol.js +1 -1
  19. package/dist/core/session/settingsFileStore.js +3 -30
  20. package/dist/core/session/settingsOperation.js +27 -19
  21. package/dist/core/session/settingsWorkflow.js +161 -87
  22. package/dist/core/session/sqliteCardStore.js +34 -14
  23. package/dist/core/session/sqliteSessionStore.js +5 -5
  24. package/dist/core/session/sqliteSettingsWorkflowStore.js +135 -41
  25. package/dist/core/session/sqliteTransactionRequest.js +18 -0
  26. package/dist/core/session/sqliteWalletConnectionOperation.js +13 -0
  27. package/dist/core/session/sqliteWalletWorkflowStore.js +569 -333
  28. package/dist/core/session/status.js +2 -2
  29. package/dist/core/session/wait.js +6 -11
  30. package/dist/core/session/walletConnection.js +71 -46
  31. package/dist/core/session/walletConnectionOperations.js +24 -0
  32. package/dist/core/session/walletRuntime.js +7 -13
  33. package/dist/core/session/walletWorkflow.js +248 -99
  34. package/dist/core/session/workflowState.js +104 -38
  35. package/dist/core/session/workflowView.js +92 -101
  36. package/dist/mcp/activeAccountResponse.js +3 -0
  37. package/dist/mcp/prompts.js +10 -4
  38. package/dist/mcp/resources.js +1 -1
  39. package/dist/mcp/responseGuidance.js +7 -9
  40. package/dist/mcp/server.js +2 -2
  41. package/dist/mcp/serverInfo.js +21 -19
  42. package/dist/mcp/toolErrors.js +5 -3
  43. package/dist/mcp/toolNames.js +47 -46
  44. package/dist/mcp/tools/action/prepareSuiActionReview.js +13 -20
  45. package/dist/mcp/tools/read/deepbookReadTools.js +1 -1
  46. package/dist/mcp/tools/read/index.js +2 -2
  47. package/dist/mcp/tools/read/readToolHelpers.js +9 -7
  48. package/dist/mcp/tools/read/serverStatusTools.js +4 -5
  49. package/dist/mcp/tools/read/transactionActivityTools.js +3 -3
  50. package/dist/mcp/tools/session/executionResultTools.js +2 -2
  51. package/dist/mcp/tools/session/shared.js +2 -2
  52. package/dist/mcp/tools/session/statusTools.js +12 -10
  53. package/dist/mcp/tools/session/walletConnectionTools.js +29 -17
  54. package/dist/mcp/tools/settings/index.js +7 -4
  55. package/dist/mcp-app/account.html +7 -7
  56. package/dist/mcp-app/chart.html +3 -3
  57. package/dist/mcp-app/connect.html +13 -13
  58. package/dist/mcp-app/disconnect.html +3637 -0
  59. package/dist/mcp-app/disconnect.notices.txt +1480 -0
  60. package/dist/mcp-app/receipt.html +393 -393
  61. package/dist/mcp-app/review.html +459 -459
  62. package/dist/mcp-app/settings.html +7 -7
  63. package/dist/mcp-ui/contracts.js +3 -1
  64. package/dist/mcp-ui/tools.js +4 -4
  65. package/dist/runtime/application.js +3 -3
  66. package/dist/runtime/config.js +3 -6
  67. package/dist/runtime/localSettingsService.js +11 -8
  68. package/dist/runtime/shared/control.js +2 -2
  69. package/dist/runtime/smokeMainnetRead.js +23 -22
  70. package/dist/runtime/smokeReview.js +7 -7
  71. package/dist/runtime/start.js +1 -1
  72. package/dist/runtime/walletConnectTransport.js +16 -16
  73. package/dist/runtime/walletSdkChildRuntime.js +29 -12
  74. package/dist/runtime/walletSdkIpc.js +5 -4
  75. package/dist/runtime/walletSdkProcess.js +24 -8
  76. package/docs/AGENT_BEHAVIOR.md +149 -120
  77. package/docs/LOCAL_DB_ARCHITECTURE.md +103 -75
  78. package/docs/MCP_SETUP.md +365 -382
  79. package/docs/MCP_TOOLS.md +387 -271
  80. package/docs/SDK_API.md +23 -11
  81. package/docs/SIGNABLE_ADAPTER_CONTRACT.md +6 -6
  82. package/docs/TRANSACTION_ACTIVITY_LOG.md +11 -7
  83. package/docs/UTILITY_INDEX.md +66 -64
  84. package/docs/WALLET_CONNECTION.md +162 -166
  85. package/package.json +1 -1
  86. package/protocols/deepbook-margin.md +1 -1
  87. package/protocols/deepbook-v3.md +2 -2
@@ -1,80 +1,146 @@
1
- import { walletConnectionSelection } from "./walletConnection.js";
1
+ import { CONNECTION_RECONCILIATION_MESSAGE, walletConnectionEligibility, usableWalletConnection, connectionHasSuiSigningScope, projectWalletConnection } from "./walletConnection.js";
2
2
  import { isInitialChainObservation } from "./transactionRequest.js";
3
- export const workflowActions = ["connect", "disconnect", "use_account", "stop_connection", "prepare_review",
3
+ import { SUI_MAINNET_WALLET_CHAIN } from "./chainAccounts.js";
4
+ import { parseSuiAddress } from "../suiAddress.js";
5
+ export const workflowActions = ["connect", "disconnect", "stop_connection", "prepare_review",
4
6
  "request_signature", "cancel", "stop_waiting", "read_result"];
5
- export function reviewPreparationAccount(boundAccount, activeAccount, selectedAccount = activeAccount) {
6
- if (!activeAccount)
7
- return { allowed: false, message: "No account from a connected wallet is selected for this review." };
8
- if (boundAccount && boundAccount !== activeAccount)
9
- return { allowed: false,
10
- message: `This review uses ${boundAccount}, but the currently selected account is ${activeAccount}.` };
11
- if (selectedAccount !== activeAccount)
12
- return { allowed: false,
13
- message: "The selected account has changed since this request was made." };
14
- return { allowed: true, account: activeAccount };
7
+ export const workflowNextSteps = ["none", "wait", "check_status", "open_settings", "request_disconnect", "request_review"];
8
+ function walletServiceNextStep(status) {
9
+ if (status === "available")
10
+ return undefined;
11
+ return { kind: status === "unavailable" ? "open_settings" : "wait", reason: "wallet_unavailable",
12
+ message: status === "unavailable" ? "Open Settings, then Troubleshooting, to restart the connection service. No wallet request was sent."
13
+ : "Wait for the connection service to finish starting, then check status." };
14
+ }
15
+ export function walletActionDecision(facts, action, targetId) {
16
+ const deny = (kind, reason, message) => ({ allowed: false, nextStep: { kind, reason, message } });
17
+ const service = walletServiceNextStep(facts.walletAvailability.status);
18
+ if (service)
19
+ return { allowed: false, nextStep: service };
20
+ if (facts.pendingOperation)
21
+ return deny("check_status", "operation_busy", "Wait for the current wallet operation and its cleanup to finish, then check this request's status.");
22
+ const selection = walletConnectionEligibility(facts.connection, Date.parse(facts.evaluatedAt), facts.connectionPresence, facts.activeAccount, facts.readAddressCleared);
23
+ if (!facts.connectionPresence.confirmed || !facts.connectionPresence.managed || selection.connectionReconciliationRequired)
24
+ return deny("check_status", "connection_state_unconfirmed", selection.connectionReconciliationRequired ? CONNECTION_RECONCILIATION_MESSAGE : "The wallet session has not been confirmed. Check its status before continuing.");
25
+ if (action === "connect") {
26
+ if (!facts.requestedChains.length)
27
+ return deny("open_settings", "wallet_networks_required", "Choose networks in Settings before requesting a wallet connection.");
28
+ return selection.pairingAllowed ? { allowed: true, nextStep: { kind: "none" } }
29
+ : deny("request_disconnect", "connection_present", "Ask in chat for a Disconnect card before requesting a new wallet connection.");
30
+ }
31
+ if (targetId && facts.connection?.connectionId !== targetId)
32
+ return deny("check_status", "connection_target_changed", "The wallet session for this card is no longer current. Ask in chat for current connection status.");
33
+ return selection.manageable ? { allowed: true, nextStep: { kind: "none" } }
34
+ : deny("none", "no_session_to_disconnect", "There is no current wallet session to disconnect. No request was sent.");
35
+ }
36
+ export function fixedReviewTarget(session, input) {
37
+ const hasInputTarget = input?.connectionId !== undefined || input?.account !== undefined;
38
+ const inputId = typeof input?.connectionId === "string" && input.connectionId.length ? input.connectionId : undefined;
39
+ const inputAccount = typeof input?.account === "string" ? parseSuiAddress(input.account) : undefined;
40
+ if (hasInputTarget && (!inputId || !inputAccount))
41
+ return undefined;
42
+ if (inputId && session.walletConnectionId && inputId !== session.walletConnectionId ||
43
+ inputAccount && session.account && inputAccount !== session.account)
44
+ return undefined;
45
+ const connectionId = inputId ?? session.walletConnectionId, account = inputAccount ?? session.account;
46
+ return connectionId && account ? { connectionId, account } : undefined;
15
47
  }
16
48
  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);
49
+ const selection = walletConnectionEligibility(facts.connection, Date.parse(facts.evaluatedAt), facts.connectionPresence, facts.activeAccount, facts.readAddressCleared);
18
50
  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 : [],
51
+ return { selection, usableConnectionId: available && dependent ? selection.connection?.connectionId : undefined,
52
+ assetReadAccount: !dependent ? undefined : available ? selection.assetReadAccount : { status: "address_required" },
53
+ connection: projectWalletConnection(facts.connection, Date.parse(facts.evaluatedAt), facts.connectionPresence, available),
54
+ pendingOperation: facts.pendingOperation,
55
+ canDisconnect: available && selection.manageable,
24
56
  connectionReconciliationRequired: available && dependent ? selection.connectionReconciliationRequired : undefined };
25
57
  }
26
58
  export function workflowEligibility(facts) {
27
59
  const { record, session, request, authority, walletAvailability } = facts;
28
60
  const at = Date.parse(facts.evaluatedAt);
29
- const cardRemaining = record?.ownerId === facts.ownerId ? Math.max(0, Date.parse(record.state.expiresAt) - at) : 0;
61
+ const cardRemaining = record?.ownerId === facts.ownerId && record.state.reason !== "cancelled"
62
+ ? Math.max(0, Date.parse(record.state.expiresAt) - at) : 0;
30
63
  const remaining = record?.scope === "review" && session && !request
31
64
  ? Math.min(cardRemaining, Math.max(0, Date.parse(session.expiresAt) - at)) : cardRemaining;
32
65
  const inputAvailable = remaining > 0 && record?.state.state === "ready" && record.acceptedInput === undefined;
33
66
  const allowedActions = [];
34
67
  const { selection, ...connectionEligibility } = workflowConnectionEligibility(facts);
35
- const { assetReadAccount } = connectionEligibility;
36
- let preparationIssue;
37
- if (record?.scope === "connect") {
68
+ const reviewTarget = session && !session.plans[0]?.reviewModel ? fixedReviewTarget(session, record?.state.input) : undefined;
69
+ const targetId = reviewTarget?.connectionId, targetAccount = reviewTarget?.account;
70
+ const reviewConnection = walletAvailability.status === "available" && !facts.connectionPresence.unrecorded && facts.walletDependent !== false && targetId && targetAccount
71
+ ? usableWalletConnection(facts.connection, at, facts.connectionPresence, targetId, SUI_MAINNET_WALLET_CHAIN, targetAccount) : undefined;
72
+ const preparationIssue = session && record?.scope === "review" && !session.plans[0]?.reviewModel && !reviewTarget
73
+ ? "This review has no matching fixed wallet target. Start a new review." : undefined;
74
+ const scopedDisconnect = record?.scope === "disconnect";
75
+ const walletDecision = walletActionDecision(facts, scopedDisconnect ? "disconnect" : "connect", scopedDisconnect ? String(record?.state.input.connectionId) : undefined);
76
+ let nextStep = facts.operation?.status === "running" && facts.operation.cardId === record?.state.cardId
77
+ ? { kind: "wait" } : walletDecision.nextStep;
78
+ const disconnectTargetMatches = !scopedDisconnect || record.state.input.connectionId === facts.connection?.connectionId;
79
+ if (record?.scope === "connect" || scopedDisconnect) {
38
80
  if (inputAvailable) {
39
81
  allowedActions.push("cancel");
40
82
  if (walletAvailability.status === "available") {
41
- if (["connect", "manage"].includes(String(record.state.input.intent)) && selection.pairingAllowed)
83
+ if (record.scope === "connect" && walletDecision.allowed)
42
84
  allowedActions.push("connect");
43
- if (selection.manageableConnectionIds.length)
85
+ if (scopedDisconnect && walletDecision.allowed)
44
86
  allowedActions.push("disconnect");
45
- if (selection.connection)
46
- allowedActions.push("use_account");
47
87
  }
48
88
  }
49
- if (remaining > 0 && facts.connection?.status === "awaiting_approval")
89
+ if (record.state.state !== "closed" && remaining > 0 && facts.operation?.action === "connect" && facts.operation.status === "running")
50
90
  allowedActions.push("stop_connection");
51
91
  }
52
92
  if (session && inputAvailable && record?.scope === "review" && session.status !== "expired" && Date.parse(session.expiresAt) > at && !session.preparationId) {
53
93
  allowedActions.push("cancel");
54
- if (walletAvailability.status === "available" && selection.connection && !session.plans[0]?.reviewModel) {
55
- const account = reviewPreparationAccount(session.account, assetReadAccount?.status === "available" ? assetReadAccount.account : undefined);
56
- if (!account.allowed)
57
- preparationIssue = account.message;
58
- else if (!facts.busyForAccount)
94
+ if (walletAvailability.status === "available" && reviewConnection && !session.plans[0]?.reviewModel) {
95
+ if (!facts.busyForAccount)
59
96
  allowedActions.push("prepare_review");
60
- if (!facts.busyForAccount && session.status === "ready_for_wallet_review" && session.reviewState?.transactionReviewData &&
97
+ if (!facts.busyForAccount && connectionHasSuiSigningScope(reviewConnection, targetAccount) && session.status === "ready_for_wallet_review" && session.reviewState?.transactionReviewData &&
61
98
  (!request || request.reviewRevision !== session.reviewRevision))
62
99
  allowedActions.push("request_signature");
63
100
  }
64
101
  }
65
- if (record && session && remaining > 0 && request && request.reviewSessionId === session.id &&
102
+ if (record && record.state.state !== "closed" && session && remaining > 0 && request && request.reviewSessionId === session.id &&
66
103
  authority?.owner_id === facts.ownerId &&
67
104
  (record.operationId === request.attemptId || record.scope === "review_manage" && record.state.input.attemptId === request.attemptId)) {
68
- if (["awaiting_signature", "submitting", "awaiting_chain_result"].includes(request.requestStatus))
105
+ if (request.requestStatus === "awaiting_signature" || !authority.observation_stopped && isInitialChainObservation(request.requestStatus))
69
106
  allowedActions.push("stop_waiting");
70
- if (isInitialChainObservation(request.requestStatus) || request.requestStatus === "outcome_unknown")
107
+ if (record.scope === "review_manage" && record.state.state === "ready" && record.acceptedInput === undefined && (isInitialChainObservation(request.requestStatus) || request.requestStatus === "outcome_unknown"))
71
108
  allowedActions.push("read_result");
72
109
  }
73
110
  const expiry = session && inputAvailable && record?.scope === "review" && !session.preparationId &&
74
111
  session.status === "ready_for_wallet_review" && (!request || request.reviewRevision !== session.reviewRevision)
75
112
  ? session.reviewState?.humanReadableReview?.freshness.expiresAt : undefined;
76
- const nextRead = expiry && session ? Math.min(remaining, Date.parse(session.expiresAt) - at, Date.parse(expiry) - at) : undefined;
77
- return { allowedActions, preparationIssue, ...connectionEligibility,
113
+ const reviewRead = expiry && session ? Math.min(remaining, Date.parse(session.expiresAt) - at, Date.parse(expiry) - at) : undefined;
114
+ const connectionDeadlines = inputAvailable && facts.walletDependent !== false && facts.connection?.status === "connected" &&
115
+ (["connect", "disconnect"].includes(record?.scope ?? "") || facts.connection.connectionId === reviewTarget?.connectionId)
116
+ ? [Date.parse(facts.connection.expiresAt) - at].filter((delay) => delay > 0) : [];
117
+ const readDelays = [reviewRead, ...connectionDeadlines].filter((delay) => delay !== undefined && delay > 0);
118
+ const nextRead = readDelays.length ? Math.min(...readDelays) : undefined;
119
+ if (session) {
120
+ nextStep = { kind: "none" };
121
+ if (!session.plans[0]?.reviewModel && !request) {
122
+ const service = walletServiceNextStep(walletAvailability.status);
123
+ if (service)
124
+ nextStep = service;
125
+ else if (facts.connectionPresence.unrecorded)
126
+ nextStep = { kind: "check_status", reason: "connection_state_unconfirmed", message: CONNECTION_RECONCILIATION_MESSAGE };
127
+ else if (facts.pendingOperation)
128
+ nextStep = { kind: "check_status", reason: "operation_busy", message: "Wait for the current wallet operation and its cleanup to finish, then check this review's status." };
129
+ else if (reviewTarget && connectionEligibility.connection?.connectionId === targetId && connectionEligibility.connection?.sessionPresence === "absent")
130
+ nextStep = { kind: "request_review", message: "The original wallet session is no longer present. Reconnect a wallet and ask in chat for a new transaction review." };
131
+ else if (reviewTarget && facts.connection && facts.connection.connectionId !== targetId)
132
+ nextStep = { kind: "request_review", message: "This review belongs to the earlier wallet connection. Ask in chat for a new transaction review." };
133
+ else if (!reviewConnection && connectionEligibility.canDisconnect && facts.connection?.connectionId === targetId)
134
+ nextStep = { kind: "request_disconnect", message: "The original wallet connection is unavailable. Ask in chat for a Disconnect card, then start a new review after reconnecting." };
135
+ else if (!reviewConnection)
136
+ nextStep = { kind: "check_status", message: "This review keeps its original account and connection. Ask in chat to check that wallet connection's status before continuing." };
137
+ else if (facts.busyForAccount)
138
+ nextStep = { kind: "wait", message: "A previous transaction request for this Sui account is still pending. Wait for it to finish, then check this review's status." };
139
+ }
140
+ }
141
+ return { allowedActions, preparationIssue, nextStep, ...connectionEligibility, reviewTarget,
142
+ canDisconnect: connectionEligibility.canDisconnect && disconnectTargetMatches,
143
+ ...(session ? { usableConnectionId: reviewConnection?.connectionId } : {}),
78
144
  actionRemainingMs: remaining, inputRemainingMs: inputAvailable ? remaining : 0,
79
145
  ...(nextRead !== undefined && nextRead > 0 ? { nextStateReadAfterMs: nextRead } : {}) };
80
146
  }
@@ -1,84 +1,86 @@
1
- import { workflowActions } from "./workflowState.js";
1
+ import { workflowActions, workflowNextSteps } from "./workflowState.js";
2
2
  import { z } from "zod";
3
- import { suiAddressStringSchema, parseSuiAddress } from "../suiAddress.js";
3
+ import { suiAddressStringSchema } from "../suiAddress.js";
4
4
  import { actionPlanSchema, internalSessionStatusSchema, reviewStateOutputSchema } from "../action/schemas.js";
5
- import { walletConnectionSchema, walletAvailabilitySchema, workflowProgressSchema, WALLET_CONNECTION_POLL_SECONDS, connectionConflictSchema, assetReadAccountSchema } from "./walletConnection.js";
5
+ import { walletConnectionSchema, walletAvailabilitySchema, workflowProgressSchema, WALLET_CONNECTION_POLL_SECONDS, connectionChainStateSchema } from "./walletConnection.js";
6
6
  import { transactionRequestSchema } from "./transactionRequest.js";
7
7
  import { workflowProgress } from "./walletConnection.js";
8
8
  import { reviewProgress, EXECUTION_POLLING_INTERVAL_SECONDS } from "./status.js";
9
- import { walletRunIdSchema, walletRecoverySchema, walletObservationSchema } from "./walletRuntime.js";
9
+ import { walletRunIdSchema, walletObservationSchema } from "./walletRuntime.js";
10
+ import { walletConnectionActionSchema, walletConnectionOperationSchema } from "./walletConnectionOperations.js";
11
+ import { walletChainSchema, walletChainsSchema, SUI_MAINNET_WALLET_CHAIN, normalizeChainAddress } from "./chainAccounts.js";
10
12
  export const CONNECT_BOUNDARY = "A wallet connection provides account context; it is not a transaction approval or proof of address ownership.";
11
13
  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
- export const connectionViewSchema = walletConnectionSchema.extend({ pendingAction: z.literal("disconnect").optional() });
14
+ export const connectionViewSchema = walletConnectionSchema.extend({
15
+ sessionPresence: z.enum(["present", "absent", "unusable", "unconfirmed"]),
16
+ chainStates: z.array(connectionChainStateSchema).optional(),
17
+ disconnectImpact: z.object({ impactId: z.string(), requestCount: z.number().int().nonnegative(), chains: walletChainsSchema }).strict().optional()
18
+ });
13
19
  export { assetReadAccountSchema } from "./walletConnection.js";
14
- export const pendingConnectionStatusSchema = z.enum(["input_required", "awaiting_approval", "disconnect_pending"]);
15
- const connectAction = z.object({ action: z.literal("connect"), walletRunId: walletRunIdSchema }).strict();
16
- const disconnectAction = z.object({ action: z.literal("disconnect"), walletRunId: walletRunIdSchema, connectionId: z.string().min(1) }).strict();
17
- const accountAction = z.object({ action: z.literal("use_account"), walletRunId: walletRunIdSchema, connectionId: z.string().min(1), account: suiAddressStringSchema }).strict();
20
+ export const pendingConnectionStatusSchema = z.enum(["awaiting_approval", "disconnect_pending", "cleanup_pending"]);
18
21
  const reviewAction = z.object({ action: z.enum(["prepare_review", "request_signature"]), connectionId: z.string().min(1),
19
22
  walletRunId: walletRunIdSchema, account: suiAddressStringSchema, reviewRevision: z.number().int().nonnegative() }).strict();
20
- const simpleAction = z.object({ action: z.enum(["cancel", "stop_connection", "stop_waiting", "read_result"]) }).strict();
21
- export const workflowActionSchema = z.union([connectAction, disconnectAction, accountAction, reviewAction, simpleAction]);
22
- export const automaticWorkflowActionSchema = z.union([connectAction, reviewAction.extend({ action: z.literal("prepare_review") })]);
23
+ const simpleAction = z.object({ action: z.enum(["cancel", "stop_waiting", "read_result"]) }).strict();
24
+ const stopConnectionAction = z.object({ action: z.literal("stop_connection"), operationId: z.string().uuid() }).strict();
25
+ export const workflowActionSchema = z.union([walletConnectionActionSchema, stopConnectionAction, reviewAction, simpleAction]);
26
+ export const automaticWorkflowActionSchema = z.union([walletConnectionActionSchema.options[0], reviewAction.extend({ action: z.literal("prepare_review") })]);
23
27
  export function parseWorkflowAction(input) {
24
28
  const action = workflowActionSchema.parse(input);
25
- return "account" in action ? { ...action, account: parseSuiAddress(action.account) } : action;
26
- }
27
- export const workflowViewSchema = z.object({
28
- kind: z.enum(["connect", "review"]),
29
- mode: z.enum(["connect", "review", "review_manage"]),
30
- allowedActions: z.array(z.enum(workflowActions)),
31
- actionRemainingMs: z.number().int().nonnegative(),
32
- nextStateReadAfterMs: z.number().int().nonnegative().optional(),
33
- automaticAction: automaticWorkflowActionSchema.optional(),
34
- observe: z.boolean(),
35
- walletAvailability: walletAvailabilitySchema,
36
- walletObservation: walletObservationSchema.optional(),
37
- runtimeRecovery: walletRecoverySchema.optional(),
38
- connectionConflict: connectionConflictSchema.optional(),
39
- manageableConnectionIds: z.array(z.string().min(1)),
40
- connectionReconciliationRequired: z.literal(true).optional(),
41
- usableConnectionId: z.string().min(1).optional(),
42
- assetReadAccount: assetReadAccountSchema.optional(),
43
- acceptedWalletRunId: walletRunIdSchema.optional(),
44
- progress: workflowProgressSchema,
45
- boundary: z.enum([CONNECT_BOUNDARY, REVIEW_BOUNDARY]),
46
- connections: z.array(connectionViewSchema),
47
- activeAccount: z.string().optional(),
48
- connection: connectionViewSchema.optional(),
49
- connectionAction: z.enum(["connect", "disconnect"]).optional(),
50
- review: z.object({
51
- reviewSessionId: z.string(), plan: actionPlanSchema, reviewRevision: z.number().int().nonnegative(),
52
- status: internalSessionStatusSchema, account: z.string().optional(), preparing: z.boolean(),
53
- accountRequestPending: z.literal(true).optional(),
54
- error: z.string().optional(),
55
- state: reviewStateOutputSchema.optional()
56
- }).strict().optional(),
57
- request: transactionRequestSchema.optional(),
58
- receipt: z.unknown().optional(),
59
- netGasMist: z.string().regex(/^-?[0-9]+$/).optional(),
60
- observationStopped: z.boolean().optional()
61
- }).strict().superRefine((view, context) => {
62
- const connection = view.connections.find((item) => item.connectionId === view.usableConnectionId);
63
- if (view.usableConnectionId && (!connection || connection.status !== "connected" ||
64
- view.walletAvailability.status !== "available" || view.connectionConflict || view.connectionReconciliationRequired ||
65
- view.connections.some((item) => item.pendingAction || item.status === "awaiting_approval"))) {
66
- context.addIssue({ code: "custom", path: ["usableConnectionId"], message: "The usable connection must match current connection facts." });
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." });
29
+ if ("account" in action) {
30
+ const account = normalizeChainAddress(SUI_MAINNET_WALLET_CHAIN, action.account);
31
+ if (!account)
32
+ throw new Error("A valid chain account is required.");
33
+ return { ...action, account };
72
34
  }
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
- }
77
- if (view.assetReadAccount?.status === "available" && (!connection ||
78
- !connection.accounts.includes(view.assetReadAccount.account) || view.activeAccount !== view.assetReadAccount.account)) {
79
- context.addIssue({ code: "custom", path: ["assetReadAccount"], message: "The default address must belong to the usable connection and stored selection." });
35
+ return action;
36
+ }
37
+ function checkReviewAccount(view, context) {
38
+ if (view.reviewTarget && (view.review?.account && view.review.account !== view.reviewTarget.account ||
39
+ view.request && view.request.account !== view.reviewTarget.account)) {
40
+ context.addIssue({ code: "custom", path: ["reviewTarget"], message: "The fixed review target must match its recorded account and request." });
80
41
  }
81
- });
42
+ }
43
+ const nextStepSchema = z.object({ kind: z.enum(workflowNextSteps), message: z.string().optional(), reason: z.string().optional() }).strict();
44
+ const liveFields = {
45
+ allowedActions: z.array(z.enum(workflowActions)), actionRemainingMs: z.number().int().nonnegative(),
46
+ nextStateReadAfterMs: z.number().int().nonnegative().optional(), observe: z.boolean(),
47
+ walletAvailability: walletAvailabilitySchema, walletObservation: walletObservationSchema.optional(),
48
+ progress: workflowProgressSchema, nextStep: nextStepSchema
49
+ };
50
+ export const connectViewSchema = z.object({ ...liveFields, kind: z.literal("connect"), mode: z.literal("connect"),
51
+ allowedActions: z.array(z.enum(["connect", "cancel", "stop_connection"])),
52
+ boundary: z.literal(CONNECT_BOUNDARY), requestedChains: walletChainsSchema,
53
+ operation: walletConnectionOperationSchema.optional(), automaticAction: walletConnectionActionSchema.options[0].optional() }).strict();
54
+ export const disconnectViewSchema = z.object({ ...liveFields, kind: z.literal("disconnect"), mode: z.literal("disconnect"),
55
+ allowedActions: z.array(z.enum(["disconnect", "cancel"])),
56
+ boundary: z.literal(CONNECT_BOUNDARY), connection: connectionViewSchema.optional(),
57
+ operation: walletConnectionOperationSchema.optional() }).strict();
58
+ const reviewPayloadSchema = z.object({
59
+ reviewSessionId: z.string(), plan: actionPlanSchema, reviewRevision: z.number().int().nonnegative(),
60
+ status: internalSessionStatusSchema, account: z.string().optional(), preparing: z.boolean(),
61
+ accountRequestPending: z.literal(true).optional(), error: z.string().optional(), state: reviewStateOutputSchema.optional()
62
+ }).strict();
63
+ const reviewTargetSchema = z.object({ connectionId: z.string(), account: suiAddressStringSchema }).strict();
64
+ const netGasSchema = z.string().regex(/^-?[0-9]+$/).optional();
65
+ export const reviewViewSchema = z.object({ ...liveFields, kind: z.literal("review"), mode: z.enum(["review", "review_manage"]),
66
+ allowedActions: z.array(z.enum(["prepare_review", "request_signature", "read_result", "stop_waiting", "cancel"])),
67
+ boundary: z.literal(REVIEW_BOUNDARY), reviewTarget: reviewTargetSchema.optional(), review: reviewPayloadSchema,
68
+ walletName: z.string().optional(), acceptedWalletRunId: walletRunIdSchema.optional(),
69
+ automaticAction: reviewAction.extend({ action: z.literal("prepare_review") }).optional(),
70
+ request: transactionRequestSchema.optional(), receipt: z.unknown().optional(), netGasMist: netGasSchema,
71
+ observationStopped: z.boolean().optional()
72
+ }).strict().superRefine(checkReviewAccount);
73
+ export const workflowViewSchema = z.discriminatedUnion("kind", [connectViewSchema, disconnectViewSchema, reviewViewSchema]);
74
+ const closedResult = z.object({ message: z.string(), recordedAt: z.string().datetime() }).strict();
75
+ const closedFields = { allowedActions: z.array(z.never()), observe: z.literal(false), actionRemainingMs: z.literal(0), result: closedResult };
76
+ export const closedWalletCardSchema = z.object({ ...closedFields, kind: z.enum(["connect", "disconnect"]),
77
+ result: closedResult.extend({ pendingWork: z.enum(["approval_response", "session_removal", "session_status"]).optional() }), walletName: z.string().optional(),
78
+ networks: z.array(z.object({ chainId: walletChainSchema, status: z.enum(["bound", "not_approved", "multiple_accounts", "invalid_response"]) }).strict()) }).strict();
79
+ export const closedReviewCardSchema = z.object({ ...closedFields, kind: z.literal("review"),
80
+ mode: z.enum(["review", "review_manage"]), review: reviewPayloadSchema.optional(),
81
+ reviewTarget: reviewTargetSchema.optional(), request: transactionRequestSchema.optional(),
82
+ receipt: z.unknown().optional(), netGasMist: netGasSchema,
83
+ observationStopped: z.boolean().optional(), boundary: z.literal(REVIEW_BOUNDARY) }).strict().superRefine(checkReviewAccount);
82
84
  function automaticReviewAction(input) {
83
85
  const { record, session, request } = input;
84
86
  if (!session || record?.scope !== "review" || request || session.preparationError ||
@@ -86,18 +88,11 @@ function automaticReviewAction(input) {
86
88
  return undefined;
87
89
  const needsPreparation = !session.reviewState && session.reviewRevision === 0 ||
88
90
  session.reviewState?.status === "refresh_required" && session.reviewState.refreshReason === "review_evidence_stale";
89
- if (!needsPreparation || input.assetReadAccount?.status !== "available")
90
- return undefined;
91
- const account = input.assetReadAccount.account;
92
- const candidates = reviewWalletChoices(input, account);
93
- if (candidates.length !== 1)
91
+ if (!needsPreparation || !input.reviewTarget)
94
92
  return undefined;
95
- return { action: "prepare_review", walletRunId: input.walletAvailability.walletRunId, connectionId: candidates[0].connectionId,
96
- account, reviewRevision: session.reviewRevision };
97
- }
98
- export function reviewWalletChoices(selection, account, requireSigningMethod = false) {
99
- return selection.connections.filter((item) => item.connectionId === selection.usableConnectionId && item.accounts.includes(account) &&
100
- (!requireSigningMethod || item.methods.includes("sui_signTransaction")));
93
+ const account = input.reviewTarget.account;
94
+ return { action: "prepare_review", walletRunId: input.walletAvailability.walletRunId,
95
+ connectionId: input.reviewTarget.connectionId, account, reviewRevision: session.reviewRevision };
101
96
  }
102
97
  function nextStateRead(input) {
103
98
  const walletInput = input.record?.state.state === "ready" && input.record.scope !== "review_manage" && !input.request &&
@@ -109,24 +104,20 @@ function nextStateRead(input) {
109
104
  return delays.length ? Math.min(...delays) : undefined;
110
105
  }
111
106
  export function projectConnectionView(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;
116
- const readAfter = nextStateRead(input);
117
- const progress = input.runtimeRecovery ? { status: "phase" in input.runtimeRecovery ? "waiting" : "idle" } :
118
- workflowProgress(connection?.status === "awaiting_approval" || connection?.pendingAction === "disconnect", true, walletAvailability);
119
- return workflowViewSchema.parse({ kind: "connect", mode: "connect", allowedActions: input.allowedActions,
120
- actionRemainingMs: input.actionRemainingMs, observe: progress.status === "waiting", progress, walletAvailability,
121
- ...(input.record?.state.input.intent === "connect" && input.allowedActions.includes("connect")
122
- ? { automaticAction: { action: "connect", walletRunId: walletAvailability.walletRunId } } : {}),
123
- runtimeRecovery: input.runtimeRecovery, walletObservation: input.walletObservation,
124
- connectionConflict: input.connectionConflict, usableConnectionId: input.usableConnectionId, assetReadAccount: input.assetReadAccount,
125
- manageableConnectionIds: input.manageableConnectionIds, connectionReconciliationRequired: input.connectionReconciliationRequired,
126
- connectionAction: ["connect", "disconnect"].includes(String(input.record?.acceptedInput?.action)) ? input.record?.acceptedInput?.action : undefined,
127
- acceptedWalletRunId: input.record?.acceptedInput?.walletRunId,
128
- ...(readAfter === undefined ? {} : { nextStateReadAfterMs: readAfter }),
129
- connections: input.connections, activeAccount: input.activeAccount, connection, boundary: CONNECT_BOUNDARY });
107
+ const { walletAvailability, operation } = input, readAfter = nextStateRead(input);
108
+ const progress = workflowProgress(!!operation && operation.status === "running", true, walletAvailability);
109
+ const common = { allowedActions: input.allowedActions, actionRemainingMs: input.actionRemainingMs,
110
+ observe: progress.status === "waiting", progress, walletAvailability, walletObservation: input.walletObservation,
111
+ operation, nextStep: input.nextStep, boundary: CONNECT_BOUNDARY,
112
+ ...(readAfter === undefined ? {} : { nextStateReadAfterMs: readAfter }) };
113
+ if (input.record?.scope === "disconnect")
114
+ return disconnectViewSchema.parse({ ...common, kind: "disconnect", mode: "disconnect",
115
+ connection: input.connection?.connectionId === input.record.state.input.connectionId ? input.connection : undefined });
116
+ return connectViewSchema.parse({ ...common, kind: "connect", mode: "connect",
117
+ requestedChains: walletChainsSchema.parse(input.record?.state.input.requestedChains ?? input.requestedChains),
118
+ ...(!operation && input.record?.operationId && input.allowedActions.includes("connect")
119
+ ? { automaticAction: { action: "connect", operationId: input.record.operationId, walletRunId: walletAvailability.walletRunId,
120
+ chains: input.record.state.input.requestedChains } } : {}) });
130
121
  }
131
122
  export function projectReviewView(input) {
132
123
  const { record, session, request, authority, walletAvailability, boundReview } = input;
@@ -139,11 +130,11 @@ export function projectReviewView(input) {
139
130
  const gas = displayedReview?.simulation?.gasCostSummary;
140
131
  const automaticAction = automaticReviewAction(input);
141
132
  const readAfter = nextStateRead(input);
142
- return workflowViewSchema.parse({ kind: "review", mode: record.scope === "review_manage" ? "review_manage" : "review",
133
+ return reviewViewSchema.parse({ kind: "review", mode: record.scope === "review_manage" ? "review_manage" : "review",
143
134
  allowedActions: input.allowedActions, actionRemainingMs: input.actionRemainingMs, observe: progress.status === "waiting", progress, walletAvailability,
144
- connections: input.connections, connectionConflict: input.connectionConflict, usableConnectionId: input.usableConnectionId,
145
- manageableConnectionIds: input.manageableConnectionIds, connectionReconciliationRequired: input.connectionReconciliationRequired,
146
- assetReadAccount: input.assetReadAccount, activeAccount: input.activeAccount, boundary: REVIEW_BOUNDARY, receipt: input.receipt,
135
+ reviewTarget: input.reviewTarget, nextStep: input.nextStep,
136
+ walletName: input.connection?.connectionId === input.reviewTarget?.connectionId ? input.connection?.walletName : undefined,
137
+ boundary: REVIEW_BOUNDARY, receipt: input.receipt,
147
138
  walletObservation: input.walletObservation,
148
139
  acceptedWalletRunId: record.acceptedInput?.walletRunId,
149
140
  ...(readAfter === undefined ? {} : { nextStateReadAfterMs: readAfter }),
@@ -153,7 +144,7 @@ export function projectReviewView(input) {
153
144
  status: boundReview?.status ?? session.status, account: boundReview?.account ?? session.account,
154
145
  ...(!request && !session.plans[0]?.reviewModel && input.busyForAccount ? { accountRequestPending: true } : {}),
155
146
  preparing: !boundReview && !!session.preparationId,
156
- error: !boundReview ? [input.preparationIssue && `Current account selection: ${input.preparationIssue}`,
147
+ error: !boundReview ? [input.preparationIssue && `Review target: ${input.preparationIssue}`,
157
148
  session.preparationError && `Earlier review message: “${session.preparationError}”`].filter(Boolean).join("\n\n") || undefined : undefined,
158
149
  state: displayedReview },
159
150
  request, observationStopped: authority ? authority.observation_stopped === 1 : undefined });
@@ -1,8 +1,10 @@
1
+ import { walletChainSchema } from "../core/session/chainAccounts.js";
1
2
  import { z } from "zod";
2
3
  export const activeAccountResponseSchema = z.discriminatedUnion("status", [
3
4
  z.object({
4
5
  status: z.literal("set"),
5
6
  account: z.string(),
7
+ chainId: walletChainSchema,
6
8
  source: z.literal("wallet_connection"),
7
9
  setAt: z.string(),
8
10
  boundary: z.literal("read_context_only_not_signing_authorization")
@@ -16,6 +18,7 @@ export function activeAccountResponse(active) {
16
18
  ? {
17
19
  status: "set",
18
20
  account: active.address,
21
+ chainId: active.chainId,
19
22
  source: active.source,
20
23
  setAt: active.setAt,
21
24
  boundary: "read_context_only_not_signing_authorization"
@@ -8,7 +8,7 @@ export const MCP_PROMPTS = [
8
8
  description: "Review current supported mainnet surfaces and tool status.",
9
9
  text: [
10
10
  "Inspect the Sui MCP server status and supported mainnet Sui protocol surfaces.",
11
- "Use read.get_server_status first, then read.list_supported_protocols.",
11
+ "Use read_get_server_status first, then read_list_supported_protocols.",
12
12
  "Report implemented tools separately from unavailable or blocked surfaces."
13
13
  ].join("\n")
14
14
  },
@@ -18,8 +18,8 @@ export const MCP_PROMPTS = [
18
18
  description: "Prepare a local review session for a supported action proposal.",
19
19
  text: [
20
20
  "Prepare a reviewable Sui action only through Sui MCP's review-session flow.",
21
- "Use action.prepare_external_proposal_review when the input is a structured external payment or Sui action proposal.",
22
- "External proposals get read-only local review and never become signing material. Use action.prepare_sui_action_review for a natural-language swap intent; after a wallet account is connected, account-bound review can reach ready_for_wallet_review, where an explicit Review card action can request approval in the user’s wallet through the backend.",
21
+ "Use action_create_proposal_review when the input is a structured external payment or Sui action proposal.",
22
+ "External proposals get read-only local review and never become signing material. Use action_start_review for a natural-language swap intent; after a wallet account is connected, account-bound review can reach ready_for_wallet_review, where an explicit Review card action can request approval in the user’s wallet through the backend.",
23
23
  "Present the internal Review card and summarize the returned review checks. 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."
24
24
  ].join("\n")
25
25
  }
@@ -56,6 +56,7 @@ function registerSurfacePrompt(server, name, surface, description) {
56
56
  }));
57
57
  }
58
58
  export function registerMcpPrompts(server, surfaces = []) {
59
+ const registeredNames = [];
59
60
  for (const prompt of MCP_PROMPTS) {
60
61
  server.registerPrompt(prompt.name, {
61
62
  title: prompt.title,
@@ -72,13 +73,18 @@ export function registerMcpPrompts(server, surfaces = []) {
72
73
  }
73
74
  ]
74
75
  }));
76
+ registeredNames.push(prompt.name);
75
77
  }
76
78
  for (const surface of surfaces) {
77
- registerSurfacePrompt(server, promptNameFor(surface), surface, surface.description);
79
+ const name = promptNameFor(surface);
80
+ registerSurfacePrompt(server, name, surface, surface.description);
81
+ registeredNames.push(name);
78
82
  }
79
83
  for (const [action, group] of actionGroups(surfaces)) {
80
84
  registerBareActionPrompt(server, action, group);
85
+ registeredNames.push(action);
81
86
  }
87
+ return registeredNames;
82
88
  }
83
89
  export function bareActionPromptText(action, group, intent, protocol) {
84
90
  const chosen = group.length === 1 ? group[0] : group.find((surface) => surface.protocolSlug === (protocol ?? "").trim());
@@ -42,7 +42,7 @@ export const MCP_RESOURCES = [
42
42
  name: "deepbook-v3",
43
43
  uri: "suimcp://protocols/deepbook-v3",
44
44
  title: "DeepBookV3",
45
- description: "Protocol reference only; use MCP tool responses and read.list_supported_protocols for current support.",
45
+ description: "Protocol reference only; use MCP tool responses and read_list_supported_protocols for current support.",
46
46
  path: "protocols/deepbook-v3.md"
47
47
  },
48
48
  {
@@ -1,13 +1,12 @@
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, reconciliationRequired = false) {
3
+ export function interactionStatusUserAnswerUse(hasWalletObservation = false, reconciliationRequired = false) {
4
4
  return {
5
5
  canAnswer: [
6
6
  "stored_active_account_read_context",
7
7
  "wallet_connections_when_wallet_availability_is_available",
8
8
  "connection_qualified_default_asset_account",
9
9
  "pending_local_wallet_connection_interactions",
10
- ...(hasConnectionConflict ? ["multiple_saved_connections_require_user_targeted_disconnection"] : []),
11
10
  ...(reconciliationRequired ? ["unrecorded_service_connection_requires_wallet_removal_and_confirmed_absence"] : []),
12
11
  "pending_local_review_interactions",
13
12
  "wallet_operation_availability_separate_from_stored_transaction_facts"
@@ -25,11 +24,10 @@ export function interactionStatusUserAnswerUse(hasWalletObservation = false, has
25
24
  "complete_wallet_history",
26
25
  "profit_or_pnl"
27
26
  ],
28
- preconditionFields: ["walletAvailability", "assetReadAccount", ...(hasConnectionConflict ? ["connectionConflict"] : []),
27
+ preconditionFields: ["walletAvailability", "assetReadAccount",
29
28
  ...(reconciliationRequired ? ["connectionReconciliationRequired"] : [])],
30
- answerFields: ["activeAccount", "connections", "assetReadAccount", "pendingWalletConnections", "pendingReviewSessions", "walletAvailability",
31
- ...(hasConnectionConflict ? ["connectionConflict"] : []),
32
- "manageableConnectionIds", ...(reconciliationRequired ? ["connectionReconciliationRequired"] : []),
29
+ answerFields: ["activeAccount", "requestedChains", "connection", "assetReadAccount", "pendingWalletConnections", "pendingReviewSessions", "walletAvailability",
30
+ "canDisconnect", ...(reconciliationRequired ? ["connectionReconciliationRequired"] : []),
33
31
  ...(hasWalletObservation ? ["walletObservation"] : [])],
34
32
  diagnosticOnlyFields: [
35
33
  "pendingWalletConnections.truncated",
@@ -69,7 +67,7 @@ export function executionResultUserAnswerUse(fields = {}) {
69
67
  "profit_or_pnl"
70
68
  ],
71
69
  answerFields: [
72
- "walletAvailability", "progress", ...(fields.hasConnectionConflict ? ["connectionConflict"] : []),
70
+ "walletAvailability", "progress",
73
71
  ...(fields.reconciliationRequired ? ["connectionReconciliationRequired"] : []), ...(hasWaitOutcome ? ["waitOutcome"] : []),
74
72
  "reviewSessionId",
75
73
  "status",
@@ -95,7 +93,7 @@ export function executionResultUserAnswerUse(fields = {}) {
95
93
  }
96
94
  };
97
95
  }
98
- export function reviewStatusUserAnswerUse(hasReviewState, hasAdapterLifecycle = false, hasHumanReadableReview = false, hasSimulation = false, hasConnectionConflict = false, reconciliationRequired = false) {
96
+ export function reviewStatusUserAnswerUse(hasReviewState, hasAdapterLifecycle = false, hasHumanReadableReview = false, hasSimulation = false, reconciliationRequired = false) {
99
97
  return {
100
98
  canAnswer: [
101
99
  "current_local_review_session_status",
@@ -119,7 +117,7 @@ export function reviewStatusUserAnswerUse(hasReviewState, hasAdapterLifecycle =
119
117
  "profit_or_pnl"
120
118
  ],
121
119
  answerFields: [
122
- "walletAvailability", "progress", ...(hasConnectionConflict ? ["connectionConflict"] : []),
120
+ "walletAvailability", "progress",
123
121
  ...(reconciliationRequired ? ["connectionReconciliationRequired"] : []), "reviewSessionId",
124
122
  "status",
125
123
  "pollingStatus",
@@ -19,9 +19,9 @@ export function createMcpServer(deps) {
19
19
  });
20
20
  registerMcpResources(server);
21
21
  registerReadCards(server, deps);
22
- registerMcpPrompts(server, deps.promptSurfaces ?? []);
22
+ const registeredPromptNames = registerMcpPrompts(server, deps.promptSurfaces ?? []);
23
23
  registerAccountTools(server, deps);
24
- registerReadTools(server, deps);
24
+ registerReadTools(server, deps, registeredPromptNames);
25
25
  registerSettingsTools(server, deps);
26
26
  registerActionTools(server, deps);
27
27
  registerSessionTools(server, deps);