Skip to content

v0.3.7 — MCP tool annotations & caller-context variables

Choose a tag to compare

@keysersoft keysersoft released this 29 Jul 07:15
· 38 commits to main since this release
d21a9d2

Features

  • MCP tool annotations (#438): tools are now advertised with the spec's ToolAnnotations (title, readOnlyHint, destructiveHint, idempotentHint, openWorldHint), so an agent can tell a probe-safe tool from a mutating one before calling it. The hints are derived from what each connector already declares — the HTTP verb for REST, query/mutation for GraphQL, the connector's readOnly flag and the SQL text for databases — and annotations reported by an upstream MCP server are now passed through instead of being discarded.

    Derivation is deliberately conservative about readOnlyHint: only the protocol may assert it. Wrongly claiming read-only would invite an agent to call a mutating tool freely, whereas omitting the hint only makes it more careful, so tool names are used solely to refine destructiveHint. The one case no heuristic can settle — a read-only search exposed over POST — is handled by a per-tool override, editable from the new Hints panel on the connector page or via GET/PATCH /api/connectors/:id/tools/:toolId/annotations. Overrides survive a re-import; upstream MCP annotations refresh on re-import, since that server is authoritative about its own tools.

    Per the MCP spec these are advisory hints — clients must not base trust decisions on them. Enforcement stays in roles and per-tool access.

  • Caller-context variables {{amcp.*}} (#438): connectors often front a service-based API while users authenticate individually (OAuth, per-user MCP API keys), leaving the target system unable to record who actually asked. The calling identity can now be forwarded explicitly in headers, query parameters, the body and the path — e.g. X-Requested-By: {{amcp.user_email}} — with user_email, user_id, org_id, server_id, server_name, auth_method and api_key_name.

    The values are resolved server-side and merged after the workspace's own environment variables, so neither a connector variable nor a tool argument can spoof them. Forwarding is opt-in (identity is personal data). Where there is no user — instance-wide static credentials, anonymous mode — a variable resolves to an empty string rather than leaking a literal placeholder, and a misspelled reserved variable is rejected when the tool is saved.

Fixes

  • Reserved-variable scanning made linear (#438): the {{amcp.*}} scanner used a pattern that backtracks polynomially on adversarial brace runs (CodeQL js/polynomial-redos). It runs over operator-supplied tool configuration, so the pattern now uses quantifiers over disjoint character classes.
  • Transient TLS and proxy failures are retried (#437): EPROTO handshake errors and 421 Misdirected Request responses are retried instead of surfacing as tool errors.

Upgrading

Adds one additive, nullable column (mcp_tools.annotations); migrations run automatically on container start. No configuration changes required — annotations appear on existing tools with no action needed.

Verification: backend 3460 tests green, typecheck clean; frontend typecheck + build clean; annotation derivation verified inside the running container against real production tool definitions.

Docs: docs/tool-definition.md — new sections Tool Annotations and Caller-Context Variables.