Files
Schulcloud-MCP/package.json
MechaCat02 60ca4d3eba Keepalive via refresh-session; GET pings measured insufficient
The endurance test refuted the sliding-window model I committed earlier.
A keepalive doing only GET /api/v3/me succeeded at t+0/30/60/90 and was
still rejected by t+120 — consistent with the session ending ~2h after
LOGIN (t+107), and inconsistent with 2h after the last request, which
would have been t+210.

This is a live-vs-source divergence, not a misreading: both the current
JwtWhitelistAdapter and the legacy Feathers ensureTokenIsWhitelisted
re-set the Valkey TTL on every authenticated request, so the source
reads as a sliding window. The instance does not behave that way.

So the keepalive now calls POST /authentication/refresh-session, the
endpoint behind the UI's "Sitzung verlängern" button, which a separate
100s test showed does hold the reported budget at 7200s. It is the only
non-GET request in the server: no body, touches only our own session,
cannot read or modify user data, and is not exposed as a tool, so no
model-driven call can ever be a POST. It logs the returned budget, which
makes a failing extension visible before the session is lost.

Whether this is sufficient is NOT established. Two mechanisms still fit:
an idle TTL that reads fail to refresh (keepalive works), or an absolute
cap/revocation anchored at login — e.g. the IDP's back-channel logout,
which clears every token for the account rather than one. Added
scripts/session-diagnose.mjs to settle it: it logs the budget every 10
min, so a decaying series indicates the former and an abrupt 401 at
7200s the latter. Docs state the open question rather than asserting a
mechanism.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 15:46:54 +02:00

40 lines
1.2 KiB
JSON

{
"name": "schulcloud-mcp",
"version": "0.1.0",
"private": true,
"description": "MCP server exposing the Schulcloud (HPI Schul-Cloud / SVS) API to Claude: courses, boards, lessons, tasks and file downloads.",
"type": "module",
"engines": {
"node": ">=22"
},
"bin": {
"schulcloud-mcp": "dist/bin/stdio.js"
},
"scripts": {
"build": "tsc -p tsconfig.json",
"dev": "node --watch --experimental-strip-types src/bin/http.ts",
"start": "node dist/bin/http.js",
"stdio": "node dist/bin/stdio.js",
"typecheck": "tsc -p tsconfig.json --noEmit",
"test": "node --test test/*.test.ts",
"probe": "node --env-file=.env scripts/probe.mjs",
"smoke": "node --env-file=.env scripts/smoke.mjs",
"session-diagnose": "node --env-file=.env scripts/session-diagnose.mjs"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.20.0",
"exceljs": "^4.4.0",
"express": "^5.1.0",
"mammoth": "^1.11.0",
"unpdf": "^1.3.2",
"unzipper": "^0.12.3",
"zod": "^3.25.76"
},
"devDependencies": {
"@types/express": "^5.0.3",
"@types/node": "^22.15.0",
"@types/unzipper": "^0.10.11",
"typescript": "^5.9.2"
}
}