@chrischall/pickuppatrol-mcp 0.1.1 → 0.1.2

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": "PickUp Patrol school-dismissal tools for Claude Code",
9
- "version": "0.1.1"
9
+ "version": "0.1.2"
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": "0.1.1",
17
+ "version": "0.1.2",
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": "0.1.1",
4
+ "version": "0.1.2",
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
@@ -31000,53 +31000,6 @@ var StdioServerTransport = class {
31000
31000
  }
31001
31001
  };
31002
31002
 
31003
- // node_modules/@chrischall/mcp-utils/dist/server/index.js
31004
- async function createMcpServer(opts) {
31005
- const server = new McpServer({ name: opts.name, version: opts.version });
31006
- if (opts.banner !== void 0) {
31007
- console.error(opts.banner);
31008
- }
31009
- const deps = opts.deps;
31010
- for (const register of opts.tools) {
31011
- await register(server, deps);
31012
- }
31013
- return server;
31014
- }
31015
- function withGracefulShutdown(server, opts = {}) {
31016
- const shouldExit = opts.exit ?? true;
31017
- let shuttingDown = false;
31018
- const handler = (signal) => {
31019
- if (shuttingDown)
31020
- return;
31021
- shuttingDown = true;
31022
- void (async () => {
31023
- try {
31024
- if (opts.onSignal)
31025
- await opts.onSignal(signal);
31026
- await server.close();
31027
- } catch (err) {
31028
- console.error(`[mcp-utils] error during graceful shutdown on ${signal}: ${err instanceof Error ? err.message : String(err)}`);
31029
- } finally {
31030
- if (shouldExit)
31031
- process.exit(0);
31032
- }
31033
- })();
31034
- };
31035
- process.on("SIGINT", () => handler("SIGINT"));
31036
- process.on("SIGTERM", () => handler("SIGTERM"));
31037
- }
31038
- async function runMcp(opts) {
31039
- const server = await createMcpServer(opts);
31040
- const shutdown = opts.shutdown ?? true;
31041
- if (shutdown !== false) {
31042
- withGracefulShutdown(server, shutdown === true ? {} : shutdown);
31043
- }
31044
- const spec = opts.transport ?? "stdio";
31045
- const transport = spec === "stdio" ? new StdioServerTransport() : spec;
31046
- await server.connect(transport);
31047
- return server;
31048
- }
31049
-
31050
31003
  // node_modules/@chrischall/mcp-utils/dist/errors/index.js
31051
31004
  var McpToolError = class extends Error {
31052
31005
  /** Actionable remediation text, when one applies. */
@@ -31105,6 +31058,75 @@ function errorResult(message) {
31105
31058
  };
31106
31059
  }
31107
31060
 
31061
+ // node_modules/@chrischall/mcp-utils/dist/server/index.js
31062
+ function hintResultOrRethrow(err) {
31063
+ if (err instanceof McpToolError && err.hint) {
31064
+ return errorResult(`${err.message}
31065
+
31066
+ Hint: ${err.hint}`);
31067
+ }
31068
+ throw err;
31069
+ }
31070
+ function surfaceToolHints(server) {
31071
+ const register = server.registerTool.bind(server);
31072
+ server.registerTool = (name, config2, cb) => register(name, config2, (...args) => {
31073
+ let result;
31074
+ try {
31075
+ result = cb(...args);
31076
+ } catch (err) {
31077
+ return hintResultOrRethrow(err);
31078
+ }
31079
+ return result instanceof Promise ? result.catch(hintResultOrRethrow) : result;
31080
+ });
31081
+ }
31082
+ async function createMcpServer(opts) {
31083
+ const server = new McpServer({ name: opts.name, version: opts.version });
31084
+ if (opts.surfaceHints !== false)
31085
+ surfaceToolHints(server);
31086
+ if (opts.banner !== void 0) {
31087
+ console.error(opts.banner);
31088
+ }
31089
+ const deps = opts.deps;
31090
+ for (const register of opts.tools) {
31091
+ await register(server, deps);
31092
+ }
31093
+ return server;
31094
+ }
31095
+ function withGracefulShutdown(server, opts = {}) {
31096
+ const shouldExit = opts.exit ?? true;
31097
+ let shuttingDown = false;
31098
+ const handler = (signal) => {
31099
+ if (shuttingDown)
31100
+ return;
31101
+ shuttingDown = true;
31102
+ void (async () => {
31103
+ try {
31104
+ if (opts.onSignal)
31105
+ await opts.onSignal(signal);
31106
+ await server.close();
31107
+ } catch (err) {
31108
+ console.error(`[mcp-utils] error during graceful shutdown on ${signal}: ${err instanceof Error ? err.message : String(err)}`);
31109
+ } finally {
31110
+ if (shouldExit)
31111
+ process.exit(0);
31112
+ }
31113
+ })();
31114
+ };
31115
+ process.on("SIGINT", () => handler("SIGINT"));
31116
+ process.on("SIGTERM", () => handler("SIGTERM"));
31117
+ }
31118
+ async function runMcp(opts) {
31119
+ const server = await createMcpServer(opts);
31120
+ const shutdown = opts.shutdown ?? true;
31121
+ if (shutdown !== false) {
31122
+ withGracefulShutdown(server, shutdown === true ? {} : shutdown);
31123
+ }
31124
+ const spec = opts.transport ?? "stdio";
31125
+ const transport = spec === "stdio" ? new StdioServerTransport() : spec;
31126
+ await server.connect(transport);
31127
+ return server;
31128
+ }
31129
+
31108
31130
  // node_modules/@chrischall/mcp-utils/dist/config/index.js
31109
31131
  var PLACEHOLDER_RE = /^\$\{[^}]*\}$/;
31110
31132
  function readEnvVar(key, opts = {}) {
@@ -31503,7 +31525,7 @@ var PickUpPatrolClient = class {
31503
31525
  var client = new PickUpPatrolClient();
31504
31526
 
31505
31527
  // src/version.ts
31506
- var VERSION = "0.1.1";
31528
+ var VERSION = "0.1.2";
31507
31529
 
31508
31530
  // src/dates.ts
31509
31531
  var WEEKDAY_NAMES = [
@@ -31861,22 +31883,6 @@ function previewUnlessConfirmed(confirm, action, method, dto, body) {
31861
31883
  });
31862
31884
  }
31863
31885
 
31864
- // src/tools/_errors.ts
31865
- function withHints(handler) {
31866
- return async (args) => {
31867
- try {
31868
- return await handler(args);
31869
- } catch (err) {
31870
- if (err instanceof McpToolError && err.hint) {
31871
- return errorResult(`${err.message}
31872
-
31873
- Hint: ${err.hint}`);
31874
- }
31875
- throw err;
31876
- }
31877
- };
31878
- }
31879
-
31880
31886
  // src/tools/plans.ts
31881
31887
  function proofsMatch(a, b) {
31882
31888
  return a.transportationId === b.transportationId && (a.note ?? "").trim() === (b.note ?? "").trim();
@@ -31935,7 +31941,7 @@ function registerPlanTools(server, client2) {
31935
31941
  confirm: schemaConfirm
31936
31942
  }
31937
31943
  },
31938
- withHints(async ({ student_id, dates, transportation_id, note, early_dismissal_time, car_number, confirm }) => {
31944
+ (async ({ student_id, dates, transportation_id, note, early_dismissal_time, car_number, confirm }) => {
31939
31945
  const student = await client2.getStudent(student_id);
31940
31946
  const transportation = transportation_id === null ? null : await resolveTransportation(client2, student.SchoolId, transportation_id);
31941
31947
  const plans = buildPlanUpdates({
@@ -32048,7 +32054,7 @@ function registerDefaultPlanTools(server, client2) {
32048
32054
  confirm: schemaConfirm
32049
32055
  }
32050
32056
  },
32051
- withHints(async ({ student_id, days, transportation_id, note, early_dismissal_time, clear_all, confirm }) => {
32057
+ (async ({ student_id, days, transportation_id, note, early_dismissal_time, clear_all, confirm }) => {
32052
32058
  const student = await client2.getStudent(student_id);
32053
32059
  if (clear_all === true) {
32054
32060
  const payload2 = clearDefaultPlans(student);
@@ -5,7 +5,6 @@ import { dayIdToName, nameToDayId } from '../dates.js';
5
5
  import { summarizeDefaultPlans } from './account.js';
6
6
  import { proofsMatch, resolveTransportation } from './plans.js';
7
7
  import { previewUnlessConfirmed, schemaConfirm } from './_confirm.js';
8
- import { withHints } from './_errors.js';
9
8
  /**
10
9
  * Accept weekdays as names ("Monday") or ids (1 = Sunday … 7 = Saturday).
11
10
  * A name that is not a weekday is rejected rather than coerced — silently
@@ -78,7 +77,7 @@ export function registerDefaultPlanTools(server, client) {
78
77
  .describe('Remove every weekday default instead of setting one (days is ignored)'),
79
78
  confirm: schemaConfirm,
80
79
  },
81
- }, withHints(async ({ student_id, days, transportation_id, note, early_dismissal_time, clear_all, confirm }) => {
80
+ }, (async ({ student_id, days, transportation_id, note, early_dismissal_time, clear_all, confirm }) => {
82
81
  // Read-modify-write: PickUp Patrol has no default-plans endpoint, so the
83
82
  // whole student record round-trips. Reading it here (before the confirm
84
83
  // gate) is what makes the dry-run show the real payload; it mutates
@@ -3,7 +3,6 @@ import { McpToolError, textResult } from '@chrischall/mcp-utils';
3
3
  import { buildPlanUpdates } from '../plans.js';
4
4
  import { weekdayOf } from '../dates.js';
5
5
  import { previewUnlessConfirmed, schemaConfirm } from './_confirm.js';
6
- import { withHints } from './_errors.js';
7
6
  /** Compare two proofs, ignoring whitespace the service may normalise off a note. */
8
7
  export function proofsMatch(a, b) {
9
8
  return a.transportationId === b.transportationId && (a.note ?? '').trim() === (b.note ?? '').trim();
@@ -79,7 +78,7 @@ export function registerPlanTools(server, client) {
79
78
  .describe('Car number, for options where usesCarNumbers is true'),
80
79
  confirm: schemaConfirm,
81
80
  },
82
- }, withHints(async ({ student_id, dates, transportation_id, note, early_dismissal_time, car_number, confirm }) => {
81
+ }, (async ({ student_id, dates, transportation_id, note, early_dismissal_time, car_number, confirm }) => {
83
82
  // The reads below resolve and validate the payload; they mutate nothing.
84
83
  // Running them before the confirm gate is deliberate: it makes the
85
84
  // dry-run show the exact bytes that would be sent, already checked
package/dist/version.d.ts CHANGED
@@ -7,4 +7,4 @@
7
7
  * annotation, so there is exactly one line to keep in sync and
8
8
  * `versionSyncTest` has exactly one line to check.
9
9
  */
10
- export declare const VERSION = "0.1.1";
10
+ export declare const VERSION = "0.1.2";
package/dist/version.js CHANGED
@@ -7,4 +7,4 @@
7
7
  * annotation, so there is exactly one line to keep in sync and
8
8
  * `versionSyncTest` has exactly one line to check.
9
9
  */
10
- export const VERSION = '0.1.1'; // x-release-please-version
10
+ export const VERSION = '0.1.2'; // x-release-please-version
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chrischall/pickuppatrol-mcp",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
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)",
@@ -56,7 +56,7 @@
56
56
  "test:watch": "vitest"
57
57
  },
58
58
  "dependencies": {
59
- "@chrischall/mcp-utils": "^0.14.0",
59
+ "@chrischall/mcp-utils": "^0.15.0",
60
60
  "@modelcontextprotocol/sdk": "^1.29.0",
61
61
  "dotenv": "^17.4.0",
62
62
  "zod": "^4.4.3"
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": "0.1.1",
9
+ "version": "0.1.2",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "@chrischall/pickuppatrol-mcp",
14
- "version": "0.1.1",
14
+ "version": "0.1.2",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  }
@@ -1,14 +0,0 @@
1
- import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
2
- /**
3
- * Surface an `McpToolError`'s `hint` to the caller.
4
- *
5
- * The MCP tool boundary turns a thrown error into a result carrying only
6
- * `message`, so a `hint` — which is where the actionable half lives here ("the
7
- * available options are …", "the school describes the note as …") — is
8
- * otherwise dropped on the floor. Wrapping the handler folds it into the text
9
- * the caller actually sees.
10
- *
11
- * Only `McpToolError` is handled: an unexpected error keeps propagating, so a
12
- * genuine bug still reads as one instead of being flattened into advice.
13
- */
14
- export declare function withHints<A>(handler: (args: A) => Promise<CallToolResult>): (args: A) => Promise<CallToolResult>;
@@ -1,26 +0,0 @@
1
- import { McpToolError, errorResult } from '@chrischall/mcp-utils';
2
- /**
3
- * Surface an `McpToolError`'s `hint` to the caller.
4
- *
5
- * The MCP tool boundary turns a thrown error into a result carrying only
6
- * `message`, so a `hint` — which is where the actionable half lives here ("the
7
- * available options are …", "the school describes the note as …") — is
8
- * otherwise dropped on the floor. Wrapping the handler folds it into the text
9
- * the caller actually sees.
10
- *
11
- * Only `McpToolError` is handled: an unexpected error keeps propagating, so a
12
- * genuine bug still reads as one instead of being flattened into advice.
13
- */
14
- export function withHints(handler) {
15
- return async (args) => {
16
- try {
17
- return await handler(args);
18
- }
19
- catch (err) {
20
- if (err instanceof McpToolError && err.hint) {
21
- return errorResult(`${err.message}\n\nHint: ${err.hint}`);
22
- }
23
- throw err;
24
- }
25
- };
26
- }