ofw-mcp 2.18.0 → 2.19.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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/dist/auth-password.js +6 -0
- package/dist/bundle.js +69 -14
- package/dist/client.js +10 -2
- package/dist/index.js +1 -1
- package/package.json +2 -2
- package/server.json +2 -2
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
8
|
"description": "OurFamilyWizard tools for Claude Code",
|
|
9
|
-
"version": "2.
|
|
9
|
+
"version": "2.19.0"
|
|
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.
|
|
17
|
+
"version": "2.19.0",
|
|
18
18
|
"author": {
|
|
19
19
|
"name": "Chris Chall"
|
|
20
20
|
},
|
package/dist/auth-password.js
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
// This file exists as a standalone helper (not a method on `OFWClient`) so
|
|
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
|
+
import { currentCallSignal } from '@chrischall/mcp-utils';
|
|
12
13
|
import { BASE_URL, OFW_PROTOCOL_HEADERS, OFW_TOKEN_TTL_MS, assertOfwUrl } from './protocol.js';
|
|
13
14
|
export async function loginWithPassword(username, password) {
|
|
14
15
|
// Step 1: get a SESSION cookie (Spring Security refuses the POST without it).
|
|
@@ -17,6 +18,10 @@ export async function loginWithPassword(username, password) {
|
|
|
17
18
|
const initResponse = await fetch(initUrl, {
|
|
18
19
|
headers: { ...OFW_PROTOCOL_HEADERS },
|
|
19
20
|
redirect: 'manual',
|
|
21
|
+
// Honour a caller who has given up (mcp-utils `cancel`). A sign-in
|
|
22
|
+
// nobody is waiting for should not keep hitting OFW, which counts
|
|
23
|
+
// failed attempts against the account.
|
|
24
|
+
signal: currentCallSignal(),
|
|
20
25
|
});
|
|
21
26
|
// headers.get('set-cookie') folds multiple Set-Cookie headers into one
|
|
22
27
|
// comma-joined string; getSetCookie() preserves them individually. Echo
|
|
@@ -30,6 +35,7 @@ export async function loginWithPassword(username, password) {
|
|
|
30
35
|
assertOfwUrl(loginUrl);
|
|
31
36
|
const response = await fetch(loginUrl, {
|
|
32
37
|
method: 'POST',
|
|
38
|
+
signal: currentCallSignal(),
|
|
33
39
|
headers: {
|
|
34
40
|
...OFW_PROTOCOL_HEADERS,
|
|
35
41
|
Accept: 'application/json',
|
package/dist/bundle.js
CHANGED
|
@@ -3710,6 +3710,24 @@ var require_websocket_server = __commonJS({
|
|
|
3710
3710
|
}
|
|
3711
3711
|
});
|
|
3712
3712
|
|
|
3713
|
+
// node_modules/@chrischall/mcp-utils/dist/cancel/index.js
|
|
3714
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3715
|
+
var storage = new AsyncLocalStorage();
|
|
3716
|
+
function withCallSignal(signal, fn) {
|
|
3717
|
+
return signal ? storage.run({ signal }, fn) : fn();
|
|
3718
|
+
}
|
|
3719
|
+
function currentCallSignal() {
|
|
3720
|
+
return storage.getStore()?.signal;
|
|
3721
|
+
}
|
|
3722
|
+
function withAmbientCancellation(own2) {
|
|
3723
|
+
const ambient = currentCallSignal();
|
|
3724
|
+
if (!ambient)
|
|
3725
|
+
return own2;
|
|
3726
|
+
if (!own2)
|
|
3727
|
+
return ambient;
|
|
3728
|
+
return AbortSignal.any([own2, ambient]);
|
|
3729
|
+
}
|
|
3730
|
+
|
|
3713
3731
|
// node_modules/@modelcontextprotocol/server/dist/chunk-Br0eD_fh.mjs
|
|
3714
3732
|
var __create2 = Object.create;
|
|
3715
3733
|
var __defProp2 = Object.defineProperty;
|
|
@@ -38155,17 +38173,41 @@ Hint: ${err.hint}`);
|
|
|
38155
38173
|
}
|
|
38156
38174
|
throw err;
|
|
38157
38175
|
}
|
|
38176
|
+
function callSignalFrom(args) {
|
|
38177
|
+
const ctx = args.at(-1);
|
|
38178
|
+
if (typeof ctx !== "object" || ctx === null)
|
|
38179
|
+
return void 0;
|
|
38180
|
+
const req = ctx.mcpReq;
|
|
38181
|
+
if (typeof req !== "object" || req === null)
|
|
38182
|
+
return void 0;
|
|
38183
|
+
const signal = req.signal;
|
|
38184
|
+
return signal instanceof AbortSignal ? signal : void 0;
|
|
38185
|
+
}
|
|
38158
38186
|
function surfaceToolHints(server) {
|
|
38159
38187
|
const register2 = server.registerTool.bind(server);
|
|
38160
|
-
server.registerTool = (name, config2, cb) => register2(name, config2, (...args) =>
|
|
38161
|
-
|
|
38162
|
-
|
|
38163
|
-
|
|
38164
|
-
|
|
38165
|
-
|
|
38166
|
-
|
|
38167
|
-
|
|
38168
|
-
|
|
38188
|
+
server.registerTool = (name, config2, cb) => register2(name, config2, (...args) => (
|
|
38189
|
+
// THE CALLER'S CANCELLATION, made ambient for the whole handler
|
|
38190
|
+
// (`cancel/index.ts`). The SDK delivers it and the fleet ignored it:
|
|
38191
|
+
// measured against @modelcontextprotocol/server 2.0.0, a cancelled
|
|
38192
|
+
// call aborts `ctx.mcpReq.signal` with the caller's reason and the
|
|
38193
|
+
// handler runs to completion regardless — so the HTTP request stays
|
|
38194
|
+
// in flight, the child keeps burning metered CPU, and the upstream
|
|
38195
|
+
// keeps being hit for somebody who has gone. claude.ai sent 101
|
|
38196
|
+
// cancellations in the week to 2026-09-20.
|
|
38197
|
+
//
|
|
38198
|
+
// Here because this is the one wrapper every tool already passes
|
|
38199
|
+
// through: threading the signal by hand would mean editing several
|
|
38200
|
+
// hundred handlers and missing exactly the ones nobody edits.
|
|
38201
|
+
withCallSignal(callSignalFrom(args), () => {
|
|
38202
|
+
let result;
|
|
38203
|
+
try {
|
|
38204
|
+
result = cb(...args);
|
|
38205
|
+
} catch (err) {
|
|
38206
|
+
return hintResultOrRethrow(err);
|
|
38207
|
+
}
|
|
38208
|
+
return result instanceof Promise ? result.catch(hintResultOrRethrow) : result;
|
|
38209
|
+
})
|
|
38210
|
+
));
|
|
38169
38211
|
}
|
|
38170
38212
|
async function createMcpServer(opts) {
|
|
38171
38213
|
const server = new McpServer({ name: opts.name, version: opts.version }, { supportedProtocolVersions: [...SERVER_PROTOCOL_VERSIONS] });
|
|
@@ -43922,13 +43964,18 @@ async function loginWithPassword(username, password) {
|
|
|
43922
43964
|
assertOfwUrl(initUrl);
|
|
43923
43965
|
const initResponse = await fetch(initUrl, {
|
|
43924
43966
|
headers: { ...OFW_PROTOCOL_HEADERS },
|
|
43925
|
-
redirect: "manual"
|
|
43967
|
+
redirect: "manual",
|
|
43968
|
+
// Honour a caller who has given up (mcp-utils `cancel`). A sign-in
|
|
43969
|
+
// nobody is waiting for should not keep hitting OFW, which counts
|
|
43970
|
+
// failed attempts against the account.
|
|
43971
|
+
signal: currentCallSignal()
|
|
43926
43972
|
});
|
|
43927
43973
|
const sessionCookie = initResponse.headers.getSetCookie().map((c) => c.split(";")[0]).join("; ");
|
|
43928
43974
|
const loginUrl = `${BASE_URL}/ofw/login`;
|
|
43929
43975
|
assertOfwUrl(loginUrl);
|
|
43930
43976
|
const response = await fetch(loginUrl, {
|
|
43931
43977
|
method: "POST",
|
|
43978
|
+
signal: currentCallSignal(),
|
|
43932
43979
|
headers: {
|
|
43933
43980
|
...OFW_PROTOCOL_HEADERS,
|
|
43934
43981
|
Accept: "application/json",
|
|
@@ -43965,7 +44012,7 @@ async function loginWithPassword(username, password) {
|
|
|
43965
44012
|
// package.json
|
|
43966
44013
|
var package_default = {
|
|
43967
44014
|
name: "ofw-mcp",
|
|
43968
|
-
version: "2.
|
|
44015
|
+
version: "2.19.0",
|
|
43969
44016
|
license: "MIT",
|
|
43970
44017
|
mcpName: "io.github.chrischall/ofw-mcp",
|
|
43971
44018
|
description: "OurFamilyWizard MCP server for Claude \u2014 developed and maintained by AI (Claude Code)",
|
|
@@ -43999,7 +44046,7 @@ var package_default = {
|
|
|
43999
44046
|
typecheck: "tsc -p tsconfig.json --noEmit"
|
|
44000
44047
|
},
|
|
44001
44048
|
dependencies: {
|
|
44002
|
-
"@chrischall/mcp-utils": "^
|
|
44049
|
+
"@chrischall/mcp-utils": "^2.0.0",
|
|
44003
44050
|
"@fetchproxy/bootstrap": "^3.0.1",
|
|
44004
44051
|
"@modelcontextprotocol/server": "^2.0.0",
|
|
44005
44052
|
dotenv: "^17.4.2",
|
|
@@ -44278,7 +44325,15 @@ var OFWClient = class {
|
|
|
44278
44325
|
response = await fetch(url2, {
|
|
44279
44326
|
method,
|
|
44280
44327
|
headers,
|
|
44281
|
-
|
|
44328
|
+
// THE CALLER'S CANCELLATION, folded in with our timeout (mcp-utils
|
|
44329
|
+
// `cancel`). Until this the only thing that could stop an OFW
|
|
44330
|
+
// request was the timeout below, so a cancelled tool call held it
|
|
44331
|
+
// open for the full budget while the child burned the CPU
|
|
44332
|
+
// mcp-host meters it on. The timeout diagnosis below is unaffected
|
|
44333
|
+
// because it asks `ac.signal`, OUR controller — a caller's abort
|
|
44334
|
+
// falls through to the generic path rather than being reported as
|
|
44335
|
+
// OFW being slow.
|
|
44336
|
+
signal: withAmbientCancellation(ac.signal),
|
|
44282
44337
|
...body !== void 0 ? { body: isFormData ? body : JSON.stringify(body) } : {}
|
|
44283
44338
|
});
|
|
44284
44339
|
} catch (err) {
|
|
@@ -48952,7 +49007,7 @@ var nodeCacheProvider = () => nodeCache ??= OFWCache.open(getCacheDbPath());
|
|
|
48952
49007
|
var nodeAttachmentIO = new NodeAttachmentIO();
|
|
48953
49008
|
await runMcp({
|
|
48954
49009
|
name: "ofw",
|
|
48955
|
-
version: "2.
|
|
49010
|
+
version: "2.19.0",
|
|
48956
49011
|
// x-release-please-version
|
|
48957
49012
|
deps: client,
|
|
48958
49013
|
tools: [
|
package/dist/client.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { loadDotenvSafely, parseBoolEnv, redactSecrets } from '@chrischall/mcp-utils';
|
|
1
|
+
import { loadDotenvSafely, parseBoolEnv, redactSecrets, withAmbientCancellation } from '@chrischall/mcp-utils';
|
|
2
2
|
import { TokenManager } from '@chrischall/mcp-utils/session';
|
|
3
3
|
import { dirname, join } from 'path';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
@@ -190,7 +190,15 @@ export class OFWClient {
|
|
|
190
190
|
response = await fetch(url, {
|
|
191
191
|
method,
|
|
192
192
|
headers,
|
|
193
|
-
|
|
193
|
+
// THE CALLER'S CANCELLATION, folded in with our timeout (mcp-utils
|
|
194
|
+
// `cancel`). Until this the only thing that could stop an OFW
|
|
195
|
+
// request was the timeout below, so a cancelled tool call held it
|
|
196
|
+
// open for the full budget while the child burned the CPU
|
|
197
|
+
// mcp-host meters it on. The timeout diagnosis below is unaffected
|
|
198
|
+
// because it asks `ac.signal`, OUR controller — a caller's abort
|
|
199
|
+
// falls through to the generic path rather than being reported as
|
|
200
|
+
// OFW being slow.
|
|
201
|
+
signal: withAmbientCancellation(ac.signal),
|
|
194
202
|
...(body !== undefined ? { body: isFormData ? body : JSON.stringify(body) } : {}),
|
|
195
203
|
});
|
|
196
204
|
}
|
package/dist/index.js
CHANGED
|
@@ -36,7 +36,7 @@ const nodeAttachmentIO = new NodeAttachmentIO();
|
|
|
36
36
|
// always succeeds before any credential check runs.
|
|
37
37
|
await runMcp({
|
|
38
38
|
name: 'ofw',
|
|
39
|
-
version: '2.
|
|
39
|
+
version: '2.19.0', // x-release-please-version
|
|
40
40
|
deps: client,
|
|
41
41
|
tools: [
|
|
42
42
|
registerHealthcheckTools,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ofw-mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.19.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"mcpName": "io.github.chrischall/ofw-mcp",
|
|
6
6
|
"description": "OurFamilyWizard MCP server for Claude — developed and maintained by AI (Claude Code)",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@chrischall/mcp-utils": "^
|
|
37
|
+
"@chrischall/mcp-utils": "^2.0.0",
|
|
38
38
|
"@fetchproxy/bootstrap": "^3.0.1",
|
|
39
39
|
"@modelcontextprotocol/server": "^2.0.0",
|
|
40
40
|
"dotenv": "^17.4.2",
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/chrischall/ofw-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "2.
|
|
9
|
+
"version": "2.19.0",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "ofw-mcp",
|
|
14
|
-
"version": "2.
|
|
14
|
+
"version": "2.19.0",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|