Skip to content

Add time-limited license handling for the standalone MCP server - #260

Merged
rhennigan merged 1 commit into
mainfrom
feature/standalone-license
Oct 28, 2026
Merged

rhennigan merged 1 commit into
mainfrom
feature/standalone-license

Conversation

@rhennigan

Copy link
Copy Markdown
Member

Summary

Implements Specs/StandaloneLicense.md: license handling for the standalone MCP server's time-limited license.

The standalone application describes the license with keys of $StandaloneMCPServerInformation ("ExpirationDate", "Expired", "InstructionsURL", "ProductName", "WarningDays"). License handling is on only when "Expired" or "ExpirationDate" is present, so nothing changes outside the standalone product. With a license, the server:

  • appends the license status to the initialize instructions
  • adds a WolframLicenseStatus tool, unless the server already lists one
  • after expiration, fails every other tool call with an isError result (the tool is not run) and every prompts/get with a JSON-RPC error (-32603), both carrying the expiration message
  • during the warning period (days remaining ≤ "WarningDays", default 14), appends a reminder to every other tool result

The license is read again on every request, so a long-running server expires on time. A missing or invalid expiration date counts as expired (fail closed). Days and dates use the time zone of the expiration date. The app detects support with KeyExistsQ[$DefaultMCPTools, "WolframLicenseStatus"].

Blocking prompts after expiration is an addition to the original spec, and the spec has been updated to say so.

Where the code is

  • Kernel/Tools/LicenseStatus.wl (new): the tool, the license logic (licenseStatus, licenseInstructions), and the message templates
  • Kernel/Server/Shared.wl: the hooks (withLicenseTool in initializeServerState, withLicenseInstructions in initResponse, the expiration and warning checks in evaluateTool, and handlePromptGet)
  • Docs: README.md, docs/tools.md, docs/usage-data.md, AGENTS.md

Tests/LicenseStatus.wlt is new; the Tools.wlt and UsageData.wlt diffs are mostly the pre-commit hook re-annotating TestID positions.

Notes / possible follow-ups (not handled here)

  • App-side DST edge case: the app builds the date with FromUnixTime[t], which uses the UTC offset at startup. Near local midnight across a DST change, the reported day can be off by one. The fix would be in the app (pass a named time zone).
  • If a server lists WolframLicenseStatus twice, nothing special happens.
  • The unknown-tool error doesn't get the warning reminder.
  • Per the spec, prompt results don't get the warning reminder.
  • Tests/LicenseStatus.wlt is large (~900 lines, 70 tests) and can be trimmed if that helps review.

Test plan

  • TestReport:
    • LicenseStatus.wlt 70/70
    • Tools.wlt 110/110
    • Prompts.wlt 110/110
    • StartMCPServer.wlt 90/90
    • UsageData.wlt 73/73
    • MCPApps.wlt 118/118
    • ToolOverrides.wlt 51/51
    • CloudDeployment.wlt 176/176
  • CodeInspector clean on LicenseStatus.wl, Shared.wl, and Tests/LicenseStatus.wlt
  • Scripts/BuildAgentSkills.wls --check: agent skills up to date
  • Real stdio server (StartMCPServer[], Wolfram server) with $StandaloneMCPServerInformation shaped like the app's license[], expiring 75 s after load:
    • Before expiration:
      • the initialize instructions report the license
      • tools/list includes WolframLicenseStatus
      • WolframLanguageEvaluator results end with the reminder
      • prompts/get works
    • After expiration (same session, no restart):
      • WolframLicenseStatus reports "has expired"
      • WolframLanguageEvaluator and unknown tools return isError with the message, without running
      • prompts/get returns a -32603 error
      • a repeated initialize gives the expired instructions

🤖 Generated with Claude Code

https://claude.ai/code/session_01KfEJrsbZDPEGGJ7quYKQBe

The standalone MCP server describes its license with keys of
$StandaloneMCPServerInformation ("ExpirationDate", "Expired",
"InstructionsURL", "ProductName", "WarningDays"). License handling is on
only when "Expired" or "ExpirationDate" is present, and the license is
read again on every request. With a license, the server:

- appends the license status to the initialize instructions
- adds a WolframLicenseStatus tool unless the server already lists one
- fails every prompt and every other tool call once the license has
  expired (a missing or invalid expiration date counts as expired)
- appends a reminder to tool results during the warning period

The standalone application detects support with
KeyExistsQ[$DefaultMCPTools, "WolframLicenseStatus"].

See Specs/StandaloneLicense.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KfEJrsbZDPEGGJ7quYKQBe
@rhennigan
rhennigan merged commit c69e8fa into main Oct 28, 2026
1 check passed
@rhennigan
rhennigan deleted the feature/standalone-license branch October 28, 2026 00:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant