Releases: PsychQuant/che-ntucool-mcp
Release list
v0.2.2: ship the argv-leak and keychain-account fixes
Fixed
-
The keychain account name was documented as
<login-id>, with a note saying it
could be any label. It cannot: the wrapper and the server both look up
${NTUCOOL_ACCOUNT:-default}, so a token stored under a login-id is simply not
found. Anyone following the setup instructions literally ended up with a token
the server could not read. Now documented asdefault, with the override
described as a lookup key rather than a label. -
Every example passed the token as
-w <token>, which places it in the process
argument list for the lifetime of the command — readable by any local process
viaps, whether or not it was ever echoed. Omitting the value makessecurity
prompt for it instead. Corrected in the README, thentucool-canvasskill, the
wrapper's stderr hint, the server'sinstructionsstring, and the token-missing
error message.The last two matter beyond documentation: they are compiled into the binary, so
until this release the shipped server told users — and told the model, through
instructions— to run the leaking form.
v0.2.1: correct the access-token path
Fixed
-
Setup instructions pointed at a token path that dead-ends as written. The Canvas
control lives under 帳戶 → 設定 → 已核准的整合 → 新訪問令牌, and NTU COOL's
custom theme hides that entire block:.approved_integration_headers, .approved_integration_content { display: none; }
So a reader following the documented path looks for a button inside a section
they cannot see, and concludes the feature is unavailable.Corrected in all four places that carried the old path: the README setup step,
the server's owninstructionsstring (delivered to the client — the model was
reading the wrong path too, and would have relayed it), thentucool-canvas
skill, and the wrapper's token-missing stderr hint.The hide is cosmetic, not Canvas's
limit_personal_access_tokensaccount
setting —.add_access_token_linkis still rendered into the page, so tokens
remain obtainable. Verified against a live NTU COOL session 2026-08-19.
v0.2.0: human-confirmed grade and announcement writes
Added — write operations, human-confirmed (Foresay protocol)
preview_grade_change/post_grades— set grades on an assignmentpreview_announcement/post_announcement— publish a course announcement
Both follow the Foresay confirmation
protocol. Foresay's operation rule is that an irreversible operation always
takes the confirm branch, and these are irreversible in its sense — students are
notified and a notification cannot be un-sent — so there is no scope threshold
below which the gate is skipped.
The gate has two independent layers, because they catch different failures:
- Elicitation (
elicitation/create) puts the confirmation in front of the
user through the client's own dialog. The model cannot skip it or answer it,
because the answer does not pass through the model. This is what Foresay's own
case study called its biggest gap — "Foresay is a protocol, not a runtime" —
and it closes it, because this project controls the server rather than only
the skill layer. - Payload-bound token. A preview mints a single-use, 10-minute token bound
to the exact payload it rendered; the write refuses any payload whose hash
differs. This catches what the dialog structurally cannot: the human approved
[85, 92, 78]and[85, 92, 87]reached the API. A mismatch burns the token,
so the correction must be re-previewed rather than riding in on the old
approval.
Fail-closed in every direction — no elicitation support, decline, cancel, or
transport error all refuse the write.
Reversibility is read from the assignment rather than assumed: an assignment on
a manual posting policy genuinely is recoverable (grades stay hidden until
posted), and the confirmation says so instead of crying wolf. An unreadable
posting policy is treated as automatic — unknown fails toward the more cautious
warning.
Fixed
Servernow runs withConfiguration.strict. The SDK's
validateClientCapabilityis a no-op unless strict mode is on, and the
default is off — so the elicitation capability check that this feature's
safety was assumed to rest on was not actually running. Caught by reading the
SDK rather than trusting the assumption.- The elicitation capability is additionally checked directly by this server
(captured at the initialize handshake) rather than relying only on the SDK's
strict-mode path, so the safety property does not hinge on a global config
flag that could later be flipped for an unrelated reason. NTUCOOL_API_BASEnow overrides the Canvas base URL.CanvasAPIClient
documented this as configurable "for testing", but the server hardcoded it,
making the claim untrue and the write gate unverifiable offline.
Verification
The gate was exercised end-to-end against a stub Canvas server: a valid token
was minted by a preview, the write was attempted from a client that declared no
elicitation support, the write was refused rather than hung, and the stub
recorded zero write requests. 16 unit tests cover replay, expiry, payload
drift, cross-payload-type redemption, and delimiter-collision resistance.