MCP Server
The ScannerSky MCP Server exposes attendance and roster data to MCP-compatible AI assistants (Claude Desktop, VS Code Copilot, Onyx, etc.) via the Model Context Protocol.
Source: mcp_server/ in the project root
Transports
| Mode | Entry point | Suitable for |
|---|---|---|
| stdio | python -m mcp_server | Claude Desktop, VS Code Copilot |
| HTTP (streamable) | python -m mcp_server.http | Onyx, any HTTP MCP client |
Quick Start
1. Install dependencies
pip install -r requirements.txt
2. Generate an API key
python -m mcp_server.keygen generate
The command prints a raw key (store securely) and a key hash (goes in the key store).
3. Create the key store
cp mcp_keys.example.json mcp_keys.json
Edit mcp_keys.json and replace "sha256:REPLACE_WITH_HASH" with the hash from step 2. Set "active": true and choose the appropriate scopes.
mcp_keys.json is git-ignored. Never commit real key hashes.
4. Verify the key
MCP_API_KEY=<raw_key> python -m mcp_server.keygen verify
5. Run (stdio)
MCP_API_KEY=<raw_key> python -m mcp_server
Environment Variables
| Variable | Default | Description |
|---|---|---|
MCP_API_KEY | (required for stdio) | Raw API key for this session |
MCP_KEYS_FILE | mcp_keys.json (project root) | Path to the key store JSON |
DJANGO_SETTINGS_MODULE | scannersky.settings | Django settings module |
MCP_HTTP_HOST | 127.0.0.1 | Bind host for HTTP mode |
MCP_HTTP_PORT | 8001 | Bind port for HTTP mode |
Authentication and Scopes
Keys are stored as SHA-256 hashes in mcp_keys.json — never the raw secret. At startup the server hashes MCP_API_KEY, matches it against the store, and caches the resolved scope set for the process lifetime.
Every tool call checks the required scope. If the key lacks it, a PermissionError is returned as a tool error.
Scope Reference
| Scope | Grants access to |
|---|---|
read:persons | Person listing, lookup, attendance timeline |
read:departments | Department listing and detail |
read:semesters | Semester listing, detail, active semester |
read:classes | Class listing, detail, student roster |
read:events | Event listing, detail, participant roster |
read:devices | Device status, area listing |
read:attendance | Attendance snapshots, calendar, dashboard stats, recent scans, semester reports |
write:class_roster | Add / remove students from class rosters |
write:event_roster | Add / remove participants from event rosters |
Key Store Format (mcp_keys.json)
[
{
"name": "read-only-client",
"key_hash": "sha256:<64-char hex digest>",
"scopes": ["read:persons", "read:departments", "read:semesters",
"read:classes", "read:events", "read:devices", "read:attendance"],
"active": true
}
]
Client Configuration
Claude Desktop
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"scannersky": {
"command": "python",
"args": ["-m", "mcp_server"],
"cwd": "/absolute/path/to/scannersky-django",
"env": {
"MCP_API_KEY": "<raw_key>",
"DJANGO_SETTINGS_MODULE": "scannersky.settings"
}
}
}
}
Restart Claude Desktop — the tools appear automatically in the tool list.
VS Code (GitHub Copilot)
Add to .vscode/mcp.json in the workspace root:
{
"servers": {
"scannersky": {
"type": "stdio",
"command": "python",
"args": ["-m", "mcp_server"],
"cwd": "${workspaceFolder}",
"env": {
"MCP_API_KEY": "${env:MCP_API_KEY}"
}
}
}
}
Set MCP_API_KEY in your shell environment before launching VS Code.
Onyx (HTTP transport)
Onyx requires HTTP transport — stdio is not supported.
1. Start the HTTP server:
# PowerShell
$env:DJANGO_SETTINGS_MODULE = "scannersky.settings"
python -m mcp_server.http --host 0.0.0.0 --port 8001
The server is available at http://<your-host>:8001/mcp.
2. Add the server in Onyx:
- Open Admin Panel → Actions → MCP Actions.
- Click Add MCP Server and set:
- Server Name:
ScannerSky - MCP Server URL:
http://<your-host>:8001/mcp
- Server Name:
- Click Add Server.
3. Configure authentication:
Select API Key → Shared Key and paste the raw API key. Onyx sends it as Authorization: Bearer <key>.
Click Connect — Onyx validates the connection and lists available tools.
4. Assign to an agent:
Go to Agents, edit or create an agent, and enable the ScannerSky tools to use.
Available Tools
Persons
| Tool | Scope | Description |
|---|---|---|
list_persons | read:persons | Paginated list with optional filters (search, person_type, department_id) |
get_person | read:persons | Single person lookup by numeric id, school_id, or card_number |
get_person_attendance_timeline | read:persons | Daily scan counts for a person over the last N days (1–365) |
Departments
| Tool | Scope | Description |
|---|---|---|
list_departments | read:departments | All departments with headcounts; optional name filter |
get_department | read:departments | Single department by id including programs and headcounts |
Semesters
| Tool | Scope | Description |
|---|---|---|
list_semesters | read:semesters | Paginated semester list ordered by most recent start date |
get_semester | read:semesters | Single semester by id |
get_active_semester | read:semesters | Semester whose date range contains today |
Classes
| Tool | Scope | Description |
|---|---|---|
list_classes | read:classes | Paginated list; filter by semester, department, or title |
get_class | read:classes | Full class detail including student count and co-instructors |
get_class_students | read:classes | Enrolled student list; paginated with name/school_id filter |
get_class_attendance_snapshot | read:attendance | Present/absent breakdown over a date range (max 90 days) |
get_class_attendance_calendar | read:attendance | Monthly calendar grid with per-day present/total/pct cells |
Events
| Tool | Scope | Description |
|---|---|---|
list_events | read:events | Paginated list; filter by semester, department, title, or upcoming-only |
get_event | read:events | Full event detail including participant count and facilitators |
get_event_participants | read:events | Registered participant list; paginated |
get_event_attendance_snapshot | read:attendance | Present/absent breakdown; optional non-participant scan visibility |
Devices
| Tool | Scope | Description |
|---|---|---|
list_devices | read:devices | All devices with live status derived from latest heartbeat |
get_device_status | read:devices | Status for specific device IDs |
list_areas | read:devices | All physical areas with device count |
Device status values: online (≤90 s), stale (≤180 s), offline (>180 s), unknown (no logs).
Attendance / Dashboard
| Tool | Scope | Description |
|---|---|---|
get_dashboard_stats | read:attendance | Top-level KPIs: today's scans, 7-day window, active devices, totals |
get_recent_scans | read:attendance | Most recent scan records; look-back 1–168 h, paginated |
Attendance Reports
| Tool | Scope | Description |
|---|---|---|
get_class_semester_attendance_report | read:attendance | Semester-scale class attendance report with summary metrics and student-level supporting rows |
get_person_semester_attendance_report | read:attendance | Semester-scale person attendance report with expected/present/absent breakdown and class/date groupings |
get_event_attendance_report | read:attendance | Single-event or multi-event attendance reporting with summary and optional attendee-level rows |
Class Roster Writes
| Tool | Scope | Description |
|---|---|---|
add_student_to_class | write:class_roster | Enroll a person in a class (idempotency error if already enrolled) |
remove_student_from_class | write:class_roster | Remove a person from a class roster |
Event Roster Writes
| Tool | Scope | Description |
|---|---|---|
add_event_participant | write:event_roster | Register a person as an event participant |
remove_event_participant | write:event_roster | Remove a person from an event participant list |
Key Management CLI
# Generate a new key and print hash for mcp_keys.json
python -m mcp_server.keygen generate
# Verify MCP_API_KEY against the key store
MCP_API_KEY=<raw_key> python -m mcp_server.keygen verify
# Print the SHA-256 hash of an arbitrary string
python -m mcp_server.keygen hash <raw_key>
File Layout
mcp_server/
├── __init__.py
├── __main__.py # python -m mcp_server (stdio entry point)
├── server.py # FastMCP app — all tool definitions
├── config.py # Django ORM bootstrap
├── auth.py # API key validation and scope enforcement
├── permissions.py # Scope name constants
├── keygen.py # CLI: generate / verify / hash keys
├── asgi.py # ASGI app for HTTP mode (Bearer auth middleware)
├── http.py # python -m mcp_server.http (uvicorn entry point)
└── services/
├── shared.py # Shared query helpers and constants
├── persons.py # Person and department queries
├── semesters.py # Semester queries
├── classes.py # Class queries and roster writes
├── events.py # Event queries and roster writes
└── devices.py # Device, area, dashboard, recent-scans queries
mcp_keys.example.json # Template key store (copy to mcp_keys.json)