An MCP server for the Open eClass platform by GUnet
This server exhibits critical quality defects across all dimensions. Tool naming is non-standard (login, logout, authstatus instead of verb_noun patterns). All four tools use a dummy 'random_string' parameter that violates the no-parameter-tools pattern. Descriptions are present but generic, averaging ~60 characters. Input schemas are present but malformed: they define only a single required dummy parameter ('random_string') that serves no purpose and suggests the actual parameters (credentials, course filters) are handled via environment variables rather than tool inputs, a critical design flaw that prevents parameter validation and LLM guidance. Output schemas are completely undocumented in the visible code. Error handling is minimal. The SessionState pattern (stateful initialization) relies on module-level mutable state, which violates the MCP 2026-07-28 stateless request model. STDIO-only transport, combined with these definition gaps, places this server well below production baseline.
Check authentication status with eClass
Get list of enrolled courses from eClass
Log in to eClass using username/password from your .env file through UoA's SSO. Configure ECLASS_USERNAME and ECLASS_PASSWORD in your .env file.
Log out from eClass
Dummy parameter anti-pattern: all four tools require a 'random_string' parameter with description 'Dummy parameter for no-parameter tools'. This violates tool input semantics, parameters should control tool behavior, not be placeholder padding. Real parameters (username, password, course_id filters) are injected via environment variables, preventing the LLM from controlling tool inputs. Agents cannot parameterize authentication, course filtering, or any dynamic behavior.
No output schema documentation: handle_login(), handle_get_courses(), handle_logout(), and handle_authstatus() return TextContent but the actual response structure (success flag, message text, course list format) is not documented. LLMs cannot plan follow-up actions without knowing what fields to expect. The code returns `types.TextContent(type='text', text=<message>)` but there is no schema annotation showing what the 'text' field contains.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 27 | <=2025-11-25 | v2 |
| 2026-03-09 | F | 35 | - | v1 |
Tool naming does not follow verb_noun convention: 'login', 'logout', 'authstatus' are imperative verbs or noun-only. Baseline expects 'get_auth_status', 'check_auth_status', or 'describe_auth_status'. 'authstatus' is ambiguous, does it return status, change status, or poll? 'get_courses' is acceptable; 'login' is imperative but acceptable.
No parameter descriptions for dummy parameter: 'random_string' is marked as required but described only as 'Dummy parameter for no-parameter tools'. This tells the LLM nothing about what value to pass or why. Real no-parameter tools should have NO parameters; if they must have one for framework compatibility, it should be optional (not required) and invisible to the agent.
Credentials exposed via environment variables, not tool parameters: ECLASS_USERNAME and ECLASS_PASSWORD are read from .env in handle_login(). While this avoids logging credentials in tool parameters (good for secrets), it also means the LLM cannot switch users or accounts without restarting the server. This design prevents multi-user or multi-tenant agent scenarios. Authentication should accept optional user/pass parameters to override .env defaults.
Session state is module-level and mutable (SessionState() instantiated once at module load in server.py). This violates the MCP 2026-07-28 stateless request model. Each request should be independent; persistent state across requests is fragile for concurrent clients, server restarts, and horizontal scaling. The session should be managed via the request context or explicit session ID parameters (which are passed per-request, not stored server-side).
Error handling returns only TextContent with a message string; no structured error codes or recovery guidance. If 'Wrong password' occurs, the LLM sees only 'Error: Username and password must be provided...' with no indication whether to retry, ask the user, or try a different tool. No distinction between retryable (network timeout) and non-retryable (auth failure) errors.
get_courses returns a list via TextContent with unspecified format. The code calls course_management.format_courses_response(success, message, courses) but the actual JSON structure of the response (e.g., is it 'courses': [{name, id, code}, ...] or a flat string?) is not visible. Without schema documentation, the LLM cannot extract course IDs for follow-up operations.