@chrischall/pickuppatrol-mcp 1.0.0 → 1.0.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 +138 -17
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/server.json +2 -2
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
8
|
"description": "PickUp Patrol school-dismissal tools for Claude Code",
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.1"
|
|
10
10
|
},
|
|
11
11
|
"plugins": [
|
|
12
12
|
{
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"displayName": "PickUp Patrol",
|
|
15
15
|
"source": "./",
|
|
16
16
|
"description": "Read and change your children's school dismissal plans in PickUp Patrol — defaults, day-by-day changes and school cutoff times — via MCP",
|
|
17
|
-
"version": "1.0.
|
|
17
|
+
"version": "1.0.1",
|
|
18
18
|
"author": {
|
|
19
19
|
"name": "Chris Chall"
|
|
20
20
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pickuppatrol",
|
|
3
3
|
"displayName": "PickUp Patrol",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.1",
|
|
5
5
|
"description": "Read and change your children's school dismissal plans in PickUp Patrol — defaults, day-by-day changes and school cutoff times — via MCP",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Chris Chall"
|
package/dist/bundle.js
CHANGED
|
@@ -23302,6 +23302,20 @@ var require_v4 = __commonJS({
|
|
|
23302
23302
|
}
|
|
23303
23303
|
});
|
|
23304
23304
|
|
|
23305
|
+
// node_modules/@chrischall/mcp-utils/dist/cancel/index.js
|
|
23306
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
23307
|
+
var storage = new AsyncLocalStorage();
|
|
23308
|
+
function withCallSignal(signal, fn, request) {
|
|
23309
|
+
return signal ? storage.run({ signal, ...request ? { request } : {} }, fn) : fn();
|
|
23310
|
+
}
|
|
23311
|
+
|
|
23312
|
+
// node_modules/@chrischall/mcp-utils/dist/caller/index.js
|
|
23313
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "node:async_hooks";
|
|
23314
|
+
var storage2 = new AsyncLocalStorage2();
|
|
23315
|
+
function withCallerCapabilities(capabilities, fn) {
|
|
23316
|
+
return capabilities ? storage2.run(capabilities, fn) : fn();
|
|
23317
|
+
}
|
|
23318
|
+
|
|
23305
23319
|
// node_modules/@modelcontextprotocol/server/dist/chunk-Br0eD_fh.mjs
|
|
23306
23320
|
var __create2 = Object.create;
|
|
23307
23321
|
var __defProp2 = Object.defineProperty;
|
|
@@ -37977,13 +37991,28 @@ var API_KEY_RE = new RegExp([
|
|
|
37977
37991
|
"whsec_[A-Za-z0-9]{16,}\\b"
|
|
37978
37992
|
// webhook signing secret (Stripe-style)
|
|
37979
37993
|
].map((p) => `\\b${p}`).join("|"), "g");
|
|
37980
|
-
var QUERY_SECRET_RE = /([?&](?:
|
|
37994
|
+
var QUERY_SECRET_RE = /([?&](?:(?:access|refresh|id|auth|session|csrf|xsrf)[_-]?token|client[_-]?secret|api[_-]?secret|api[_-]?key|password|passwd|signature|token|key|sig)=)[^&#\s"'<>`]+/gi;
|
|
37995
|
+
var OAUTH_CODE_RE = /([?&]code=)(?=[^&#\s"'<>`]{16,})[^&#\s"'<>`]+/gi;
|
|
37996
|
+
var FORM_PASSWORD_RE = /((?:^|[\s,;:"'(\[{])(?:password|passwd)=)[^&#\s"'<>`]+/gim;
|
|
37997
|
+
var HEADER_SECRET_RE = /(\b(?:x[-_][a-z0-9_-]*?(?:api[-_]?key|token|secret|auth)[a-z0-9_-]*|api[-_]?key)\s*:\s*)[^\s,;"'<>`]+/gi;
|
|
37981
37998
|
var AWS_SIGV4_RE = /([?&]X-Amz-(?:Signature|Security-Token|Credential)=)[^&#\s"'<>`]+/gi;
|
|
37982
|
-
var JSON_SECRET_KEYS =
|
|
37983
|
-
|
|
37984
|
-
|
|
37999
|
+
var JSON_SECRET_KEYS = [
|
|
38000
|
+
"(?:access|refresh|id|auth|session|bearer|csrf|xsrf)[_-]?token",
|
|
38001
|
+
"client[_-]?secret",
|
|
38002
|
+
"api[_-]?secret",
|
|
38003
|
+
"(?:x[_-])?api[_-]?key",
|
|
38004
|
+
"private[_-]?key",
|
|
38005
|
+
"x[_-][a-z0-9_-]*?(?:api[_-]?key|token|secret|auth)[a-z0-9_-]*",
|
|
38006
|
+
"(?:proxy-)?authorization",
|
|
38007
|
+
"password",
|
|
38008
|
+
"passwd",
|
|
38009
|
+
"secret",
|
|
38010
|
+
"token"
|
|
38011
|
+
].join("|");
|
|
38012
|
+
var JSON_SECRET_DQ_RE = new RegExp(`("(?:${JSON_SECRET_KEYS})"\\s*:\\s*")(?:[^"\\\\]|\\\\.)*(")`, "gi");
|
|
38013
|
+
var JSON_SECRET_SQ_RE = new RegExp(`('(?:${JSON_SECRET_KEYS})'\\s*:\\s*')(?:[^'\\\\]|\\\\.)*(')`, "gi");
|
|
37985
38014
|
function redactSecrets(text) {
|
|
37986
|
-
return text.replace(BEARER_RE, "$1[REDACTED]").replace(BASIC_AUTH_RE, "$1[REDACTED]").replace(SET_COOKIE_RE, "$1$2=[REDACTED]").replace(COOKIE_HEADER_RE, (_m, prefix, pairs) => `${prefix}${pairs.replace(/=[^;,\s]*/g, "=[REDACTED]")}`).replace(API_KEY_RE, "[REDACTED]").replace(QUERY_SECRET_RE, "$1[REDACTED]").replace(AWS_SIGV4_RE, "$1[REDACTED]").replace(JSON_SECRET_DQ_RE, "$1[REDACTED]$2").replace(JSON_SECRET_SQ_RE, "$1[REDACTED]$2").replace(JWT_RE, "[REDACTED]");
|
|
38015
|
+
return text.replace(BEARER_RE, "$1[REDACTED]").replace(BASIC_AUTH_RE, "$1[REDACTED]").replace(SET_COOKIE_RE, "$1$2=[REDACTED]").replace(COOKIE_HEADER_RE, (_m, prefix, pairs) => `${prefix}${pairs.replace(/=[^;,\s]*/g, "=[REDACTED]")}`).replace(API_KEY_RE, "[REDACTED]").replace(HEADER_SECRET_RE, "$1[REDACTED]").replace(QUERY_SECRET_RE, "$1[REDACTED]").replace(OAUTH_CODE_RE, "$1[REDACTED]").replace(FORM_PASSWORD_RE, "$1[REDACTED]").replace(AWS_SIGV4_RE, "$1[REDACTED]").replace(JSON_SECRET_DQ_RE, "$1[REDACTED]$2").replace(JSON_SECRET_SQ_RE, "$1[REDACTED]$2").replace(JWT_RE, "[REDACTED]");
|
|
37987
38016
|
}
|
|
37988
38017
|
function messageOf(err) {
|
|
37989
38018
|
if (err instanceof Error)
|
|
@@ -57690,17 +57719,73 @@ Hint: ${err.hint}`);
|
|
|
57690
57719
|
}
|
|
57691
57720
|
throw err;
|
|
57692
57721
|
}
|
|
57722
|
+
function mcpRequestFrom(args) {
|
|
57723
|
+
const ctx = args.at(-1);
|
|
57724
|
+
if (typeof ctx !== "object" || ctx === null)
|
|
57725
|
+
return void 0;
|
|
57726
|
+
const req = ctx.mcpReq;
|
|
57727
|
+
if (typeof req !== "object" || req === null)
|
|
57728
|
+
return void 0;
|
|
57729
|
+
return typeof req.notify === "function" ? req : void 0;
|
|
57730
|
+
}
|
|
57731
|
+
function callSignalFrom(args) {
|
|
57732
|
+
const ctx = args.at(-1);
|
|
57733
|
+
if (typeof ctx !== "object" || ctx === null)
|
|
57734
|
+
return void 0;
|
|
57735
|
+
const req = ctx.mcpReq;
|
|
57736
|
+
if (typeof req !== "object" || req === null)
|
|
57737
|
+
return void 0;
|
|
57738
|
+
const signal = req.signal;
|
|
57739
|
+
return signal instanceof AbortSignal ? signal : void 0;
|
|
57740
|
+
}
|
|
57741
|
+
function declaredCapabilitiesFrom(server) {
|
|
57742
|
+
const inner = server.server;
|
|
57743
|
+
if (typeof inner !== "object" || inner === null)
|
|
57744
|
+
return void 0;
|
|
57745
|
+
const read = inner.getClientCapabilities;
|
|
57746
|
+
if (typeof read !== "function")
|
|
57747
|
+
return void 0;
|
|
57748
|
+
try {
|
|
57749
|
+
const declared = read.call(inner);
|
|
57750
|
+
return typeof declared === "object" && declared !== null ? declared : void 0;
|
|
57751
|
+
} catch {
|
|
57752
|
+
return void 0;
|
|
57753
|
+
}
|
|
57754
|
+
}
|
|
57693
57755
|
function surfaceToolHints(server) {
|
|
57694
57756
|
const register2 = server.registerTool.bind(server);
|
|
57695
|
-
server.registerTool = (name, config2, cb) => register2(name, config2, (...args) =>
|
|
57696
|
-
|
|
57697
|
-
|
|
57698
|
-
|
|
57699
|
-
|
|
57700
|
-
|
|
57701
|
-
|
|
57702
|
-
|
|
57703
|
-
|
|
57757
|
+
server.registerTool = (name, config2, cb) => register2(name, config2, (...args) => (
|
|
57758
|
+
// THE CALLER'S CANCELLATION, made ambient for the whole handler
|
|
57759
|
+
// (`cancel/index.ts`). The SDK delivers it and the fleet ignored it:
|
|
57760
|
+
// measured against @modelcontextprotocol/server 2.0.0, a cancelled
|
|
57761
|
+
// call aborts `ctx.mcpReq.signal` with the caller's reason and the
|
|
57762
|
+
// handler runs to completion regardless — so the HTTP request stays
|
|
57763
|
+
// in flight, the child keeps burning metered CPU, and the upstream
|
|
57764
|
+
// keeps being hit for somebody who has gone. claude.ai sent 101
|
|
57765
|
+
// cancellations in the week to 2026-09-20.
|
|
57766
|
+
//
|
|
57767
|
+
// Here because this is the one wrapper every tool already passes
|
|
57768
|
+
// through: threading the signal by hand would mean editing several
|
|
57769
|
+
// hundred handlers and missing exactly the ones nobody edits.
|
|
57770
|
+
withCallSignal(callSignalFrom(args), () => (
|
|
57771
|
+
// WHAT THE CALLER CAN DO, made ambient for the same reason and in
|
|
57772
|
+
// the same place (`caller/index.ts`). Only the 2025-era half needs
|
|
57773
|
+
// the wrapper — a 2026-07-28 request answers for itself off its own
|
|
57774
|
+
// envelope — but a guarded tool that cannot tell whether the caller
|
|
57775
|
+
// can be shown a prompt returns one the SDK then refuses to deliver,
|
|
57776
|
+
// and that refusal reaches the caller as an unexplained protocol
|
|
57777
|
+
// error it had no chance to catch.
|
|
57778
|
+
withCallerCapabilities(declaredCapabilitiesFrom(server), () => {
|
|
57779
|
+
let result;
|
|
57780
|
+
try {
|
|
57781
|
+
result = cb(...args);
|
|
57782
|
+
} catch (err) {
|
|
57783
|
+
return hintResultOrRethrow(err);
|
|
57784
|
+
}
|
|
57785
|
+
return result instanceof Promise ? result.catch(hintResultOrRethrow) : result;
|
|
57786
|
+
})
|
|
57787
|
+
), mcpRequestFrom(args))
|
|
57788
|
+
));
|
|
57704
57789
|
}
|
|
57705
57790
|
async function createMcpServer(opts) {
|
|
57706
57791
|
const server = new McpServer({ name: opts.name, version: opts.version }, { supportedProtocolVersions: [...SERVER_PROTOCOL_VERSIONS] });
|
|
@@ -57715,13 +57800,47 @@ async function createMcpServer(opts) {
|
|
|
57715
57800
|
}
|
|
57716
57801
|
return server;
|
|
57717
57802
|
}
|
|
57803
|
+
var DEFAULT_SHUTDOWN_TIMEOUT_MS = 5e3;
|
|
57804
|
+
var DEFAULT_REPEAT_SIGNAL_GRACE_MS = 500;
|
|
57718
57805
|
function withGracefulShutdown(target, opts = {}) {
|
|
57719
57806
|
const shouldExit = opts.exit ?? true;
|
|
57807
|
+
if (opts.timeoutMs !== void 0 && !(Number.isFinite(opts.timeoutMs) && opts.timeoutMs > 0)) {
|
|
57808
|
+
throw new RangeError("withGracefulShutdown: timeoutMs must be a finite number greater than 0.");
|
|
57809
|
+
}
|
|
57810
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_SHUTDOWN_TIMEOUT_MS;
|
|
57811
|
+
if (opts.repeatSignalGraceMs !== void 0 && !(Number.isFinite(opts.repeatSignalGraceMs) && opts.repeatSignalGraceMs >= 0)) {
|
|
57812
|
+
throw new RangeError("withGracefulShutdown: repeatSignalGraceMs must be a finite number >= 0.");
|
|
57813
|
+
}
|
|
57814
|
+
const repeatGraceMs = opts.repeatSignalGraceMs ?? DEFAULT_REPEAT_SIGNAL_GRACE_MS;
|
|
57720
57815
|
let shuttingDown = false;
|
|
57816
|
+
let firstSignalAt = 0;
|
|
57817
|
+
let exited = false;
|
|
57818
|
+
const exitOnce = () => {
|
|
57819
|
+
if (exited)
|
|
57820
|
+
return;
|
|
57821
|
+
exited = true;
|
|
57822
|
+
process.exit(0);
|
|
57823
|
+
};
|
|
57721
57824
|
const handler = (signal) => {
|
|
57722
|
-
if (shuttingDown)
|
|
57825
|
+
if (shuttingDown) {
|
|
57826
|
+
if (Date.now() - firstSignalAt < repeatGraceMs)
|
|
57827
|
+
return;
|
|
57828
|
+
if (shouldExit) {
|
|
57829
|
+
console.error(`[mcp-utils] second ${signal} during shutdown \u2014 exiting now`);
|
|
57830
|
+
exitOnce();
|
|
57831
|
+
}
|
|
57723
57832
|
return;
|
|
57833
|
+
}
|
|
57724
57834
|
shuttingDown = true;
|
|
57835
|
+
firstSignalAt = Date.now();
|
|
57836
|
+
let timer;
|
|
57837
|
+
if (shouldExit) {
|
|
57838
|
+
timer = setTimeout(() => {
|
|
57839
|
+
console.error(`[mcp-utils] graceful shutdown on ${signal} did not finish in ${timeoutMs}ms \u2014 exiting`);
|
|
57840
|
+
exitOnce();
|
|
57841
|
+
}, timeoutMs);
|
|
57842
|
+
timer.unref?.();
|
|
57843
|
+
}
|
|
57725
57844
|
void (async () => {
|
|
57726
57845
|
try {
|
|
57727
57846
|
if (opts.onSignal)
|
|
@@ -57730,8 +57849,10 @@ function withGracefulShutdown(target, opts = {}) {
|
|
|
57730
57849
|
} catch (err) {
|
|
57731
57850
|
console.error(`[mcp-utils] error during graceful shutdown on ${signal}: ${err instanceof Error ? err.message : String(err)}`);
|
|
57732
57851
|
} finally {
|
|
57852
|
+
if (timer !== void 0)
|
|
57853
|
+
clearTimeout(timer);
|
|
57733
57854
|
if (shouldExit)
|
|
57734
|
-
|
|
57855
|
+
exitOnce();
|
|
57735
57856
|
}
|
|
57736
57857
|
})();
|
|
57737
57858
|
};
|
|
@@ -58158,7 +58279,7 @@ var PickUpPatrolClient = class {
|
|
|
58158
58279
|
var client = new PickUpPatrolClient();
|
|
58159
58280
|
|
|
58160
58281
|
// src/version.ts
|
|
58161
|
-
var VERSION = "1.0.
|
|
58282
|
+
var VERSION = "1.0.1";
|
|
58162
58283
|
|
|
58163
58284
|
// src/dates.ts
|
|
58164
58285
|
var WEEKDAY_NAMES = [
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrischall/pickuppatrol-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"mcpName": "io.github.chrischall/pickuppatrol-mcp",
|
|
6
6
|
"description": "PickUp Patrol MCP server for Claude — developed and maintained by AI (Claude Code)",
|
|
@@ -57,10 +57,10 @@
|
|
|
57
57
|
"test:watch": "vitest"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@chrischall/mcp-utils": "^
|
|
60
|
+
"@chrischall/mcp-utils": "^2.4.0",
|
|
61
61
|
"@modelcontextprotocol/server": "^2.0.0",
|
|
62
62
|
"dotenv": "^17.4.0",
|
|
63
|
-
"zod": "^4.6.
|
|
63
|
+
"zod": "^4.6.5"
|
|
64
64
|
},
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"@modelcontextprotocol/client": "^2.0.0",
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/chrischall/pickuppatrol-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.1",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@chrischall/pickuppatrol-mcp",
|
|
14
|
-
"version": "1.0.
|
|
14
|
+
"version": "1.0.1",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
}
|