ofw-mcp 2.20.0 → 2.20.1

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.
@@ -6,7 +6,7 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "OurFamilyWizard tools for Claude Code",
9
- "version": "2.20.0"
9
+ "version": "2.20.1"
10
10
  },
11
11
  "plugins": [
12
12
  {
@@ -14,7 +14,7 @@
14
14
  "displayName": "OurFamilyWizard",
15
15
  "source": "./",
16
16
  "description": "OurFamilyWizard co-parenting tools for Claude — messages, calendar, expenses, and journal via MCP",
17
- "version": "2.20.0",
17
+ "version": "2.20.1",
18
18
  "author": {
19
19
  "name": "Chris Chall"
20
20
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ofw",
3
3
  "displayName": "OurFamilyWizard",
4
- "version": "2.20.0",
4
+ "version": "2.20.1",
5
5
  "description": "OurFamilyWizard co-parenting tools for Claude — messages, calendar, expenses, and journal via MCP",
6
6
  "author": {
7
7
  "name": "Chris Chall"
package/README.md CHANGED
@@ -235,7 +235,7 @@ Previews name what you are approving — recipients by name, subject and full bo
235
235
  |---|---|---|
236
236
  | `MCP_CONFIRM_MODE` | `ask-user` | What a gated write does on a client that cannot show a prompt. `ask-user`: two steps, and the model must get your approval in chat before using the token. `auto`: two steps, but the model may use the token after reviewing the preview itself. `refuse`: such writes are refused (do them on ourfamilywizard.com). An unrecognised value is treated as `refuse`. |
237
237
  | `MCP_CONFIRM_TTL_SECONDS` | `600` | How long a token stays valid. |
238
- | `MCP_CONFIRM_SECRET` | random per process | Signing key; set it only if tokens must survive a server restart. |
238
+ | `MCP_CONFIRM_SECRET` | random per process | Signing key; set it only if tokens must survive a server restart. On mcp-host the host supplies a stable per-child key (`MCP_HOST_CONFIRM_SECRET`) and spent tokens are recorded under `MCP_DATA_DIR`, so an approval survives an idle restart. |
239
239
 
240
240
  Private events and `PRIVATE` uploads — which the co-parent never sees — are not gated. `OFW_WRITE_MODE` below stays the structural layer underneath: a tool your write mode excludes does not exist at all.
241
241
 
@@ -10,7 +10,7 @@
10
10
  // `resolveAuth()` in `./auth.ts` can call it without a Client instance, and
11
11
  // so tests can mock it at the module boundary.
12
12
  import { createHash } from 'node:crypto';
13
- import { currentCallSignal } from '@chrischall/mcp-utils';
13
+ import { EdgeBlockedError, currentCallSignal, detectEdgeBlock } from '@chrischall/mcp-utils';
14
14
  import { BASE_URL, OFW_PROTOCOL_HEADERS, OFW_TOKEN_TTL_MS, assertOfwUrl } from './protocol.js';
15
15
  /**
16
16
  * OFW definitively refused this username/password (it re-rendered its login
@@ -86,6 +86,22 @@ export async function loginWithPassword(username, password) {
86
86
  }).toString(),
87
87
  });
88
88
  if (!response.ok) {
89
+ // A CDN/WAF refusal page is not OFW judging the password: name it, so the
90
+ // healthcheck reports edge_blocked instead of a missing credential, and
91
+ // nothing is latched as rejected (chrischall/mcp-host#1015). The page
92
+ // itself stays out of the message.
93
+ const edge = detectEdgeBlock({
94
+ body: await response.text().catch(() => ''),
95
+ headers: response.headers,
96
+ status: response.status,
97
+ });
98
+ if (edge !== null) {
99
+ throw new EdgeBlockedError(response.status, edge.vendor, {
100
+ service: 'OurFamilyWizard',
101
+ method: 'POST',
102
+ path: '/ofw/login',
103
+ });
104
+ }
89
105
  throw new Error(`OFW login failed: ${response.status} ${response.statusText}`);
90
106
  }
91
107
  const contentType = response.headers.get('content-type') ?? '';