wanderlog-mcp 0.1.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 (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +256 -0
  3. package/dist/cache/trip-cache.js +87 -0
  4. package/dist/cache/trip-cache.js.map +1 -0
  5. package/dist/config.js +38 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/context.js +12 -0
  8. package/dist/context.js.map +1 -0
  9. package/dist/errors.js +86 -0
  10. package/dist/errors.js.map +1 -0
  11. package/dist/formatters/trip-summary.js +280 -0
  12. package/dist/formatters/trip-summary.js.map +1 -0
  13. package/dist/index.js +47 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/ot/apply.js +282 -0
  16. package/dist/ot/apply.js.map +1 -0
  17. package/dist/resolvers/day.js +83 -0
  18. package/dist/resolvers/day.js.map +1 -0
  19. package/dist/resolvers/place-ref.js +192 -0
  20. package/dist/resolvers/place-ref.js.map +1 -0
  21. package/dist/server.js +100 -0
  22. package/dist/server.js.map +1 -0
  23. package/dist/tools/add-checklist.js +59 -0
  24. package/dist/tools/add-checklist.js.map +1 -0
  25. package/dist/tools/add-hotel.js +92 -0
  26. package/dist/tools/add-hotel.js.map +1 -0
  27. package/dist/tools/add-note.js +63 -0
  28. package/dist/tools/add-note.js.map +1 -0
  29. package/dist/tools/add-place.js +98 -0
  30. package/dist/tools/add-place.js.map +1 -0
  31. package/dist/tools/create-trip.js +85 -0
  32. package/dist/tools/create-trip.js.map +1 -0
  33. package/dist/tools/get-trip-url.js +52 -0
  34. package/dist/tools/get-trip-url.js.map +1 -0
  35. package/dist/tools/get-trip.js +43 -0
  36. package/dist/tools/get-trip.js.map +1 -0
  37. package/dist/tools/list-trips.js +32 -0
  38. package/dist/tools/list-trips.js.map +1 -0
  39. package/dist/tools/remove-place.js +95 -0
  40. package/dist/tools/remove-place.js.map +1 -0
  41. package/dist/tools/search-places.js +81 -0
  42. package/dist/tools/search-places.js.map +1 -0
  43. package/dist/tools/shared.js +194 -0
  44. package/dist/tools/shared.js.map +1 -0
  45. package/dist/tools/update-trip-dates.js +208 -0
  46. package/dist/tools/update-trip-dates.js.map +1 -0
  47. package/dist/transport/rest.js +125 -0
  48. package/dist/transport/rest.js.map +1 -0
  49. package/dist/transport/sharedb.js +313 -0
  50. package/dist/transport/sharedb.js.map +1 -0
  51. package/dist/types.js +7 -0
  52. package/dist/types.js.map +1 -0
  53. package/package.json +57 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 shaikhspeare
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,256 @@
1
+ # wanderlog-mcp
2
+
3
+ [![npm](https://img.shields.io/npm/v/wanderlog-mcp)](https://www.npmjs.com/package/wanderlog-mcp)
4
+ [![npm downloads](https://img.shields.io/npm/dm/wanderlog-mcp)](https://www.npmjs.com/package/wanderlog-mcp)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D22-brightgreen)](https://nodejs.org/)
7
+
8
+ An MCP server that lets Claude (or any MCP-compatible agent) view and build [Wanderlog](https://wanderlog.com) trip itineraries through conversation.
9
+
10
+ Instead of clicking through the Wanderlog UI to plan a trip, you just ask:
11
+
12
+ > *"Create a 14-day Japan Golden Route trip — Tokyo, Hakone, Kyoto, Nara, and Osaka."*
13
+
14
+ The agent calls the tools, interleaves places and notes for each day, adds hotel blocks and checklists, and you end up with a fully populated Wanderlog trip in a few minutes.
15
+
16
+ **See a real example:** [14-day Japan Golden Route](https://wanderlog.com/view/dmvegdhqsa/japan-golden-route--tokyo--hakone--kyoto--nara--osaka) — built entirely by an AI agent using this MCP server.
17
+
18
+ ## What's New in v0.1.0
19
+
20
+ - Full itinerary building: places, notes, hotels, and checklists in a single conversation
21
+ - `wanderlog_search_places` — find real-world places near any destination using Wanderlog's place database
22
+ - `wanderlog_add_note` — interleave transit tips, booking info, and local advice between places
23
+ - `wanderlog_add_checklist` — pre-trip and per-day checklists (visa, currency, timed-entry tickets)
24
+ - MCP server instructions injected at startup so Claude builds complete itineraries automatically
25
+ - Startup auth probe — catches expired cookies immediately instead of failing mid-conversation
26
+
27
+ ## Example Prompts
28
+
29
+ ```
30
+ "What trips do I have in Wanderlog?"
31
+ ```
32
+ ```
33
+ "Create a 7-day itinerary for Lisbon starting June 1 — include restaurants, day trips,
34
+ and a hotel near the waterfront."
35
+ ```
36
+ ```
37
+ "Add a day trip to Sintra on day 3 of my Lisbon trip."
38
+ ```
39
+ ```
40
+ "I'm spending 5 days in Tokyo — build me a full itinerary with museum visits, ramen spots,
41
+ and a ryokan in Shinjuku."
42
+ ```
43
+ ```
44
+ "Look at my Barcelona trip and add practical notes for getting between each place."
45
+ ```
46
+ ```
47
+ "Add a pre-trip checklist to my Paris trip — visa, currency, offline maps, travel insurance."
48
+ ```
49
+ ```
50
+ "Move my Rome trip back by two weeks."
51
+ ```
52
+ ```
53
+ "Give me the shareable link to my Kyoto itinerary."
54
+ ```
55
+ ```
56
+ "Remove the Colosseum from day 2 of my Rome trip."
57
+ ```
58
+
59
+ ## Tools
60
+
61
+ | Tool | What it does |
62
+ |---|---|
63
+ | `wanderlog_list_trips` | List trips in your account |
64
+ | `wanderlog_get_trip` | View a full itinerary, or filter to a single day |
65
+ | `wanderlog_get_trip_url` | Get a shareable wanderlog.com link |
66
+ | `wanderlog_search_places` | Find real-world places near a trip's destination |
67
+ | `wanderlog_create_trip` | Create a new trip with destination + date range |
68
+ | `wanderlog_add_place` | Add a place to a specific day or general list |
69
+ | `wanderlog_add_note` | Add a note (transit tips, booking info, local advice) |
70
+ | `wanderlog_add_hotel` | Add a hotel booking with check-in/check-out dates |
71
+ | `wanderlog_add_checklist` | Add a pre-trip or per-day checklist |
72
+ | `wanderlog_remove_place` | Remove a place by natural-language reference |
73
+ | `wanderlog_update_trip_dates` | Change a trip's date range |
74
+
75
+ ## Prerequisites
76
+
77
+ - **Node.js 22 or newer**
78
+ - **A [Wanderlog](https://wanderlog.com) account**
79
+ - An MCP-compatible client: Claude Code, Claude Desktop, OpenAI Codex, Cursor, VS Code, or any stdio MCP host
80
+
81
+ ## Setup
82
+
83
+ ### Step 1 — Get your Wanderlog session cookie
84
+
85
+ Wanderlog doesn't have a public API, so wanderlog-mcp authenticates using your browser session cookie (`connect.sid`). It's valid for roughly a year and never leaves your machine.
86
+
87
+ **Treat it like a password** — it grants the same access you have in the Wanderlog UI.
88
+
89
+ #### Chrome / Edge
90
+
91
+ 1. Go to [wanderlog.com](https://wanderlog.com) and log in
92
+ 2. Press `F12` to open DevTools
93
+ 3. Click the **Application** tab
94
+ 4. In the left sidebar expand **Storage → Cookies → https://wanderlog.com**
95
+ 5. Find the row where **Name** is `connect.sid`
96
+ 6. Click the row, then double-click the **Value** cell and copy the full string — it starts with `s%3A` and is ~100 characters long
97
+
98
+ #### Firefox
99
+
100
+ 1. Go to [wanderlog.com](https://wanderlog.com) and log in
101
+ 2. Press `F12` to open DevTools
102
+ 3. Click the **Storage** tab
103
+ 4. In the left sidebar expand **Cookies → https://wanderlog.com**
104
+ 5. Find `connect.sid` in the table, click it, and copy the **Value**
105
+
106
+ > **Why can't I use `document.cookie` in the console?**
107
+ > Wanderlog sets `connect.sid` with the `HttpOnly` flag, which deliberately blocks JavaScript from reading it (XSS protection). DevTools bypasses this restriction — that's why it works and the console doesn't.
108
+
109
+ ### Step 2 — Configure your MCP client
110
+
111
+ #### Claude Code
112
+
113
+ ```bash
114
+ claude mcp add wanderlog-mcp npx wanderlog-mcp \
115
+ --env WANDERLOG_COOKIE="s%3A...your value here..."
116
+ ```
117
+
118
+ #### Claude Desktop
119
+
120
+ Edit `claude_desktop_config.json`:
121
+
122
+ - **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
123
+ - **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
124
+ - **Linux:** `~/.config/Claude/claude_desktop_config.json`
125
+
126
+ ```json
127
+ {
128
+ "mcpServers": {
129
+ "wanderlog": {
130
+ "command": "npx",
131
+ "args": ["wanderlog-mcp"],
132
+ "env": {
133
+ "WANDERLOG_COOKIE": "s%3A...your value here..."
134
+ }
135
+ }
136
+ }
137
+ }
138
+ ```
139
+
140
+ Restart Claude Desktop after saving.
141
+
142
+ #### Cursor
143
+
144
+ Settings → MCP → Add server, or edit `~/.cursor/mcp.json`:
145
+
146
+ ```json
147
+ {
148
+ "mcpServers": {
149
+ "wanderlog": {
150
+ "command": "npx",
151
+ "args": ["wanderlog-mcp"],
152
+ "env": {
153
+ "WANDERLOG_COOKIE": "s%3A...your value here..."
154
+ }
155
+ }
156
+ }
157
+ }
158
+ ```
159
+
160
+ #### VS Code (GitHub Copilot)
161
+
162
+ Add to your workspace `.vscode/mcp.json`:
163
+
164
+ ```json
165
+ {
166
+ "servers": {
167
+ "wanderlog": {
168
+ "type": "stdio",
169
+ "command": "npx",
170
+ "args": ["wanderlog-mcp"],
171
+ "env": {
172
+ "WANDERLOG_COOKIE": "s%3A...your value here..."
173
+ }
174
+ }
175
+ }
176
+ }
177
+ ```
178
+
179
+ #### OpenAI Codex
180
+
181
+ Edit `~/.codex/config.toml`:
182
+
183
+ ```toml
184
+ [mcp_servers.wanderlog]
185
+ command = "npx"
186
+ args = ["wanderlog-mcp"]
187
+
188
+ [mcp_servers.wanderlog.env]
189
+ WANDERLOG_COOKIE = "s%3A...your value here..."
190
+ ```
191
+
192
+ Run `/mcp` inside Codex to confirm the server loaded.
193
+
194
+ #### Smithery (one-click install)
195
+
196
+ ```bash
197
+ npx @smithery/cli install wanderlog-mcp --client claude
198
+ ```
199
+
200
+ ### Step 3 — Verify
201
+
202
+ Ask your agent: *"What trips do I have in Wanderlog?"*
203
+
204
+ It should call `wanderlog_list_trips` and return your account's trips. If it fails, see [Troubleshooting](#troubleshooting) below.
205
+
206
+ ## Refreshing your cookie
207
+
208
+ The cookie lasts about a year but can die sooner if you log out of wanderlog.com, change your password, or Wanderlog revokes the session. When that happens every tool call returns:
209
+
210
+ > **Wanderlog session invalid or expired** — Capture a fresh connect.sid cookie from wanderlog.com DevTools and update WANDERLOG_COOKIE in your MCP config.
211
+
212
+ Repeat Step 1 above, update your config, and restart your MCP client.
213
+
214
+ ## Troubleshooting
215
+
216
+ **Server starts but list_trips returns an auth error**
217
+ Your cookie is expired or wrong. Re-capture it from DevTools and update your config.
218
+
219
+ **`npx wanderlog-mcp` hangs or does nothing**
220
+ The server speaks stdio MCP — it's designed to be launched by an MCP host, not run directly in a terminal. Run it through Claude Code or Claude Desktop as described above.
221
+
222
+ **Tools work but the agent ignores notes/checklists**
223
+ The server injects instructions into the MCP `initialize` response that tell the agent to interleave places and notes and add checklists. This works reliably with Claude. Other clients may vary.
224
+
225
+ ## Security
226
+
227
+ - The cookie is stored only in your MCP client config, never committed or logged
228
+ - wanderlog-mcp runs entirely on your machine — there's no relay server
229
+ - The startup auth probe validates your cookie without printing its value
230
+ - To revoke access: log out of wanderlog.com (invalidates all sessions), then re-capture
231
+
232
+ ## Contributing
233
+
234
+ Pull requests are welcome. Before submitting:
235
+
236
+ ```bash
237
+ npm run build && npm run test
238
+ ```
239
+
240
+ For changes to transport or tool code, also run:
241
+
242
+ ```bash
243
+ npm run test:integration
244
+ ```
245
+
246
+ ## Disclaimer
247
+
248
+ wanderlog-mcp is an unofficial third-party tool, not affiliated with or endorsed by Wanderlog. It works by calling Wanderlog's private web-client API, which may change without notice. Use at your own risk.
249
+
250
+ ## License
251
+
252
+ MIT — see [LICENSE](LICENSE)
253
+
254
+ ---
255
+
256
+ Made by [shaikhspeare](https://github.com/shaikhspeare)
@@ -0,0 +1,87 @@
1
+ import { applyOp } from "../ot/apply.js";
2
+ /**
3
+ * Live trip cache. On first access, validates the trip exists via REST
4
+ * (fast 404 path for bad keys), then subscribes via ShareDBPool for live
5
+ * updates. Incoming remote ops are applied to the cached doc so reads stay
6
+ * current without refetching.
7
+ *
8
+ * Callers can read `entry.snapshot` and `entry.version` to prepare submit
9
+ * ops with the correct version vector.
10
+ */
11
+ export class TripCache {
12
+ rest;
13
+ pool;
14
+ entries = new Map();
15
+ subscribing = new Map();
16
+ constructor(rest, pool) {
17
+ this.rest = rest;
18
+ this.pool = pool;
19
+ }
20
+ async get(tripKey) {
21
+ const entry = await this.ensureEntry(tripKey);
22
+ return entry.snapshot;
23
+ }
24
+ async getEntry(tripKey) {
25
+ return this.ensureEntry(tripKey);
26
+ }
27
+ async ensureEntry(tripKey) {
28
+ const existing = this.entries.get(tripKey);
29
+ if (existing)
30
+ return existing;
31
+ const pending = this.subscribing.get(tripKey);
32
+ if (pending)
33
+ return pending;
34
+ const promise = this.subscribeAndCache(tripKey);
35
+ this.subscribing.set(tripKey, promise);
36
+ try {
37
+ return await promise;
38
+ }
39
+ finally {
40
+ this.subscribing.delete(tripKey);
41
+ }
42
+ }
43
+ async subscribeAndCache(tripKey) {
44
+ // REST pre-check: fails fast with 404 → WanderlogNotFoundError.
45
+ // Without this, a bogus trip key hangs on the WS subscribe timeout.
46
+ // The response also gives us the trip's associated geos, which the
47
+ // WebSocket snapshot doesn't include — we store them for search biasing.
48
+ const { geos } = await this.rest.getTripWithResources(tripKey);
49
+ const client = this.pool.get(tripKey);
50
+ const snapshot = await client.subscribe();
51
+ const entry = { snapshot, version: client.version, geos };
52
+ this.entries.set(tripKey, entry);
53
+ client.on("remoteOp", (ops, version) => {
54
+ const current = this.entries.get(tripKey);
55
+ if (!current)
56
+ return;
57
+ try {
58
+ current.snapshot = applyOp(current.snapshot, ops);
59
+ current.version = version;
60
+ }
61
+ catch {
62
+ // If a remote op fails to apply to our snapshot, our view is stale.
63
+ // Drop the entry; next get() re-subscribes from a fresh snapshot.
64
+ this.entries.delete(tripKey);
65
+ }
66
+ });
67
+ return entry;
68
+ }
69
+ /**
70
+ * Called after submitting an op ourselves. Applies the op locally and
71
+ * bumps the version so the cache matches what the server just accepted.
72
+ */
73
+ applyLocalOp(tripKey, ops, newVersion) {
74
+ const entry = this.entries.get(tripKey);
75
+ if (!entry)
76
+ return;
77
+ entry.snapshot = applyOp(entry.snapshot, ops);
78
+ entry.version = newVersion;
79
+ }
80
+ invalidate(tripKey) {
81
+ this.entries.delete(tripKey);
82
+ }
83
+ clear() {
84
+ this.entries.clear();
85
+ }
86
+ }
87
+ //# sourceMappingURL=trip-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trip-cache.js","sourceRoot":"","sources":["../../src/cache/trip-cache.ts"],"names":[],"mappings":"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"}
package/dist/config.js ADDED
@@ -0,0 +1,38 @@
1
+ import { WanderlogValidationError } from "./errors.js";
2
+ const DEFAULT_USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36";
3
+ /**
4
+ * Normalizes a cookie value into a valid Cookie header.
5
+ *
6
+ * Accepts:
7
+ * - `s%3A...` → wraps as `connect.sid=s%3A...`
8
+ * - `connect.sid=s%3A...` → passes through
9
+ * - `connect.sid=s%3A...; other=x` → passes through
10
+ *
11
+ * Rejects empty strings and obviously malformed values.
12
+ */
13
+ export function normalizeCookie(raw) {
14
+ const trimmed = raw.trim();
15
+ if (trimmed.length === 0) {
16
+ throw new WanderlogValidationError("WANDERLOG_COOKIE is empty", "Set WANDERLOG_COOKIE to the connect.sid cookie value from wanderlog.com.");
17
+ }
18
+ if (trimmed.includes("connect.sid=")) {
19
+ return trimmed;
20
+ }
21
+ if (trimmed.startsWith("s%3A") || trimmed.startsWith("s:")) {
22
+ return `connect.sid=${trimmed}`;
23
+ }
24
+ throw new WanderlogValidationError("WANDERLOG_COOKIE does not look like a connect.sid cookie", "Expected a value starting with 's%3A' or 'connect.sid=s%3A'. Copy the exact value from DevTools → Application → Cookies → wanderlog.com → connect.sid.");
25
+ }
26
+ export function loadConfig(env = process.env) {
27
+ const raw = env.WANDERLOG_COOKIE;
28
+ if (!raw) {
29
+ throw new WanderlogValidationError("WANDERLOG_COOKIE environment variable is not set", "Set WANDERLOG_COOKIE in your MCP config. See README for how to capture the cookie.");
30
+ }
31
+ return {
32
+ cookieHeader: normalizeCookie(raw),
33
+ baseUrl: env.WANDERLOG_BASE_URL ?? "https://wanderlog.com",
34
+ wsBaseUrl: env.WANDERLOG_WS_BASE_URL ?? "wss://wanderlog.com",
35
+ userAgent: env.WANDERLOG_USER_AGENT ?? DEFAULT_USER_AGENT,
36
+ };
37
+ }
38
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AASvD,MAAM,kBAAkB,GACtB,uGAAuG,CAAC;AAE1G;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,wBAAwB,CAChC,2BAA2B,EAC3B,0EAA0E,CAC3E,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;QACrC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3D,OAAO,eAAe,OAAO,EAAE,CAAC;IAClC,CAAC;IAED,MAAM,IAAI,wBAAwB,CAChC,0DAA0D,EAC1D,wJAAwJ,CACzJ,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAyB,OAAO,CAAC,GAAG;IAC7D,MAAM,GAAG,GAAG,GAAG,CAAC,gBAAgB,CAAC;IACjC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,wBAAwB,CAChC,kDAAkD,EAClD,oFAAoF,CACrF,CAAC;IACJ,CAAC;IAED,OAAO;QACL,YAAY,EAAE,eAAe,CAAC,GAAG,CAAC;QAClC,OAAO,EAAE,GAAG,CAAC,kBAAkB,IAAI,uBAAuB;QAC1D,SAAS,EAAE,GAAG,CAAC,qBAAqB,IAAI,qBAAqB;QAC7D,SAAS,EAAE,GAAG,CAAC,oBAAoB,IAAI,kBAAkB;KAC1D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { TripCache } from "./cache/trip-cache.js";
2
+ import { loadConfig } from "./config.js";
3
+ import { RestClient } from "./transport/rest.js";
4
+ import { ShareDBPool } from "./transport/sharedb.js";
5
+ export function createContext() {
6
+ const config = loadConfig();
7
+ const rest = new RestClient(config);
8
+ const pool = new ShareDBPool(config);
9
+ const tripCache = new TripCache(rest, pool);
10
+ return { config, rest, pool, tripCache };
11
+ }
12
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAe,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAWrD,MAAM,UAAU,aAAa;IAC3B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5C,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AAC3C,CAAC"}
package/dist/errors.js ADDED
@@ -0,0 +1,86 @@
1
+ export class WanderlogError extends Error {
2
+ code;
3
+ hint;
4
+ followUps;
5
+ constructor(message, code, hintOrOptions) {
6
+ super(message);
7
+ this.name = "WanderlogError";
8
+ this.code = code;
9
+ if (typeof hintOrOptions === "string") {
10
+ this.hint = hintOrOptions;
11
+ }
12
+ else if (hintOrOptions) {
13
+ this.hint = hintOrOptions.hint;
14
+ this.followUps = hintOrOptions.followUps;
15
+ }
16
+ }
17
+ /**
18
+ * Render the error for the calling agent. Includes the hint (human advice)
19
+ * and a "Next steps" list of suggested follow-up tool calls when present.
20
+ * Follow-ups are phrased as concrete actions the model can take without
21
+ * asking the user for more information.
22
+ */
23
+ toUserMessage() {
24
+ const parts = [this.message];
25
+ if (this.hint)
26
+ parts.push("", this.hint);
27
+ if (this.followUps && this.followUps.length > 0) {
28
+ parts.push("", "Next steps:");
29
+ for (const step of this.followUps) {
30
+ parts.push(`• ${step}`);
31
+ }
32
+ }
33
+ return parts.join("\n");
34
+ }
35
+ }
36
+ export class WanderlogAuthError extends WanderlogError {
37
+ constructor(message = "Wanderlog session invalid or expired") {
38
+ super(message, "auth_expired", {
39
+ hint: "Capture a fresh connect.sid cookie from wanderlog.com DevTools (Application → Cookies) and update WANDERLOG_COOKIE in your MCP config.",
40
+ followUps: [
41
+ "Ask the user to refresh WANDERLOG_COOKIE in the MCP config, then restart the server.",
42
+ ],
43
+ });
44
+ this.name = "WanderlogAuthError";
45
+ }
46
+ }
47
+ export class WanderlogNotFoundError extends WanderlogError {
48
+ constructor(resource, identifier) {
49
+ const id = identifier ? ` '${identifier}'` : "";
50
+ const res = resource.toLowerCase();
51
+ const options = res === "trip"
52
+ ? {
53
+ hint: "Use wanderlog_list_trips to see available trips.",
54
+ followUps: [
55
+ "Call wanderlog_list_trips to find the correct trip_key, then retry this tool with that key.",
56
+ ],
57
+ }
58
+ : res === "place"
59
+ ? {
60
+ hint: "Try a more specific name or use wanderlog_search_places to find the exact place.",
61
+ followUps: [
62
+ "Call wanderlog_search_places with a broader query to see candidates.",
63
+ "Retry this tool with a more specific place name (include the city or neighborhood).",
64
+ ],
65
+ }
66
+ : {};
67
+ super(`${resource}${id} not found`, "not_found", options);
68
+ this.name = "WanderlogNotFoundError";
69
+ }
70
+ }
71
+ export class WanderlogValidationError extends WanderlogError {
72
+ constructor(message, hintOrOptions) {
73
+ super(message, "validation", hintOrOptions);
74
+ this.name = "WanderlogValidationError";
75
+ }
76
+ }
77
+ export class WanderlogNetworkError extends WanderlogError {
78
+ constructor(message) {
79
+ super(message, "network", {
80
+ hint: "Check your internet connection and that wanderlog.com is reachable.",
81
+ followUps: ["Retry the same tool call in a moment."],
82
+ });
83
+ this.name = "WanderlogNetworkError";
84
+ }
85
+ }
86
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}