Skip to main content

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

ModeEntry pointSuitable for
stdiopython -m mcp_serverClaude Desktop, VS Code Copilot
HTTP (streamable)python -m mcp_server.httpOnyx, 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.

caution

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

VariableDefaultDescription
MCP_API_KEY(required for stdio)Raw API key for this session
MCP_KEYS_FILEmcp_keys.json (project root)Path to the key store JSON
DJANGO_SETTINGS_MODULEscannersky.settingsDjango settings module
MCP_HTTP_HOST127.0.0.1Bind host for HTTP mode
MCP_HTTP_PORT8001Bind 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

ScopeGrants access to
read:personsPerson listing, lookup, attendance timeline
read:departmentsDepartment listing and detail
read:semestersSemester listing, detail, active semester
read:classesClass listing, detail, student roster
read:eventsEvent listing, detail, participant roster
read:devicesDevice status, area listing
read:attendanceAttendance snapshots, calendar, dashboard stats, recent scans, semester reports
write:class_rosterAdd / remove students from class rosters
write:event_rosterAdd / 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:

  1. Open Admin Panel → Actions → MCP Actions.
  2. Click Add MCP Server and set:
    • Server Name: ScannerSky
    • MCP Server URL: http://<your-host>:8001/mcp
  3. 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

ToolScopeDescription
list_personsread:personsPaginated list with optional filters (search, person_type, department_id)
get_personread:personsSingle person lookup by numeric id, school_id, or card_number
get_person_attendance_timelineread:personsDaily scan counts for a person over the last N days (1–365)

Departments

ToolScopeDescription
list_departmentsread:departmentsAll departments with headcounts; optional name filter
get_departmentread:departmentsSingle department by id including programs and headcounts

Semesters

ToolScopeDescription
list_semestersread:semestersPaginated semester list ordered by most recent start date
get_semesterread:semestersSingle semester by id
get_active_semesterread:semestersSemester whose date range contains today

Classes

ToolScopeDescription
list_classesread:classesPaginated list; filter by semester, department, or title
get_classread:classesFull class detail including student count and co-instructors
get_class_studentsread:classesEnrolled student list; paginated with name/school_id filter
get_class_attendance_snapshotread:attendancePresent/absent breakdown over a date range (max 90 days)
get_class_attendance_calendarread:attendanceMonthly calendar grid with per-day present/total/pct cells

Events

ToolScopeDescription
list_eventsread:eventsPaginated list; filter by semester, department, title, or upcoming-only
get_eventread:eventsFull event detail including participant count and facilitators
get_event_participantsread:eventsRegistered participant list; paginated
get_event_attendance_snapshotread:attendancePresent/absent breakdown; optional non-participant scan visibility

Devices

ToolScopeDescription
list_devicesread:devicesAll devices with live status derived from latest heartbeat
get_device_statusread:devicesStatus for specific device IDs
list_areasread:devicesAll physical areas with device count

Device status values: online (≤90 s), stale (≤180 s), offline (>180 s), unknown (no logs).

Attendance / Dashboard

ToolScopeDescription
get_dashboard_statsread:attendanceTop-level KPIs: today's scans, 7-day window, active devices, totals
get_recent_scansread:attendanceMost recent scan records; look-back 1–168 h, paginated

Attendance Reports

ToolScopeDescription
get_class_semester_attendance_reportread:attendanceSemester-scale class attendance report with summary metrics and student-level supporting rows
get_person_semester_attendance_reportread:attendanceSemester-scale person attendance report with expected/present/absent breakdown and class/date groupings
get_event_attendance_reportread:attendanceSingle-event or multi-event attendance reporting with summary and optional attendee-level rows

Class Roster Writes

ToolScopeDescription
add_student_to_classwrite:class_rosterEnroll a person in a class (idempotency error if already enrolled)
remove_student_from_classwrite:class_rosterRemove a person from a class roster

Event Roster Writes

ToolScopeDescription
add_event_participantwrite:event_rosterRegister a person as an event participant
remove_event_participantwrite:event_rosterRemove 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)