McpArguments.h header

#include <ew/app/McpArguments.h>

Namespace ew::app

Functions

std::optional< bool > ew::app::mcp::boolArg(const QJsonObject &args, const QString &key)

The boolean at key of args – a tool's arguments, or a nested object within them. nullopt when the key is absent or when its value cannot be read as a boolean at all.

The boolean twin of stringArg, and it exists for the same reason. QJsonValue::toBool() returns its DEFAULT for anything that is not a JSON true/false, so a model sending the string "true" – which models do routinely, and which F-0051 fixed for strings – silently got the opposite of what it asked for. Twice the opposite was destructive: find_replace rewrote the manuscript when dry_run: "true" asked for a preview, and update_map's reveal_region revealed a GM secret when revealed: "false" asked to hide it (F-0057).

Reads a JSON bool as itself, a number as non-zero, and the strings true/false, 1/0, yes/no and on/off (case-insensitive, trimmed). Anything else is nullopt rather than a guess, so a caller for whom the wrong direction is destructive can distinguish "absent" from "unreadable" with args.contains(key) and refuse instead of defaulting.

std::optional< int > ew::app::mcp::intArg(const QJsonObject &args, const QString &key)

The whole-number argument key of args, or nullopt when it is absent, not a number, or not a whole number.

QJsonValue::toInt() returns its default – zero – for a value that is numeric but not integral, and isDouble() is true for 2.5. So a guard shaped isDouble() && toInt() >= 0 accepts a fraction and then acts on 0: move_field with position: 2.5 moved the field to the FRONT and reported "position 0", and word_count_target: 1500.5 CLEARED the target and reported it cleared (F-0076). Both read as the tool doing something deliberate.

A numeric string is accepted, for the same reason stringArg coerces the other direction: the client is a language model and sends "3" about as often as 3.

QString ew::app::mcp::stringArg(const QJsonObject &args, const QString &key)

The trimmed string argument key of args, empty when absent.

A number or bool is rendered as its text rather than dropped. The client of these tools is a language model, and models routinely send a bare scalar where a string is expected – a name that looks numeric ("2024"), a chapter number, a version. QJsonValue::toString() returns an empty string for those, which made a tool report a supplied argument as missing: the least actionable error a tool can give, since the caller can see the field in its own request (F-0051). Every tool family reads its string arguments through this, so the coercion is defined once rather than repeated at each call site.

An absent, null, object or array argument still reads as empty, so a tool's "required argument" check keeps working unchanged.

std::set< QString > ew::app::mcp::stringSetArg(const QJsonObject &args, const QString &key)

The de-duplicated, non-empty strings of array argument key, each coerced as stringArg coerces a scalar. A non-array argument yields an empty set.

QString ew::app::mcp::stringValue(const QJsonObject &object, const QString &key)

The string value of key inside a nested object – a glyph, a mapping, a rule – coerced from a number or bool exactly as stringArg does, and not trimmed.

Nested content values reach the same models and carry the same risk of arriving as a bare scalar, but they are not tool arguments: a writing system may legitimately define a glyph whose grapheme is a space, so trimming here could erase a real value. stringArg trims because a tool argument with surrounding whitespace is always a mistake; this does not, because a nested value's whitespace may be the content.