@mysten-incubation/memwal-mcp 0.0.1-dev.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.
- package/dist/auth-required.d.ts +5 -0
- package/dist/auth-required.d.ts.map +1 -0
- package/dist/auth-required.js +175 -0
- package/dist/auth-required.js.map +1 -0
- package/dist/auth.d.ts +30 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +75 -0
- package/dist/auth.js.map +1 -0
- package/dist/bin/memwal-mcp.d.ts +3 -0
- package/dist/bin/memwal-mcp.d.ts.map +1 -0
- package/dist/bin/memwal-mcp.js +10 -0
- package/dist/bin/memwal-mcp.js.map +1 -0
- package/dist/bridge.d.ts +28 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/bridge.js +330 -0
- package/dist/bridge.js.map +1 -0
- package/dist/crypto.d.ts +16 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +41 -0
- package/dist/crypto.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +240 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +13 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +28 -0
- package/dist/logger.js.map +1 -0
- package/dist/login.d.ts +19 -0
- package/dist/login.d.ts.map +1 -0
- package/dist/login.js +272 -0
- package/dist/login.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-required.d.ts","sourceRoot":"","sources":["../src/auth-required.ts"],"names":[],"mappings":"AAiIA;;GAEG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAiE3D"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* "Auth-required" stdio MCP server — run when ~/.memwal/credentials.json is
|
|
3
|
+
* missing but the package was spawned by an MCP client (Cursor / Claude
|
|
4
|
+
* Desktop / etc.).
|
|
5
|
+
*
|
|
6
|
+
* Instead of exiting (which makes the MCP client show a cryptic
|
|
7
|
+
* "Failed to start server" error that the user can't act on), we boot a
|
|
8
|
+
* minimal MCP server that:
|
|
9
|
+
*
|
|
10
|
+
* - Responds to `initialize` so the client sees a healthy server.
|
|
11
|
+
* - Advertises the 4 real MemWal tools in `tools/list` so the agent
|
|
12
|
+
* knows what's available.
|
|
13
|
+
* - Returns an `isError: true` envelope on any `tools/call` with a
|
|
14
|
+
* friendly login instruction inline in the chat.
|
|
15
|
+
*
|
|
16
|
+
* This is a Phase B (current) compromise — Phase B.5 will replace it with
|
|
17
|
+
* the MCP OAuth flow so the client's host drives the browser dance and
|
|
18
|
+
* retries the tool call automatically (no client restart needed).
|
|
19
|
+
*/
|
|
20
|
+
import { log } from "./logger.js";
|
|
21
|
+
const TOOL_DEFINITIONS = [
|
|
22
|
+
{
|
|
23
|
+
name: "memwal_remember",
|
|
24
|
+
description: "Save a fact to the user's MemWal personal memory. Call ONLY when the user explicitly asks to remember/save something. Pass the full, detailed text — never summarize.",
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: "object",
|
|
27
|
+
properties: {
|
|
28
|
+
text: { type: "string", minLength: 1 },
|
|
29
|
+
namespace: { type: "string" },
|
|
30
|
+
},
|
|
31
|
+
required: ["text"],
|
|
32
|
+
additionalProperties: false,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
name: "memwal_recall",
|
|
37
|
+
description: "Search the user's MemWal memory for facts relevant to a query. Returns matching memories ranked by relevance.",
|
|
38
|
+
inputSchema: {
|
|
39
|
+
type: "object",
|
|
40
|
+
properties: {
|
|
41
|
+
query: { type: "string", minLength: 1 },
|
|
42
|
+
limit: { type: "integer", minimum: 1, maximum: 100, default: 10 },
|
|
43
|
+
namespace: { type: "string" },
|
|
44
|
+
},
|
|
45
|
+
required: ["query"],
|
|
46
|
+
additionalProperties: false,
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: "memwal_analyze",
|
|
51
|
+
description: "Extract memorable facts from a passage of text (preferences, habits, biographical info, constraints) and save each as a separate MemWal memory.",
|
|
52
|
+
inputSchema: {
|
|
53
|
+
type: "object",
|
|
54
|
+
properties: {
|
|
55
|
+
text: { type: "string", minLength: 1 },
|
|
56
|
+
namespace: { type: "string" },
|
|
57
|
+
},
|
|
58
|
+
required: ["text"],
|
|
59
|
+
additionalProperties: false,
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: "memwal_restore",
|
|
64
|
+
description: "Re-index a namespace from Walrus blobs back into the relayer's search index. Returns counts only.",
|
|
65
|
+
inputSchema: {
|
|
66
|
+
type: "object",
|
|
67
|
+
properties: {
|
|
68
|
+
namespace: { type: "string", minLength: 1 },
|
|
69
|
+
limit: { type: "integer", minimum: 1, maximum: 500, default: 50 },
|
|
70
|
+
},
|
|
71
|
+
required: ["namespace"],
|
|
72
|
+
additionalProperties: false,
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
const LOGIN_INSTRUCTION = [
|
|
77
|
+
"❌ MemWal isn't signed in yet.",
|
|
78
|
+
"",
|
|
79
|
+
"To connect this MCP client to your MemWal memory, run **once** in a terminal:",
|
|
80
|
+
"",
|
|
81
|
+
" npx -y @mysten-incubation/memwal-mcp login",
|
|
82
|
+
"",
|
|
83
|
+
"(or `npx -y @mysten-incubation/memwal-mcp login --local` / `--dev` to point at a non-prod env)",
|
|
84
|
+
"",
|
|
85
|
+
"A browser tab will open — click **Connect Sui Wallet** and approve the on-chain ",
|
|
86
|
+
"`add_delegate_key` transaction. The flow takes about 30 seconds.",
|
|
87
|
+
"",
|
|
88
|
+
"After login completes, restart this MCP client so it picks up the new credentials ",
|
|
89
|
+
"at `~/.memwal/credentials.json`. You won't need to do this again unless you revoke ",
|
|
90
|
+
"the delegate key from the dashboard.",
|
|
91
|
+
].join("\n");
|
|
92
|
+
function writeStdoutMessage(msg) {
|
|
93
|
+
process.stdout.write(JSON.stringify(msg) + "\n");
|
|
94
|
+
}
|
|
95
|
+
function readStdinLines(onLine) {
|
|
96
|
+
return new Promise((resolve) => {
|
|
97
|
+
let buf = "";
|
|
98
|
+
process.stdin.setEncoding("utf8");
|
|
99
|
+
process.stdin.on("data", (chunk) => {
|
|
100
|
+
buf += chunk;
|
|
101
|
+
let nl;
|
|
102
|
+
while ((nl = buf.indexOf("\n")) >= 0) {
|
|
103
|
+
const line = buf.slice(0, nl).replace(/\r$/, "");
|
|
104
|
+
buf = buf.slice(nl + 1);
|
|
105
|
+
if (line.length > 0)
|
|
106
|
+
onLine(line);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
process.stdin.on("end", () => resolve());
|
|
110
|
+
process.stdin.on("close", () => resolve());
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Run the auth-required stdio MCP server. Returns when stdin closes.
|
|
115
|
+
*/
|
|
116
|
+
export async function runAuthRequiredServer() {
|
|
117
|
+
log.info("auth_required_server.started", {});
|
|
118
|
+
await readStdinLines((line) => {
|
|
119
|
+
let req;
|
|
120
|
+
try {
|
|
121
|
+
req = JSON.parse(line);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
// Notifications don't need a response.
|
|
127
|
+
if (req.id == null && typeof req.method === "string") {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const id = req.id ?? null;
|
|
131
|
+
const method = req.method;
|
|
132
|
+
if (method === "initialize") {
|
|
133
|
+
writeStdoutMessage({
|
|
134
|
+
jsonrpc: "2.0",
|
|
135
|
+
id,
|
|
136
|
+
result: {
|
|
137
|
+
protocolVersion: "2024-11-05",
|
|
138
|
+
capabilities: { tools: { listChanged: false } },
|
|
139
|
+
serverInfo: { name: "memwal", version: "0.0.1" },
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (method === "tools/list") {
|
|
145
|
+
writeStdoutMessage({
|
|
146
|
+
jsonrpc: "2.0",
|
|
147
|
+
id,
|
|
148
|
+
result: { tools: TOOL_DEFINITIONS },
|
|
149
|
+
});
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (method === "tools/call") {
|
|
153
|
+
writeStdoutMessage({
|
|
154
|
+
jsonrpc: "2.0",
|
|
155
|
+
id,
|
|
156
|
+
result: {
|
|
157
|
+
content: [{ type: "text", text: LOGIN_INSTRUCTION }],
|
|
158
|
+
isError: true,
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
// Anything else — return Method not found per JSON-RPC.
|
|
164
|
+
writeStdoutMessage({
|
|
165
|
+
jsonrpc: "2.0",
|
|
166
|
+
id,
|
|
167
|
+
error: {
|
|
168
|
+
code: -32601,
|
|
169
|
+
message: `Method not found: ${method ?? "(missing)"}`,
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
log.info("auth_required_server.closed", {});
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=auth-required.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-required.js","sourceRoot":"","sources":["../src/auth-required.ts"],"names":[],"mappings":"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"}
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface MemWalCredentials {
|
|
2
|
+
/** 64-hex Ed25519 private key seed (32 bytes). NEVER log this. */
|
|
3
|
+
delegatePrivateKey: string;
|
|
4
|
+
/** 64-hex Ed25519 public key derived from the seed. Safe to display. */
|
|
5
|
+
delegatePublicKeyHex: string;
|
|
6
|
+
/** 0x-prefixed 64-hex Sui address derived from the delegate public key. */
|
|
7
|
+
delegateAddress: string;
|
|
8
|
+
/** 0x-prefixed Sui wallet address that signed the add_delegate_key tx. */
|
|
9
|
+
walletAddress: string;
|
|
10
|
+
/** 0x-prefixed MemWalAccount object id this delegate is registered against. */
|
|
11
|
+
accountId: string;
|
|
12
|
+
/** 0x-prefixed MemWal package id the account lives in. */
|
|
13
|
+
packageId: string;
|
|
14
|
+
/** Relayer base URL the bridge should connect to. */
|
|
15
|
+
relayerUrl: string;
|
|
16
|
+
/** Human-readable label, e.g. "Cursor MCP" — surfaced in dashboard. */
|
|
17
|
+
label?: string;
|
|
18
|
+
/** ISO timestamp credentials were saved. */
|
|
19
|
+
createdAt: string;
|
|
20
|
+
/** Schema version — bump when we change shape. */
|
|
21
|
+
version: 1;
|
|
22
|
+
}
|
|
23
|
+
export declare function credsPath(): string;
|
|
24
|
+
/** Load credentials from disk. Returns null if missing or malformed. */
|
|
25
|
+
export declare function loadCreds(): MemWalCredentials | null;
|
|
26
|
+
/** Write credentials with secure (`0600`) permission. */
|
|
27
|
+
export declare function saveCreds(creds: MemWalCredentials): void;
|
|
28
|
+
/** Delete credentials. No-op if the file does not exist. */
|
|
29
|
+
export declare function clearCreds(): void;
|
|
30
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,iBAAiB;IAC9B,kEAAkE;IAClE,kBAAkB,EAAE,MAAM,CAAC;IAC3B,wEAAwE;IACxE,oBAAoB,EAAE,MAAM,CAAC;IAC7B,2EAA2E;IAC3E,eAAe,EAAE,MAAM,CAAC;IACxB,0EAA0E;IAC1E,aAAa,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB,qDAAqD;IACrD,UAAU,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,OAAO,EAAE,CAAC,CAAC;CACd;AAKD,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,wEAAwE;AACxE,wBAAgB,SAAS,IAAI,iBAAiB,GAAG,IAAI,CAUpD;AAED,yDAAyD;AACzD,wBAAgB,SAAS,CAAC,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAUxD;AAED,4DAA4D;AAC5D,wBAAgB,UAAU,IAAI,IAAI,CAQjC"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credentials persistence — `~/.memwal/credentials.json`.
|
|
3
|
+
*
|
|
4
|
+
* The file is created with mode `0600` so it's only readable by the owning
|
|
5
|
+
* user; the delegate private key inside is sensitive (compromise lets an
|
|
6
|
+
* attacker write/read the user's memories until revoked from the
|
|
7
|
+
* dashboard).
|
|
8
|
+
*
|
|
9
|
+
* Format mirrors Walcraft's `credentials.json` so existing tooling +
|
|
10
|
+
* documentation patterns transfer cleanly.
|
|
11
|
+
*/
|
|
12
|
+
import { homedir } from "node:os";
|
|
13
|
+
import { join, dirname } from "node:path";
|
|
14
|
+
import { mkdirSync, readFileSync, writeFileSync, chmodSync, unlinkSync, existsSync } from "node:fs";
|
|
15
|
+
const CREDS_DIR = join(homedir(), ".memwal");
|
|
16
|
+
const CREDS_PATH = join(CREDS_DIR, "credentials.json");
|
|
17
|
+
export function credsPath() {
|
|
18
|
+
return CREDS_PATH;
|
|
19
|
+
}
|
|
20
|
+
/** Load credentials from disk. Returns null if missing or malformed. */
|
|
21
|
+
export function loadCreds() {
|
|
22
|
+
if (!existsSync(CREDS_PATH))
|
|
23
|
+
return null;
|
|
24
|
+
try {
|
|
25
|
+
const raw = readFileSync(CREDS_PATH, "utf8");
|
|
26
|
+
const parsed = JSON.parse(raw);
|
|
27
|
+
if (!isValid(parsed))
|
|
28
|
+
return null;
|
|
29
|
+
return parsed;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** Write credentials with secure (`0600`) permission. */
|
|
36
|
+
export function saveCreds(creds) {
|
|
37
|
+
mkdirSync(dirname(CREDS_PATH), { recursive: true, mode: 0o700 });
|
|
38
|
+
writeFileSync(CREDS_PATH, JSON.stringify(creds, null, 2), { encoding: "utf8", mode: 0o600 });
|
|
39
|
+
// writeFileSync's `mode` argument is only honored on file creation; ensure
|
|
40
|
+
// the permission on an existing file matches.
|
|
41
|
+
try {
|
|
42
|
+
chmodSync(CREDS_PATH, 0o600);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
/* Windows etc. — best effort */
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/** Delete credentials. No-op if the file does not exist. */
|
|
49
|
+
export function clearCreds() {
|
|
50
|
+
if (existsSync(CREDS_PATH)) {
|
|
51
|
+
try {
|
|
52
|
+
unlinkSync(CREDS_PATH);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
/* swallow */
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function isValid(obj) {
|
|
60
|
+
if (!obj || typeof obj !== "object")
|
|
61
|
+
return false;
|
|
62
|
+
const c = obj;
|
|
63
|
+
return (typeof c.delegatePrivateKey === "string" &&
|
|
64
|
+
/^[0-9a-fA-F]{64}$/.test(c.delegatePrivateKey) &&
|
|
65
|
+
typeof c.delegatePublicKeyHex === "string" &&
|
|
66
|
+
typeof c.delegateAddress === "string" &&
|
|
67
|
+
typeof c.walletAddress === "string" &&
|
|
68
|
+
typeof c.accountId === "string" &&
|
|
69
|
+
/^0x[0-9a-fA-F]{64}$/.test(c.accountId) &&
|
|
70
|
+
typeof c.packageId === "string" &&
|
|
71
|
+
typeof c.relayerUrl === "string" &&
|
|
72
|
+
typeof c.createdAt === "string" &&
|
|
73
|
+
c.version === 1);
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAyBpG,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AAC7C,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;AAEvD,MAAM,UAAU,SAAS;IACrB,OAAO,UAAU,CAAC;AACtB,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,SAAS;IACrB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IACzC,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAC;QAClC,OAAO,MAA2B,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,SAAS,CAAC,KAAwB;IAC9C,SAAS,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACjE,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7F,2EAA2E;IAC3E,8CAA8C;IAC9C,IAAI,CAAC;QACD,SAAS,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACL,gCAAgC;IACpC,CAAC;AACL,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,UAAU;IACtB,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QACzB,IAAI,CAAC;YACD,UAAU,CAAC,UAAU,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACL,aAAa;QACjB,CAAC;IACL,CAAC;AACL,CAAC;AAED,SAAS,OAAO,CAAC,GAAY;IACzB,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAClD,MAAM,CAAC,GAAG,GAA8B,CAAC;IACzC,OAAO,CACH,OAAO,CAAC,CAAC,kBAAkB,KAAK,QAAQ;QACxC,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC;QAC9C,OAAO,CAAC,CAAC,oBAAoB,KAAK,QAAQ;QAC1C,OAAO,CAAC,CAAC,eAAe,KAAK,QAAQ;QACrC,OAAO,CAAC,CAAC,aAAa,KAAK,QAAQ;QACnC,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ;QAC/B,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QACvC,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ;QAC/B,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ;QAChC,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ;QAC/B,CAAC,CAAC,OAAO,KAAK,CAAC,CAClB,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memwal-mcp.d.ts","sourceRoot":"","sources":["../../src/bin/memwal-mcp.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { main } from "../index.js";
|
|
3
|
+
main().catch((err) => {
|
|
4
|
+
process.stderr.write(`[memwal-mcp] fatal: ${err?.message ?? String(err)}\n`);
|
|
5
|
+
if (err?.stack && process.env.MEMWAL_MCP_DEBUG) {
|
|
6
|
+
process.stderr.write(err.stack + "\n");
|
|
7
|
+
}
|
|
8
|
+
process.exit(1);
|
|
9
|
+
});
|
|
10
|
+
//# sourceMappingURL=memwal-mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memwal-mcp.js","sourceRoot":"","sources":["../../src/bin/memwal-mcp.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEnC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACjB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,GAAG,EAAE,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC7E,IAAI,GAAG,EAAE,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QAC7C,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC,CAAC,CAAC"}
|
package/dist/bridge.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* stdio ↔ remote-SSE bridge.
|
|
3
|
+
*
|
|
4
|
+
* The MCP client (Cursor, Claude Desktop, etc.) speaks **stdio** MCP — JSON
|
|
5
|
+
* lines on stdin, JSON lines on stdout. The MemWal relayer speaks **remote
|
|
6
|
+
* SSE** MCP at `/api/mcp/sse` + `/api/mcp/messages`. This module glues the
|
|
7
|
+
* two together so the user only adds a `command + args` entry to their MCP
|
|
8
|
+
* client config (no headers, no URL).
|
|
9
|
+
*
|
|
10
|
+
* On 401 from the relayer, we surface a clear error to the MCP client but
|
|
11
|
+
* leave the local credentials file untouched. A naive `clearCreds()` here
|
|
12
|
+
* was a creds-wipe DoS: anyone able to coerce a 401 response (transient WAF
|
|
13
|
+
* rule, future http_proxy MITM, local malware racing the relayer port on
|
|
14
|
+
* `--local`) would have wiped the user's saved seed without consent.
|
|
15
|
+
* Re-auth requires an explicit `memwal-mcp login` from the user.
|
|
16
|
+
*/
|
|
17
|
+
import type { MemWalCredentials } from "./auth.js";
|
|
18
|
+
/**
|
|
19
|
+
* Open the SSE bridge and forward stdio ↔ relayer until stdin closes.
|
|
20
|
+
*
|
|
21
|
+
* On SSE drop (idle timeout in the Rust proxy / undici keep-alive / network
|
|
22
|
+
* blip), we transparently reopen the stream — the relayer issues a fresh
|
|
23
|
+
* sessionId, we route subsequent POSTs there. stdin stays open the whole
|
|
24
|
+
* time, so the MCP client (Cursor / Claude Desktop / etc.) never sees the
|
|
25
|
+
* reconnection.
|
|
26
|
+
*/
|
|
27
|
+
export declare function runBridge(creds: MemWalCredentials): Promise<void>;
|
|
28
|
+
//# sourceMappingURL=bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAmOnD;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAqIvE"}
|