Skip to content
NeuroDock

mcp-translation

ToolWhat it takesWhat it returnsWhy your brain cares
translate_incoming{ text, channel?, thread_context?, target_language? }explicit ask, ranked subtext hypotheses, ambiguity spans, recommended next actionreads the “happy to discuss further” you’ve been staring at for ten minutes and tells you whether it’s a soft no or a real opening — without you having to mask-rehearse seven interpretations
check_tone{ text, baseline_messages?, target_register?, channel? }scores on directness, warmth, urgency; flagged phrasesshows you that your draft reads as 92/100 urgent when your usual baseline is 40 — useful when the social-meter in your head is offline
rewrite_outgoing{ text, target_register, preserve_terms? }rewritten text, preserved/unpreserved terms, diff summarylets you keep the ticket IDs and jargon verbatim while a tool handles the register shift you find exhausting
brief_meeting{ transcript, me, project?, speakers? }my asks / others’ asks / decisions / ambiguous items (with verbatim quotes)turns ninety minutes of transcript into the four lists you actually need; ambiguous items are quoted character-for-character so nothing is invented

mcp-translation decodes corporate ambiguity. It is the substrate’s communication-layer server: it scores tone, rewrites for register, decodes incoming subtext, and briefs meeting transcripts. The server itself contains no LLM SDK — every tool returns a deterministic baseline plus a structured prompt the caller’s MCP client executes against its configured model.

  • Package: packages/mcp-translation/
  • Version: 0.0.2
  • Schemas: packages/mcp-translation/schemas/*.schema.json
  • ADR: 0005 — Translation tool design
  • Schema $id prefix: https://schemas.neurodock.org/mcp-translation/v0.1.0/

Per ADR 0005 §2, the server imports no anthropic, no openai, no ollama. The substrate is vendor-neutral by construction. Each tool returns an envelope:

{
"deterministic_analysis": { /* v0.1.0 output shape, populated heuristically */ },
"prompt_for_llm_refinement": {
"role": "user",
"content": "<rendered prompt template>",
"output_schema_ref": "packages/mcp-translation/schemas/<tool>.schema.json"
},
"eval_corpus_slice": "packages/evals/corpora/translation/<slice>.jsonl"
}

The caller MAY use the deterministic analysis alone (no LLM required) or feed prompt_for_llm_refinement.content to its configured model and replace the deterministic block with the refined response. This makes the server useful without a connected LLM and vendor-neutral when one is connected.

ToolInputOutput
translate_incoming{ text, channel?, thread_context?, target_language? }{ explicit_ask, likely_subtext[], ambiguity, recommended_next_action, model_provenance, eval_corpus_slice }
check_tone{ text, baseline_messages?, target_register?, channel? }{ axes, axes_target?, baseline_delta, flagged_phrases[], suggested_rewrite_hint, model_provenance, eval_corpus_slice }
rewrite_outgoing{ text, target_register, preserve_terms?, channel?, preserve_intent? }{ rewritten, preserved_terms[], unpreserved_terms[], diff_summary, model_provenance, eval_corpus_slice }
brief_meeting{ transcript, me, project?, speakers? }{ my_asks[], others_asks[], decisions[], ambiguous_items[], model_provenance, eval_corpus_slice }

Decode subtext, ambiguity, and the likely implicit ask in an incoming corporate message. Returns the explicit ask (or null if there is none), a ranked list of likely subtext hypotheses with confidence scores, ambiguity spans with character offsets, and a recommended next action.

  • channel is an enum: email | slack | linear | github | notion | gdocs | outlook | generic. Influences register expectations.
  • thread_context accepts up to twenty prior messages, oldest first.
  • target_language is BCP-47 (en, en-IE, de, ja). Used to select a language pack when one is registered.

Score an outgoing message on three axes — directness, warmth, urgency — on a 0..100 scale. 50 is neutral, <30 is notably low, >70 is notably high. When baseline_messages is supplied (at least three), baseline_delta reports how each axis diverges from the sender’s usual register in signed percentage points.

  • Does not rewrite. Pair with rewrite_outgoing to actually shift register.
  • flagged_phrases use {start_char, end_char, reason} — the same shape as translate_incoming.ambiguity.spans and brief_meeting.*.quoted_span for shared rendering.

Rewrite an outgoing message toward a target_register while preserving caller-named technical terms and the message’s underlying intent.

  • target_register enum: direct | warm | formal | concise | clarifying.
  • preserve_terms is a caller-supplied list of exact substrings (jargon, system names, ticket ids) that MUST appear verbatim in the rewrite. The server checks this with exact substring match and reports gaps in unpreserved_terms — but does not auto-retry. A non-empty unpreserved_terms is a soft signal the caller may surface or chain another rewrite.
  • preserve_intent defaults to true and SHOULD be left at the default.

Convert a transcript into a four-section brief: asks of the recipient, asks the recipient is making of others, concrete decisions, and ambiguous items quoted verbatim from the transcript.

  • transcript is 20–200,000 characters (roughly a 90-minute meeting). Longer transcripts MUST be chunked by the caller; the tool returns TRANSCRIPT_TOO_LONG otherwise.
  • me is required. Without a speaker label that identifies the recipient, the four-section partition is ill-defined; the tool returns ME_REQUIRED rather than guessing.
  • ambiguous_items[].quoted_span.text MUST equal input.transcript[start_char:end_char]. The server validates this on every response (including its own deterministic output) and raises VERBATIM_ANCHOR_FAILED if the model fabricates a span. This is anti-hallucination armour — a fabricated “ambiguous item” not in the transcript is worse than no brief at all.
CodeMeaning
VERBATIM_ANCHOR_FAILEDbrief_meeting produced an ambiguous item whose quoted_span.text did not match transcript[start_char:end_char]. Caller MUST surface; never silently retry.
TRANSCRIPT_TOO_LONGbrief_meeting transcript exceeded 200,000 characters. Caller chunks.
ME_REQUIREDbrief_meeting was called without a me label.
MODEL_UNAVAILABLEThe caller’s MCP client could not reach its configured LLM during refinement. The deterministic baseline is still returned; this error appears in the envelope only when the caller explicitly required refinement.
INPUT_TOO_LARGEAn input string exceeded its per-field cap. Caller MUST truncate before retrying.
  • The server stores no inputs. All text is in-memory for the call duration only.
  • The server logs structured event names and outcomes, never input text.
  • PII redaction is upstream (browser extension or caller). The server analyses whatever it is given.
  • model_provenance is required output: {mode, provider, model}. Surfaces cloud vs local honestly so a calling surface can render an accurate cloud-mode banner.
  • brief_meeting operates on third-party speech (meeting transcripts). Cloud-mode for brief_meeting SHOULD prompt the user with a stronger consent surface; that is the calling skill or extension’s responsibility, not the server’s.
  • v0.0.2 envelopes wrap the v0.1.0 wire contract. The envelope collapses to the wire contract once Phase 2 LLM-refinement flow is the default path.
  • Additive-only within the v0.1.x line. Channel enum, target-register enum, and error codes are closed at v0.1.0; additions are minor bumps.
  • English-only deterministic heuristics. BCP-47 target_language is accepted but only passed through to the prompt template.
  • No model_provenance from a real LLM. The deterministic analysis sets mode="unknown" on every response; a connected MCP client populates this in the refined response.
  • No eval-corpus integration yet. The eval_corpus_slice paths are recorded on every response, but the slices themselves are owned by eval-curator and land in Phase 2.
  • No streaming. Long meeting transcripts (>200k chars) must be chunked.