ps-mcp
ps-mcp
A Model Context Protocol (MCP) server for PowerSchool plugin developers. It gives an AI assistant (Claude, Cursor, etc.) structured, read/write access to your plugin workspace — so it can scaffold artifacts, validate XML, sync access request fields, package ZIPs, and answer questions about the PS data model, all with knowledge of your actual files.
What it does
ps-mcp exposes three categories of capability to an MCP client:
Tools (actions the AI can take)
Tool | What it does |
| Read current plugin.xml and workspace layout |
| Generate a new plugin.xml with all optional blocks |
| Validate plugin.xml against PS requirements |
| Increment major/minor/patch or set an explicit version |
| Pre-flight validate and build a distributable ZIP |
| Refactor plugin name and all query/permission namespaces (ports |
| Generate a named query XML file with correct column refs |
| List all named queries in the workspace |
| Check for duplicate names, bad column refs, arg/param mismatches |
| Generate a |
| List all DB extensions in the workspace |
| Browse U_* custom tables in the PS data dictionary |
| Find existing extensions and tables relevant to a description |
| Add a field to an existing extension XML |
| Scan all named queries and rebuild the |
| Add a single TABLE.FIELD entry to |
| Generate a |
| Save a lesson learned, pattern, or gotcha about PS plugin development |
| Search saved lessons |
| Read a saved lesson in full |
| Remove a saved lesson |
Resources (read-only data the AI can load)
URI | Contents |
| All PS HTML tag categories |
| Tag reference for a category (e.g. |
| All table names in the PS data dictionary |
| All fields for a table with types and descriptions |
| Keyword search across tables and fields |
| Parsed plugin.xml + workspace layout |
| All named query definitions in the workspace |
| All DB extension definitions in the workspace |
| Index of bundled PS documentation |
| A specific documentation file |
| Index of saved lessons |
| A specific saved lesson |
Prompts (guided templates)
Prompt | What it guides |
| Design a named query end-to-end; produces a |
| Choose extend-existing vs. create-new; produces the right scaffold call |
| Look up and explain a PS HTML tag pattern |
| Design a permission mapping file; produces a |
Bundled reference data
The server loads these assets at startup from .docs/:
Data dictionary (
data_dictionary.csv) — Complete PS database schema: every core table and field with types and descriptions. Used for column validation in named queries, access request sync, and schema analysis.Tag reference (
.docs/tags/*.json) — PS HTML tag documentation covering ~37 categories (tlist_sql, powerquery, frn, if/logic, dates, grades, gpa, contacts, etc.).Documentation (
.docs/*.md) — 62+ markdown files covering PS customization, the Data Access API, OAuth, SSO, DB extensions, named queries, permissions, and more.
Installation
Prerequisites
Node.js 20+
An MCP-compatible client (Claude Code, Claude Desktop, VS Code with MCP extension, Cursor, etc.)
Build
cd /path/to/ps-mcp
npm install
npm run buildThis produces dist/index.js — a single self-contained ESM bundle with a #!/usr/bin/env node shebang.
Configuration
Option A — VS Code (recommended)
Add to your plugin project's .vscode/mcp.json:
{
"servers": {
"ps-mcp": {
"type": "stdio",
"command": "node",
"args": ["/path/to/ps-mcp/dist/index.js"],
"env": {
"PS_PLUGIN_ROOT": "${workspaceFolder}"
}
}
}
}Set PS_PLUGIN_ROOT to ${workspaceFolder} — the server resolves both flat and src-based layouts automatically. See Workspace detection for details.
Option B — Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or the equivalent on your platform:
{
"mcpServers": {
"ps-mcp": {
"command": "node",
"args": ["/path/to/ps-mcp/dist/index.js"],
"env": {
"PS_PLUGIN_ROOT": "/path/to/your/plugin"
}
}
}
}Set PS_PLUGIN_ROOT to the project root directory (the VS Code workspace folder equivalent). The server will find plugin.xml whether it is at the root or inside a src/ subdirectory.
Option C — Claude Code CLI
Add to ~/.claude/settings.json under mcpServers, or use the VS Code .vscode/mcp.json approach above.
Workspace detection
The server locates your plugin project automatically on every tool call using this priority order:
1. PS_PLUGIN_ROOT env var (highest priority)
When PS_PLUGIN_ROOT is set, the server tries two candidates derived from it:
{PS_PLUGIN_ROOT}/plugin.xml— treats the env var as the artifacts root directly (flat layout, or already-resolved path){PS_PLUGIN_ROOT}/src/plugin.xml— treats the env var as the workspace root with a src-based layout
This means PS_PLUGIN_ROOT can point to the VS Code ${workspaceFolder} for any layout — you never need to change the mcp.json value when switching between flat and src-based projects.
If PS_PLUGIN_ROOT is set but neither candidate finds plugin.xml, a warning is written to stderr and detection falls through to the walk-up method.
2. Walk up from the current working directory
Tries {dir}/src/plugin.xml then {dir}/plugin.xml at each level, walking up to 10 parent directories. Used when PS_PLUGIN_ROOT is not set or yields no match.
Common configurations
Layout |
| How it resolves |
Src-based ( |
| Tries |
Flat ( |
| Tries |
Explicit artifacts root |
| Tries |
Not set | (none) | Walk-up from cwd finds |
Verifying detection
Call get_plugin_info — the response includes discoveryMethod (e.g. PS_PLUGIN_ROOT="/path" (src subfolder) or cwd walk-up (/path/to/dir)) so you can confirm the right workspace was found.
Artifact directories
Once plugin.xml is found, the server also discovers any artifact subdirectories present alongside it:
Directory | Purpose |
| Named query XML files ( |
| Permission mapping XML files ( |
| DB extension schema XML files |
| PS HTML page fragments |
| Page catalog entries |
If no workspace is detected, tools that require one will return a clear error. Read-only tools (tag reference, data dictionary, docs, lessons) work without a workspace.
Plugin project layout
ps-mcp supports both common layouts:
src-based (typical for projects with a build step):
my-plugin/
└── src/
├── plugin.xml
├── queries_root/
│ └── com.example.data.students.named_queries.xml
├── user_schema_root/
│ └── U_Laptops.xml
├── permissions_root/
│ └── com.example.data.students.permission_mappings.xml
└── web_root/flat (artifacts directly at root):
my-plugin/
├── plugin.xml
├── queries_root/
├── user_schema_root/
└── permissions_root/Lessons learned store
The record_lesson / list_lessons / get_lesson tools provide a persistent knowledge base for capturing non-obvious PS behaviors and hard-won workarounds. Lessons are stored as JSON files in .docs/lessons/ and survive across sessions.
Topics: named-queries · db-extensions · permissions · ps-html · plugin-xml · access-request · packaging · general
Example — recording a gotcha mid-session:
"Record a lesson: when extending the Users table, tlist_child links must use
204~([teachers]USERS_DCID)instead of~(frn)because the Unified Teacher Record splits TEACHERS into USERS (204) and SCHOOLSTAFF (203)."
The lesson is saved and automatically available in all future sessions via ps://lessons/list.
Development
npm run dev # Run via tsx (no build step, for development)
npm run build # Bundle to dist/index.js
npm run test # Run unit tests (vitest)
npm run test:watch # Watch modeArchitecture
src/
├── index.ts # Entry point — calls startServer()
├── server.ts # Asset loading, workspace detection, registration
├── lib/
│ ├── workspace.ts # Workspace detection + artifact dir resolution
│ ├── plugin-xml.ts # plugin.xml parse/build (fast-xml-parser + xmlbuilder2)
│ ├── query-xml.ts # named_queries XML parse/build
│ ├── schema-xml.ts # user_schema_root XML parse/build
│ ├── permission-xml.ts # permission_mappings XML build
│ ├── access-sync.ts # Port of sync_plugin_access_request.rb
│ ├── packager.ts # Pre-flight validation + archiver ZIP builder
│ ├── data-dictionary.ts # CSV parser for data_dictionary.csv
│ ├── tag-index.ts # Tag JSON file loader/indexer
│ └── lessons.ts # Lessons JSON store (upsert/search/delete)
├── tools/ # One file per tool group
├── resources/ # One file per resource group
└── prompts/ # Prompt templatesThe server runs over stdio transport. Each tool call re-detects the workspace so the server stays correct if files change between calls. Data assets (dictionary, tags) are loaded once at startup.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/zuvy/ps-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server