Skip to content

v1.4.0 - Tool names and descriptions

Choose a tag to compare

@pacnpal pacnpal released this 09 Aug 00:06
· 32 commits to main since this release
3f4e45c

Per-tool name and description overrides

Some MCP servers ship tool names and descriptions that models handle badly. On an
open-source server you can rebuild it; on a closed-source or paid HTTP endpoint you
can't. 1.4.0 lets an operator relabel any tool in place — rename it, rewrite its
description, or both — applied to every surface the server exposes, with no upstream
rebuild.

Existing installs are unaffected until you use it: the new column is nullable, so
servers with no policy serve their tools exactly as the upstream declares them.


Per-tool overrides (#113, closes #112)

A new tool_overrides map on the Server row — upstream tool name
{name?, description?} — with both fields optional and independent.

  • A renamed tool answers to its new name only, exactly as if the upstream had been
    rebuilt. No alias and no two names for one tool, so clients pointed at the old name
    must be updated (called out in the UI and README).
  • Keyed by the upstream name, which is the stable identity: an override survives
    being renamed again, and a rename never orphans its own description. The bridge
    stamps a renamed tool's pre-rename name into _meta, the discovery probe lifts it to
    upstream_name, and the UI keys rows off that rather than reversing the rename map —
    an exposed name isn't unique.
  • The labels change and nothing else. Schema, _meta, icons, execution (MCP
    task support) and dispatch remain the upstream's, including open-ended input schemas
    and the argument forwarding that goes with them.
  • Hiding wins over renaming, and hiding also frees a tool's name so another tool
    may be renamed onto it.
  • A rename never takes a name that's already answered to. If a live tool holds the
    target the rename goes inert and both tools stay reachable under their own names; the
    rest of the policy still applies. Symmetrically, a rename whose source has vanished
    upstream doesn't reserve its target.
  • Every surface at once: MCP tools/list and tools/call, the REST routes (a
    renamed tool is served at its new path segment and appears that way in the generated
    openapi.json), and the group hub.

One mechanism, not two

Rather than add a second per-tool rewriting path beside the disabled_tools
middleware from #105, both controls are now applied by a single FastMCP
ToolTransform in the bridge, which deletes the hand-rolled
DisabledToolsMiddleware. Hiding is unchanged in behaviour: a disabled tool drops out
of tools/list and is refused on call with the identical Unknown tool error.

The transform copies the upstream tool with new labels instead of rebuilding it —
a rebuild drops icons and execution, replaces rather than merges _meta, and
regenerates the input schema and the argument-forwarding closure from it. It also owns
name resolution, so list_tools and get_tool can never disagree about which tools
exist, and strips the reserved identity key from every upstream tool so an upstream
can't forge an identity the UI would key policy off.

Persistence and validation

Overrides are part of the launch spec (config_hash), so a change restarts the bridge
and persists as ordinary desired state. Values are trimmed, blank fields and no-op
entries are dropped, and keys are sorted, so re-submitting the same policy in a
different order doesn't bounce the bridge.

Rename targets are validated (≤64 chars of [A-Za-z0-9_.-], bare dot-segments
refused) because the name has to survive as a REST path segment and a model-facing
function name. Colliding renames and rename chains are refused at write time, while a
rename involving a hidden tool is allowed because the bridge applies exactly that.
Unknown override fields are rejected at the HTTP boundary, so a typo can't read as a
saved override that does nothing. Sizes are bounded per description and across the
whole map, and both write paths refuse a config too large to hand the bridge in one
environment variable — checked before committing, so an accepted write can never take
a running endpoint offline.

API and UI

PATCH /api/servers/<id>
{"tool_overrides": {"do_thing": {"name": "run_report", "description": "Runs the report."}}}

Send {} to restore every tool's upstream labels. Both fields are optional on the way
in and on the way out: an override of one field is stored and echoed carrying only that
field. Accepted on create, echoed on GET, and carried through clone.

In the UI, each tool row on the server detail page gains Name and Description
fields, staged alongside the existing enable/disable switches and saved by the same
single Apply — one PATCH, one bridge restart for the whole batch. A name collision
is flagged as an early signal but doesn't block the write, since the bridge decides
name ownership against the live tool list. A row for a name that isn't in the live list
— a hidden tool or a stale override key — stays editable but offers no playground.


Fixes and maintenance

  • Tool names are matched exactly. disabled_tools and tool_overrides keys are no
    longer trimmed on write. The key is the upstream tool's identity, so rewriting it
    meant a policy could be saved against a tool that doesn't exist; a tool whose real
    name carries whitespace can now be hidden or relabelled.
  • Dependency bumps (#111). postcss 8.5.16 → 8.5.25 and undici 7.28.0 → 7.29.0
    in the frontend dev toolchain.

Upgrade notes

  • No migration. tool_overrides is added via the existing forward-only
    ADD COLUMN path and is nullable, so legacy rows read as {} — no behaviour change
    for servers that don't use it.
  • No new environment variables. Overrides are per-server config managed in the
    UI/API.
  • Renaming is client-visible. A renamed tool stops answering to its upstream name,
    so any client, prompt, or script referencing the old name needs updating.
  • Exported .mcpb bundles are unaffected — per-tool policy is a property of this
    instance's proxying, not of the packaged server.

Full Changelog: v1.3.1...v1.4.0

License

MIT © pacnpal