splitwise-mcp 3.2.3 → 3.3.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.
@@ -7,7 +7,7 @@
7
7
  },
8
8
  "metadata": {
9
9
  "description": "MCP server for Splitwise — natural-language expense and group management via the Splitwise API",
10
- "version": "3.2.3"
10
+ "version": "3.3.0"
11
11
  },
12
12
  "plugins": [
13
13
  {
@@ -15,7 +15,7 @@
15
15
  "displayName": "Splitwise",
16
16
  "source": "./",
17
17
  "description": "MCP server for Splitwise — manage expenses, groups, and friends via natural language",
18
- "version": "3.2.3",
18
+ "version": "3.3.0",
19
19
  "author": {
20
20
  "name": "Chris Hall"
21
21
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "splitwise-mcp",
3
3
  "displayName": "Splitwise",
4
- "version": "3.2.3",
4
+ "version": "3.3.0",
5
5
  "description": "MCP server for Splitwise — natural-language expense and group management via the Splitwise API",
6
6
  "author": {
7
7
  "name": "Chris Hall",
package/README.md CHANGED
@@ -117,11 +117,12 @@ Add to Claude Desktop config:
117
117
 
118
118
  ## Confirmations
119
119
 
120
- Every Splitwise write (creating, editing or deleting expenses, groups, friends, comments, or your profile) notifies other people, so it asks you to confirm first. A client that can show a confirmation prompt (Claude Code) shows one. On a client that cannot (claude.ai, Claude Desktop), the first call changes nothing and returns a preview of exactly what will be sent plus a `confirmToken`; only a repeat call with that token goes through, and the token is refused if anything in the request changed in between.
120
+ Every Splitwise write (creating, editing or deleting expenses, groups, friends, comments, or your profile) notifies other people, so it asks you to confirm first. A client that can show a confirmation prompt (Claude Code) shows one (unless `MCP_CONFIRM_ELICITATION=off`). On a client that cannot (claude.ai, Claude Desktop), the first call changes nothing and returns a preview of exactly what will be sent plus a `confirmToken`; only a repeat call with that token goes through, and the token is refused if anything in the request changed in between.
121
121
 
122
122
  | variable | default | |
123
123
  |---|---|---|
124
- | `MCP_CONFIRM_MODE` | `ask-user` | What a write does on a client that cannot show a confirmation prompt (claude.ai, Claude Desktop). `ask-user`: two steps — the first call does nothing and returns a preview plus a token, and the model must get your approval in chat before calling again with it. `auto`: the same two steps, but the model may use the token after reviewing the preview itself. `refuse`: writes are refused on such clients. A client that can show prompts (Claude Code) always gets the real prompt. An unrecognised value is treated as `refuse`. |
124
+ | `MCP_CONFIRM_MODE` | `ask-user` | What a write does on a client that cannot show a confirmation prompt (claude.ai, Claude Desktop). `ask-user`: two steps — the first call does nothing and returns a preview plus a token, and the model must get your approval in chat before calling again with it. `auto`: the same two steps, but the model may use the token after reviewing the preview itself. `refuse`: writes are refused on such clients. A client that can show prompts (Claude Code) always gets the real prompt, unless `MCP_CONFIRM_ELICITATION=off`. An unrecognised value is treated as `refuse`. |
125
+ | `MCP_CONFIRM_ELICITATION` | `on` | `off` never shows a confirmation prompt, so every client gets the `MCP_CONFIRM_MODE` behaviour. Set it for a client that says it can show prompts but never does (the write hangs — opencode 2.0.x). Any other value is treated as `on`, with a warning on stderr. |
125
126
  | `MCP_CONFIRM_TTL_SECONDS` | `600` | How long a token stays valid. |
126
127
  | `MCP_CONFIRM_SECRET` | random per process | Signing key; set it only if tokens must survive a server restart. |
127
128
 
package/dist/bundle.js CHANGED
@@ -97980,6 +97980,7 @@ function escapeKey(key) {
97980
97980
  var DEFAULT_REQUEST_KEY = "confirmation";
97981
97981
  var DEFAULT_CONFIRMATION_LABEL = "Confirm this action should proceed.";
97982
97982
  var UNSUPPORTED_NOTE = "Nothing was done because this client cannot show a confirmation prompt (it declares no MCP elicitation capability), and this action is never taken without one";
97983
+ var DISABLED_NOTE = "Nothing was done because confirmation prompts are turned off for this server, and this action is never taken without one";
97983
97984
  var STATE_PREFIX = "mcpu.confirm.v1.";
97984
97985
  function bindingKey(binding) {
97985
97986
  if (binding.ttlSeconds !== void 0 && !(Number.isFinite(binding.ttlSeconds) && binding.ttlSeconds > 0)) {
@@ -98052,6 +98053,15 @@ ${JSON.stringify(preview, null, 2)}`,
98052
98053
  };
98053
98054
  const response = inputResponse(ctx.mcpReq.inputResponses, requestKey);
98054
98055
  const accepted = acceptedContent(ctx.mcpReq.inputResponses, requestKey, confirmationSchema);
98056
+ if (options.elicitation === false) {
98057
+ return textResult({
98058
+ confirmed: false,
98059
+ dispatched: false,
98060
+ action: options.action,
98061
+ reason: "confirmation-unsupported",
98062
+ note: options.unsupportedNote ? `${DISABLED_NOTE}. ${options.unsupportedNote}` : `${DISABLED_NOTE}.`
98063
+ });
98064
+ }
98055
98065
  if (response.kind === "missing") {
98056
98066
  if (callerAcceptsFormElicitation(ctx) === false) {
98057
98067
  return textResult({
@@ -98246,7 +98256,7 @@ async function tokenConfirmation(action, fb) {
98246
98256
  }
98247
98257
  async function requireConfirmationWithFallback(ctx, options) {
98248
98258
  const { tokenFallback, ...confirmation } = options;
98249
- if (tokenFallback && callerAcceptsFormElicitation(ctx) === false) {
98259
+ if (tokenFallback && (options.elicitation === false || callerAcceptsFormElicitation(ctx) === false)) {
98250
98260
  return tokenConfirmation(options.action, tokenFallback);
98251
98261
  }
98252
98262
  return requireConfirmation(ctx, confirmation);
@@ -98394,6 +98404,20 @@ function readConfirmMode(env = process.env) {
98394
98404
  }
98395
98405
  return "refuse";
98396
98406
  }
98407
+ function readConfirmElicitation(env = process.env) {
98408
+ const raw = readEnvVar("MCP_CONFIRM_ELICITATION", { env })?.trim().toLowerCase();
98409
+ if (!raw || raw === "on")
98410
+ return "on";
98411
+ if (raw === "off")
98412
+ return "off";
98413
+ const key = `elicitation:${raw}`;
98414
+ if (!warned.has(key)) {
98415
+ warned.add(key);
98416
+ process.stderr.write(`MCP_CONFIRM_ELICITATION="${raw}" is not one of on, off; treating it as on.
98417
+ `);
98418
+ }
98419
+ return "on";
98420
+ }
98397
98421
  function readConfirmTtl(env) {
98398
98422
  const raw = readEnvVar("MCP_CONFIRM_TTL_SECONDS", { env })?.trim();
98399
98423
  if (!raw)
@@ -98438,6 +98462,7 @@ function spentTokenStoreFromEnv(env = process.env) {
98438
98462
  }
98439
98463
  var CONFIRM_TOKEN_AUTO_INSTRUCTION = "Nothing has been done yet. Review this preview; if it is what was intended, call again with the same arguments plus confirmToken. (This server runs with MCP_CONFIRM_MODE=auto, so the user's approval in chat is not required.)";
98440
98464
  var REFUSE_HINT = "Set MCP_CONFIRM_MODE=ask-user on the server to allow two-step confirmation instead.";
98465
+ var ELICITATION_OFF_HINT = "MCP_CONFIRM_ELICITATION=off on the server turns confirmation prompts off.";
98441
98466
  var BAD_TTL_HINT = "MCP_CONFIRM_TTL_SECONDS on the server is not a positive whole number of seconds; fix it to allow two-step confirmation.";
98442
98467
  function boundArgs(args) {
98443
98468
  if (args === null || typeof args !== "object" || Array.isArray(args) || !("confirmToken" in args))
@@ -98451,10 +98476,13 @@ function confirmationFromEnv(options) {
98451
98476
  const spent = callerSpent ?? spentTokenStoreFromEnv(env);
98452
98477
  const mode = readConfirmMode(env);
98453
98478
  const ttlSeconds = readConfirmTtl(env);
98479
+ const elicitationOff = readConfirmElicitation(env) === "off";
98454
98480
  const bound = args === void 0 ? void 0 : boundArgs(args);
98455
- const confirmation = bound === void 0 || rest.binding ? rest : { ...rest, binding: { key: confirmKeyFromEnv(env), args: bound, ttlSeconds: ttlSeconds ?? DEFAULT_TTL_SECONDS2 } };
98481
+ const bindingAdded = bound === void 0 || rest.binding ? rest : { ...rest, binding: { key: confirmKeyFromEnv(env), args: bound, ttlSeconds: ttlSeconds ?? DEFAULT_TTL_SECONDS2 } };
98482
+ const confirmation = elicitationOff ? { ...bindingAdded, elicitation: false } : bindingAdded;
98456
98483
  if (mode === "refuse" || ttlSeconds === void 0) {
98457
- const hint = mode === "refuse" ? REFUSE_HINT : BAD_TTL_HINT;
98484
+ const reason = mode === "refuse" ? REFUSE_HINT : BAD_TTL_HINT;
98485
+ const hint = elicitationOff ? `${ELICITATION_OFF_HINT} ${reason}` : reason;
98458
98486
  return {
98459
98487
  ...confirmation,
98460
98488
  unsupportedNote: confirmation.unsupportedNote ? `${confirmation.unsupportedNote} ${hint}` : hint
@@ -100586,7 +100614,7 @@ function registerUtilityTools(server, client2) {
100586
100614
  // src/index.ts
100587
100615
  await runMcp({
100588
100616
  name: "splitwise-mcp",
100589
- version: "3.2.3",
100617
+ version: "3.3.0",
100590
100618
  // x-release-please-version
100591
100619
  deps: client,
100592
100620
  banner: "[splitwise-mcp] This project was developed and is maintained by AI (Claude Sonnet 4.6). Use at your own discretion.",
package/dist/index.js CHANGED
@@ -19,7 +19,7 @@ import { registerUtilityTools } from './tools/utilities.js';
19
19
  // client into the same registrars instead of this singleton.
20
20
  await runMcp({
21
21
  name: 'splitwise-mcp',
22
- version: '3.2.3', // x-release-please-version
22
+ version: '3.3.0', // x-release-please-version
23
23
  deps: client,
24
24
  banner: '[splitwise-mcp] This project was developed and is maintained by AI (Claude Sonnet 4.6). Use at your own discretion.',
25
25
  tools: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "splitwise-mcp",
3
- "version": "3.2.3",
3
+ "version": "3.3.0",
4
4
  "mcpName": "io.github.chrischall/splitwise-mcp",
5
5
  "description": "Splitwise MCP server for Claude — developed and maintained by AI (Claude Code)",
6
6
  "author": "Claude Code (AI) <https://www.anthropic.com/claude>",
@@ -45,7 +45,7 @@
45
45
  "typecheck": "tsc -p tsconfig.json --noEmit"
46
46
  },
47
47
  "dependencies": {
48
- "@chrischall/mcp-utils": "^2.14.0",
48
+ "@chrischall/mcp-utils": "^2.15.0",
49
49
  "@modelcontextprotocol/server": "^2.3.0",
50
50
  "dotenv": "^18.0.2",
51
51
  "unpdf": "^1.8.1",
package/server.json CHANGED
@@ -6,12 +6,12 @@
6
6
  "url": "https://github.com/chrischall/splitwise-mcp",
7
7
  "source": "github"
8
8
  },
9
- "version": "3.2.3",
9
+ "version": "3.3.0",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "splitwise-mcp",
14
- "version": "3.2.3",
14
+ "version": "3.3.0",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },
@@ -221,7 +221,7 @@ sw_update_expense(expense_id, description: "Corrected description", cost: "95.00
221
221
 
222
222
  ## Notes
223
223
 
224
- - Every write except `sw_undelete_expense` / `sw_undelete_group` asks the user to confirm first. Where the client can show a prompt, it does. Otherwise the first call changes nothing and returns `status: "confirmation-required"` with a `preview` (method, path, `willSend`) and a `confirmToken`: show the preview to the user, get their approval in chat, then repeat the same call with the same arguments plus `confirmToken` (see `MCP_CONFIRM_MODE`). A token acts once, expires, and is refused (`DRAFT_CHANGED`) if any argument changed
224
+ - Every write except `sw_undelete_expense` / `sw_undelete_group` asks the user to confirm first. Where the client can show a prompt, it does (unless the server sets `MCP_CONFIRM_ELICITATION=off`). Otherwise the first call changes nothing and returns `status: "confirmation-required"` with a `preview` (method, path, `willSend`) and a `confirmToken`: show the preview to the user, get their approval in chat, then repeat the same call with the same arguments plus `confirmToken` (see `MCP_CONFIRM_MODE`). A token acts once, expires, and is refused (`DRAFT_CHANGED`) if any argument changed
225
225
  - `cost` is always a decimal string (e.g. `"25.00"`)
226
226
  - `split_equally: true` and `users` array are mutually exclusive
227
227
  - For custom split updates, the **full `users` array is required** — the API replaces the entire split