wontopos-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +65 -0
  3. package/index.mjs +184 -0
  4. package/package.json +34 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Wontopos
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # wontopos-mcp — one memory across every AI tool
2
+
3
+ [Wontopos (WOS)](https://wontopos.com) long-term memory as an [MCP](https://modelcontextprotocol.io) server.
4
+
5
+ Memory belongs to your **account**, not to a tool. The same store recalls in
6
+ Claude Code, Claude Desktop, Cursor — and in ChatGPT via Actions with the same
7
+ API ([openapi.json](https://api.wontopos.com/openapi.json)) — so a conversation
8
+ started in one tool continues in another. Pure semantic retrieval, identical
9
+ recall in every language, bounded context (~1,200 tokens) per recall.
10
+
11
+ ## Claude Code
12
+
13
+ ```bash
14
+ claude mcp add wontopos --env WONTOPOS_API_KEY=wos-live-... -- npx -y wontopos-mcp
15
+ ```
16
+
17
+ ## Claude Desktop / Cursor / any MCP host
18
+
19
+ ```json
20
+ {
21
+ "mcpServers": {
22
+ "wontopos": {
23
+ "command": "npx",
24
+ "args": ["-y", "wontopos-mcp"],
25
+ "env": { "WONTOPOS_API_KEY": "wos-live-..." }
26
+ }
27
+ }
28
+ }
29
+ ```
30
+
31
+ Create a key in the [console](https://wontopos.com). Optional env:
32
+ `WONTOPOS_USER_ID` (default store, default `"default"`), `WONTOPOS_MODEL`
33
+ (`tablet-1` default, `scroll-1`), `WONTOPOS_BASE_URL` (self-hosted).
34
+
35
+ ## Tools
36
+
37
+ | Tool | What the agent does with it |
38
+ |---|---|
39
+ | `recall` | One-call context: recent turns + relevant long-term memories + surroundings. First call when past context matters. |
40
+ | `remember` | Store a durable fact/decision/preference. `speaker: "me"` = the agent's own words; a registered name = who said it. |
41
+ | `search` | Semantic search, optional per-person filter (`speaker`). |
42
+ | `forget` | Delete one memory by id. |
43
+ | `speakers` | Register / list / unregister the people a store remembers (50 to start; `"me"` is free). |
44
+ | `create_store` | Stores are explicit — create one per end-user, project, or agent. |
45
+
46
+ ## One memory, many tools
47
+
48
+ Same `WONTOPOS_API_KEY` + same store id ⇒ the memory follows you:
49
+
50
+ ```
51
+ ChatGPT (Actions) ─┐
52
+ Claude / Claude Code ─┼──▶ store "you" on api.wontopos.com
53
+ Cursor / your agent ─┘
54
+ ```
55
+
56
+ Tell Claude Code "remember that we ship on Fridays", then ask ChatGPT "when do
57
+ we ship?" — same memory answers.
58
+
59
+ Uses the [`wontopos`](https://www.npmjs.com/package/wontopos) SDK underneath, so
60
+ automatic retries, redirect refusal, response caps, and key hygiene apply as-is.
61
+
62
+ - Docs: <https://wontopos.com/en/why>
63
+ - Spec: <https://api.wontopos.com/openapi.json> · <https://wontopos.com/llms.txt>
64
+
65
+ License: MIT.
package/index.mjs ADDED
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env node
2
+ // wontopos-mcp — use Wontopos (WOS) long-term memory from any MCP host:
3
+ // Claude Code, Claude Desktop, Cursor, Windsurf, or your own agent.
4
+ //
5
+ // claude mcp add wontopos --env WONTOPOS_API_KEY=wos-live-... -- npx -y wontopos-mcp
6
+ //
7
+ // One store id = one memory across every tool. The same user_id written from
8
+ // ChatGPT (via Actions + openapi.json) recalls here, and vice versa — memory
9
+ // belongs to the account, not the tool.
10
+ //
11
+ // Env:
12
+ // WONTOPOS_API_KEY required (wos-live-...)
13
+ // WONTOPOS_USER_ID default store for every tool call (default: "default")
14
+ // WONTOPOS_MODEL engine, e.g. tablet-1 (default) or scroll-1
15
+ // WONTOPOS_BASE_URL self-hosted deployments only
16
+ //
17
+ // Thin wrapper over the `wontopos` SDK, so retries, redirect refusal, response
18
+ // caps, and key hygiene all apply as-is.
19
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
20
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
21
+ import { z } from "zod";
22
+ import { Client, WosError } from "wontopos";
23
+
24
+ const VERSION = "1.0.0";
25
+
26
+ const apiKey = process.env.WONTOPOS_API_KEY ?? process.env.WOS_API_KEY;
27
+ if (!apiKey || !apiKey.trim()) {
28
+ console.error(
29
+ "wontopos-mcp: set WONTOPOS_API_KEY (create a key in the console at https://wontopos.com)."
30
+ );
31
+ process.exit(1);
32
+ }
33
+
34
+ const mem = new Client({
35
+ apiKey,
36
+ userId: process.env.WONTOPOS_USER_ID || "default",
37
+ ...(process.env.WONTOPOS_MODEL ? { model: process.env.WONTOPOS_MODEL } : {}),
38
+ ...(process.env.WONTOPOS_BASE_URL ? { baseUrl: process.env.WONTOPOS_BASE_URL } : {}),
39
+ });
40
+
41
+ const server = new McpServer({ name: "wontopos", version: VERSION });
42
+
43
+ /** Wrap a handler: JSON out, typed WosError in-band so the agent can react. */
44
+ function run(fn) {
45
+ return async (args) => {
46
+ try {
47
+ const result = await fn(args ?? {});
48
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 1) }] };
49
+ } catch (e) {
50
+ // WosError.message already carries "[status] ... (request_id: ...)".
51
+ const msg = e instanceof WosError ? e.message : String(e?.message ?? e);
52
+ return { content: [{ type: "text", text: msg }], isError: true };
53
+ }
54
+ };
55
+ }
56
+
57
+ const userIdArg = z
58
+ .string()
59
+ .optional()
60
+ .describe("Store to use. Omit for the configured default store — only set this when the user explicitly works with multiple stores.");
61
+
62
+ server.registerTool(
63
+ "recall",
64
+ {
65
+ title: "Recall memory context",
66
+ description:
67
+ "One-call memory context: recent turns + relevant long-term memories + surrounding context. " +
68
+ "Call this FIRST whenever the user references past work, preferences, people, or decisions " +
69
+ "('like last time', 'the bug we fixed', 'what does she like'). Returns bounded output (~1,200 tokens) " +
70
+ "regardless of how much is stored. Works in every language.",
71
+ inputSchema: {
72
+ query: z.string().describe("What you want to remember about, phrased like the user's need."),
73
+ user_id: userIdArg,
74
+ },
75
+ },
76
+ run(({ query, user_id }) => mem.recall(query, user_id))
77
+ );
78
+
79
+ server.registerTool(
80
+ "remember",
81
+ {
82
+ title: "Store a memory",
83
+ description:
84
+ "Store one durable fact, decision, preference, or event worth recalling in future sessions. " +
85
+ "Write it as a standalone sentence with names and concrete details ('Sunwoo prefers dark mode in the console'), " +
86
+ "not a chat log. Optional speaker: 'me' = the agent's OWN words/commitments (no registration needed); " +
87
+ "a person's name = who said it (register the person once with the speakers tool first, or this returns 400). " +
88
+ "Identical content is deduplicated (status 'duplicate').",
89
+ inputSchema: {
90
+ content: z.string().describe("The memory, as one self-contained sentence."),
91
+ speaker: z
92
+ .string()
93
+ .optional()
94
+ .describe("'me' for the agent's own words, or a REGISTERED person's name. Omit for untagged."),
95
+ event_date: z
96
+ .string()
97
+ .optional()
98
+ .describe("RFC3339 date when the event actually happened, if different from now."),
99
+ user_id: userIdArg,
100
+ },
101
+ },
102
+ run(({ content, speaker, event_date, user_id }) => {
103
+ const metadata = {};
104
+ if (speaker) metadata.speaker = speaker;
105
+ if (event_date) metadata.event_date = event_date;
106
+ return mem.add(content, user_id, metadata);
107
+ })
108
+ );
109
+
110
+ server.registerTool(
111
+ "search",
112
+ {
113
+ title: "Search memories",
114
+ description:
115
+ "Semantic search over stored memories, most relevant first. Pure semantic (no keywords) — " +
116
+ "query by meaning in any language. Optional speaker filter recalls one person's words only " +
117
+ "('me' or a registered name; unregistered names return 404).",
118
+ inputSchema: {
119
+ query: z.string(),
120
+ limit: z.number().int().min(1).max(60).optional().describe("Max results (default 10)."),
121
+ speaker: z.string().optional().describe("Only this person's words: 'me' or a registered name."),
122
+ user_id: userIdArg,
123
+ },
124
+ },
125
+ run(({ query, limit, speaker, user_id }) =>
126
+ mem.search(query, user_id, limit ?? 10, speaker ? { speaker } : {})
127
+ )
128
+ );
129
+
130
+ server.registerTool(
131
+ "forget",
132
+ {
133
+ title: "Forget one memory",
134
+ description:
135
+ "Delete a single memory by its id (from search/remember results). Destructive and permanent — " +
136
+ "only when the user asks to forget or a stored fact is wrong (prefer remember with corrected " +
137
+ "content for updates).",
138
+ inputSchema: {
139
+ memory_id: z.string().describe("The memory id to delete."),
140
+ user_id: userIdArg,
141
+ },
142
+ },
143
+ run(({ memory_id, user_id }) => mem.delete(user_id, memory_id))
144
+ );
145
+
146
+ server.registerTool(
147
+ "speakers",
148
+ {
149
+ title: "Manage speakers (who said it)",
150
+ description:
151
+ "WHO can say memories in this store. action 'list' shows registered people with memory counts; " +
152
+ "'add' registers a person (explicit, like stores — up to 50 per store to start; a typo can never " +
153
+ "silently become a new person); 'remove' unregisters (their memories stay, the name tag goes). " +
154
+ "'me' (the agent itself) is reserved and never needs registration.",
155
+ inputSchema: {
156
+ action: z.enum(["list", "add", "remove"]),
157
+ speaker: z.string().optional().describe("The person's name (required for add/remove)."),
158
+ user_id: userIdArg,
159
+ },
160
+ },
161
+ run(({ action, speaker, user_id }) => {
162
+ if (action === "list") return mem.listSpeakers(user_id);
163
+ if (!speaker) throw new Error("speaker is required for add/remove.");
164
+ return action === "add" ? mem.addSpeaker(speaker, user_id) : mem.removeSpeaker(speaker, user_id);
165
+ })
166
+ );
167
+
168
+ server.registerTool(
169
+ "create_store",
170
+ {
171
+ title: "Create a memory store",
172
+ description:
173
+ "Create a store (a user_id namespace). Stores are explicit: writing to or reading a store that " +
174
+ "does not exist returns 404 — create it once first. Idempotent. Every account already has a " +
175
+ "'default' store, so this is only needed for additional stores (per end-user, per project, ...).",
176
+ inputSchema: {
177
+ user_id: z.string().describe("The store id to create."),
178
+ },
179
+ },
180
+ run(({ user_id }) => mem.createStore(user_id))
181
+ );
182
+
183
+ await server.connect(new StdioServerTransport());
184
+ console.error(`wontopos-mcp ${VERSION} ready (store: ${process.env.WONTOPOS_USER_ID || "default"})`);
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "wontopos-mcp",
3
+ "version": "1.0.0",
4
+ "description": "Wontopos (WOS) long-term memory as an MCP server — one memory across Claude Code, Claude Desktop, Cursor, ChatGPT, and your own agents.",
5
+ "keywords": [
6
+ "mcp",
7
+ "model-context-protocol",
8
+ "memory",
9
+ "ai",
10
+ "agent",
11
+ "claude",
12
+ "long-term-memory"
13
+ ],
14
+ "homepage": "https://wontopos.com",
15
+ "license": "MIT",
16
+ "author": "Wontopos",
17
+ "type": "module",
18
+ "bin": {
19
+ "wontopos-mcp": "./index.mjs"
20
+ },
21
+ "files": [
22
+ "index.mjs",
23
+ "README.md",
24
+ "LICENSE"
25
+ ],
26
+ "engines": {
27
+ "node": ">=18"
28
+ },
29
+ "dependencies": {
30
+ "@modelcontextprotocol/sdk": "^1.29.0",
31
+ "wontopos": "^2.2.9",
32
+ "zod": "^3.23.0"
33
+ }
34
+ }