@zktx.io/sui-mcp 0.6.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.
- package/README.md +18 -18
- package/dist/adapters/adapterPromptSurfaces.js +0 -20
- package/dist/adapters/deepbook/deepbookQuotePolicy.js +0 -4
- package/dist/adapters/deepbook/deepbookReviewEvidence.js +0 -9
- package/dist/adapters/deepbook/deepbookTransactionMaterialProducer.js +0 -9
- package/dist/adapters/intentPlanFactories.js +0 -6
- package/dist/core/action/contractNameRegistry.js +0 -53
- package/dist/core/action/forbiddenFields.js +0 -4
- package/dist/core/action/ptbVisualizationProducer.js +0 -3
- package/dist/core/action/receiptPtbGraph.js +0 -17
- package/dist/core/action/reviewTimeSimulationEvidence.js +0 -4
- package/dist/core/action/signableAdapterContract.js +0 -5
- package/dist/core/action/suiChainReceiptMapping.js +0 -18
- package/dist/core/action/suiChainReceiptReader.js +1 -21
- package/dist/core/action/suiChainReceiptVerifier.js +0 -10
- package/dist/core/action/transactionFunding.js +0 -7
- package/dist/core/action/types.js +0 -1
- package/dist/core/action/walletReviewContractAssembler.js +0 -2
- package/dist/core/activity/localDataService.js +0 -6
- package/dist/core/activity/sqliteActivityStore.js +0 -8
- package/dist/core/activity/sqliteActivityStoreRows.js +0 -2
- package/dist/core/activity/sqliteActivityStoreSchema.js +0 -4
- package/dist/core/read/deepbookReadHelpers.js +0 -2
- package/dist/core/read/deepbookRegistry.js +0 -19
- package/dist/core/read/deepbookUsdcChartService.js +0 -2
- package/dist/core/read/readCardResult.js +0 -2
- package/dist/core/read/readService.js +0 -19
- package/dist/core/read/readServiceTypes.js +0 -2
- package/dist/core/session/cardSession.js +0 -4
- package/dist/core/session/cardSessionStore.js +1 -4
- package/dist/core/session/reviewValidity.js +0 -3
- package/dist/core/session/sessionRecordStore.js +0 -1
- package/dist/core/session/sessionStore.js +0 -15
- package/dist/core/session/settingsFileIdentity.js +0 -2
- package/dist/core/session/settingsFileProtocol.js +0 -5
- package/dist/core/session/settingsFileStore.js +1 -10
- package/dist/core/session/settingsInputError.js +0 -2
- package/dist/core/session/settingsOperation.js +0 -4
- package/dist/core/session/settingsPreparationSql.js +0 -2
- package/dist/core/session/settingsWorkflow.js +1 -37
- package/dist/core/session/sqliteCardStore.js +0 -2
- package/dist/core/session/sqliteSessionStore.js +0 -11
- package/dist/core/session/sqliteSettingsWorkflowStore.js +0 -10
- package/dist/core/session/sqliteTransactionMaterialStore.js +0 -11
- package/dist/core/session/sqliteWalletWorkflowStore.js +0 -29
- package/dist/core/session/status.js +0 -2
- package/dist/core/session/transactionMaterialStore.js +0 -4
- package/dist/core/session/transactionRequest.js +0 -4
- package/dist/core/session/walletConnection.js +0 -3
- package/dist/core/session/walletWorkflow.js +3 -21
- package/dist/core/session/workflowState.js +0 -8
- package/dist/core/session/workflowView.js +0 -6
- package/dist/core/suiAddress.js +0 -5
- package/dist/core/suiEndpoint.js +0 -3
- package/dist/mcp/prompts.js +0 -12
- package/dist/mcp/schemas.js +0 -3
- package/dist/mcp/tools/action/prepareSuiActionReview.js +0 -6
- package/dist/mcp/tools/read/serverStatusTools.js +0 -1
- package/dist/mcp/tools/session/shared.js +0 -2
- package/dist/mcp/tools/session/statusTools.js +0 -2
- package/dist/mcp-app/account.html +1 -1
- package/dist/mcp-app/chart.html +6 -6
- package/dist/mcp-app/connect.html +6 -6
- package/dist/mcp-app/receipt.html +298 -298
- package/dist/mcp-app/review.html +237 -237
- package/dist/mcp-app/settings.html +1 -1
- package/dist/mcp-ui/tools.js +3 -4
- package/dist/review-server/server.js +0 -2
- package/dist/runtime/application.js +1 -1
- package/dist/runtime/config.js +0 -2
- package/dist/runtime/localSettingsService.js +0 -3
- package/dist/runtime/logger.js +0 -2
- package/dist/runtime/reviewServerAcquire.js +1 -18
- package/dist/runtime/runtimeTermination.js +1 -4
- package/dist/runtime/shared/authenticatedFetch.js +0 -6
- package/dist/runtime/shared/control.js +0 -2
- package/dist/runtime/shared/dataAccess.js +0 -2
- package/dist/runtime/shared/mcpHttp.js +0 -5
- package/dist/runtime/shared/ownerLease.js +0 -4
- package/dist/runtime/shared/server.js +0 -1
- package/dist/runtime/shared/stdio.js +2 -5
- package/dist/runtime/smokeMainnetRead.js +0 -2
- package/dist/runtime/smokeReview.js +0 -4
- package/dist/runtime/start.js +0 -2
- package/dist/runtime/suiTransactionGraphqlMapping.js +0 -2
- package/dist/runtime/suiTransactionGraphqlQueries.js +0 -3
- package/dist/runtime/walletConnectConfig.js +0 -2
- package/dist/runtime/walletConnectStorage.js +0 -6
- package/dist/runtime/walletConnectTransport.js +0 -11
- package/dist/runtime/walletSdkChildRuntime.js +0 -5
- package/dist/runtime/walletSdkProcess.js +0 -6
- package/docs/AGENT_BEHAVIOR.md +1 -5
- package/docs/LOCAL_DB_ARCHITECTURE.md +3 -3
- package/docs/MCP_SETUP.md +14 -14
- package/docs/MCP_TOOLS.md +15 -0
- package/docs/SDK_API.md +12 -0
- package/docs/WALLET_CONNECTION.md +2 -1
- package/package.json +10 -2
- package/docs/AGENT_DEVELOPMENT_POLICY.md +0 -819
- package/docs/FRONTEND_POLICY.md +0 -611
- package/docs/golden-scenarios/BEHAVIOR_MATRIX.md +0 -166
- package/docs/golden-scenarios/INTENT_EVIDENCE_GOLDEN_ANSWERS.md +0 -161
- package/docs/golden-scenarios/INTENT_EVIDENCE_MATRIX.md +0 -259
package/dist/mcp-ui/tools.js
CHANGED
|
@@ -21,8 +21,9 @@ export function supportsCards(server) {
|
|
|
21
21
|
const capabilities = server.server.getClientCapabilities();
|
|
22
22
|
const { extensions, ...standard } = capabilities ?? {};
|
|
23
23
|
const current = capabilities === undefined ? undefined : { ...standard, ...(extensions === undefined ? {} : { extensions }) };
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
const ui = getUiCapability(current);
|
|
25
|
+
return ui !== null && typeof ui === "object" && !Array.isArray(ui) && Array.isArray(ui.mimeTypes) &&
|
|
26
|
+
ui.mimeTypes.every((mimeType) => typeof mimeType === "string") && ui.mimeTypes.includes(RESOURCE_MIME_TYPE);
|
|
26
27
|
}
|
|
27
28
|
export function cardToolResult(response, savedLink = false) {
|
|
28
29
|
const snapshot = response.snapshot;
|
|
@@ -141,8 +142,6 @@ export function registerReadCards(server, deps) {
|
|
|
141
142
|
try {
|
|
142
143
|
if (!deps.cards)
|
|
143
144
|
throw new CardError("Card service is unavailable.");
|
|
144
|
-
// Measure the actual response shape, including its text fallback and UI
|
|
145
|
-
// metadata. Reserve maximum safe-integer digit widths for size fields.
|
|
146
145
|
const base = okToolResult({ status: "read", fileId: input.fileId, offset: input.offset, rangeSize: Number.MAX_SAFE_INTEGER });
|
|
147
146
|
const metadata = { ...(input.attemptId ? { attemptId: input.attemptId } : {}), cardId: input.cardId, operationId: input.operationId, fileId: input.fileId, offset: input.offset, totalSize: Number.MAX_SAFE_INTEGER,
|
|
148
147
|
sha256: "0".repeat(64), chunkBase64: "" };
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { validateHostOrigin } from "./middleware/hostOrigin.js";
|
|
2
2
|
import { sendJson } from "../runtime/shared/http.js";
|
|
3
3
|
import { ALLOWED_HOSTNAMES } from "./reviewServerPolicy.js";
|
|
4
|
-
// The shared runtime serves authenticated private MCP/control routes itself.
|
|
5
|
-
// There are no public browser pages, Settings APIs or static-asset fallbacks.
|
|
6
4
|
export function createReviewRequestHandler(options) {
|
|
7
5
|
return async (request, response) => {
|
|
8
6
|
try {
|
|
@@ -184,7 +184,7 @@ export async function createRuntimeApplication(bootConfig, logger, ownerId = ran
|
|
|
184
184
|
try {
|
|
185
185
|
logger.error("Temporary settings file cleanup is incomplete", { stage: "settings_file_cleanup" });
|
|
186
186
|
}
|
|
187
|
-
catch {
|
|
187
|
+
catch { }
|
|
188
188
|
});
|
|
189
189
|
return {
|
|
190
190
|
handleMcp: (request, response) => access.run(() => mcp.handle(request, response)),
|
package/dist/runtime/config.js
CHANGED
|
@@ -17,8 +17,6 @@ export function loadBootConfig(env = process.env) {
|
|
|
17
17
|
activityDatabasePath: resolveActivityDatabasePath(env)
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
|
-
// Existing shared-backend port: clients using the same data directory must
|
|
21
|
-
// agree on this port and configuration. It is not browser-wallet authority.
|
|
22
20
|
export const DEFAULT_REVIEW_PORT = 8765;
|
|
23
21
|
function parseReviewPort(value) {
|
|
24
22
|
if (value === undefined || value === "") {
|
|
@@ -57,8 +57,6 @@ export class RuntimeLocalSettingsService {
|
|
|
57
57
|
suiGraphqlUrl: withBootEffectiveEndpoint(currentStoredGraphqlView, this.bootSuiGraphqlUrl)
|
|
58
58
|
};
|
|
59
59
|
}
|
|
60
|
-
// The same side-effect-free target resolution serves display and final
|
|
61
|
-
// verification. Default URLs belong to this service, never to the View.
|
|
62
60
|
resolveEndpointChange(input) {
|
|
63
61
|
const value = input.kind === "restore_endpoint"
|
|
64
62
|
? input.endpoint === "grpc" ? this.defaultSuiGrpcUrl : this.defaultSuiGraphqlUrl
|
|
@@ -66,7 +64,6 @@ export class RuntimeLocalSettingsService {
|
|
|
66
64
|
return { key: input.endpoint === "grpc" ? "suiGrpcUrl" : "suiGraphqlUrl", value,
|
|
67
65
|
status: input.kind === "restore_endpoint" ? "reset" : "saved" };
|
|
68
66
|
}
|
|
69
|
-
// Verification does not store a value or change this parent's effective URL.
|
|
70
67
|
async prepareEndpointChange(input) {
|
|
71
68
|
const target = this.resolveEndpointChange(input);
|
|
72
69
|
await this.verifyEndpointForTool(target.value, input.endpoint);
|
package/dist/runtime/logger.js
CHANGED
|
@@ -3,8 +3,6 @@ export function flushStderr() {
|
|
|
3
3
|
const failed = (error) => { process.stderr.off("error", failed); reject(error); };
|
|
4
4
|
process.stderr.once("error", failed);
|
|
5
5
|
process.stderr.write("", (error) => {
|
|
6
|
-
// A failed stream write also emits error; keep its handler through that
|
|
7
|
-
// event instead of allowing EPIPE to replace the intended exit code.
|
|
8
6
|
if (error) {
|
|
9
7
|
reject(error);
|
|
10
8
|
return;
|
|
@@ -4,8 +4,6 @@ function errorCode(error) {
|
|
|
4
4
|
? error.code
|
|
5
5
|
: undefined;
|
|
6
6
|
}
|
|
7
|
-
// Bind the port: returns the server on success, undefined when the port is already
|
|
8
|
-
// in use, and rethrows any other (non-EADDRINUSE) startup error.
|
|
9
7
|
async function tryStart(start, port) {
|
|
10
8
|
try {
|
|
11
9
|
return await start(port);
|
|
@@ -17,17 +15,6 @@ async function tryStart(start, port) {
|
|
|
17
15
|
throw error;
|
|
18
16
|
}
|
|
19
17
|
}
|
|
20
|
-
/**
|
|
21
|
-
* Bind the review server to its fixed port, or defer to a healthy peer already
|
|
22
|
-
* serving it.
|
|
23
|
-
*
|
|
24
|
-
* - Port free → bind and own the single review origin.
|
|
25
|
-
* - Port held by a separate healthy instance of our review server → defer (run no
|
|
26
|
-
* local server; the peer serves the shared database for every client) and watch for
|
|
27
|
-
* the owner to exit, then take the origin over. No peer process is signalled.
|
|
28
|
-
* - Port held by anything else (foreign, no identity answer, or our own pid) → clear
|
|
29
|
-
* error; the origin is never silently reassigned.
|
|
30
|
-
*/
|
|
31
18
|
export async function startOrDeferReviewServer(start, port, deps) {
|
|
32
19
|
const owned = await tryStart(start, port);
|
|
33
20
|
if (owned) {
|
|
@@ -58,14 +45,12 @@ export async function startOrDeferReviewServer(start, port, deps) {
|
|
|
58
45
|
next = await tryStart(start, port);
|
|
59
46
|
}
|
|
60
47
|
catch (error) {
|
|
61
|
-
// An authenticated prior owner may have closed its port while its SDK
|
|
62
|
-
// still owns private storage. Reuse the existing takeover observation.
|
|
63
48
|
if (typeof error === "object" && error !== null && "code" in error && error.code === "DATA_DIRECTORY_OWNED")
|
|
64
49
|
continue;
|
|
65
50
|
throw error;
|
|
66
51
|
}
|
|
67
52
|
if (!next) {
|
|
68
|
-
continue;
|
|
53
|
+
continue;
|
|
69
54
|
}
|
|
70
55
|
if (stopped) {
|
|
71
56
|
await next.close();
|
|
@@ -82,8 +67,6 @@ export async function startOrDeferReviewServer(start, port, deps) {
|
|
|
82
67
|
return {
|
|
83
68
|
deferred: true,
|
|
84
69
|
close: async () => {
|
|
85
|
-
// Stop watching; the loop's stopped-check closes any bind that lands in-flight,
|
|
86
|
-
// so we never await the (possibly mid-delay) watch loop here.
|
|
87
70
|
stopped = true;
|
|
88
71
|
if (acquired) {
|
|
89
72
|
await acquired.close();
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { SuiEndpointError } from "../core/suiEndpoint.js";
|
|
2
|
-
// Keep arbitrary SDK/server exception text, endpoint values and stacks private.
|
|
3
2
|
export function runtimeFailureReason(error, stage) {
|
|
4
3
|
if (error instanceof SuiEndpointError)
|
|
5
4
|
return `Sui mainnet endpoint verification failed (${error.kind}). Check the configured endpoint.`;
|
|
@@ -16,8 +15,6 @@ export function runtimeFailureReason(error, stage) {
|
|
|
16
15
|
return "The private runtime control identity could not be loaded. Check data directory ownership and permissions.";
|
|
17
16
|
return "The local runtime could not complete this stage. Check local data permissions and runtime configuration.";
|
|
18
17
|
}
|
|
19
|
-
// Bootstrap alone decides exit intent. Cleanup-induced onclose notifications
|
|
20
|
-
// join the same promise; they cannot replace a fatal or signal exit with EOF.
|
|
21
18
|
export class RuntimeTermination {
|
|
22
19
|
options;
|
|
23
20
|
closing;
|
|
@@ -34,7 +31,7 @@ export class RuntimeTermination {
|
|
|
34
31
|
try {
|
|
35
32
|
this.options.logger.error(message, { stage, reason: runtimeFailureReason(error, stage) });
|
|
36
33
|
}
|
|
37
|
-
catch {
|
|
34
|
+
catch { }
|
|
38
35
|
};
|
|
39
36
|
if (cause.kind === "failure")
|
|
40
37
|
report("fatal runtime error", cause.stage, cause.error);
|
|
@@ -4,8 +4,6 @@ import { randomBytes } from "node:crypto";
|
|
|
4
4
|
import { Readable } from "node:stream";
|
|
5
5
|
import { MAX_JSON_BODY_BYTES } from "./http.js";
|
|
6
6
|
import { IDENTITY_CHALLENGE_HEADER, IDENTITY_PATH, IDENTITY_TIMEOUT_MS, INTERNAL_MCP_PATH, SERVER_INSTANCE_HEADER, verifyServerIdentity } from "./control.js";
|
|
7
|
-
// Proof and authenticated request use the same TCP socket. A closed socket is never
|
|
8
|
-
// transparently replaced: no credential or UI permission can reach a new listener.
|
|
9
7
|
async function authenticatedChannel(port, control, signal) {
|
|
10
8
|
signal?.throwIfAborted();
|
|
11
9
|
const socket = connect({ host: "127.0.0.1", port });
|
|
@@ -86,10 +84,6 @@ export function createAuthenticatedFetch(port, control, expectedInstanceId) {
|
|
|
86
84
|
headers.set("host", url.host);
|
|
87
85
|
headers.set("authorization", `Bearer ${control.key}`);
|
|
88
86
|
headers.set(SERVER_INSTANCE_HEADER, channel.identity.instanceId);
|
|
89
|
-
// An early rejection (for example the SDK's body-size guard) must reach
|
|
90
|
-
// the caller while the request is still being written. Server-side
|
|
91
|
-
// Connection: close can race that response with EPIPE. This channel is
|
|
92
|
-
// still destroyed after the response and never reused or replaced.
|
|
93
87
|
headers.set("connection", "keep-alive");
|
|
94
88
|
const body = init?.body;
|
|
95
89
|
if (body !== undefined && body !== null && typeof body !== "string") {
|
|
@@ -3,12 +3,10 @@ import { link, lstat, mkdir, readFile, realpath, unlink, writeFile } from "node:
|
|
|
3
3
|
import { basename, dirname, join } from "node:path";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { SERVER_VERSION } from "../../mcp/serverInfo.js";
|
|
6
|
-
// Peers use the one package release identity, with no separate API counter.
|
|
7
6
|
export const IDENTITY_PATH = "/__runtime/identity";
|
|
8
7
|
export const INTERNAL_MCP_PATH = "/__runtime/mcp";
|
|
9
8
|
export const IDENTITY_CHALLENGE_HEADER = "x-sui-mcp-identity-challenge";
|
|
10
9
|
export const SERVER_INSTANCE_HEADER = "x-sui-mcp-server-instance";
|
|
11
|
-
// The existing review-server identity probe allows one second for a local response.
|
|
12
10
|
export const IDENTITY_TIMEOUT_MS = 1000;
|
|
13
11
|
const secretSchema = z.string().regex(/^[A-Za-z0-9_-]{43}$/);
|
|
14
12
|
export const serverIdentitySchema = z.object({
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
-
// An asynchronous read may finish after import/reset. Its original generation
|
|
3
|
-
// remains attached to the continuation and cannot read or write the replacement DB.
|
|
4
2
|
export class RuntimeDataAccess {
|
|
5
3
|
context = new AsyncLocalStorage();
|
|
6
4
|
generation = 0;
|
|
@@ -9,8 +9,6 @@ export function createInternalMcpHandler(createServer) {
|
|
|
9
9
|
const connections = new Set();
|
|
10
10
|
return {
|
|
11
11
|
async handle(request, response) {
|
|
12
|
-
// This product has no unsolicited server requests. POST returns JSON, and
|
|
13
|
-
// clients do not create a reconnecting SSE channel or replay requests.
|
|
14
12
|
if (request.method === "GET") {
|
|
15
13
|
response.setHeader("Allow", "POST, DELETE");
|
|
16
14
|
sendJson(response, 405, { error: "method_not_allowed" });
|
|
@@ -49,9 +47,6 @@ export function createInternalMcpHandler(createServer) {
|
|
|
49
47
|
close: () => transport.close()
|
|
50
48
|
};
|
|
51
49
|
transport.onmessage = (message, extra) => {
|
|
52
|
-
// The SDK enforces its 4 MiB HTTP body limit before this callback.
|
|
53
|
-
// Card calls additionally have a 64 KiB JSON-RPC envelope budget;
|
|
54
|
-
// ordinary MCP calls do not inherit that smaller card limit.
|
|
55
50
|
if (isJSONRPCRequest(message) && message.method === "tools/call" &&
|
|
56
51
|
Object.values(CARD_TOOLS).some((name) => name === message.params?.name) &&
|
|
57
52
|
Buffer.byteLength(JSON.stringify(message)) > MAX_JSON_BODY_BYTES) {
|
|
@@ -4,8 +4,6 @@ import { dirname, join } from "node:path";
|
|
|
4
4
|
export class DataDirectoryOwnedError extends Error {
|
|
5
5
|
code = "DATA_DIRECTORY_OWNED";
|
|
6
6
|
}
|
|
7
|
-
/** An OS-released ownership lock, separate from the product database. No
|
|
8
|
-
* business transaction is held while waiting for a wallet or network reply. */
|
|
9
7
|
export function acquireDataDirectoryOwner(databasePath) {
|
|
10
8
|
const directory = dirname(databasePath);
|
|
11
9
|
mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
@@ -31,8 +29,6 @@ export function acquireDataDirectoryOwner(databasePath) {
|
|
|
31
29
|
process.umask(mask);
|
|
32
30
|
}
|
|
33
31
|
try {
|
|
34
|
-
// A second owner is refused immediately, including one using another port.
|
|
35
|
-
// SQLite retains the EXCLUSIVE lock after commit until this handle closes.
|
|
36
32
|
lock.pragma("locking_mode=EXCLUSIVE");
|
|
37
33
|
lock.exec("BEGIN EXCLUSIVE");
|
|
38
34
|
lock.exec("CREATE TABLE IF NOT EXISTS owner_lock (singleton INTEGER PRIMARY KEY CHECK (singleton=1))");
|
|
@@ -64,7 +64,6 @@ export async function startSharedServer(input) {
|
|
|
64
64
|
server.listen(port, "127.0.0.1");
|
|
65
65
|
});
|
|
66
66
|
port = server.address().port;
|
|
67
|
-
// Only the process that owns the port opens SQLite or initializes services.
|
|
68
67
|
application = Promise.resolve().then(() => input.createApplication(instanceId));
|
|
69
68
|
const closeListener = async () => {
|
|
70
69
|
if (!server.listening)
|
|
@@ -5,9 +5,6 @@ import { CallToolRequestSchema, CallToolResultSchema, CompleteRequestSchema, Get
|
|
|
5
5
|
import { SERVER_INSTRUCTIONS, SERVER_NAME, SERVER_VERSION } from "../../mcp/serverInfo.js";
|
|
6
6
|
import { createAuthenticatedFetch, probeAuthenticatedServer } from "./authenticatedFetch.js";
|
|
7
7
|
import { INTERNAL_MCP_PATH } from "./control.js";
|
|
8
|
-
// The SDK owns request IDs, initialization, cancellation and response parsing.
|
|
9
|
-
// This proxy has no domain services or writable stores. A new request may open a
|
|
10
|
-
// new MCP session after ownership changes; an already dispatched call is never replayed.
|
|
11
8
|
export async function startSharedStdio(input) {
|
|
12
9
|
const server = new Server({ name: SERVER_NAME, version: SERVER_VERSION }, {
|
|
13
10
|
capabilities: { tools: {}, resources: {}, prompts: {}, completions: {} }, instructions: SERVER_INSTRUCTIONS
|
|
@@ -56,7 +53,7 @@ export async function startSharedStdio(input) {
|
|
|
56
53
|
close: async () => { try {
|
|
57
54
|
await http.terminateSession();
|
|
58
55
|
}
|
|
59
|
-
catch {
|
|
56
|
+
catch { } await http.close(); }
|
|
60
57
|
};
|
|
61
58
|
http.onmessage = (message) => { if (http.sessionId !== undefined)
|
|
62
59
|
transport.sessionId = http.sessionId; transport.onmessage?.(message); };
|
|
@@ -105,7 +102,7 @@ export async function startSharedStdio(input) {
|
|
|
105
102
|
try {
|
|
106
103
|
await connecting;
|
|
107
104
|
}
|
|
108
|
-
catch {
|
|
105
|
+
catch { }
|
|
109
106
|
await connection?.client.close();
|
|
110
107
|
connection = undefined;
|
|
111
108
|
}
|
|
@@ -125,8 +125,6 @@ async function main() {
|
|
|
125
125
|
});
|
|
126
126
|
const reviewDependencies = createRuntimeReviewDependencies({ client: suiClient, chainIdentifier,
|
|
127
127
|
expectedChainIdentifier: config.expectedChainIdentifier, materialStore: transactionMaterialStore, readService });
|
|
128
|
-
// Utility-only read context in this script's temporary DB. This does not
|
|
129
|
-
// create a live wallet session or prove address ownership.
|
|
130
128
|
await activityStore.setActiveAccount(smokeAddress, "wallet_connection", new Date(), { name: "Explicit smoke read fixture" });
|
|
131
129
|
server = createMcpServer({
|
|
132
130
|
sessions,
|
|
@@ -3,8 +3,6 @@ import { computeReviewStateWithPrivateArtifacts } from "../core/review/reviewCom
|
|
|
3
3
|
export class SmokeReviewConfigError extends Error {
|
|
4
4
|
}
|
|
5
5
|
const requiredSwapInputs = ["SMOKE_SWAP_PROTOCOL", "SMOKE_SWAP_FROM_SYMBOL", "SMOKE_SWAP_TO_SYMBOL", "SMOKE_SWAP_AMOUNT_DISPLAY"];
|
|
6
|
-
/** Optional read-only review computation. This never establishes a wallet
|
|
7
|
-
* connection; the caller owns the explicit temporary read-account fixture. */
|
|
8
6
|
export async function computeSmokeReview(options) {
|
|
9
7
|
const { env, sessions, computation, account } = options;
|
|
10
8
|
const rawSlippage = env.SMOKE_SWAP_MAX_SLIPPAGE_BPS;
|
|
@@ -16,8 +14,6 @@ export async function computeSmokeReview(options) {
|
|
|
16
14
|
return { status: "not_run", notRunReason: "missing_env", requiredEnv: [...requiredSwapInputs] };
|
|
17
15
|
if (missing.length)
|
|
18
16
|
throw new SmokeReviewConfigError(`Partial account-bound swap smoke configuration; missing: ${missing.join(", ")}`);
|
|
19
|
-
// Preserve the utility's existing 50 bps CLI default; it is not a product
|
|
20
|
-
// recommendation or a silently selected protocol/settlement asset.
|
|
21
17
|
const parsed = swapIntentInputSchema.safeParse({ type: "swap", protocol: env.SMOKE_SWAP_PROTOCOL,
|
|
22
18
|
from: { symbol: env.SMOKE_SWAP_FROM_SYMBOL, amount: env.SMOKE_SWAP_AMOUNT_DISPLAY },
|
|
23
19
|
to: { symbol: env.SMOKE_SWAP_TO_SYMBOL }, maxSlippageBps: Number(env.SMOKE_SWAP_MAX_SLIPPAGE_BPS ?? "50") });
|
package/dist/runtime/start.js
CHANGED
|
@@ -43,8 +43,6 @@ async function main() {
|
|
|
43
43
|
grpcOverride: process.env.SUI_GRPC_URL ?? null, graphqlOverride: process.env.SUI_GRAPHQL_URL ?? null
|
|
44
44
|
});
|
|
45
45
|
void controlReady.catch(() => { });
|
|
46
|
-
// The SDK owns stdin from the start, including fragmented initialization
|
|
47
|
-
// and EOF while backend startup is pending. No second reader buffers bytes.
|
|
48
46
|
stage = "stdio_start";
|
|
49
47
|
bridge = await startSharedStdio({ stdio, port: bootConfig.reviewPort, control: controlReady, ready: backendReady,
|
|
50
48
|
onError: (error) => logger.error("MCP transport failed", { error: error.message }) });
|
|
@@ -187,8 +187,6 @@ function executionStatusFromGraphql(value) {
|
|
|
187
187
|
return "success";
|
|
188
188
|
if (value === "FAILURE")
|
|
189
189
|
return "failure";
|
|
190
|
-
// Null status can occur before checkpointed effects are available; unmapped
|
|
191
|
-
// provider enum values stay unknown until explicitly mapped.
|
|
192
190
|
return "unknown";
|
|
193
191
|
}
|
|
194
192
|
function normalizeGraphqlTimestamp(value) {
|
|
@@ -211,9 +211,6 @@ async function queryGraphql(client, options) {
|
|
|
211
211
|
const result = await client.query({ query: options.query, variables: options.variables ?? {} });
|
|
212
212
|
if (result.errors && result.errors.length > 0) {
|
|
213
213
|
const message = result.errors.map((error) => error.message).join("; ");
|
|
214
|
-
// The pinned SDK exposes provider GraphQL errors as messages here. Cursor
|
|
215
|
-
// rejection is intentionally detected conservatively and otherwise falls
|
|
216
|
-
// back to provider_error.
|
|
217
214
|
throw new TransactionActivitySourceError(message.toLowerCase().includes("cursor") ? "cursor_invalid" : "provider_error", "Sui GraphQL query returned errors", { message });
|
|
218
215
|
}
|
|
219
216
|
if (!result.data) {
|
|
@@ -2,9 +2,6 @@ import { existsSync, lstatSync, mkdirSync } from "node:fs";
|
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { serialize, deserialize } from "node:v8";
|
|
4
4
|
import Database from "better-sqlite3";
|
|
5
|
-
// Restoration namespaces of pinned SignClient/Core 2.23.10. Request history,
|
|
6
|
-
// pending requests, messages, unacknowledged envelopes and new namespaces are
|
|
7
|
-
// intentionally volatile; they may contain transaction or signature material.
|
|
8
5
|
const persistentKeys = new Set([
|
|
9
6
|
"wc@2:core:0.3//keychain", "wc@2:core:0.3//pairing",
|
|
10
7
|
"wc@2:core:0.3//subscription", "wc@2:core:0.3//expirer",
|
|
@@ -60,8 +57,6 @@ export function openWalletConnectStorage(dataDirectory) {
|
|
|
60
57
|
db.exec(storageSchema);
|
|
61
58
|
})();
|
|
62
59
|
}
|
|
63
|
-
// There is exactly one SDK owner. FULL protects the session material that
|
|
64
|
-
// the SDK needs to resume an acknowledged connection after process exit.
|
|
65
60
|
db.pragma("journal_mode = DELETE");
|
|
66
61
|
db.pragma("synchronous = FULL");
|
|
67
62
|
}
|
|
@@ -92,6 +87,5 @@ export function openWalletConnectStorage(dataDirectory) {
|
|
|
92
87
|
volatile.delete(key);
|
|
93
88
|
}
|
|
94
89
|
};
|
|
95
|
-
// Once injected, SDK timers own the storage until the owner process exits.
|
|
96
90
|
return { storage, closeBeforeSdkUse: () => { volatile.clear(); db.close(); } };
|
|
97
91
|
}
|
|
@@ -27,8 +27,6 @@ export async function createWalletConnectTransport(options) {
|
|
|
27
27
|
if (!/^[0-9a-f]{32}$/i.test(options.projectId))
|
|
28
28
|
throw new Error("WalletConnect project ID format is invalid.");
|
|
29
29
|
const owner = openWalletConnectStorage(options.dataDirectory);
|
|
30
|
-
// SDK log bodies can contain pairing credentials and serialized requests.
|
|
31
|
-
// Product failure stages are recorded by the caller without these values.
|
|
32
30
|
options.onSdkStart?.();
|
|
33
31
|
const client = await (options.initialize ?? SignClient.init.bind(SignClient))({ projectId: options.projectId, metadata: { ...options.metadata, icons: [] },
|
|
34
32
|
storage: owner.storage, logger: "silent", telemetryEnabled: false });
|
|
@@ -37,8 +35,6 @@ export async function createWalletConnectTransport(options) {
|
|
|
37
35
|
const changed = (event) => { if (!stopped)
|
|
38
36
|
for (const listener of listeners)
|
|
39
37
|
listener(event.topic); };
|
|
40
|
-
// Pinned SignClient emits session_event without changing session.namespaces.
|
|
41
|
-
// Treat active account/chain changes as invalidation, not new authorization.
|
|
42
38
|
const selectionChanged = (event) => {
|
|
43
39
|
if (!stopped && ["accountsChanged", "chainChanged"].includes(event.params.event.name)) {
|
|
44
40
|
for (const listener of listeners)
|
|
@@ -60,7 +56,6 @@ export async function createWalletConnectTransport(options) {
|
|
|
60
56
|
const inspect = (topic) => {
|
|
61
57
|
if (stopped)
|
|
62
58
|
throw new Error("WalletConnect owner stopped.");
|
|
63
|
-
// A store failure is not evidence that the session disappeared.
|
|
64
59
|
const session = client.session.getAll().find((item) => item.topic === topic);
|
|
65
60
|
return session ? inspectValue(session) : { topic, status: "absent" };
|
|
66
61
|
};
|
|
@@ -75,8 +70,6 @@ export async function createWalletConnectTransport(options) {
|
|
|
75
70
|
return {
|
|
76
71
|
async restore() {
|
|
77
72
|
requireActive();
|
|
78
|
-
// A pending proposal is not an approved session and must not reappear as
|
|
79
|
-
// a new approval ceremony after owner replacement.
|
|
80
73
|
for (const pairing of client.core.pairing.getPairings()) {
|
|
81
74
|
if (!pairing.active)
|
|
82
75
|
await client.core.pairing.disconnect({ topic: pairing.topic });
|
|
@@ -89,8 +82,6 @@ export async function createWalletConnectTransport(options) {
|
|
|
89
82
|
chains: [SUI_MAINNET_WALLET_CHAIN], methods: [SUI_SIGN_TRANSACTION_METHOD], events: ["accountsChanged", "chainChanged"]
|
|
90
83
|
} } });
|
|
91
84
|
const approval = connecting.approval().then(sessionValue).catch((error) => { throw transportError(error); });
|
|
92
|
-
// Attach a rejection handler immediately; the backend records the same
|
|
93
|
-
// promise's outcome once the private QR has been associated with its row.
|
|
94
85
|
void approval.catch(() => undefined);
|
|
95
86
|
if (!connecting.uri)
|
|
96
87
|
throw new Error("The wallet pairing could not be prepared.");
|
|
@@ -121,8 +112,6 @@ export async function createWalletConnectTransport(options) {
|
|
|
121
112
|
client.off("session_delete", changed);
|
|
122
113
|
client.off("session_expire", changed);
|
|
123
114
|
client.off("session_event", selectionChanged);
|
|
124
|
-
// SignClient has no supported complete in-process disposal. The runtime
|
|
125
|
-
// ends the owner process; it must not close injected storage under timers.
|
|
126
115
|
}
|
|
127
116
|
};
|
|
128
117
|
}
|
|
@@ -4,8 +4,6 @@ import { isDeepStrictEqual } from "node:util";
|
|
|
4
4
|
import { WalletUserRejectedError } from "../core/session/walletConnection.js";
|
|
5
5
|
import { acquireDataDirectoryOwner } from "./shared/ownerLease.js";
|
|
6
6
|
import { walletCommandSchema, walletEventSchema } from "./walletSdkIpc.js";
|
|
7
|
-
// Production and the real-SDK wire fixture run this same process lifecycle.
|
|
8
|
-
// The factory is a code dependency, never a serialized command or setting.
|
|
9
7
|
export function runWalletSdkChild(createTransport) {
|
|
10
8
|
let init, transport;
|
|
11
9
|
let sequence = 0, lastRequest = 0, ready = false, exiting = false;
|
|
@@ -30,7 +28,6 @@ export function runWalletSdkChild(createTransport) {
|
|
|
30
28
|
ready = false;
|
|
31
29
|
if (init && !exiting)
|
|
32
30
|
send({ ...envelope(), type: "failure", reason });
|
|
33
|
-
// Neither SDK cleanup nor a callback is a prerequisite for process exit.
|
|
34
31
|
if (!exiting) {
|
|
35
32
|
exiting = true;
|
|
36
33
|
process.exit(1);
|
|
@@ -75,7 +72,6 @@ export function runWalletSdkChild(createTransport) {
|
|
|
75
72
|
};
|
|
76
73
|
const start = async (input) => {
|
|
77
74
|
init = input;
|
|
78
|
-
// The child alone opens the SDK store; OS exit releases this separate lock.
|
|
79
75
|
ownership = acquireDataDirectoryOwner(join(input.dataDirectory, "walletconnect", "sessions.sqlite"));
|
|
80
76
|
send({ ...envelope(), type: "stage", stage: "sdk_start" });
|
|
81
77
|
transport = await createTransport(input);
|
|
@@ -154,7 +150,6 @@ export function runWalletSdkChild(createTransport) {
|
|
|
154
150
|
}
|
|
155
151
|
if (!init || input.runId !== init.runId || input.requestId <= lastRequest)
|
|
156
152
|
return;
|
|
157
|
-
// Reserve before awaiting anything, including a connect approval.
|
|
158
153
|
lastRequest = input.requestId;
|
|
159
154
|
void command(input).catch(() => fail("wallet_state_unavailable"));
|
|
160
155
|
});
|
|
@@ -5,8 +5,6 @@ import { isDeepStrictEqual } from "node:util";
|
|
|
5
5
|
import { walletUnavailable, WalletUnavailableError, WalletUserRejectedError } from "../core/session/walletConnection.js";
|
|
6
6
|
import { WalletRunInterruptedError, WalletReplacementFailedError } from "../core/session/walletRuntime.js";
|
|
7
7
|
import { walletCommandSchema, walletEventSchema } from "./walletSdkIpc.js";
|
|
8
|
-
/** Owns one SDK process. Business authority and all database transitions remain
|
|
9
|
-
* in the workflow; a process event is never transaction approval. */
|
|
10
8
|
export class WalletSdkProcess {
|
|
11
9
|
options;
|
|
12
10
|
run = this.newRun();
|
|
@@ -75,7 +73,6 @@ export class WalletSdkProcess {
|
|
|
75
73
|
child.once("exit", () => this.exited(run));
|
|
76
74
|
child.once("error", () => {
|
|
77
75
|
this.lose(run, this.failureReason());
|
|
78
|
-
// Failed spawn has no process and therefore cannot emit exit.
|
|
79
76
|
if (child.pid === undefined)
|
|
80
77
|
this.exited(run);
|
|
81
78
|
});
|
|
@@ -93,7 +90,6 @@ export class WalletSdkProcess {
|
|
|
93
90
|
send(run, message) {
|
|
94
91
|
if (run !== this.run || run.fenced || this.closed || !run.child?.connected)
|
|
95
92
|
throw new WalletRunInterruptedError(run.id);
|
|
96
|
-
// A false return means backpressure, not permission to repeat the command.
|
|
97
93
|
run.child.send(walletCommandSchema.parse(message), (error) => { if (error)
|
|
98
94
|
this.lose(run, "wallet_state_unavailable"); });
|
|
99
95
|
}
|
|
@@ -271,8 +267,6 @@ export class WalletSdkProcess {
|
|
|
271
267
|
if (this.closed || this.run !== old || this.replacement !== replacement)
|
|
272
268
|
throw new WalletRunInterruptedError(runId);
|
|
273
269
|
const next = this.newRun();
|
|
274
|
-
// A failed reservation ends this attempt. Reads may save its failure,
|
|
275
|
-
// but only a new explicit admission may start another SDK process.
|
|
276
270
|
beforeStart(next.id);
|
|
277
271
|
this.run = next;
|
|
278
272
|
this.state = this.starting(next.id, "process_start");
|
package/docs/AGENT_BEHAVIOR.md
CHANGED
|
@@ -4,7 +4,7 @@ This document is the MCP-exposed answer playbook for AI clients. It owns user-qu
|
|
|
4
4
|
|
|
5
5
|
It does not define tool schemas or field contracts. Use `docs/MCP_TOOLS.md` for the MCP API reference, response fields, statuses, and follow-up fields.
|
|
6
6
|
|
|
7
|
-
It is not the contributor rulebook and it is not enforcement. Development rules live in `AGENTS.md` and `docs/AGENT_DEVELOPMENT_POLICY.md
|
|
7
|
+
It is not the contributor rulebook and it is not enforcement. Development rules live in `AGENTS.md` and `docs/AGENT_DEVELOPMENT_POLICY.md` in the [source repository](https://github.com/zktx-mcp/sui-mcp). They are not installed MCP resources. Hard product boundaries live in code, schemas, allowlists, mainnet guards, and the local review layer.
|
|
8
8
|
|
|
9
9
|
## Support Matrix
|
|
10
10
|
|
|
@@ -552,7 +552,3 @@ Avoid unqualified words such as best, recommended, guaranteed, or safe. Prefer:
|
|
|
552
552
|
## Language
|
|
553
553
|
|
|
554
554
|
This reference document stays in English. Reply in the user's language. Translate response patterns as needed, but keep SDK names, tool names, object IDs, package IDs, and token symbols in their original form.
|
|
555
|
-
|
|
556
|
-
## Golden Scenarios
|
|
557
|
-
|
|
558
|
-
Detailed expected response classes live in `docs/golden-scenarios/BEHAVIOR_MATRIX.md`. They are documentation for release review, not automated cross-client results.
|
|
@@ -178,7 +178,7 @@ target must name the recorded file and pass size/SHA checks before `saved` is
|
|
|
178
178
|
committed. Existing destinations are never overwritten or removed. Private
|
|
179
179
|
unlink follows that result and actual descriptor closure; the final file has
|
|
180
180
|
no automatic expiry. Historical export path validation remains distinct from
|
|
181
|
-
the private `.download` row identity.
|
|
181
|
+
the private `.download` row identity.
|
|
182
182
|
|
|
183
183
|
Unknown file effects remain `saving`, retaining their source and reservations.
|
|
184
184
|
A failed DB result write retains the ended physical outcome for settlement.
|
|
@@ -476,7 +476,7 @@ The runtime accepts one current SQLite structure, checked against its table, col
|
|
|
476
476
|
|
|
477
477
|
A current backup carries `format`, `network`, `exportedAt` and its product data. It has no numeric schema version. Import rejects a different format, unknown or missing fields, invalid references or invalid raw quantities. Missing settings or activity arrays are not filled from defaults. Supported `function_scan` provenance remains part of the current format. Validation failure leaves current data intact.
|
|
478
478
|
|
|
479
|
-
|
|
479
|
+
With a new empty data directory, users configure account context and endpoints; environment overrides retain their existing precedence. Empty local history does not imply an absence of on-chain transactions. Existing DB and backup files are not deleted by startup.
|
|
480
480
|
|
|
481
481
|
## Boundaries
|
|
482
482
|
|
|
@@ -496,7 +496,7 @@ Ownership and simulation private artifacts use their v2 evidence formats to
|
|
|
496
496
|
bind transaction funding to the stored material. They cover real coin objects,
|
|
497
497
|
address withdrawals, gas reservations, and their observed balance/epoch facts.
|
|
498
498
|
They are deeply copied and revalidated before admission, and are excluded from
|
|
499
|
-
public backup.
|
|
499
|
+
public backup.
|
|
500
500
|
|
|
501
501
|
Old private evidence is not upgraded into funding proof. Existing owner recovery
|
|
502
502
|
removes private material; a new review recomputes it. Historical public reviews,
|
package/docs/MCP_SETUP.md
CHANGED
|
@@ -6,7 +6,7 @@ It does not define tool field contracts or response wording. Use `docs/MCP_TOOLS
|
|
|
6
6
|
|
|
7
7
|
The README keeps only the short entry path; client-specific setup, restart behavior, and troubleshooting live here.
|
|
8
8
|
|
|
9
|
-
These instructions target `@zktx.io/sui-mcp@0.6.
|
|
9
|
+
These instructions target `@zktx.io/sui-mcp@0.6.1`. Package installation requires
|
|
10
10
|
that exact version to be published; use the developer checkout instructions when
|
|
11
11
|
it is not available. A repository rename or local build does not publish the
|
|
12
12
|
package. Changing client settings or rebuilding files does not replace an
|
|
@@ -130,7 +130,7 @@ per-client configuration below, which give the exact `command` and `args`.
|
|
|
130
130
|
|
|
131
131
|
The npm package for this release is `@zktx.io/sui-mcp`. The commands below
|
|
132
132
|
require the requested version to be published; confirm it with
|
|
133
|
-
`npm view @zktx.io/sui-mcp@0.6.
|
|
133
|
+
`npm view @zktx.io/sui-mcp@0.6.1 version` before switching. Both installation
|
|
134
134
|
methods start the same `sui-mcp` stdio MCP server. Use a local checkout when
|
|
135
135
|
working on a version that has not been published.
|
|
136
136
|
|
|
@@ -193,20 +193,20 @@ command, for example `"command": "cmd", "args": ["/c", "npx", "-y", "@zktx.io/su
|
|
|
193
193
|
### Updating an Existing Sui MCP Installation
|
|
194
194
|
|
|
195
195
|
Confirm that the requested package version is available before changing every
|
|
196
|
-
participating client's configuration.
|
|
197
|
-
directory
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
Use the same new data directory and review port in every participating client.
|
|
201
|
-
Fully quit the participating apps, update
|
|
196
|
+
participating client's configuration. A compatible update can retain the current
|
|
197
|
+
data directory, backups and private WalletConnect store. Use the same directory
|
|
198
|
+
and review port in every participating client. Stop the participating MCP
|
|
199
|
+
connections and wait for the shared backend to exit, update
|
|
202
200
|
the installed package or configured version, then reopen them and check
|
|
203
201
|
`read.get_server_status` in each client. The package name, version and server
|
|
204
202
|
name must match the intended installation. Updating the package does not
|
|
205
203
|
replace a backend that is already running.
|
|
206
204
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
205
|
+
Incompatible databases and backups are rejected without migration. To use a
|
|
206
|
+
different database structure, choose a new empty directory and preserve the
|
|
207
|
+
existing data and backups. Configure endpoints and read context as needed and
|
|
208
|
+
connect through a new card. See
|
|
209
|
+
[Local Database Architecture](LOCAL_DB_ARCHITECTURE.md#current-format-and-backups).
|
|
210
210
|
Do not reset data or resend a transaction as an update step. Coordinate a safe
|
|
211
211
|
restart if a transaction request is still in progress.
|
|
212
212
|
|
|
@@ -229,7 +229,7 @@ restart first. A previous wallet pairing can remain in the wallet app; remove
|
|
|
229
229
|
an unwanted pairing there rather than assuming new local storage disconnected it.
|
|
230
230
|
|
|
231
231
|
Replace the old registration instead of adding a second one. Use exactly
|
|
232
|
-
`sui-mcp` for the registration name and select `@zktx.io/sui-mcp@0.6.
|
|
232
|
+
`sui-mcp` for the registration name and select `@zktx.io/sui-mcp@0.6.1` in its
|
|
233
233
|
command arguments. Do not append an environment label, version or numeric
|
|
234
234
|
suffix. Remove obsolete runtime environment overrides. If you set
|
|
235
235
|
`SUI_MCP_DATA_DIR`, choose a new empty directory; never point it at another
|
|
@@ -534,7 +534,7 @@ A card accepts one read selection. Moving between chats or recreating its frame
|
|
|
534
534
|
|
|
535
535
|
## Local data format
|
|
536
536
|
|
|
537
|
-
Start this runtime with an empty `SUI_MCP_DATA_DIR` or a database already in its current format. A mismatched existing database is refused before writes
|
|
537
|
+
Start this runtime with an empty `SUI_MCP_DATA_DIR` or a database already in its current format. A mismatched existing database is refused before writes; incompatible databases and backups are not migrated or converted. A database with different table, constraint or field definitions requires a new empty data folder, preserving the existing folder. Databases and backups do not carry a separate numeric schema version. With a new empty folder, configure the required account context and endpoints. Existing files are left in place, and environment overrides keep their existing precedence. See [Local DB Architecture](LOCAL_DB_ARCHITECTURE.md) for the current format, backup scope and card-result retention. Card results do not expire with the input period and can increase DB size. Reset/import removes them along with the affected local data; it is not a card-only space cleanup operation.
|
|
538
538
|
|
|
539
539
|
## Local Settings
|
|
540
540
|
|
|
@@ -776,7 +776,7 @@ If the user supplied a specific Sui address for `read.summarize_wallet_assets` o
|
|
|
776
776
|
|
|
777
777
|
A 404 means the requested package or version could not be retrieved from the
|
|
778
778
|
selected registry. Confirm the exact name and version, for example with
|
|
779
|
-
`npm view @zktx.io/sui-mcp@0.6.
|
|
779
|
+
`npm view @zktx.io/sui-mcp@0.6.1 version --registry=https://registry.npmjs.org`.
|
|
780
780
|
A new version may not have been published or become visible yet; a mistyped name
|
|
781
781
|
or an alternate/private registry can also explain the response. Check the
|
|
782
782
|
publication result and registry configuration before retrying. Do not assume
|