{
  "markdown": "# ParentSquare MCP Server\n\n[![MCP Registry](https://img.shields.io/badge/MCP-Registry-blue)](https://registry.modelcontextprotocol.io) [![PyPI](https://img.shields.io/pypi/v/parentsquare-mcp)](https://pypi.org/project/parentsquare-mcp/)\n\nAn [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server that gives Claude access to [ParentSquare](https://www.parentsquare.com), a school-parent communication platform. Since ParentSquare has no public API, this server scrapes the web interface using saved session cookies.\n\nCovers both the **parent/guardian experience** (feeds, posts, calendars, messages, directories, sign-ups, forms, payments) and **school admin roster management** — reading student and guardian rosters, and creating/editing students and guardians plus sending registration invitations. Admin write tools are **off by default**, gated behind `PS_ENABLE_WRITES`, and every write is recorded to a local audit log.\n\nAvailable on the [MCP Registry](https://registry.modelcontextprotocol.io) as `io.github.thehesiod/psquare` and on [PyPI](https://pypi.org/project/parentsquare-mcp/) as `parentsquare-mcp`.\n\n## Disclaimer\n\n> **This project is not affiliated with, endorsed by, or sponsored by ParentSquare, Inc.** \"ParentSquare\" and all related names, logos, and trademarks are the property of ParentSquare, Inc.\n>\n> This server communicates with ParentSquare's **undocumented internal APIs** (scraping the web UI and calling its non-public `/api/v2/` JSON endpoints) — these are not published, not guaranteed to be stable, and may change or be blocked at any time without notice. Use of those interfaces may violate ParentSquare's Terms of Service; you are responsible for reviewing the ToS and deciding whether your use is acceptable.\n>\n> **Use at your own risk.** The authors and contributors accept no responsibility for any consequences of using this software, including but not limited to: account suspension or termination, data loss or corruption, missed or incorrect notifications, MFA lockouts, leaked session cookies, IP blocks, or any other direct or indirect damages. No warranty is provided — see [LICENSE](LICENSE) for the full MIT no-warranty clause.\n>\n> If ParentSquare publishes an official API, this project should be considered deprecated in favor of that.\n\n## Features\n\n### Feed & Posts\n- **`get_feeds`** — Browse paginated school feed with titles, authors, summaries, and attachment names\n- **`get_post`** — Full post details with body text, comments, poll results, signup items, and **inline image/PDF content** (Claude can \"see\" attached calendars, flyers, etc.)\n- **`get_group_feed`** — Posts from a specific group\n\n### Calendar\n- **`get_calendar_events`** — Events from ICS calendar as structured JSON (title, start/end, location, description)\n- Falls back to guiding Claude to search feed posts for image/PDF calendars when ICS is empty\n\n### Communication\n- **`list_conversations`** / **`get_conversation`** — Read message threads\n- **`get_directory`** — Staff directory as structured JSON (name, role, phone, user_id)\n- **`get_staff_member`** — Full staff details with email, office hours, and **inline profile photo**\n\n### Media & Files\n- **`list_photos`** — Photo gallery with URLs\n- **`list_files`** — Document files\n- **`download_file`** — Download any attachment to local disk\n\n### Participate\n- **`list_signups`** — Sign-up and RSVP posts with progress tracking (e.g. \"53/103 Items\")\n- **`list_notices`** — Alerts and secure documents\n- **`list_polls`** — Polls with vote counts and winning options\n- **`list_forms`** — Permission slips and signable forms\n- **`list_payments`** — Payment items with prices and summary stats\n- **`list_volunteer_hours`** — Logged volunteer hours with totals\n\n### Groups & Discovery\n- **`list_schools`** — Schools and students as structured JSON\n- **`list_school_features`** — Available sections per school (parsed from sidebar)\n- **`list_groups`** — Groups with member counts, descriptions, and membership status\n- **`list_links`** — Quick-access links (Google Drive, external sites)\n\n### Student\n- **`get_student_dashboard`** — School, grade, classes, and teachers as structured JSON\n\n### Admin\nRead tools are always available; the tools marked *(write)* below are **disabled by default** and only run when `PS_ENABLE_WRITES` is set (see [Enabling admin write tools](#enabling-admin-write-tools)). Every write *attempt*, including one blocked by the gate, is recorded to a local audit log. **No tool deletes a record** — students, guardians, classes, and staff can be created and edited but never deleted, and the tools that remove something only unlink a relationship (a staff assignment or a class enrollment), leaving the underlying people and classes intact. Deletion is deliberately left to the ParentSquare website.\n\n#### Roster: students & guardians\n- **`list_students`** — School roster (id, name, grade, SIS id, guardians) as structured JSON, with optional `grade` / `name_contains` filters\n- **`list_parents`** — Guardian roster (user_id, name, email, phone, linked students) as structured JSON, with optional `name_contains` / `student_name_contains` filters; provides the `user_id` needed by `edit_parent` / `link_guardian_to_student`\n- **`list_grades`** — A school's grades and their `grade_id` values (needed for add/edit)\n- **`get_student`** — Admin detail for one student (name, grade, SIS id, linked guardians, classes)\n- **`add_student`** *(write)* — Create a student in a grade\n- **`edit_student`** *(write)* — Update a student's name, SIS id, or grade (unchanged fields preserved)\n- **`add_parent`** *(write)* — Create a guardian linked to a student\n- **`edit_parent`** *(write)* — Update a guardian's name, email, or phone (existing links preserved)\n- **`link_guardian_to_student`** *(write)* — Link an existing guardian to an additional student\n- **`invite_parent`** *(write)* — Send (or resend) a ParentSquare registration invitation to one guardian\n- **`bulk_invite_parents`** *(write)* — Invite many guardians at once; already-registered guardians are skipped automatically\n\n#### Classes, staff & enrollment\n- **`list_classes`** / **`get_class`** — A school's classes, and one class with its full staff list (teachers, assistants, room parents)\n- **`add_class`** *(write)* — Create a class; new classes start **hidden** until `set_class_visibility`\n- **`edit_class`** *(write)* — Rename a class or change its grades\n- **`set_class_visibility`** *(write)* — Show or hide classes (date-driven, defaults to today)\n- **`list_staff`** — Staff and admin roster (user_id, name, email, phone, role/title) as structured JSON, with an optional `name_contains` filter; provides the `user_id` needed by `edit_staff` / `add_class_staff`\n- **`add_staff`** *(write)* — Add a teacher, staff member, or admin, optionally assigning them to classes\n- **`edit_staff`** *(write)* — Update a staff member's name, email, phone, title, or staff ID (class assignments and STAFF/ADMIN access preserved; guardians are rejected — use `edit_parent`)\n- **`add_class_staff`** / **`remove_class_staff`** *(write)* — Assign or unassign teachers, assistants, and room parents for a class. Section-membership writes are serialized inside one server process; never issue them in parallel, and verify each result with a fresh read.\n- **`list_class_students`** — The students enrolled in a class\n- **`add_class_students`** / **`remove_class_students`** / **`move_student_to_class`** *(write)* — Manage which students are enrolled in which classes. These share the same global serialization lock as class-staff writes because student-section updates can replace a student's full enrollment list.\n\n### Authentication\n- **`submit_mfa_code`** — Complete MFA verification with a 6-digit code\n- Supports MCP elicitation for inline MFA prompts (set `PS_NO_ELICIT` to disable for unattended callers)\n- Session cookies persisted to `~/.parentsquare_cookies.json`\n- Credentials loaded from environment variables, 1Password, or LastPass CLI on session expiry\n\n## Setup\n\n### Enabling admin write tools\n\nThe admin write tools — every tool marked *(write)* under [Admin](#admin), covering\nthe student/guardian roster, classes, staff, and class enrollment — modify live\nschool data, so they are **off by default**. To enable them, set `PS_ENABLE_WRITES=1`\n(or `true`/`yes`/`on`) in the server's environment and restart. Every write attempt\n(including blocked ones) is appended as JSONL to `PS_AUDIT_LOG` (default\n`~/.parentsquare_audit.log`). The admin read tools work regardless.\n\nParentSquare's form endpoints answer every accepted POST with the same generic\n`200` \"reload\" response, which some silent failures also return. To avoid\nfalse-positive successes, the create/link tools (`add_student`, `add_parent`,\n`link_guardian_to_student`) **read back authoritative state after the write** and\nonly report `✅ Success (verified)` once the new record is actually found. If the\nPOST is accepted but the read-back can't find the change, they return a `⚠️`\nwarning that it likely did not persist; if the read-back itself can't run, they\nreport the write as submitted-but-unverified.\n\nThe read-back also overrules a `5xx`. ParentSquare renders its error page *after*\nthe transaction commits, so a server error can hide a write that actually landed\n— `add_student` did exactly that on every create until a missing\n`student[section_ids][]` form param was tracked down. Reporting those as failures\ninvited retries, and each retry duplicated a real student with no API route to\ndelete one. So when a write returns a `5xx` but the record is found on read-back,\nthe tool reports `✅ Success (verified)` with a note not to retry. An explicit\nrejection (a `4xx`, or a `200` carrying an `alert-danger` flash) is still\nreported as a failure regardless of read-back.\n\n### Prerequisites\n\nCredentials can be provided in either of two ways (checked in this order):\n\n1. **Environment variables** — set `PS_USERNAME` and `PS_PASSWORD`\n2. **A credential manager** selected by `PS_CREDENTIAL_PROVIDER` (default `1password`):\n   - **[1Password CLI](https://developer.1password.com/docs/cli/)** (`op`) — with a \"Parentsquare\" item containing `username` and `password` fields\n   - **[LastPass CLI](https://github.com/LastPass/lastpass-cli)** (`lpass`) — set `PS_CREDENTIAL_PROVIDER=lastpass`. Run `lpass login <your-lastpass-email>` in a terminal first (may prompt for MFA). The item read defaults to `parentsquare.com` and can be overridden with `PS_LASTPASS_ITEM` (an exact entry name or entry ID).\n\n### Install in Claude Code\n\n```bash\nclaude mcp add --transport stdio parentsquare -- uvx --from \"parentsquare-mcp @ git+https://github.com/thehesiod/psquare-mcp\" parentsquare-mcp\n```\n\nTo enable PDF text extraction for post attachments (optional, AGPL-3.0 licensed):\n\n```bash\nclaude mcp add --transport stdio parentsquare -- uvx --from \"parentsquare-mcp[pdf] @ git+https://github.com/thehesiod/psquare-mcp\" parentsquare-mcp\n```\n\n### That's It\n\nNo further configuration needed. The server **auto-discovers** your schools, students, and user ID from ParentSquare on first use. Authentication is handled automatically — when the session expires, the server loads your credentials from environment variables (or 1Password CLI) and re-authenticates (including MFA if needed).\n\nTo use environment variables with Claude Code, add an `env` block to your MCP config:\n\n```json\n{\n  \"mcpServers\": {\n    \"parentsquare\": {\n      \"command\": \"uvx\",\n      \"args\": [\"parentsquare-mcp\"],\n      \"env\": {\n        \"PS_USERNAME\": \"your@email.com\",\n        \"PS_PASSWORD\": \"your-password\"\n      }\n    }\n  }\n}\n```\n\n> **Security note:** environment variables place your password in plaintext inside your MCP config file. If you chose a password manager specifically to avoid that, prefer the 1Password or LastPass CLI path.\n\nTo use the LastPass CLI instead of 1Password, log in once (`lpass login <your-lastpass-email>`) and set the provider in your MCP config:\n\n```json\n{\n  \"mcpServers\": {\n    \"parentsquare\": {\n      \"command\": \"uvx\",\n      \"args\": [\"parentsquare-mcp\"],\n      \"env\": {\n        \"PS_CREDENTIAL_PROVIDER\": \"lastpass\",\n        \"PS_LASTPASS_ITEM\": \"parentsquare.com\"\n      }\n    }\n  }\n}\n```\n\n`PS_LASTPASS_ITEM` is optional (defaults to `parentsquare.com`).\n\n### Unattended use (`PS_NO_ELICIT`)\n\nWhen MFA is required, the server prompts for the code inline via MCP elicitation.\nThat prompt waits for a human, so an unattended caller — a claude.ai routine, a\nscheduled job — has nobody to answer it and the tool call simply blocks until the\nelicitation times out.\n\nSet `PS_NO_ELICIT=1` to skip the prompt. The tool returns the \"MFA verification\nrequired\" message immediately, and the caller can retrieve the code out of band\n(via a Gmail or Microsoft 365 MCP, for example) and pass it to `submit_mfa_code`:\n\n```json\n{\n  \"mcpServers\": {\n    \"parentsquare\": {\n      \"command\": \"uvx\",\n      \"args\": [\"parentsquare-mcp\"],\n      \"env\": {\n        \"PS_NO_ELICIT\": \"1\"\n      }\n    }\n  }\n}\n```\n\nThe check is presence-based: **any** non-empty value disables elicitation, so\n`PS_NO_ELICIT=0` and `PS_NO_ELICIT=false` also disable it. To re-enable inline\nprompting, unset the variable entirely.\n\n## How It Works\n\nThe server uses `requests` + `BeautifulSoup` to scrape ParentSquare's server-rendered HTML pages. Each tool follows the pattern:\n\n1. **Fetch** the HTML page via `PSClient.get_page()` or JSON via `PSClient.get_json()` (auto-relogins on session expiry)\n2. **Parse** with a dedicated parser in `parsers/` that extracts structured data into dataclasses\n3. **Return** results as either structured JSON dicts (for data-lookup tools) or markdown text (for content-rich tools)\n\nData-lookup tools (`list_schools`, `get_directory`, `get_calendar_events`, `get_student_dashboard`, `get_staff_member`) return structured JSON for easy programmatic access. Content tools (`get_post`, `get_feeds`, `get_conversation`) return markdown.\n\nOn first use, the server auto-discovers your schools, students, and user ID from ParentSquare (no config file needed).\n\nFor `get_post`, image attachments are downloaded and returned as MCP `Image` objects (so Claude can see them), and PDF attachments have their text extracted via pymupdf. `get_staff_member` also returns inline profile photos.\n\nGroups use a GraphQL endpoint (`/graphql`) instead of HTML scraping. The directory and staff details use the internal `/api/v2/` JSON:API.\n\n## Dependencies\n\n| Package | Purpose | License |\n|---------|---------|---------|\n| `mcp` | Model Context Protocol SDK | MIT |\n| `requests` | HTTP client | Apache 2.0 |\n| `beautifulsoup4` | HTML parsing | MIT |\n| `icalendar` | ICS calendar parsing | BSD |\n| `pymupdf` | PDF text extraction (optional) | AGPL-3.0 |\n\n## License\n\nMIT — see [LICENSE](LICENSE). Note: the optional `pymupdf` dependency is AGPL-3.0 licensed.\n\nmcp-name: io.github.thehesiod/psquare\n",
  "bytes": 14888,
  "sha": "5e273fcdc80eff772edf00df6582f1fd6f821bed9093350f6a4db9d0d7541a6b",
  "repo_slug": "thehesiod/psquare-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_thehesiod_psquare_6f84662d/readme"
}