0005 — Translation tool design
Source:
docs/decisions/0005-translation-tool-design.mdis the canonical artefact. This page is a short summary; read the full ADR for the four alternatives considered, the binding design decisions, and the implementer’s notes.
- Status: Accepted
- Date: 2026-05-16
- Deciders: Thomas Lennon (maintainer),
mcp-architect
Context
Section titled “Context”mcp-translation is the third substrate MCP server and the engine of the communication-and-translation area. It ships in Phase 2 alongside a browser extension, and the same prompt library and eval corpus power both surfaces — one MCP server, one extension, one prompt repo, one test harness.
The user stories partition cleanly into four jobs: decode an incoming message, score an outgoing message’s tone, rewrite an outgoing message toward a target register, and brief a meeting transcript into a four-section structure.
Decision
Section titled “Decision”Adopt Option B: four-tool decomposition — translate_incoming, check_tone, rewrite_outgoing, brief_meeting. Each maps one-to-one with a user story; each is independently versionable; each is independently testable against its own eval slice.
View alternative approaches and technical debates
Alternatives rejected:
- One tool
analyze_message(direction, ...)— mixes two concepts in one parameter. Versioning becomes brittle (a meeting-brief change forces a major bump on tone-check). LLM invocation is harder with an overloaded discriminator. - One tool per channel (
translate_slack,translate_gmail, …) — channel is a parameter, not a tool boundary. Combinatorial explosion: 4 jobs × 8 channels = 32 tools. - A pipeline tool (
translate_then_rewrite) — stateful pipelines belong to skills, not servers. The caller composes more flexibly.
Cross-cutting rules established here
Section titled “Cross-cutting rules established here”- No LLM SDK inside the server. This is the third substrate server in a row to enforce vendor-neutrality. The rule is now substrate-wide doctrine: substrate servers construct prompts and validate structured outputs; the caller’s MCP client (Claude Desktop, Claude Code, custom MCP host) invokes the model.
- Local-first / cloud-mode parity. The server’s behaviour is identical regardless of which provider the user has configured. Each tool returns
model_provenance: {mode, provider, model}so a calling surface can render an honest “cloud mode” banner. - Verbatim-anchor enforcement on
brief_meeting.ambiguous_items[].quoted_span.textMUST equaltranscript[start_char:end_char]. The server validates this on every response and raisesVERBATIM_ANCHOR_FAILEDrather than fabricating spans. This is anti-hallucination armour for a meeting brief an autistic director will rely on. - Eval-corpus binding is structural. Every tool’s output requires an
eval_corpus_sliceidentifier. Every prompt change SHALL run the named slice in CI before merge. - Channel and target-register enums are closed. Channels:
email | slack | linear | github | notion | gdocs | outlook | generic. Registers:direct | warm | formal | concise | clarifying. Additions are minor bumps. - Ambiguity span shape is shared.
{start_char, end_char, reason}zero-indexed appears intranslate_incoming.ambiguity.spans,check_tone.flagged_phrases, andbrief_meeting.*.quoted_span— one rendering primitive for in-page highlighting. - PII redaction is upstream. The server analyses whatever text it is given. The extension and the user’s profile decide what gets passed.
Open questions
Section titled “Open questions”The full ADR carries six open questions:
- Where do
baseline_messagesforcheck_tonecome from? (Recommended: caller-supplied; skill-level wrappers may inject from the cognitive graph.) - Should
brief_meetingoptionally output a Mermaid sequence diagram? (Recommended: no — the visual-organizer skill composes.) - How do language packs override prompt templates? (Recommended: align with the plugin model; defer manifest detail to ADR 0007.)
- Should
translate_incomingdraft a reply inline, or always defer torewrite_outgoing? (Recommended: inline draft as convenience; chain torewrite_outgoingwhen register matters.) - PII handling boundary — confirm the server explicitly does NOT redact. (Recommended: confirm; it is the only choice consistent with vendor-neutrality.)
brief_meeting.meis required — confirmME_REQUIREDover defaulting tonull. (Recommended: confirm; the partition is ill-defined without it.)
What’s next
Section titled “What’s next”- Read the full ADR.
mcp-translationreference for the tool surface.asd-meeting-translator— Phase 2 reference consumer ofbrief_meeting.