@mysten-incubation/memwal-mcp 0.0.14-dev.1 → 0.0.14-dev.11
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 +238 -1
- package/dist/auth-required.d.ts +105 -0
- package/dist/auth-required.d.ts.map +1 -1
- package/dist/auth-required.js +48 -14
- package/dist/auth-required.js.map +1 -1
- package/dist/auth.d.ts +179 -18
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +458 -35
- package/dist/auth.js.map +1 -1
- package/dist/auto-save.d.ts +100 -0
- package/dist/auto-save.d.ts.map +1 -0
- package/dist/auto-save.js +290 -0
- package/dist/auto-save.js.map +1 -0
- package/dist/bridge.d.ts +10 -2
- package/dist/bridge.d.ts.map +1 -1
- package/dist/bridge.js +155 -25
- package/dist/bridge.js.map +1 -1
- package/dist/compatibility.d.ts.map +1 -1
- package/dist/compatibility.js +17 -2
- package/dist/compatibility.js.map +1 -1
- package/dist/consent.d.ts +36 -0
- package/dist/consent.d.ts.map +1 -0
- package/dist/consent.js +129 -0
- package/dist/consent.js.map +1 -0
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +13 -1
- package/dist/crypto.js.map +1 -1
- package/dist/health-probe.d.ts +35 -0
- package/dist/health-probe.d.ts.map +1 -0
- package/dist/health-probe.js +87 -0
- package/dist/health-probe.js.map +1 -0
- package/dist/index.d.ts +11 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +266 -5
- package/dist/index.js.map +1 -1
- package/dist/instructions.d.ts +17 -21
- package/dist/instructions.d.ts.map +1 -1
- package/dist/instructions.js +74 -12
- package/dist/instructions.js.map +1 -1
- package/dist/login.d.ts +15 -1
- package/dist/login.d.ts.map +1 -1
- package/dist/login.js +109 -9
- package/dist/login.js.map +1 -1
- package/dist/memory-policy.d.ts +38 -0
- package/dist/memory-policy.d.ts.map +1 -0
- package/dist/memory-policy.js +80 -0
- package/dist/memory-policy.js.map +1 -0
- package/dist/messages.d.ts +10 -3
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +16 -5
- package/dist/messages.js.map +1 -1
- package/dist/recovery.d.ts +1 -0
- package/dist/recovery.d.ts.map +1 -1
- package/dist/recovery.js +15 -13
- package/dist/recovery.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,86 @@ Add Walrus Memory MCP to your MCP client config:
|
|
|
23
23
|
}
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
+
## How the plugin launches the server
|
|
27
|
+
|
|
28
|
+
The [MemWal plugin](https://memory.walrus.xyz/mcp/claude-code) does **not** use the
|
|
29
|
+
`npx` form above. `npx` resolves a package *name* against the directory the MCP
|
|
30
|
+
client was started in — your project — so a project that contains an installed
|
|
31
|
+
`@mysten-incubation/memwal-mcp` claiming the pinned version would be run instead of
|
|
32
|
+
the published one. Pinning the version in the `npx` command does not prevent that:
|
|
33
|
+
the planted package simply claims the pinned version.
|
|
34
|
+
|
|
35
|
+
Instead, every plugin launch config runs the plugin's launcher:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"mcpServers": {
|
|
40
|
+
"memwal": {
|
|
41
|
+
"command": "node",
|
|
42
|
+
"args": ["${CLAUDE_PLUGIN_ROOT}/scripts/launch_mcp.mjs"]
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The launcher installs the pinned version once into a directory it owns and then
|
|
49
|
+
runs that absolute entry point with the current `node` binary:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
~/.memwal/runtime/memwal-mcp@<version>/node_modules/@mysten-incubation/memwal-mcp/dist/bin/memwal-mcp.js
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
It never consults your project's `node_modules` or a `PATH`-relative bin shim, and
|
|
56
|
+
it fails rather than falling back to the package name if the pinned version cannot
|
|
57
|
+
be installed. Everything after the script path is forwarded to the server
|
|
58
|
+
unchanged, so flags such as `--namespace work` or `--relayer <url>` work exactly as
|
|
59
|
+
they do above.
|
|
60
|
+
|
|
61
|
+
The runtime directory is trusted because of what it is, not how it is spelled:
|
|
62
|
+
|
|
63
|
+
- It must be outside the project the client started in. An absolute path is not
|
|
64
|
+
enough on its own — a client expands `${workspaceFolder}` to an absolute path
|
|
65
|
+
inside the repository, and a repository can commit a whole fake install there.
|
|
66
|
+
- It must be a real directory (not a symlink), owned by you, and not group- or
|
|
67
|
+
world-writable. The launcher creates it with mode `0700` and refuses to run code
|
|
68
|
+
out of it otherwise. If you see a refusal, `chmod 700 ~/.memwal ~/.memwal/runtime`.
|
|
69
|
+
- `MEMWAL_MCP_RUNTIME_DIR` moves it, subject to exactly the same rules.
|
|
70
|
+
|
|
71
|
+
The one-off install is run with `--ignore-scripts` (so no `preinstall` or
|
|
72
|
+
`postinstall` from the package or its dependencies executes), against an explicitly
|
|
73
|
+
pinned public registry, with the `npm_config_*` and `NODE_OPTIONS` environment
|
|
74
|
+
scrubbed for that spawn — npm ranks environment variables above every `.npmrc`, so
|
|
75
|
+
a client `env` block would otherwise choose the registry. npm itself is run as
|
|
76
|
+
`node <npm-cli.js>` resolved from the running node binary where that layout exists.
|
|
77
|
+
|
|
78
|
+
What that does **not** give you is an integrity check of the package contents: it
|
|
79
|
+
establishes where the code came from and that nobody else can write it, not that
|
|
80
|
+
the registry served the bytes a reviewer read. If you install from a private
|
|
81
|
+
registry, pre-populate the directory yourself (below) — the launcher then finds the
|
|
82
|
+
install and never runs npm at all.
|
|
83
|
+
|
|
84
|
+
If you configure MemWal without the plugin and want the same property, install the
|
|
85
|
+
version you intend to run into a directory outside any project and point your
|
|
86
|
+
client at its absolute path:
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
mkdir -p ~/.memwal/runtime/memwal-mcp@0.0.14
|
|
90
|
+
chmod 700 ~/.memwal ~/.memwal/runtime
|
|
91
|
+
npm install --ignore-scripts --prefix ~/.memwal/runtime/memwal-mcp@0.0.14 \
|
|
92
|
+
@mysten-incubation/memwal-mcp@0.0.14
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"mcpServers": {
|
|
98
|
+
"memwal": {
|
|
99
|
+
"command": "node",
|
|
100
|
+
"args": ["/absolute/path/to/home/.memwal/runtime/memwal-mcp@0.0.14/node_modules/@mysten-incubation/memwal-mcp/dist/bin/memwal-mcp.js"]
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
26
106
|
## Login
|
|
27
107
|
|
|
28
108
|
Run the login flow manually:
|
|
@@ -38,6 +118,7 @@ The command opens your browser, asks you to connect your Sui wallet, and saves c
|
|
|
38
118
|
```sh
|
|
39
119
|
memwal-mcp
|
|
40
120
|
memwal-mcp login
|
|
121
|
+
memwal-mcp auto-save on|off
|
|
41
122
|
memwal-mcp --logout
|
|
42
123
|
memwal-mcp --help
|
|
43
124
|
```
|
|
@@ -52,9 +133,111 @@ Use CLI flags or environment variables to override the default Walrus Memory end
|
|
|
52
133
|
| `--web-url <url>` | `MEMWAL_WEB_URL` | Override the web app URL used during login. |
|
|
53
134
|
| `--label <text>` | `MEMWAL_CLIENT_LABEL` | Friendly delegate-key label shown in Walrus Memory. |
|
|
54
135
|
| `--namespace <name>` (alias `--ns`) | `MEMWAL_NAMESPACE` | Default memory namespace applied when the agent omits one. |
|
|
136
|
+
| `auto-save on\|off` | `MEMWAL_AUTO_SAVE` | Whether the agent saves durable facts unprompted. On once you agree at login; see [Automatic Memory](#automatic-memory). |
|
|
55
137
|
|
|
56
138
|
Enable verbose stderr logging with `MEMWAL_MCP_DEBUG=1`.
|
|
57
139
|
|
|
140
|
+
Set `MEMWAL_MCP_TRANSPORT=http` to dial the relayer's Streamable HTTP endpoint instead of the default SSE pair. Opt-in: reconnect replay is not transport-aware yet, so a write interrupted mid-send may be retried and duplicated.
|
|
141
|
+
|
|
142
|
+
## Automatic Memory
|
|
143
|
+
|
|
144
|
+
MemWal saves durable facts — preferences, decisions, constraints, recurring
|
|
145
|
+
workflows — as you state them, without asking each time. That is what it is for,
|
|
146
|
+
so it is on. It asks you once first.
|
|
147
|
+
|
|
148
|
+
The question comes up in your terminal the first time you run `login`:
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
MemWal can save things about you automatically.
|
|
152
|
+
|
|
153
|
+
What that means: when you state a preference, a decision, or a setting in
|
|
154
|
+
chat — "I prefer pnpm", "we deploy from dev", "the relayer is at X" —
|
|
155
|
+
MemWal writes it to your memory without asking each time, so it is there
|
|
156
|
+
in your next session and in every other client you use.
|
|
157
|
+
|
|
158
|
+
Before you choose:
|
|
159
|
+
|
|
160
|
+
- Saved memories are permanent. They go to Walrus, which is immutable
|
|
161
|
+
storage. You can stop saving new ones at any time, but you cannot
|
|
162
|
+
delete one that is already saved.
|
|
163
|
+
- They are encrypted to your account. Only your delegate key reads them.
|
|
164
|
+
- MemWal strips obvious credentials — API keys, tokens, passwords,
|
|
165
|
+
private keys — before saving. Treat that as a safety net, not a
|
|
166
|
+
guarantee: do not paste secrets into a session with this on.
|
|
167
|
+
|
|
168
|
+
[1] Save automatically recommended, this is what MemWal is for
|
|
169
|
+
[2] Only save when I ask nothing is saved unless you say "remember this"
|
|
170
|
+
|
|
171
|
+
Your choice [1/2]:
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
**Saved memories are permanent.** Walrus is immutable storage: you can stop
|
|
175
|
+
saving new ones at any time, but you cannot delete one already saved — which is
|
|
176
|
+
why you are asked before it starts rather than after.
|
|
177
|
+
|
|
178
|
+
Until you answer, nothing is saved unprompted on a new install; "remember this"
|
|
179
|
+
and recall work throughout. If you were using MemWal before this question
|
|
180
|
+
existed, it keeps saving as it always has and asks you at your next login.
|
|
181
|
+
|
|
182
|
+
The question is only ever asked in a terminal. It is never an MCP tool and never
|
|
183
|
+
something the assistant can answer for you. Change it any time:
|
|
184
|
+
|
|
185
|
+
```sh
|
|
186
|
+
npx -y @mysten-incubation/memwal-mcp auto-save on
|
|
187
|
+
npx -y @mysten-incubation/memwal-mcp auto-save off
|
|
188
|
+
npx -y @mysten-incubation/memwal-mcp auto-save # report the current setting
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
The answer is stored as `{"autoSave": true}` in `settings.json` next to your
|
|
192
|
+
credentials file, so it follows the same project-local-beats-global resolution.
|
|
193
|
+
To pin one MCP client instead, set the environment variable — it overrides the
|
|
194
|
+
file and skips the question:
|
|
195
|
+
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"mcpServers": {
|
|
199
|
+
"memwal": {
|
|
200
|
+
"command": "npx",
|
|
201
|
+
"args": ["-y", "@mysten-incubation/memwal-mcp"],
|
|
202
|
+
"env": { "MEMWAL_AUTO_SAVE": "1" }
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Recall is never gated, and neither is an explicit "remember this" — the setting
|
|
209
|
+
only decides whether the agent saves things you did not ask it to save. Saying
|
|
210
|
+
no costs nothing and is not asked about again.
|
|
211
|
+
|
|
212
|
+
### What is never saved
|
|
213
|
+
|
|
214
|
+
Walrus storage is append-only and encrypted: a memory that lands **cannot be
|
|
215
|
+
edited or deleted**. So credentials are excluded whichever way you answer, by the same
|
|
216
|
+
rules stated in the server instructions, the tool descriptions and the plugin
|
|
217
|
+
hooks — and enforced by a check that runs before any text is sent:
|
|
218
|
+
|
|
219
|
+
- passwords, API keys, access and refresh tokens, private keys, seed and
|
|
220
|
+
recovery phrases, authorization headers, session cookies, and connection
|
|
221
|
+
strings or URLs with an embedded `user:password`;
|
|
222
|
+
- anything you say not to save ("don't save this", "off the record");
|
|
223
|
+
- pasted third-party content — a fenced block, a quoted passage — which is not
|
|
224
|
+
a fact about you.
|
|
225
|
+
|
|
226
|
+
When a message mixes a preference with a credential, the **preference is kept**
|
|
227
|
+
and only the credential is removed: "I prefer dark mode, db is
|
|
228
|
+
`postgres://admin:hunter2@db.internal/app`" is stored with the password gone and
|
|
229
|
+
the host intact. The agent is told which kinds were removed; the secret itself
|
|
230
|
+
is never stored, logged, or echoed back.
|
|
231
|
+
|
|
232
|
+
Detection targets specific credential shapes rather than "looks random", so
|
|
233
|
+
identifiers you *do* want remembered — blob ids, Sui object ids, commit SHAs,
|
|
234
|
+
digests — pass through untouched. Where a secret is indistinguishable from an
|
|
235
|
+
identifier, the **label** decides: pasting your `credentials.json` has its
|
|
236
|
+
`delegatePrivateKey` removed, while the same 64 hex characters with nothing
|
|
237
|
+
calling them a key are stored as the digest they look like. The trade-off is
|
|
238
|
+
that a secret in no recognisable shape, and with no label near it, can still
|
|
239
|
+
slip past the check — which is why the model-facing rules exist alongside it.
|
|
240
|
+
|
|
58
241
|
## Default Namespace
|
|
59
242
|
|
|
60
243
|
By default the MCP tool schemas expose an optional `namespace` argument and the
|
|
@@ -146,12 +329,66 @@ You can also pass explicit URLs:
|
|
|
146
329
|
|
|
147
330
|
## Credential Storage
|
|
148
331
|
|
|
149
|
-
Credentials are stored locally in `~/.memwal/credentials.json
|
|
332
|
+
Credentials are stored locally in `~/.memwal/credentials.json`, and the
|
|
333
|
+
automatic-memory setting in `settings.json` beside it. To remove the
|
|
334
|
+
credentials:
|
|
150
335
|
|
|
151
336
|
```sh
|
|
152
337
|
npx -y @mysten-incubation/memwal-mcp --logout
|
|
153
338
|
```
|
|
154
339
|
|
|
340
|
+
A sign-in that is still in flight also writes a `login-pending.json`
|
|
341
|
+
write-ahead record, beside `credentials.json` in `~/.memwal`. It holds the
|
|
342
|
+
delegate keypair minted for that sign-in, written before the browser can
|
|
343
|
+
register the public half on-chain so an interrupted login can be reclaimed
|
|
344
|
+
instead of paid for a second time. Same owner-only mode `0600` as
|
|
345
|
+
`credentials.json`.
|
|
346
|
+
|
|
347
|
+
It is removed once the sign-in completes, on `--logout`, and on a successful
|
|
348
|
+
recovery at the next start. A record older than 24 hours is discarded rather
|
|
349
|
+
than reused.
|
|
350
|
+
|
|
351
|
+
### Per-project credentials
|
|
352
|
+
|
|
353
|
+
A project can keep its own `.memwal/credentials.json` so memory written from it
|
|
354
|
+
goes to a separate account. That file lives inside the repository, where anyone
|
|
355
|
+
who can commit to it — or who can get you to open a clone — could otherwise
|
|
356
|
+
choose the account and relayer your memories go to. So it is **ignored until you
|
|
357
|
+
approve it**, once per machine:
|
|
358
|
+
|
|
359
|
+
```sh
|
|
360
|
+
cd path/to/project
|
|
361
|
+
npx -y @mysten-incubation/memwal-mcp approve-project
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Until then the global credentials are used, and a line on stderr names the file
|
|
365
|
+
that was skipped and the destination it wanted. An approval covers one exact
|
|
366
|
+
project path, account, delegate key and relayer: if any of those change, it has
|
|
367
|
+
to be approved again. The record is kept in `~/.memwal/project-approvals.json`,
|
|
368
|
+
outside the repository, so a repository cannot carry its own approval.
|
|
369
|
+
`revoke-project` withdraws it.
|
|
370
|
+
|
|
371
|
+
Approving also picks the file that is **written**: a later sign-in from that
|
|
372
|
+
project saves a delegate private key into `.memwal/credentials.json` in plain
|
|
373
|
+
text, inside the repository. `approve-project` says so, and so does the sign-in
|
|
374
|
+
warning. Add `.memwal/` to your `.gitignore`. The write-ahead record is the one
|
|
375
|
+
thing that stays out: a project sign-in keeps it in `~/.memwal/login-pending/`,
|
|
376
|
+
one file per approved project, so no key material lands in the checkout and a
|
|
377
|
+
sign-in is still reclaimable only by the project that started it.
|
|
378
|
+
|
|
379
|
+
`MEMWAL_CREDS_DIR` points the credentials, the approval record and the
|
|
380
|
+
write-ahead record at a directory of your choosing and overrides project
|
|
381
|
+
resolution entirely, with no approval. Because it skips the gate, it must be an
|
|
382
|
+
**absolute path outside the current project**: a relative value would resolve
|
|
383
|
+
against the working directory and put the approval record inside the
|
|
384
|
+
repository, and an MCP client passes on the `env` block it reads from
|
|
385
|
+
`.cursor/mcp.json` / `.vscode/mcp.json` / `.claude/settings.json` in the
|
|
386
|
+
checkout — where `${workspaceFolder}` is expanded, so an in-project absolute
|
|
387
|
+
path is not proof you chose it. Anything else is refused with an error naming
|
|
388
|
+
the value, rather than quietly ignored. An empty value means unset.
|
|
389
|
+
|
|
390
|
+
`memwal_health` reports the destination in use as `account=… relayer=…`.
|
|
391
|
+
|
|
155
392
|
## License
|
|
156
393
|
|
|
157
394
|
Apache-2.0
|
package/dist/auth-required.d.ts
CHANGED
|
@@ -67,6 +67,7 @@ export declare const ALL_TOOL_DEFINITIONS: ({
|
|
|
67
67
|
query?: undefined;
|
|
68
68
|
limit?: undefined;
|
|
69
69
|
maxDistance?: undefined;
|
|
70
|
+
freshKey?: undefined;
|
|
70
71
|
};
|
|
71
72
|
required: string[];
|
|
72
73
|
additionalProperties: boolean;
|
|
@@ -102,6 +103,7 @@ export declare const ALL_TOOL_DEFINITIONS: ({
|
|
|
102
103
|
query?: undefined;
|
|
103
104
|
limit?: undefined;
|
|
104
105
|
maxDistance?: undefined;
|
|
106
|
+
freshKey?: undefined;
|
|
105
107
|
};
|
|
106
108
|
required: string[];
|
|
107
109
|
additionalProperties: boolean;
|
|
@@ -142,6 +144,7 @@ export declare const ALL_TOOL_DEFINITIONS: ({
|
|
|
142
144
|
query?: undefined;
|
|
143
145
|
limit?: undefined;
|
|
144
146
|
maxDistance?: undefined;
|
|
147
|
+
freshKey?: undefined;
|
|
145
148
|
};
|
|
146
149
|
additionalProperties: boolean;
|
|
147
150
|
required?: undefined;
|
|
@@ -181,6 +184,7 @@ export declare const ALL_TOOL_DEFINITIONS: ({
|
|
|
181
184
|
job_id?: undefined;
|
|
182
185
|
job_ids?: undefined;
|
|
183
186
|
waitMs?: undefined;
|
|
187
|
+
freshKey?: undefined;
|
|
184
188
|
};
|
|
185
189
|
required: string[];
|
|
186
190
|
additionalProperties: boolean;
|
|
@@ -213,6 +217,7 @@ export declare const ALL_TOOL_DEFINITIONS: ({
|
|
|
213
217
|
waitMs?: undefined;
|
|
214
218
|
query?: undefined;
|
|
215
219
|
maxDistance?: undefined;
|
|
220
|
+
freshKey?: undefined;
|
|
216
221
|
};
|
|
217
222
|
required: string[];
|
|
218
223
|
additionalProperties: boolean;
|
|
@@ -237,6 +242,36 @@ export declare const ALL_TOOL_DEFINITIONS: ({
|
|
|
237
242
|
query?: undefined;
|
|
238
243
|
limit?: undefined;
|
|
239
244
|
maxDistance?: undefined;
|
|
245
|
+
freshKey?: undefined;
|
|
246
|
+
};
|
|
247
|
+
additionalProperties: boolean;
|
|
248
|
+
required?: undefined;
|
|
249
|
+
};
|
|
250
|
+
} | {
|
|
251
|
+
name: string;
|
|
252
|
+
title: string;
|
|
253
|
+
annotations: {
|
|
254
|
+
readOnlyHint: boolean;
|
|
255
|
+
destructiveHint: boolean;
|
|
256
|
+
};
|
|
257
|
+
description: string;
|
|
258
|
+
inputSchema: {
|
|
259
|
+
type: string;
|
|
260
|
+
properties: {
|
|
261
|
+
freshKey: {
|
|
262
|
+
type: string;
|
|
263
|
+
default: boolean;
|
|
264
|
+
description: string;
|
|
265
|
+
};
|
|
266
|
+
text?: undefined;
|
|
267
|
+
namespace?: undefined;
|
|
268
|
+
facts?: undefined;
|
|
269
|
+
job_id?: undefined;
|
|
270
|
+
job_ids?: undefined;
|
|
271
|
+
waitMs?: undefined;
|
|
272
|
+
query?: undefined;
|
|
273
|
+
limit?: undefined;
|
|
274
|
+
maxDistance?: undefined;
|
|
240
275
|
};
|
|
241
276
|
additionalProperties: boolean;
|
|
242
277
|
required?: undefined;
|
|
@@ -271,6 +306,7 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
271
306
|
query?: undefined;
|
|
272
307
|
limit?: undefined;
|
|
273
308
|
maxDistance?: undefined;
|
|
309
|
+
freshKey?: undefined;
|
|
274
310
|
};
|
|
275
311
|
required: string[];
|
|
276
312
|
additionalProperties: boolean;
|
|
@@ -306,6 +342,7 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
306
342
|
query?: undefined;
|
|
307
343
|
limit?: undefined;
|
|
308
344
|
maxDistance?: undefined;
|
|
345
|
+
freshKey?: undefined;
|
|
309
346
|
};
|
|
310
347
|
required: string[];
|
|
311
348
|
additionalProperties: boolean;
|
|
@@ -346,6 +383,7 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
346
383
|
query?: undefined;
|
|
347
384
|
limit?: undefined;
|
|
348
385
|
maxDistance?: undefined;
|
|
386
|
+
freshKey?: undefined;
|
|
349
387
|
};
|
|
350
388
|
additionalProperties: boolean;
|
|
351
389
|
required?: undefined;
|
|
@@ -385,6 +423,7 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
385
423
|
job_id?: undefined;
|
|
386
424
|
job_ids?: undefined;
|
|
387
425
|
waitMs?: undefined;
|
|
426
|
+
freshKey?: undefined;
|
|
388
427
|
};
|
|
389
428
|
required: string[];
|
|
390
429
|
additionalProperties: boolean;
|
|
@@ -417,6 +456,7 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
417
456
|
waitMs?: undefined;
|
|
418
457
|
query?: undefined;
|
|
419
458
|
maxDistance?: undefined;
|
|
459
|
+
freshKey?: undefined;
|
|
420
460
|
};
|
|
421
461
|
required: string[];
|
|
422
462
|
additionalProperties: boolean;
|
|
@@ -441,6 +481,36 @@ export declare const TOOL_DEFINITIONS: ({
|
|
|
441
481
|
query?: undefined;
|
|
442
482
|
limit?: undefined;
|
|
443
483
|
maxDistance?: undefined;
|
|
484
|
+
freshKey?: undefined;
|
|
485
|
+
};
|
|
486
|
+
additionalProperties: boolean;
|
|
487
|
+
required?: undefined;
|
|
488
|
+
};
|
|
489
|
+
} | {
|
|
490
|
+
name: string;
|
|
491
|
+
title: string;
|
|
492
|
+
annotations: {
|
|
493
|
+
readOnlyHint: boolean;
|
|
494
|
+
destructiveHint: boolean;
|
|
495
|
+
};
|
|
496
|
+
description: string;
|
|
497
|
+
inputSchema: {
|
|
498
|
+
type: string;
|
|
499
|
+
properties: {
|
|
500
|
+
freshKey: {
|
|
501
|
+
type: string;
|
|
502
|
+
default: boolean;
|
|
503
|
+
description: string;
|
|
504
|
+
};
|
|
505
|
+
text?: undefined;
|
|
506
|
+
namespace?: undefined;
|
|
507
|
+
facts?: undefined;
|
|
508
|
+
job_id?: undefined;
|
|
509
|
+
job_ids?: undefined;
|
|
510
|
+
waitMs?: undefined;
|
|
511
|
+
query?: undefined;
|
|
512
|
+
limit?: undefined;
|
|
513
|
+
maxDistance?: undefined;
|
|
444
514
|
};
|
|
445
515
|
additionalProperties: boolean;
|
|
446
516
|
required?: undefined;
|
|
@@ -475,6 +545,7 @@ export declare const SIGNED_OUT_TOOL_DEFINITIONS: ({
|
|
|
475
545
|
query?: undefined;
|
|
476
546
|
limit?: undefined;
|
|
477
547
|
maxDistance?: undefined;
|
|
548
|
+
freshKey?: undefined;
|
|
478
549
|
};
|
|
479
550
|
required: string[];
|
|
480
551
|
additionalProperties: boolean;
|
|
@@ -510,6 +581,7 @@ export declare const SIGNED_OUT_TOOL_DEFINITIONS: ({
|
|
|
510
581
|
query?: undefined;
|
|
511
582
|
limit?: undefined;
|
|
512
583
|
maxDistance?: undefined;
|
|
584
|
+
freshKey?: undefined;
|
|
513
585
|
};
|
|
514
586
|
required: string[];
|
|
515
587
|
additionalProperties: boolean;
|
|
@@ -550,6 +622,7 @@ export declare const SIGNED_OUT_TOOL_DEFINITIONS: ({
|
|
|
550
622
|
query?: undefined;
|
|
551
623
|
limit?: undefined;
|
|
552
624
|
maxDistance?: undefined;
|
|
625
|
+
freshKey?: undefined;
|
|
553
626
|
};
|
|
554
627
|
additionalProperties: boolean;
|
|
555
628
|
required?: undefined;
|
|
@@ -589,6 +662,7 @@ export declare const SIGNED_OUT_TOOL_DEFINITIONS: ({
|
|
|
589
662
|
job_id?: undefined;
|
|
590
663
|
job_ids?: undefined;
|
|
591
664
|
waitMs?: undefined;
|
|
665
|
+
freshKey?: undefined;
|
|
592
666
|
};
|
|
593
667
|
required: string[];
|
|
594
668
|
additionalProperties: boolean;
|
|
@@ -621,6 +695,7 @@ export declare const SIGNED_OUT_TOOL_DEFINITIONS: ({
|
|
|
621
695
|
waitMs?: undefined;
|
|
622
696
|
query?: undefined;
|
|
623
697
|
maxDistance?: undefined;
|
|
698
|
+
freshKey?: undefined;
|
|
624
699
|
};
|
|
625
700
|
required: string[];
|
|
626
701
|
additionalProperties: boolean;
|
|
@@ -645,6 +720,36 @@ export declare const SIGNED_OUT_TOOL_DEFINITIONS: ({
|
|
|
645
720
|
query?: undefined;
|
|
646
721
|
limit?: undefined;
|
|
647
722
|
maxDistance?: undefined;
|
|
723
|
+
freshKey?: undefined;
|
|
724
|
+
};
|
|
725
|
+
additionalProperties: boolean;
|
|
726
|
+
required?: undefined;
|
|
727
|
+
};
|
|
728
|
+
} | {
|
|
729
|
+
name: string;
|
|
730
|
+
title: string;
|
|
731
|
+
annotations: {
|
|
732
|
+
readOnlyHint: boolean;
|
|
733
|
+
destructiveHint: boolean;
|
|
734
|
+
};
|
|
735
|
+
description: string;
|
|
736
|
+
inputSchema: {
|
|
737
|
+
type: string;
|
|
738
|
+
properties: {
|
|
739
|
+
freshKey: {
|
|
740
|
+
type: string;
|
|
741
|
+
default: boolean;
|
|
742
|
+
description: string;
|
|
743
|
+
};
|
|
744
|
+
text?: undefined;
|
|
745
|
+
namespace?: undefined;
|
|
746
|
+
facts?: undefined;
|
|
747
|
+
job_id?: undefined;
|
|
748
|
+
job_ids?: undefined;
|
|
749
|
+
waitMs?: undefined;
|
|
750
|
+
query?: undefined;
|
|
751
|
+
limit?: undefined;
|
|
752
|
+
maxDistance?: undefined;
|
|
648
753
|
};
|
|
649
754
|
additionalProperties: boolean;
|
|
650
755
|
required?: undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-required.d.ts","sourceRoot":"","sources":["../src/auth-required.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAwB,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"auth-required.d.ts","sourceRoot":"","sources":["../src/auth-required.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAwB,KAAK,iBAAiB,EAAE,MAAM,WAAW,CAAC;AA2MzE;;;;;;;;;;;;;;0EAc0E;AAC1E,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,MAAM,CAOrD,CAAC;AAMH;;0EAE0E;AAC1E,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAA6B,CAAC;AAS/D;;4CAE4C;AAC5C,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAAuB,CAAC;AAErD;;8BAE8B;AAC9B,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAAwB,CAAC;AA+CjE;;;mCAGmC;AACnC,MAAM,WAAW,kBAAkB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd;;;;4DAIwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;CACtB;AA6ID;;yCAEyC;AACzC,MAAM,WAAW,WAAW;IACxB,KAAK,EAAE,iBAAiB,CAAC;IACzB;;sCAEkC;IAClC,YAAY,EAAE,MAAM,EAAE,CAAC;CAC1B;AA4ID;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,qBAAqB,CACvC,MAAM,EAAE,kBAAkB,GAC3B,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAgE7B"}
|
package/dist/auth-required.js
CHANGED
|
@@ -25,11 +25,24 @@ import { credsPath, loadCreds } from "./auth.js";
|
|
|
25
25
|
import { rememberInitializeClientInfo } from "./client-info.js";
|
|
26
26
|
import { loginFailureNotice, loginPrompt, loginSuccessNotification } from "./messages.js";
|
|
27
27
|
import { log } from "./logger.js";
|
|
28
|
-
import { startOrReuseLoginFlow, resolveLoginTimeoutMs } from "./login.js";
|
|
28
|
+
import { startOrReuseLoginFlow, resolveLoginTimeoutMs, isLoginSuperseded } from "./login.js";
|
|
29
29
|
import { AUTH_REQUIRED_INSTRUCTIONS } from "./instructions.js";
|
|
30
|
+
import { SECRET_EXCLUSION_RULES, SECRET_EXCLUSION_SUMMARY, AUTO_SAVE_OPT_IN_RULE, } from "./memory-policy.js";
|
|
30
31
|
import { MEMWAL_MCP_VERSION } from "./version.js";
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
/**
|
|
33
|
+
* WALM-642: every write-tool description below ends with the shared policy
|
|
34
|
+
* block, the same text the `instructions` field and the plugin hooks carry, so
|
|
35
|
+
* an agent that only ever sees one of the three still gets the same rules.
|
|
36
|
+
* The signed-out variants get the one-line summary — they exist to keep a
|
|
37
|
+
* credential-less model from spamming writes, and the full block would be the
|
|
38
|
+
* longest thing in a list of tools that cannot run yet.
|
|
39
|
+
*/
|
|
40
|
+
const SIGNED_OUT_REMEMBER = "Save a fact to the user's Walrus Memory personal memory. Call ONLY when the user explicitly asks to remember/save something. Pass the full, detailed text — never summarize. " +
|
|
41
|
+
SECRET_EXCLUSION_SUMMARY;
|
|
42
|
+
const SIGNED_IN_REMEMBER = "Save a durable fact about the user or project to their Walrus Memory. Call this PROACTIVELY whenever the user states a preference, decision, constraint, correction, identity detail, or recurring workflow — even if they did not say 'remember this' — provided they have turned automatic memory on. Skip one-off tasks, the current file or bug, and small talk. Pass the full statement; do not summarize. To save several facts at once, use memwal_remember_bulk instead. By default this returns in ~1s once the relayer has accepted the job (job_id) — the Walrus write is still in flight and the fact is NOT stored yet. Do not claim it is saved. Settle it with the job-status tool this server advertises (re-list tools if you do not see one). A blob_id in the same reply means it already stored (optional wait budget). " +
|
|
43
|
+
AUTO_SAVE_OPT_IN_RULE +
|
|
44
|
+
" " +
|
|
45
|
+
SECRET_EXCLUSION_RULES;
|
|
33
46
|
const SIGNED_OUT_RECALL = "Search the user's Walrus Memory for facts relevant to a query. Returns matching memories ranked by relevance.";
|
|
34
47
|
const SIGNED_IN_RECALL = "Search the user's Walrus Memory for relevant facts before responding. Call this PROACTIVELY at the start of a task, or whenever the user references past work, prior decisions, their preferences, or anything you may have stored earlier — don't wait to be asked. A single focused query is usually enough — recall is a real retrieval over encrypted storage, so do NOT fire multiple redundant searches for the same question. Returns matching memories ranked by relevance.";
|
|
35
48
|
/** Build the static memory-tool list. `proactive` is true for the signed-in
|
|
@@ -56,7 +69,8 @@ function buildToolDefinitions(proactive) {
|
|
|
56
69
|
name: "memwal_remember_bulk",
|
|
57
70
|
title: "Remember Multiple Facts",
|
|
58
71
|
annotations: { readOnlyHint: false, destructiveHint: false },
|
|
59
|
-
description: "Save multiple durable facts in one call. Use when you learned several distinct facts at once (onboarding details, a list of preferences, decisions from a discussion). Pass an array of complete fact statements (max 20) — do not summarize. Prefer this over repeated memwal_remember calls. By default this returns in ~1s once the relayer has accepted the batch (job_ids) — the Walrus writes are still in flight and the facts are NOT stored yet. Do not claim they are saved. Settle them with the job-status tool this server advertises (re-list tools if you do not see one). A blob_id in the same reply means that fact already stored (optional wait budget)."
|
|
72
|
+
description: "Save multiple durable facts in one call. Use when you learned several distinct facts at once (onboarding details, a list of preferences, decisions from a discussion). Pass an array of complete fact statements (max 20) — do not summarize. Prefer this over repeated memwal_remember calls. By default this returns in ~1s once the relayer has accepted the batch (job_ids) — the Walrus writes are still in flight and the facts are NOT stored yet. Do not claim they are saved. Settle them with the job-status tool this server advertises (re-list tools if you do not see one). A blob_id in the same reply means that fact already stored (optional wait budget). " +
|
|
73
|
+
(proactive ? AUTO_SAVE_OPT_IN_RULE + " " + SECRET_EXCLUSION_RULES : SECRET_EXCLUSION_SUMMARY),
|
|
60
74
|
inputSchema: {
|
|
61
75
|
type: "object",
|
|
62
76
|
properties: {
|
|
@@ -125,7 +139,8 @@ function buildToolDefinitions(proactive) {
|
|
|
125
139
|
name: "memwal_analyze",
|
|
126
140
|
title: "Analyze and Remember",
|
|
127
141
|
annotations: { readOnlyHint: false, destructiveHint: true },
|
|
128
|
-
description: "Extract memorable facts from a longer passage of text (preferences, habits, biographical info, constraints) and save each as a separate Walrus Memory memory. Use this when you want MemWal's LLM to split the facts out of a transcript or notes for you; if you already know the exact facts, use memwal_remember or memwal_remember_bulk instead."
|
|
142
|
+
description: "Extract memorable facts from a longer passage of text (preferences, habits, biographical info, constraints) and save each as a separate Walrus Memory memory. Use this when you want MemWal's LLM to split the facts out of a transcript or notes for you; if you already know the exact facts, use memwal_remember or memwal_remember_bulk instead. " +
|
|
143
|
+
(proactive ? AUTO_SAVE_OPT_IN_RULE + " " + SECRET_EXCLUSION_RULES : SECRET_EXCLUSION_SUMMARY),
|
|
129
144
|
inputSchema: {
|
|
130
145
|
type: "object",
|
|
131
146
|
properties: {
|
|
@@ -169,7 +184,13 @@ function buildToolDefinitions(proactive) {
|
|
|
169
184
|
description: "Sign this MCP client into your Walrus Memory account by opening a browser. Run once when the agent reports Walrus Memory is not signed in. Opens the dashboard in the default browser, waits for wallet approval, then writes credentials to ~/.memwal/credentials.json. Other memwal_* tools become usable on the next call after a successful login.",
|
|
170
185
|
inputSchema: {
|
|
171
186
|
type: "object",
|
|
172
|
-
properties: {
|
|
187
|
+
properties: {
|
|
188
|
+
freshKey: {
|
|
189
|
+
type: "boolean",
|
|
190
|
+
default: false,
|
|
191
|
+
description: "Mint a new delegate key instead of reusing the one a previous unfinished sign-in left pending. Leave false for an ordinary login. Set it only after a normal sign-in has already failed on the pending key — it abandons that key, which must then be removed from the dashboard if it was approved on-chain, and the new one needs its own add_delegate_key transaction.",
|
|
192
|
+
},
|
|
193
|
+
},
|
|
173
194
|
additionalProperties: false,
|
|
174
195
|
},
|
|
175
196
|
},
|
|
@@ -239,13 +260,17 @@ const LOGIN_INSTRUCTION = [
|
|
|
239
260
|
/** Replaces {@link LOGIN_INSTRUCTION} after a failed attempt, which
|
|
240
261
|
* {@link loginFailureNotice} has just described. The generic copy promises "no
|
|
241
262
|
* client restart" and leads with `memwal_login`; for a key the user already
|
|
242
|
-
* approved, a restart is the only thing that recovers it and
|
|
243
|
-
*
|
|
244
|
-
*
|
|
263
|
+
* approved, a restart is the only thing that recovers it and a plain retry
|
|
264
|
+
* reuses it rather than registering a second one. So the retry names
|
|
265
|
+
* `freshKey` for the case the plain one cannot fix. */
|
|
245
266
|
const LOGIN_RETRY_INSTRUCTION = [
|
|
246
|
-
"
|
|
247
|
-
"
|
|
248
|
-
"
|
|
267
|
+
"Start a new sign-in: call the `memwal_login` tool from this client, or run",
|
|
268
|
+
"`npx -y @mysten-incubation/memwal-mcp login`. Open the new link straight away and",
|
|
269
|
+
"leave this client running through the wallet prompt.",
|
|
270
|
+
"",
|
|
271
|
+
"If that keeps failing on the same key, call `memwal_login` with `freshKey: true` to",
|
|
272
|
+
"mint a new one. That abandons the pending key: if you already approved it on-chain,",
|
|
273
|
+
"remove it from the dashboard afterwards.",
|
|
249
274
|
].join("\n");
|
|
250
275
|
/** Set when a background `memwal_login` ends without credentials. The tool call
|
|
251
276
|
* already returned the URL by then, so this is the only place left to say so. */
|
|
@@ -286,7 +311,7 @@ function sendLogMessage(level, text) {
|
|
|
286
311
|
* issues any other memwal_* tool to verify — which now succeeds because
|
|
287
312
|
* the bridge picks up the saved creds on its next call.
|
|
288
313
|
*/
|
|
289
|
-
async function handleLoginToolCall(config, _progressToken) {
|
|
314
|
+
async function handleLoginToolCall(config, _progressToken, freshKey) {
|
|
290
315
|
// Fire login but DO NOT await the wallet callback — it runs in the
|
|
291
316
|
// background. openBrowser: false because (a) child-process spawning a
|
|
292
317
|
// browser is unreliable across MCP clients, and (b) macOS `open <url>`
|
|
@@ -297,12 +322,17 @@ async function handleLoginToolCall(config, _progressToken) {
|
|
|
297
322
|
// Concurrent memwal_login calls join this in-flight flow instead of
|
|
298
323
|
// opening a second listener (that race hung later recall/remember).
|
|
299
324
|
lastLoginFailure = null;
|
|
325
|
+
let discardedKey;
|
|
300
326
|
const session = startOrReuseLoginFlow({
|
|
301
327
|
relayerUrl: config.relayerUrl,
|
|
302
328
|
webUrl: config.webUrl,
|
|
303
329
|
label: config.label,
|
|
304
330
|
timeoutMs: resolveLoginTimeoutMs(),
|
|
305
331
|
openBrowser: false,
|
|
332
|
+
freshKey,
|
|
333
|
+
onDiscarded: (key) => {
|
|
334
|
+
discardedKey = key;
|
|
335
|
+
},
|
|
306
336
|
onUrl: (url) => {
|
|
307
337
|
sendLogMessage("info", `Walrus Memory MCP login URL: ${url}`);
|
|
308
338
|
},
|
|
@@ -336,6 +366,9 @@ async function handleLoginToolCall(config, _progressToken) {
|
|
|
336
366
|
url = await Promise.race([session.url, timeoutPromise]);
|
|
337
367
|
}
|
|
338
368
|
catch (err) {
|
|
369
|
+
if (isLoginSuperseded(err)) {
|
|
370
|
+
return { isError: true, text: "This sign-in was replaced by a newer memwal_login. Open that result instead of starting another login." };
|
|
371
|
+
}
|
|
339
372
|
const msg = err instanceof Error ? err.message : String(err);
|
|
340
373
|
log.error("memwal_login.tool.url_not_ready", { msg });
|
|
341
374
|
return {
|
|
@@ -360,6 +393,7 @@ async function handleLoginToolCall(config, _progressToken) {
|
|
|
360
393
|
url,
|
|
361
394
|
credentialsPath: credsPath(),
|
|
362
395
|
signedIn: loadCreds() !== null,
|
|
396
|
+
discardedKey,
|
|
363
397
|
}),
|
|
364
398
|
};
|
|
365
399
|
}
|
|
@@ -433,7 +467,7 @@ function handleAuthLine(line, config) {
|
|
|
433
467
|
// Returns near-instantly with the click-able URL. The listener
|
|
434
468
|
// stays alive in the background — see handleLoginToolCall for the
|
|
435
469
|
// rationale on not blocking.
|
|
436
|
-
void handleLoginToolCall(config, progressToken).then((result) => {
|
|
470
|
+
void handleLoginToolCall(config, progressToken, params.arguments?.freshKey === true).then((result) => {
|
|
437
471
|
writeStdoutMessage({
|
|
438
472
|
jsonrpc: "2.0",
|
|
439
473
|
id,
|