MARS-Curiosity 1.8: TMS Smart Setup, MCP Apps and JWT key rotation

MARS-Curiosity 1.8 is out. Less than two weeks after 1.7.1, it brings a new way to install the library, takes the MCP support introduced in 1.7 one step further, and closes a long-standing gap in JWT handling. It also does some spring cleaning: Delphi 10.4 Sydney is now the minimum supported version.

If you are new here: MARS-Curiosity is an open source, lightweight REST library for Delphi. You write plain classes, decorate them with attributes, and MARS takes care of routing, parameter binding, serialization and authentication. Everything is documented on the documentation site.

Install with TMS Smart Setup

MARS is now listed in the community registry of TMS Smart Setup, the open source command line tool by TMS Software that fetches, builds and installs Delphi libraries from sources. Once Smart Setup (3.5 or later) is installed and the community server enabled, this is all it takes:

tms server-enable community true
tms install andreamagni.mars

Smart Setup clones the repository, compiles the runtime and design-time packages for every Delphi version it finds (10.4 and later, Win32 and Win64), registers them in the IDE and sets up the library path. tms update andreamagni.mars keeps you on the latest version.

The JOSE JWT backend uses a weak dependency: MARS.JOSE is built only if paolo-rossi.delphi-jose-jwt is installed too. Install it before or after MARS (tms install paolo-rossi.delphi-jose-jwt): Smart Setup rebuilds MARS and adds the package. The default mORMot backend needs nothing else.

A big thank you to Adrian Gallero of TMS Software, who reviewed the submission, suggested the dependency model and fixed the build for Delphi 12. The executable installer is still available, and manual installation from sources keeps working: pick one method only.

MCP Apps: interactive views for your tools

In 1.7 MARS learned to speak the Model Context Protocol: Delphi methods become tools that AI agents like Claude can discover and call. With 1.8, a tool can also come with an interactive HTML view, rendered by the host right next to the tool result. This is the MCP Apps extension, and in MARS it is, once again, a matter of attributes:

const
  DASHBOARD_VIEW_URI = 'ui://mars-demo/server-dashboard.html';

// the tool: hosts supporting MCP Apps show the view, other clients get the usual JSON
[MCPTool('server_dashboard', 'Shows an interactive dashboard with information about this server')
, MCPToolUI(DASHBOARD_VIEW_URI)]
function ServerDashboard: TServerInfo;

// callable by the view only (its Refresh button): hidden from the model
[MCPTool('dashboard_refresh', 'Refreshes the server dashboard')
, MCPToolUI(DASHBOARD_VIEW_URI, 'app')]
function DashboardRefresh: TServerInfo;

// the view itself: an HTML page talking to the host via postMessage
[MCPAppResource(DASHBOARD_VIEW_URI, 'server_dashboard_view', 'Interactive server dashboard')
, MCPAppBorder(True)]
function DashboardView: string;

The view receives the tool result and can call back the server tools it is allowed to use. [MCPAppCSP] declares the domains the page may reach, and the new [MCPMeta] attribute adds free-form _meta to any tool or resource, for whatever the next extension will need. The Demos/MCPServer project ships the dashboard above, written in plain HTML and JavaScript.

Also new on the MCP side: [MCPDefault('<JSON literal>')] makes a tool parameter optional, advertising the default value in the schema.

JWT key rotation

A signing secret should not live forever. Until now, replacing JWT.Secret invalidated every token already issued and logged everybody out. MARS 1.8 implements key ids (the kid header of RFC 7515): each key gets a name, written in the tokens it signs, and retired keys stay valid for verification only, until their tokens expire.

[DefaultApp]
; the active key: signs new tokens, its id goes in the "kid" header
JWT.KeyId=2026-10
JWT.Secret=<new long random value>
; retired keys: accepted only for tokens carrying that "kid"
JWT.PreviousSecret.2026-07=<the secret used until now>

A kid selects exactly one key, and an unknown kid makes the token invalid. Keys are read through a pluggable IMARSTokenKeyProvider, so you can keep them in a database or a vault, or rotate them automatically. Rotation is opt-in: without JWT.KeyId your tokens do not change. Thanks to @pontusbredin, who asked for it back in 2020 (#82): better late than never. The documentation walks through a rotation, including the multi-server case.

JSON options in the configuration file

The JSON serialization options (skip empty strings, numbers, booleans, objects, arrays and nulls, dates as UTC, display format for dataset numbers) used to be set in code only. Now each application can set them in its .ini file, without recompiling:

[DefaultApp]
JSON.SkipEmptyStrings=false
JSON.DateIsUTC=true

Resource and method attributes still win over the configuration, which wins over the global default set in code. The same options now drive the request readers too, so a date is read with the same DateIsUTC it is written with.

Related: the new JSON.EscapeNonASCII parameter (#208, thanks to @AlexanderN86). By default MARS writes characters above 127 as \uXXXX escapes: perfectly valid JSON, but hard to read when your data is in Greek, Cyrillic or Chinese. Set it to false and, with a Unicode response encoding, those characters are written as they are.

Security

  • The JOSE backend accepted tokens signed with HS384/HS512 when the token header asked for them. It now accepts HS256 only, like the mORMot backend.
  • TFileSystemResource: Windows 8.3 short names (for example WEB~1.CON for web.config) could bypass the [Exclude]/[Include] masks. Thanks to Nando Dessena for the report and the fix (#210).

Spring cleaning

  • Delphi 10.4 Sydney or later is required. Packages for XE up to 10.3 Rio are gone, together with about 340 conditional blocks for older compilers. Less code, fewer surprises.
  • delphi-jose-jwt jumps from a 2019 copy to v4.0.2, now a git submodule: clone with git clone --recurse-submodules. MARS.JOSE requires its JOSE package instead of bundling the units, so MARS can be installed side by side with other libraries using JOSE.
  • Every bundled third-party library is documented (origin, version, license, local changes) in ThirdParty/README.md.
  • The MARS.DCS packages for Delphi 10.4, 11 and 12 now have the right search paths (#209).

Before upgrading, please read the upgrade notes in the release: library path changes for delphi-jose-jwt v4, the JOSE package to deploy with runtime packages, and a renamed method for TMCPOAuthServer descendants.

Get it

As always, feedback, issues and pull requests are welcome on GitHub. And if you build an MCP App with MARS, I would love to see it!

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.