wontopos-mcp 1.0.6 → 1.0.7

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 (2) hide show
  1. package/index.mjs +30 -6
  2. package/package.json +2 -2
package/index.mjs CHANGED
@@ -27,8 +27,12 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
27
27
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
28
28
  import { z } from "zod";
29
29
  import { Client, WosError } from "wontopos";
30
+ import { createRequire } from "node:module";
30
31
 
31
- const VERSION = "1.0.5";
32
+ // Read the version from package.json rather than restating it: a hand-kept copy
33
+ // silently drifts (1.0.6 shipped announcing itself as "1.0.5" in the MCP
34
+ // handshake, so hosts logged — and bug reports cited — the wrong build).
35
+ const VERSION = createRequire(import.meta.url)("./package.json").version;
32
36
  const flag = (v) => ["1", "true", "yes"].includes((v ?? "").trim().toLowerCase());
33
37
  const READ_ONLY = flag(process.env.WONTOPOS_READ_ONLY);
34
38
  // Store pinning (default ON): every call goes to WONTOPOS_USER_ID and the tools
@@ -61,6 +65,22 @@ function truncateToBytes(s, maxBytes) {
61
65
  return s.slice(0, read);
62
66
  }
63
67
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
68
+ const DATE_ONLY_RE = /^\d{4}-\d{2}-\d{2}$/;
69
+ /** Canonicalize event_date to the full RFC3339 the API requires.
70
+ * The API accepts only a complete date-TIME: a bare "2026-03-14" — the form a
71
+ * model naturally emits, and the form this tool's own example suggested — came
72
+ * back as an opaque 400 "Invalid request body or parameters." Normalize here
73
+ * instead of asking every agent to guess the shape.
74
+ * Returns null when the value is not a date at all, so the caller can refuse it. */
75
+ function normalizeEventDate(raw) {
76
+ const s = String(raw).trim();
77
+ if (Number.isNaN(Date.parse(s))) return null;
78
+ // Date-only is completed by string append, never through Date: parsing and
79
+ // re-serializing would re-interpret it in the host's zone and can shift the
80
+ // stated day by one, which is exactly the fact the user was pinning down.
81
+ if (DATE_ONLY_RE.test(s)) return `${s}T00:00:00Z`;
82
+ return new Date(s).toISOString();
83
+ }
64
84
 
65
85
  // First env var with a NON-EMPTY value wins. `??` only skips null/undefined, so
66
86
  // an empty WONTOPOS_API_KEY="" would shadow a valid WOS_API_KEY — the exact bug
@@ -174,7 +194,10 @@ server.registerTool(
174
194
  "('Sunwoo prefers dark mode in the console'), not a chat log. For your own side, store only " +
175
195
  "commitments you actually SAID to the user (speaker 'me') — never internal reasoning or thinking " +
176
196
  "output. Do NOT store fetched material: web search results, crawled pages, file contents, and " +
177
- "tool outputs are session context, not memories. Identical content is deduplicated (status 'duplicate').",
197
+ "tool outputs are session context, not memories. A memory close enough to one already stored is " +
198
+ "rejected as status 'duplicate' and is NOT saved — the match is by meaning, not by exact text, so " +
199
+ "when a new fact only narrows or contrasts an existing one ('allergic to shellfish' next to " +
200
+ "'allergic to peanuts'), write it as one sentence that states both, or supersede the old one with update.",
178
201
  inputSchema: {
179
202
  content: z.string().describe("The memory, as one self-contained sentence."),
180
203
  speaker: z
@@ -184,7 +207,7 @@ server.registerTool(
184
207
  event_date: z
185
208
  .string()
186
209
  .nullish()
187
- .describe("RFC3339 date when the event actually happened, if different from now."),
210
+ .describe("When the event actually happened, if different from now. A plain date ('2026-03-14') or a full RFC3339 timestamp; a bare date is read as UTC midnight."),
188
211
  ...storeArg,
189
212
  },
190
213
  },
@@ -194,11 +217,12 @@ server.registerTool(
194
217
  throw new Error("content too long (max 8192 bytes) — a memory is one fact; backfill large text with the SDK's add_bulk.");
195
218
  if (speaker && speaker !== "me")
196
219
  throw new Error("speaker must be 'me' (something the agent itself said) or omitted (the user's fact).");
197
- if (event_date && Number.isNaN(Date.parse(event_date)))
198
- throw new Error("event_date is not a parseable date — use RFC3339, e.g. 2026-07-01.");
220
+ const eventDate = event_date ? normalizeEventDate(event_date) : null;
221
+ if (event_date && !eventDate)
222
+ throw new Error("event_date is not a parseable date — use a date (2026-07-01) or RFC3339 (2026-07-01T09:00:00Z).");
199
223
  const metadata = {};
200
224
  if (speaker) metadata.speaker = speaker;
201
- if (event_date) metadata.event_date = event_date;
225
+ if (eventDate) metadata.event_date = eventDate;
202
226
  return mem.add(content, uid(user_id), metadata);
203
227
  })
204
228
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wontopos-mcp",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "mcpName": "com.wontopos/mcp",
5
5
  "description": "(beta) Wontopos (WOS) long-term memory as an MCP server — one memory across Claude Code, Claude Desktop, Cursor, ChatGPT, and your own agents.",
6
6
  "keywords": [
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@modelcontextprotocol/sdk": "^1.29.0",
35
- "wontopos": "^2.2.13",
35
+ "wontopos": "^2.2.22",
36
36
  "zod": "^3.23.0"
37
37
  }
38
38
  }