@chrischall/pickuppatrol-mcp 0.1.2 → 0.2.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 +6964 -2285
- package/dist/tools/_confirm.js +2 -2
- package/dist/tools/account.js +6 -6
- package/dist/tools/defaults.js +5 -5
- package/dist/tools/plans.js +4 -4
- package/dist/tools/school.js +6 -6
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/mint.yaml +22 -0
- package/package.json +10 -9
- package/server.json +2 -2
package/dist/tools/_confirm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { minifiedResult, schemaConfirm } from '@chrischall/mcp-utils';
|
|
2
2
|
export { schemaConfirm };
|
|
3
3
|
/**
|
|
4
4
|
* Confirm-gate for a mutating tool (the fleet convention). Without
|
|
@@ -12,7 +12,7 @@ export { schemaConfirm };
|
|
|
12
12
|
export function previewUnlessConfirmed(confirm, action, method, dto, body) {
|
|
13
13
|
if (confirm === true)
|
|
14
14
|
return null;
|
|
15
|
-
return
|
|
15
|
+
return minifiedResult({
|
|
16
16
|
dryRun: true,
|
|
17
17
|
action,
|
|
18
18
|
method,
|
package/dist/tools/account.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import { messageOf, minifiedResult } from '@chrischall/mcp-utils';
|
|
3
3
|
import { dayIdToName } from '../dates.js';
|
|
4
4
|
import { VERSION } from '../version.js';
|
|
5
5
|
/** Project a student down to the fields a parent actually asks about. */
|
|
@@ -36,7 +36,7 @@ export function registerAccountTools(server, client) {
|
|
|
36
36
|
annotations: { readOnlyHint: true },
|
|
37
37
|
}, async () => {
|
|
38
38
|
const session = await client.getSession();
|
|
39
|
-
return
|
|
39
|
+
return minifiedResult({
|
|
40
40
|
userId: session.UserId ?? null,
|
|
41
41
|
name: session.DisplayName ?? [session.FirstName, session.LastName].filter(Boolean).join(' '),
|
|
42
42
|
email: session.Email ?? session.PrimaryEmail ?? null,
|
|
@@ -55,7 +55,7 @@ export function registerAccountTools(server, client) {
|
|
|
55
55
|
client.getDefaultPlansReviewNeeded(),
|
|
56
56
|
]);
|
|
57
57
|
const needsReview = new Map(review.map((r) => [r.StudentId, r.NeedsReview]));
|
|
58
|
-
return
|
|
58
|
+
return minifiedResult(students.map((student) => ({
|
|
59
59
|
...summarizeStudent(student),
|
|
60
60
|
needsDefaultsReview: needsReview.get(student.StudentId) ?? false,
|
|
61
61
|
})));
|
|
@@ -72,7 +72,7 @@ export function registerAccountTools(server, client) {
|
|
|
72
72
|
},
|
|
73
73
|
}, async ({ student_id, raw }) => {
|
|
74
74
|
const student = await client.getStudent(student_id);
|
|
75
|
-
return
|
|
75
|
+
return minifiedResult(raw === true ? student : summarizeStudent(student));
|
|
76
76
|
});
|
|
77
77
|
server.registerTool('pup_healthcheck', {
|
|
78
78
|
description: 'Verify the configured credentials sign in and the PickUp Patrol API answers. Reports the server version and the students the account can see.',
|
|
@@ -80,7 +80,7 @@ export function registerAccountTools(server, client) {
|
|
|
80
80
|
}, async () => {
|
|
81
81
|
try {
|
|
82
82
|
const session = await client.getSession();
|
|
83
|
-
return
|
|
83
|
+
return minifiedResult({
|
|
84
84
|
ok: true,
|
|
85
85
|
version: VERSION,
|
|
86
86
|
signedInAs: session.Email ?? session.PrimaryEmail ?? session.DisplayName ?? null,
|
|
@@ -91,7 +91,7 @@ export function registerAccountTools(server, client) {
|
|
|
91
91
|
// A healthcheck reports rather than throws: the whole point is to say
|
|
92
92
|
// what is wrong, and an exception here reads to the host as the tool
|
|
93
93
|
// itself being broken.
|
|
94
|
-
return
|
|
94
|
+
return minifiedResult({ ok: false, version: VERSION, error: messageOf(err) });
|
|
95
95
|
}
|
|
96
96
|
});
|
|
97
97
|
}
|
package/dist/tools/defaults.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { McpToolError,
|
|
2
|
+
import { McpToolError, minifiedResult } from '@chrischall/mcp-utils';
|
|
3
3
|
import { applyDefaultPlans, clearDefaultPlans } from '../plans.js';
|
|
4
4
|
import { dayIdToName, nameToDayId } from '../dates.js';
|
|
5
5
|
import { summarizeDefaultPlans } from './account.js';
|
|
@@ -42,7 +42,7 @@ export function registerDefaultPlanTools(server, client) {
|
|
|
42
42
|
client.getStudent(student_id),
|
|
43
43
|
client.getDefaultPlansReviewNeeded(),
|
|
44
44
|
]);
|
|
45
|
-
return
|
|
45
|
+
return minifiedResult({
|
|
46
46
|
studentId: student.StudentId,
|
|
47
47
|
name: [student.FirstName, student.LastName].filter(Boolean).join(' '),
|
|
48
48
|
schoolId: student.SchoolId,
|
|
@@ -91,7 +91,7 @@ export function registerDefaultPlanTools(server, client) {
|
|
|
91
91
|
await client.updateStudent(payload);
|
|
92
92
|
const after = await client.getStudent(student_id);
|
|
93
93
|
const remaining = after.DefaultPlans ?? [];
|
|
94
|
-
return
|
|
94
|
+
return minifiedResult({
|
|
95
95
|
action: 'Cleared every weekday default',
|
|
96
96
|
defaultPlans: summarizeDefaultPlans(remaining),
|
|
97
97
|
verified: remaining.length === 0,
|
|
@@ -138,7 +138,7 @@ export function registerDefaultPlanTools(server, client) {
|
|
|
138
138
|
return true;
|
|
139
139
|
return !proofsMatch({ transportationId: plan.TransportationId ?? null, note: plan.Note ?? null }, { transportationId: transportation.TransportationId, note: sentNote });
|
|
140
140
|
});
|
|
141
|
-
return
|
|
141
|
+
return minifiedResult({
|
|
142
142
|
action,
|
|
143
143
|
defaultPlans: summarizeDefaultPlans(after.DefaultPlans),
|
|
144
144
|
verified: unchanged.length === 0,
|
|
@@ -165,7 +165,7 @@ export function registerDefaultPlanTools(server, client) {
|
|
|
165
165
|
await client.setDefaultsReviewed(student_id, value);
|
|
166
166
|
const review = await client.getDefaultPlansReviewNeeded();
|
|
167
167
|
const needsReview = review.find((r) => r.StudentId === student_id)?.NeedsReview ?? false;
|
|
168
|
-
return
|
|
168
|
+
return minifiedResult({
|
|
169
169
|
studentId: student_id,
|
|
170
170
|
needsDefaultsReview: needsReview,
|
|
171
171
|
verified: needsReview === !value,
|
package/dist/tools/plans.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { McpToolError,
|
|
2
|
+
import { McpToolError, minifiedResult } 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';
|
|
@@ -45,7 +45,7 @@ export function registerPlanTools(server, client) {
|
|
|
45
45
|
start_date: z.string().describe('YYYY-MM-DD'),
|
|
46
46
|
end_date: z.string().describe('YYYY-MM-DD'),
|
|
47
47
|
},
|
|
48
|
-
}, async ({ start_date, end_date }) =>
|
|
48
|
+
}, async ({ start_date, end_date }) => minifiedResult(await client.getParentPlans(start_date, end_date)));
|
|
49
49
|
server.registerTool('pup_get_plan', {
|
|
50
50
|
description: 'The dismissal plan for one student on one date — the option in force, any note, the early-dismissal time, and whether the date is locked because the cutoff has passed.',
|
|
51
51
|
annotations: { readOnlyHint: true },
|
|
@@ -53,7 +53,7 @@ export function registerPlanTools(server, client) {
|
|
|
53
53
|
student_id: z.number().int().describe('Student id, from pup_list_students'),
|
|
54
54
|
date: z.string().describe('YYYY-MM-DD'),
|
|
55
55
|
},
|
|
56
|
-
}, async ({ student_id, date }) =>
|
|
56
|
+
}, async ({ student_id, date }) => minifiedResult(await client.getPlanEdit(date, student_id)));
|
|
57
57
|
server.registerTool('pup_set_plan', {
|
|
58
58
|
description: "Change how a student is dismissed on one or more specific dates, or clear those dates back to the student's weekly default. This changes how a child actually leaves school, so it requires confirm: true; without it you get a dry-run of the exact payload. Read pup_list_transportations first — options differ in whether they require a note, a car number or an early-dismissal time.",
|
|
59
59
|
inputSchema: {
|
|
@@ -131,7 +131,7 @@ export function registerPlanTools(server, client) {
|
|
|
131
131
|
};
|
|
132
132
|
}));
|
|
133
133
|
const failed = verification.filter((v) => !v.verified);
|
|
134
|
-
return
|
|
134
|
+
return minifiedResult({
|
|
135
135
|
action,
|
|
136
136
|
applied: verification,
|
|
137
137
|
verified: failed.length === 0,
|
package/dist/tools/school.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import {
|
|
2
|
+
import { minifiedResult } from '@chrischall/mcp-utils';
|
|
3
3
|
/**
|
|
4
4
|
* Project a transportation to its identity plus the rules that decide what a
|
|
5
5
|
* plan using it must carry — an agent choosing an option needs those rules up
|
|
@@ -32,7 +32,7 @@ export function registerSchoolTools(server, client) {
|
|
|
32
32
|
}, async ({ school_id, include_inactive }) => {
|
|
33
33
|
const options = await client.getTransportations(school_id);
|
|
34
34
|
const visible = include_inactive === true ? options : options.filter((o) => o.IsActive !== false);
|
|
35
|
-
return
|
|
35
|
+
return minifiedResult(visible.map(summarizeTransportation));
|
|
36
36
|
});
|
|
37
37
|
server.registerTool('pup_get_school', {
|
|
38
38
|
description: 'A school profile together with its per-weekday notify times and plan cutoff times, and the settings that decide whether parents may set plans at all.',
|
|
@@ -46,7 +46,7 @@ export function registerSchoolTools(server, client) {
|
|
|
46
46
|
client.getSchoolNotifyTimes(school_id),
|
|
47
47
|
client.getSchoolSettings(school_id),
|
|
48
48
|
]);
|
|
49
|
-
return
|
|
49
|
+
return minifiedResult({ school, notifyTimes, settings });
|
|
50
50
|
});
|
|
51
51
|
server.registerTool('pup_list_non_school_days', {
|
|
52
52
|
description: 'Dates a plan cannot be set for at a school (holidays, closures, weekends), and optionally the dates in a range that already differ from the student defaults.',
|
|
@@ -62,10 +62,10 @@ export function registerSchoolTools(server, client) {
|
|
|
62
62
|
}, async ({ school_id, start_date, end_date }) => {
|
|
63
63
|
const invalidDates = await client.getInvalidPlanDates(school_id);
|
|
64
64
|
if (start_date === undefined || end_date === undefined) {
|
|
65
|
-
return
|
|
65
|
+
return minifiedResult({ invalidDates });
|
|
66
66
|
}
|
|
67
67
|
const changedDates = await client.getBoldedDates(start_date, end_date);
|
|
68
|
-
return
|
|
68
|
+
return minifiedResult({ invalidDates, changedDates });
|
|
69
69
|
});
|
|
70
70
|
server.registerTool('pup_list_car_numbers', {
|
|
71
71
|
description: 'The car numbers a school has issued to this account, for dismissal options where usesCarNumbers is true.',
|
|
@@ -73,5 +73,5 @@ export function registerSchoolTools(server, client) {
|
|
|
73
73
|
inputSchema: {
|
|
74
74
|
school_id: z.number().int().describe('School id, from pup_list_students'),
|
|
75
75
|
},
|
|
76
|
-
}, async ({ school_id }) =>
|
|
76
|
+
}, async ({ school_id }) => minifiedResult(await client.getCarNumbers(school_id)));
|
|
77
77
|
}
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
package/mint.yaml
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
version: 1
|
|
2
|
+
name: PickUp Patrol
|
|
3
|
+
slug: pickuppatrol
|
|
4
|
+
summary: >-
|
|
5
|
+
Read and change your children's school dismissal plans in PickUp Patrol —
|
|
6
|
+
defaults, day-by-day changes and school cutoff times
|
|
7
|
+
env:
|
|
8
|
+
- name: PICKUPPATROL_USERNAME
|
|
9
|
+
required: false
|
|
10
|
+
help: >-
|
|
11
|
+
The email address you sign in to app.pickuppatrol.net with.
|
|
12
|
+
- name: PICKUPPATROL_PASSWORD
|
|
13
|
+
secret: true
|
|
14
|
+
required: false
|
|
15
|
+
help: >-
|
|
16
|
+
Your PickUp Patrol password. Stored by the host, never logged by this
|
|
17
|
+
server.
|
|
18
|
+
egress:
|
|
19
|
+
allow:
|
|
20
|
+
# Only hosts the SERVER process actually fetches. Hosts that appear
|
|
21
|
+
# solely in a URL this server BUILDS and returns are excluded.
|
|
22
|
+
- app.pickuppatrol.net
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrischall/pickuppatrol-mcp",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.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)",
|
|
@@ -44,28 +44,29 @@
|
|
|
44
44
|
".claude-plugin",
|
|
45
45
|
"skills",
|
|
46
46
|
".mcp.json",
|
|
47
|
-
"server.json"
|
|
47
|
+
"server.json",
|
|
48
|
+
"mint.yaml"
|
|
48
49
|
],
|
|
49
50
|
"scripts": {
|
|
50
51
|
"build": "tsc && npm run bundle",
|
|
51
52
|
"bundle": "esbuild src/index.ts --bundle --platform=node --format=esm --external:dotenv --outfile=dist/bundle.js",
|
|
52
53
|
"dev": "node dist/index.js",
|
|
53
54
|
"typecheck": "tsc --noEmit",
|
|
54
|
-
"test": "vitest run",
|
|
55
|
-
"test:coverage": "vitest run --coverage",
|
|
55
|
+
"test": "npm run typecheck && vitest run",
|
|
56
|
+
"test:coverage": "npm run typecheck && vitest run --coverage",
|
|
56
57
|
"test:watch": "vitest"
|
|
57
58
|
},
|
|
58
59
|
"dependencies": {
|
|
59
|
-
"@chrischall/mcp-utils": "^0.
|
|
60
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
60
|
+
"@chrischall/mcp-utils": "^0.26.1",
|
|
61
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
61
62
|
"dotenv": "^17.4.0",
|
|
62
|
-
"zod": "^4.4
|
|
63
|
+
"zod": "^4.5.4"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
66
|
"@types/node": "^26.1.1",
|
|
66
|
-
"@vitest/coverage-v8": "^
|
|
67
|
+
"@vitest/coverage-v8": "^5.0.0",
|
|
67
68
|
"esbuild": "^0.28.0",
|
|
68
69
|
"typescript": "^7.0.2",
|
|
69
|
-
"vitest": "^
|
|
70
|
+
"vitest": "^5.0.0"
|
|
70
71
|
}
|
|
71
72
|
}
|
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
|
|
9
|
+
"version": "0.2.1",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "@chrischall/pickuppatrol-mcp",
|
|
14
|
-
"version": "0.1
|
|
14
|
+
"version": "0.2.1",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
}
|