Skip to main content
Glama

format_text

Apply bold, italic, or underline styling to exact matching text in Google Docs without altering content, even inside merged table cells. Returns proof of style changes.

Instructions

Apply character styling (bold/italic/underline) to a matched text span.

Use this tool when you need to style existing text in place — bold a phrase, un-bold it, italicize it — without touching its content. Unlike replace_text (which deletes and reinserts text and cannot express styling), this tool compiles ONLY updateTextStyle requests, so it is safe to use inside a table cell even when the table has hand-merged cells: no delete/insert/merge request is ever compiled, and the response reports every compiled_request_kinds entry so that claim is checked, not just asserted.

Call list_tabs first to get the tab_id, then read_document to confirm the text you want to style is present as-is. style maps any of bold/italic/underline to true or false — e.g. {"bold": true} to bold, {"bold": false} to un-bold. At least one key is required.

Matching uses the same normalization ladder and match-count guard as replace_text (exact → curly/straight quote equivalence → NBSP/whitespace collapse → soft-hyphen strip; refuses unless the match count equals expected_matches). If the matched text already carries every requested style value, the call is a no-op: it returns applied: true, style_mutated: false, and issues no write at all (so an idempotent re-run does not create a new document revision).

The response includes, per matched span, the actual textRun style flags before and after (runs_before/runs_after) — not a markdown or plain-text diff, since genuine bold and a literal **word** both render identically as text. content_mutated is always false, proven by compiled_request_kinds containing only updateTextStyle. Style reflects textRun.textStyle only: a heading rendered bold by its named/paragraph style rather than an explicit run style will not show bold: true here, matching every other style read in this server. A pending style-only suggestion on the target span is allowed through (see SUGGESTIONS_PRESENT below) and evidence reflects the base, non-suggested style, same as every read in this server.

Set dry_run=True to preview the operation without writing; the response carries applied: false and a predicted runs_after (the requested fields overlaid on the current runs) but makes no API call.

Errors are returned as typed envelopes with error_code, message, diagnostics, and retryable so the caller can act on them precisely: ZERO_MATCH – find string not found; near-miss span included MATCH_COUNT_MISMATCH – wrong number of matches; all locations listed STRUCTURAL_BOUNDARY – match crosses a paragraph or table-cell boundary REVISION_CONFLICT – document changed mid-call; re-read and retry VERIFICATION_FAILED – the write landed but could not be confirmed on re-read; check diagnostics before assuming a manual restore is needed — a concurrent edit near the target text is a common, benign cause INVALID_INPUT – empty find, or style is empty/unknown-key/non-bool TAB_NOT_FOUND – tab_id not in document; available tabs listed SUGGESTIONS_PRESENT – tab has a pending suggested insertion/deletion (not a style suggestion); accept/reject it in the Docs UI first, then retry

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
findYes
styleYes
doc_idYes
tab_idYes
dry_runNo
expected_matchesNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Schema Changelog

Changes observed during successful MCP inspections.

  1. First observedv0.2.0

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure, and it delivers extensively: idempotent no-op behavior ('returns applied: true, style_mutated: false, and issues no write'), the compiled_request_kinds proof that content_mutated is always false, response shape (runs_before/runs_after), the textRun.textStyle-only caveat, the suggestion nuance, dry_run semantics, the normalization ladder, and a documented typed-error envelope with nine codes. All are disclosed, not asserted.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long, but the length is earned: it disentangles many edge cases (no-op, suggestions, heading-style reads, dry_run, merge cells). It is front-loaded with purpose and usage before descending into behavioral detail, and the error list is structured. Minor redundancy exists — the compiled_request_kinds proof appears twice and 'same as every read in this server' recurs near-identically — so it is not perfectly trimmed, but it earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 6-parameter tool with no annotations, this is complete: all parameters are semantically grounded, prerequisites are given, return-value semantics are described (runs_before/runs_after, content_mutated, applied, style_mutated) despite an output schema existing, error handling is exhaustive, and the sibling boundary with replace_text is explicit. There is no meaningful gap an agent would hit when deciding to call or invoke this tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it covers nearly every parameter: style is fully specified with key/value semantics and an example ('{"bold": true} to bold, {"bold": false} to un-bold. At least one key is required'), dry_run is explained with its response contract, expected_matches is grounded in the match-count guard, tab_id has an acquisition path via list_tabs, and find is described through the matching semantics and ZERO_MATCH error. Only doc_id is left implicit, which is acceptable for a self-evident document identifier.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb+resource statement: 'Apply character styling (bold/italic/underline) to a matched text span.' It explicitly contrasts with replace_text ('which deletes and reinserts text and cannot express styling') and pins the scope to in-place styling without content mutation, so an agent can distinguish it from its siblings at a glance.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit when-to-use guidance ('Use this tool when you need to style existing text in place... without touching its content'), names the alternative (replace_text) and why format_text wins in a specific scenario (table cells with hand-merged cells), and states the prerequisite call sequence: 'Call list_tabs first to get the tab_id, then read_document to confirm the text you want to style is present as-is.'

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.