# pickuppatrol-mcp [Health: Active]

**Category:** 💻 Developer Tools  
**Repository:** https://github.com/chrischall/pickuppatrol-mcp  
**GitHub Stars:** 0  
**Views:** 0  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/pickuppatrol-mcp

## Description
Read and change your children's school dismissal plans in PickUp Patrol

## Tools
Capabilities this server exposes over MCP:

- **pup_get_session** — The signed-in account and the students linked to it
- **pup_list_students** — Every student with their weekly defaults and review flag
- **pup_get_student** — One student in full
- **pup_get_default_plans** — A student's weekly default plan, day by day
- **pup_list_plans** — Day-by-day plans across a date range
- **pup_get_plan** — One student, one date — including whether it is locked
- **pup_list_transportations** — A school's dismissal options and the rules each imposes
- **pup_get_school** — School profile, notify times, cutoff times, settings
- **pup_list_non_school_days** — Dates no plan can be set for, and dates already changed
- **pup_list_car_numbers** — Car numbers the school issued to this account
- **pup_healthcheck** — Credentials sign in and the API answers
- **pup_set_plan** — Dismissal for one or more specific dates, or clears them back to the default
- **pup_set_default_plans** — The weekly default plan, or clears every default
- **pup_mark_defaults_reviewed** — The school's "defaults need review" prompt

## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `npx` (confidence: high):

```json
"mcpServers": {
  "pickuppatrol-mcp": {
    "command": "npx",
    "args": ["-y","@chrischall/pickuppatrol-mcp"]
  }
}
```

## Documentation & README

# pickuppatrol-mcp

An MCP server for [PickUp Patrol](https://www.pickuppatrol.net/) — the school
dismissal app. Read and change how your children leave school: their weekly
default plan, one-off changes for specific dates, and the school's dismissal
options and cutoff times.

> Developed and maintained by AI (Claude Code). Use at your own discretion.

## What it talks to

`app.pickuppatrol.net` runs a [ServiceStack](https://servicestack.net/) JSON API
behind an Ionic/Vue SPA. There is no published API, but the service is reachable
server-side with an ordinary HTTPS request — no browser extension, no bot wall,
no captcha. The server signs in with your own email and password and holds the
resulting session in memory.

Every request shape is captured in [`docs/PICKUPPATROL-API.md`](https://github.com/chrischall/pickuppatrol-mcp/blob/HEAD/docs/PICKUPPATROL-API.md),
read off the shipped client rather than guessed, and exercised against a real
account — reads, a write, and its restore.

## Install

```jsonc
// .mcp.json
{
  "mcpServers": {
    "pickuppatrol": {
      "command": "npx",
      "args": ["-y", "@chrischall/pickuppatrol-mcp"],
      "env": {
        "PICKUPPATROL_USERNAME": "you@example.com",
        "PICKUPPATROL_PASSWORD": "…"
      }
    }
  }
}
```

For local development, copy `.env.example` to `.env` and fill it in.

The server starts without credentials — it answers the host's install-time probe
and only reports the configuration error on the first tool call.

## Tools

**Reads**

| Tool | What it gives you |
|---|---|
| `pup_get_session` | The signed-in account and the students linked to it |
| `pup_list_students` | Every student with their weekly defaults and review flag |
| `pup_get_student` | One student in full |
| `pup_get_default_plans` | A student's weekly default plan, day by day |
| `pup_list_plans` | Day-by-day plans across a date range |
| `pup_get_plan` | One student, one date — including whether it is locked |
| `pup_list_transportations` | A school's dismissal options and the rules each imposes |
| `pup_get_school` | School profile, notify times, cutoff times, settings |
| `pup_list_non_school_days` | Dates no plan can be set for, and dates already changed |
| `pup_list_car_numbers` | Car numbers the school issued to this account |
| `pup_healthcheck` | Credentials sign in and the API answers |

**Writes** — every one requires `confirm: true`. Without it the tool makes no
change and returns a dry-run of the exact payload it would send.

| Tool | What it changes |
|---|---|
| `pup_set_plan` | Dismissal for one or more specific dates, or clears them back to the default |
| `pup_set_default_plans` | The weekly default plan, or clears every default |
| `pup_mark_defaults_reviewed` | The school's "defaults need review" prompt |

### Two things the tools do that the API does not

**Rules are enforced before anything is sent.** Each dismissal option carries its
own requirements — a note, a car number, an early-dismissal time, or a
restriction to particular students. `pup_set_plan` checks them against the
school's own list and refuses with the school's wording, so a rejected write is
a validation message rather than an opaque 400.

**Writes are verified by re-reading.** A 2xx from PickUp Patrol is not proof: a
change made after the school's cutoff is accepted and silently ignored. Every
write re-reads the affected dates and compares the transportation id **and the
note** — never `ModifiedDate`, which advances on its own and would make every
write look successful. The note is part of the proof because every dismissal
option seen so far requires one, which makes a note-only edit ordinary: an
id-only comparison would report success from a field that never had to move.
The result says `verified: true/false`, and names the dates that did not move.

## Without the MCP server

`skills/pickuppatrol-api/` is a shell-out skill covering the same API with
`curl` and `jq`, for scripts or a machine where the server is not installed.

## Development

```bash
npm install
npm run build
npm test              # fast
npm run test:coverage # coverage-enforced at 100%
```

Tests never touch the network: the transport is injected, and the MCP tools run
through a real in-memory client/server pair.

## Two things about the API worth knowing

**`GetPlanEdit` returns a date's override, not the effective plan.** A date with
no specific plan reads back `TransportationId: null` even when the student has a
weekly default for that weekday. `pup_get_plan` passes that through as-is;
`pup_list_students` is where the weekly defaults live.

**Sign-in is a session cookie, not a JWT.** `Authenticate` returns
`BearerToken: null` on this deployment and sets `ss-id`/`ss-pid`/`ss-opt`. The
client keeps whichever the server returns and sends both, so a future switch to
JWTs needs no change here.

## Safety notes

- A rejected sign-in is **never retried**. PickUp Patrol counts failed attempts
  against the account and a lockout clears only through their support desk, so
  the error is cached and every later call fails instantly with the same message.
- The weekly-default write is a read-modify-write of the whole student record,
  because the API has no default-plans endpoint. The server always reads the
  student immediately before writing, and changes only `DefaultPlans`.
- Credentials live in `.env` (gitignored) or the MCP host's config, and are
  never written to a result or a log.

## License

MIT

