You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Caller strings interpolated into trusted code no longer reach sage_eval. Four
tool parameters -- graph_operation.graph, group_operation.group, coding_theory_operation.code_type and polynomial_ring_operation.base_ring -- were
embedded into generated Sage without validation. Generated code runs under a policy
that re-permits sage_eval (every helper template is built on it), so a crafted
parameter reached arbitrary execution: reading files, running shell commands and
opening outbound connections were all demonstrated against a real SageMath runtime.
All four now pass the same validation gate as every other expression, variable names
must be plain identifiers, and a test fails the build if any future tool interpolates
a caller string without a gate.
Forbidden names are rejected wherever they are read, not only where they are
called. f = open followed by f("/etc/passwd"), a lambda default, or a list
literal all bypassed the previous check, through the specialized tools as well as evaluate_sage. The same applies to module names: m = os and from sage.all import os as m both returned the container uid.
The worker namespace no longer contains open, eval, exec, compile, input, breakpoint, globals, locals, vars, memoryview, help, exit or quit, as a
backstop for spellings the validator does not see.
Changed
Integer results at or above 2^53 are returned as decimal strings, and the same parameters accept them on the way in (combinatorics_operation, elliptic_curve_operation, graph_operation vertices joined number_theory_operation). They were
returned as JSON numbers, and JavaScript-based MCP clients parse those as IEEE
doubles, so exact values were silently corrupted: bell(30) reached one CLI as 846749014511809388871680 rather than 846749014511809332450147. Integers
below the boundary keep their numeric type, so ordinary results are unchanged.
This mirrors the input side, which has required decimal strings for the same
values since 0.4.0.
interrupt_sage_session no longer signals an idle worker. When nothing is running
it returns No running computation in session '<name>' instead of claiming state was
preserved. Signalling an idle worker was not harmless: it is blocked reading its input,
where the signal has no computation to abort, and a real Sage worker was left unable to
answer the next request -- which then timed out and restarted it, destroying the
namespace the interrupt exists to protect.
The container runs with a read-only root filesystem, writable tmpfs for /tmp and
Sage's own directory only. The Helm chart gained readOnlyRootFilesystem, matching emptyDir scratch, and default CPU and memory requests and limits.
Internal
server.py split from 2327 lines into app.py (the FastMCP object and lifecycle), runtime.py (settings and session manager), codegen.py (the code-building helpers)
and a tools/ package by domain. Tool names, schemas and descriptions are unchanged
and held that way by a committed snapshot test; from sagemath_mcp import server
still works.
Coverage raised to 100% of statements and branches, enforced in CI.
Added
interrupt_sage_session stops a running computation while keeping every variable
defined so far. The worker turns the signal into an Interrupted response rather than
exiting, so the namespace survives. cancel_sage_session still restarts the worker and
is now documented as the escape hatch for a wedged one, not the first resort. POSIX
only.
Named workspaces.start_sage_session, list_sage_sessions and stop_sage_session, plus an optional session argument on the tools that carry state.
Workspaces have independent variables, so a long exploration and a scratch calculation
no longer collide. Omitting session uses default, which behaves exactly as before,
and the default workspace still keys on the bare client scope so persisted journals
keep working.