ofw-mcp 2.16.0 → 2.16.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.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/dist/bundle.js +121 -96
- package/dist/index.js +1 -1
- package/package.json +4 -4
- 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.16.
|
|
9
|
+
"version": "2.16.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.16.
|
|
17
|
+
"version": "2.16.1",
|
|
18
18
|
"author": {
|
|
19
19
|
"name": "Chris Chall"
|
|
20
20
|
},
|
package/dist/bundle.js
CHANGED
|
@@ -39449,6 +39449,11 @@ function warn(opts, why) {
|
|
|
39449
39449
|
console.error(`[${opts.label}] WARNING: could not project ${opts.context} (${why}); returning the unprojected payload. The upstream shape has probably changed \u2014 the projection needs updating.`);
|
|
39450
39450
|
}
|
|
39451
39451
|
|
|
39452
|
+
// node_modules/@chrischall/mcp-utils/dist/response/media.js
|
|
39453
|
+
var MEDIA_NOUN = "(?:avatar|picture|photo|thumbnail|thumb|image|icon|banner|profile_pic(?:ture)?|logo)";
|
|
39454
|
+
var MEDIA_QUALIFIER = "(?:primary|secondary|main|default|cover|hero|profile|master|rendered|small|medium|large|full|original|tall)";
|
|
39455
|
+
var MEDIA_KEY = new RegExp(`^(?:(?:${MEDIA_QUALIFIER}|${MEDIA_NOUN})[_-]?)?${MEDIA_NOUN}s?(?:[_-]?(?:link|uri|url|src)s?)?$`, "i");
|
|
39456
|
+
|
|
39452
39457
|
// node_modules/@chrischall/mcp-utils/dist/response/index.js
|
|
39453
39458
|
function rawTextResult(text) {
|
|
39454
39459
|
return { content: [{ type: "text", text }] };
|
|
@@ -42199,11 +42204,20 @@ var FetchproxyNoTabError = class extends FetchproxyHintedError {
|
|
|
42199
42204
|
this.name = "FetchproxyNoTabError";
|
|
42200
42205
|
}
|
|
42201
42206
|
};
|
|
42207
|
+
var FetchproxyTabOpeningError = class extends FetchproxyHintedError {
|
|
42208
|
+
constructor(originalError) {
|
|
42209
|
+
super(originalError, "the extension is opening that tab now \u2014 retry in a few seconds. You do not need to open one yourself, and this is not a version problem.");
|
|
42210
|
+
this.name = "FetchproxyTabOpeningError";
|
|
42211
|
+
}
|
|
42212
|
+
};
|
|
42202
42213
|
var SCOPE_REJECTION = /not in declared/;
|
|
42203
|
-
var NO_TAB_REJECTION = /no tab matching (?!.*content script loaded)/;
|
|
42214
|
+
var NO_TAB_REJECTION = /no tab matching (?!.*(content script loaded|one is still opening))/;
|
|
42215
|
+
var TAB_OPENING_REJECTION = /no tab matching .*one is still opening/;
|
|
42204
42216
|
function protocolErrorFrom(error61) {
|
|
42205
42217
|
if (SCOPE_REJECTION.test(error61))
|
|
42206
42218
|
return new FetchproxyScopeError(error61);
|
|
42219
|
+
if (TAB_OPENING_REJECTION.test(error61))
|
|
42220
|
+
return new FetchproxyTabOpeningError(error61);
|
|
42207
42221
|
if (NO_TAB_REJECTION.test(error61))
|
|
42208
42222
|
return new FetchproxyNoTabError(error61);
|
|
42209
42223
|
return new FetchproxyProtocolError(error61);
|
|
@@ -44235,6 +44249,8 @@ var CREDENTIAL_ARMS = /* @__PURE__ */ new Set([
|
|
|
44235
44249
|
"ok",
|
|
44236
44250
|
"no_credential",
|
|
44237
44251
|
"credential_rejected",
|
|
44252
|
+
"session_expired",
|
|
44253
|
+
"verification_pending",
|
|
44238
44254
|
"timeout",
|
|
44239
44255
|
"http",
|
|
44240
44256
|
"transport",
|
|
@@ -44251,6 +44267,10 @@ function credentialHint(arm, prefix, hostLabel, source) {
|
|
|
44251
44267
|
return `No credential resolved. Nothing was available to authenticate with \u2014 sign in and reconnect the connector so ${prefix} receives a token, or set the documented environment variable.`;
|
|
44252
44268
|
case "credential_rejected":
|
|
44253
44269
|
return `${hostLabel} rejected the credential from '${source}'. It is present but no longer valid \u2014 most often expired or revoked upstream. Re-authenticate and reconnect; retrying will not fix it.`;
|
|
44270
|
+
case "session_expired":
|
|
44271
|
+
return `The credential from '${source}' is configured, but no session is live \u2014 ${hostLabel} served a sign-in page rather than the data. Sign in again; a cookie-session portal expires these on its own, so this recurs between uses.`;
|
|
44272
|
+
case "verification_pending":
|
|
44273
|
+
return `${hostLabel} is holding the sign-in on a second factor rather than refusing it. Supply the verification code the ACCOUNT HOLDER received \u2014 the credential itself is not the problem, so changing it will not help.`;
|
|
44254
44274
|
case "timeout":
|
|
44255
44275
|
return `The credential from '${source}' resolved, but ${hostLabel} did not answer in time. Usually transient \u2014 retry. If it persists, ${hostLabel} is slow or unreachable from here.`;
|
|
44256
44276
|
case "http":
|
|
@@ -44261,12 +44281,102 @@ function credentialHint(arm, prefix, hostLabel, source) {
|
|
|
44261
44281
|
return `Unexpected failure \u2014 see error.message.`;
|
|
44262
44282
|
}
|
|
44263
44283
|
}
|
|
44284
|
+
function credentialHealthcheckDescription(hostLabel) {
|
|
44285
|
+
return `Resolves the credential the way real tools do, then makes one authenticated request to ${hostLabel}. Reports which source supplied the credential, whether ${hostLabel} accepted it, the round-trip time, and a plain-English hint distinguishing 'no credential' from 'credential rejected' from 'a ${hostLabel}-side problem'. Read-only; never returns the credential itself.`;
|
|
44286
|
+
}
|
|
44287
|
+
async function runCredentialHealthcheck(args) {
|
|
44288
|
+
const { prefix, hostLabel, probePath, resolveCredential, probeFn, classifyThrown, hints } = args;
|
|
44289
|
+
const probeUrl = probePath ? `https://${hostLabel}${probePath.startsWith("/") ? "" : "/"}${probePath}` : void 0;
|
|
44290
|
+
let probeStarted = 0;
|
|
44291
|
+
let state;
|
|
44292
|
+
try {
|
|
44293
|
+
state = await resolveCredential();
|
|
44294
|
+
} catch (e) {
|
|
44295
|
+
const classified = classifyThrown?.(e);
|
|
44296
|
+
const result2 = {
|
|
44297
|
+
ok: false,
|
|
44298
|
+
// Still false, and still no source: a classification explains WHY
|
|
44299
|
+
// nothing resolved, it does not invent a credential that did.
|
|
44300
|
+
credential: { source: null, resolved: false },
|
|
44301
|
+
// No `url`: nothing was probed, and naming one implies it was tried.
|
|
44302
|
+
probe: { elapsed_ms: 0 },
|
|
44303
|
+
error: {
|
|
44304
|
+
kind: classified?.kind ?? "no_credential",
|
|
44305
|
+
message: truncateErrorMessage(messageOf(e)),
|
|
44306
|
+
...classified?.detail !== void 0 ? { detail: classified.detail } : {}
|
|
44307
|
+
},
|
|
44308
|
+
// The hint must follow the KIND beside it. Falling back to
|
|
44309
|
+
// `no_credential`'s copy under a classified kind would state a cause
|
|
44310
|
+
// the kind contradicts — the same disagreement this path exists to
|
|
44311
|
+
// remove. So: an inline hint wins; else the classified arm's own
|
|
44312
|
+
// copy (consumer override first); else, for a kind this module has
|
|
44313
|
+
// no copy for, the neutral `unknown` text rather than one that
|
|
44314
|
+
// asserts a cause; else the unclassified `no_credential` default.
|
|
44315
|
+
hint: classified?.hint ?? (isArm(classified?.kind) ? hints?.[classified.kind] ?? credentialHint(classified.kind, prefix, hostLabel, null) : classified !== void 0 ? credentialHint("unknown", prefix, hostLabel, null) : hints?.no_credential ?? credentialHint("no_credential", prefix, hostLabel, null))
|
|
44316
|
+
};
|
|
44317
|
+
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
44318
|
+
}
|
|
44319
|
+
const credential = {
|
|
44320
|
+
source: state.source,
|
|
44321
|
+
resolved: state.source !== null,
|
|
44322
|
+
...state.detail !== void 0 ? { detail: state.detail } : {}
|
|
44323
|
+
};
|
|
44324
|
+
if (!credential.resolved) {
|
|
44325
|
+
const result2 = {
|
|
44326
|
+
ok: false,
|
|
44327
|
+
credential,
|
|
44328
|
+
probe: { elapsed_ms: 0 },
|
|
44329
|
+
error: { kind: "no_credential", message: "no credential source resolved" },
|
|
44330
|
+
hint: hints?.no_credential ?? credentialHint("no_credential", prefix, hostLabel, null)
|
|
44331
|
+
};
|
|
44332
|
+
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
44333
|
+
}
|
|
44334
|
+
let arm = "ok";
|
|
44335
|
+
let error61;
|
|
44336
|
+
let status;
|
|
44337
|
+
let customHint;
|
|
44338
|
+
probeStarted = Date.now();
|
|
44339
|
+
try {
|
|
44340
|
+
await probeFn();
|
|
44341
|
+
} catch (e) {
|
|
44342
|
+
status = statusOf(e);
|
|
44343
|
+
const aborted2 = e instanceof Error && e.name === "AbortError";
|
|
44344
|
+
arm = status === 401 || status === 403 ? "credential_rejected" : status !== void 0 ? "http" : aborted2 || /timeout|timed out|ETIMEDOUT/i.test(messageOf(e)) ? "timeout" : /fetch failed|ENOTFOUND|ECONNREFUSED|ECONNRESET|network/i.test(messageOf(e)) ? "transport" : "unknown";
|
|
44345
|
+
let kind = arm;
|
|
44346
|
+
let detail;
|
|
44347
|
+
const custom2 = classifyThrown?.(e);
|
|
44348
|
+
if (custom2) {
|
|
44349
|
+
kind = custom2.kind;
|
|
44350
|
+
customHint = custom2.hint;
|
|
44351
|
+
detail = custom2.detail;
|
|
44352
|
+
arm = isArm(kind) ? kind : "unknown";
|
|
44353
|
+
}
|
|
44354
|
+
error61 = {
|
|
44355
|
+
kind,
|
|
44356
|
+
// Redacted AND bounded before it reaches the result: an upstream
|
|
44357
|
+
// failure routinely quotes what it was sent, and a healthcheck is
|
|
44358
|
+
// the tool people paste into a chat when something is broken.
|
|
44359
|
+
message: truncateErrorMessage(messageOf(e)),
|
|
44360
|
+
...detail !== void 0 ? { detail } : {}
|
|
44361
|
+
};
|
|
44362
|
+
}
|
|
44363
|
+
const result = {
|
|
44364
|
+
ok: error61 === void 0,
|
|
44365
|
+
credential,
|
|
44366
|
+
probe: {
|
|
44367
|
+
...probeUrl ? { url: probeUrl } : {},
|
|
44368
|
+
elapsed_ms: Date.now() - probeStarted,
|
|
44369
|
+
...status !== void 0 ? { status } : {}
|
|
44370
|
+
},
|
|
44371
|
+
...error61 ? { error: error61 } : {},
|
|
44372
|
+
hint: customHint ?? hints?.[arm] ?? credentialHint(arm, prefix, hostLabel, state.source)
|
|
44373
|
+
};
|
|
44374
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
44375
|
+
}
|
|
44264
44376
|
function registerCredentialHealthcheckTool(args) {
|
|
44265
|
-
|
|
44266
|
-
const probeUrl = probePath ? `https://${hostLabel}${probePath}` : void 0;
|
|
44267
|
-
server.registerTool(`${prefix}_healthcheck`, {
|
|
44377
|
+
args.server.registerTool(`${args.prefix}_healthcheck`, {
|
|
44268
44378
|
title: "Verify credentials and upstream reachability",
|
|
44269
|
-
description:
|
|
44379
|
+
description: `${credentialHealthcheckDescription(args.hostLabel)} Call this when a real tool fails and you want to know which hop broke.`,
|
|
44270
44380
|
annotations: {
|
|
44271
44381
|
title: "Verify credentials and upstream reachability",
|
|
44272
44382
|
readOnlyHint: true,
|
|
@@ -44274,92 +44384,7 @@ function registerCredentialHealthcheckTool(args) {
|
|
|
44274
44384
|
openWorldHint: true
|
|
44275
44385
|
},
|
|
44276
44386
|
inputSchema: {}
|
|
44277
|
-
}, async () =>
|
|
44278
|
-
let probeStarted = 0;
|
|
44279
|
-
let state;
|
|
44280
|
-
try {
|
|
44281
|
-
state = await resolveCredential();
|
|
44282
|
-
} catch (e) {
|
|
44283
|
-
const classified = classifyThrown?.(e);
|
|
44284
|
-
const result2 = {
|
|
44285
|
-
ok: false,
|
|
44286
|
-
// Still false, and still no source: a classification explains WHY
|
|
44287
|
-
// nothing resolved, it does not invent a credential that did.
|
|
44288
|
-
credential: { source: null, resolved: false },
|
|
44289
|
-
// No `url`: nothing was probed, and naming one implies it was tried.
|
|
44290
|
-
probe: { elapsed_ms: 0 },
|
|
44291
|
-
error: {
|
|
44292
|
-
kind: classified?.kind ?? "no_credential",
|
|
44293
|
-
message: truncateErrorMessage(messageOf(e)),
|
|
44294
|
-
...classified?.detail !== void 0 ? { detail: classified.detail } : {}
|
|
44295
|
-
},
|
|
44296
|
-
// The hint must follow the KIND beside it. Falling back to
|
|
44297
|
-
// `no_credential`'s copy under a classified kind would state a cause
|
|
44298
|
-
// the kind contradicts — the same disagreement this path exists to
|
|
44299
|
-
// remove. So: an inline hint wins; else the classified arm's own
|
|
44300
|
-
// copy (consumer override first); else, for a kind this module has
|
|
44301
|
-
// no copy for, the neutral `unknown` text rather than one that
|
|
44302
|
-
// asserts a cause; else the unclassified `no_credential` default.
|
|
44303
|
-
hint: classified?.hint ?? (isArm(classified?.kind) ? hints?.[classified.kind] ?? credentialHint(classified.kind, prefix, hostLabel, null) : classified !== void 0 ? credentialHint("unknown", prefix, hostLabel, null) : hints?.no_credential ?? credentialHint("no_credential", prefix, hostLabel, null))
|
|
44304
|
-
};
|
|
44305
|
-
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
44306
|
-
}
|
|
44307
|
-
const credential = {
|
|
44308
|
-
source: state.source,
|
|
44309
|
-
resolved: state.source !== null,
|
|
44310
|
-
...state.detail !== void 0 ? { detail: state.detail } : {}
|
|
44311
|
-
};
|
|
44312
|
-
if (!credential.resolved) {
|
|
44313
|
-
const result2 = {
|
|
44314
|
-
ok: false,
|
|
44315
|
-
credential,
|
|
44316
|
-
probe: { elapsed_ms: 0 },
|
|
44317
|
-
error: { kind: "no_credential", message: "no credential source resolved" },
|
|
44318
|
-
hint: hints?.no_credential ?? credentialHint("no_credential", prefix, hostLabel, null)
|
|
44319
|
-
};
|
|
44320
|
-
return { content: [{ type: "text", text: JSON.stringify(result2, null, 2) }] };
|
|
44321
|
-
}
|
|
44322
|
-
let arm = "ok";
|
|
44323
|
-
let error61;
|
|
44324
|
-
let status;
|
|
44325
|
-
let customHint;
|
|
44326
|
-
probeStarted = Date.now();
|
|
44327
|
-
try {
|
|
44328
|
-
await probeFn();
|
|
44329
|
-
} catch (e) {
|
|
44330
|
-
status = statusOf(e);
|
|
44331
|
-
const aborted2 = e instanceof Error && e.name === "AbortError";
|
|
44332
|
-
arm = status === 401 || status === 403 ? "credential_rejected" : status !== void 0 ? "http" : aborted2 || /timeout|timed out|ETIMEDOUT/i.test(messageOf(e)) ? "timeout" : /fetch failed|ENOTFOUND|ECONNREFUSED|ECONNRESET|network/i.test(messageOf(e)) ? "transport" : "unknown";
|
|
44333
|
-
let kind = arm;
|
|
44334
|
-
let detail;
|
|
44335
|
-
const custom2 = classifyThrown?.(e);
|
|
44336
|
-
if (custom2) {
|
|
44337
|
-
kind = custom2.kind;
|
|
44338
|
-
customHint = custom2.hint;
|
|
44339
|
-
detail = custom2.detail;
|
|
44340
|
-
}
|
|
44341
|
-
error61 = {
|
|
44342
|
-
kind,
|
|
44343
|
-
// Redacted AND bounded before it reaches the result: an upstream
|
|
44344
|
-
// failure routinely quotes what it was sent, and a healthcheck is
|
|
44345
|
-
// the tool people paste into a chat when something is broken.
|
|
44346
|
-
message: truncateErrorMessage(messageOf(e)),
|
|
44347
|
-
...detail !== void 0 ? { detail } : {}
|
|
44348
|
-
};
|
|
44349
|
-
}
|
|
44350
|
-
const result = {
|
|
44351
|
-
ok: error61 === void 0,
|
|
44352
|
-
credential,
|
|
44353
|
-
probe: {
|
|
44354
|
-
...probeUrl ? { url: probeUrl } : {},
|
|
44355
|
-
elapsed_ms: Date.now() - probeStarted,
|
|
44356
|
-
...status !== void 0 ? { status } : {}
|
|
44357
|
-
},
|
|
44358
|
-
...error61 ? { error: error61 } : {},
|
|
44359
|
-
hint: customHint ?? hints?.[arm] ?? credentialHint(arm, prefix, hostLabel, state.source)
|
|
44360
|
-
};
|
|
44361
|
-
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
44362
|
-
});
|
|
44387
|
+
}, async () => runCredentialHealthcheck(args));
|
|
44363
44388
|
}
|
|
44364
44389
|
|
|
44365
44390
|
// src/protocol.ts
|
|
@@ -44434,7 +44459,7 @@ async function loginWithPassword(username, password) {
|
|
|
44434
44459
|
// package.json
|
|
44435
44460
|
var package_default = {
|
|
44436
44461
|
name: "ofw-mcp",
|
|
44437
|
-
version: "2.16.
|
|
44462
|
+
version: "2.16.1",
|
|
44438
44463
|
license: "MIT",
|
|
44439
44464
|
mcpName: "io.github.chrischall/ofw-mcp",
|
|
44440
44465
|
description: "OurFamilyWizard MCP server for Claude \u2014 developed and maintained by AI (Claude Code)",
|
|
@@ -44468,11 +44493,11 @@ var package_default = {
|
|
|
44468
44493
|
typecheck: "tsc -p tsconfig.json --noEmit"
|
|
44469
44494
|
},
|
|
44470
44495
|
dependencies: {
|
|
44471
|
-
"@chrischall/mcp-utils": "^0.
|
|
44496
|
+
"@chrischall/mcp-utils": "^0.26.1",
|
|
44472
44497
|
"@fetchproxy/bootstrap": "^2.2.0",
|
|
44473
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
44498
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
44474
44499
|
dotenv: "^17.4.2",
|
|
44475
|
-
zod: "^4.4
|
|
44500
|
+
zod: "^4.5.4"
|
|
44476
44501
|
},
|
|
44477
44502
|
devDependencies: {
|
|
44478
44503
|
"@types/node": "^26.0.0",
|
|
@@ -49420,7 +49445,7 @@ var nodeCacheProvider = () => nodeCache ??= OFWCache.open(getCacheDbPath());
|
|
|
49420
49445
|
var nodeAttachmentIO = new NodeAttachmentIO();
|
|
49421
49446
|
await runMcp({
|
|
49422
49447
|
name: "ofw",
|
|
49423
|
-
version: "2.16.
|
|
49448
|
+
version: "2.16.1",
|
|
49424
49449
|
// x-release-please-version
|
|
49425
49450
|
deps: client,
|
|
49426
49451
|
tools: [
|
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.16.
|
|
39
|
+
version: '2.16.1', // 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.16.
|
|
3
|
+
"version": "2.16.1",
|
|
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,11 +34,11 @@
|
|
|
34
34
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@chrischall/mcp-utils": "^0.
|
|
37
|
+
"@chrischall/mcp-utils": "^0.26.1",
|
|
38
38
|
"@fetchproxy/bootstrap": "^2.2.0",
|
|
39
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
39
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
40
40
|
"dotenv": "^17.4.2",
|
|
41
|
-
"zod": "^4.4
|
|
41
|
+
"zod": "^4.5.4"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/node": "^26.0.0",
|
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.16.
|
|
9
|
+
"version": "2.16.1",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "ofw-mcp",
|
|
14
|
-
"version": "2.16.
|
|
14
|
+
"version": "2.16.1",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|