Skip to main content
Glama

svg-annotate-mcp

Аннотирование SVG-рисунков к статьям прямо в браузере — клик по элементу (при наведении подсвечивается семантический элемент, в стиле Claude Design) или выделение области. Аннотация (включая информацию о задетых SVG-элементах) передаётся обратно в Claude через MCP; Claude изменяет исходный файл (SVG или генерирующий скрипт), а страница следит за изменениями файла и автоматически обновляется, образуя цикл «аннотация → изменение → обновление → повторная аннотация».

  • Бэкенд: Python + официальный SDK mcp (MCPServer, stdio), в процессе запускается HTTP-поток из стандартной библиотеки (127.0.0.1, временный порт).

  • Фронтенд: один файл src/svg_annotate_mcp/web/index.html. SVG через fetch + DOMParser добавляется в Shadow DOM (двусторонняя изоляция от стилей и id страницы); аннотации рисуются на отдельном оверлее; при отправке определение попаданий выполняется на стороне браузера.

Установка и регистрация

cd ~/Projects/svg-annotate-mcp && uv sync
claude mcp add --scope user svg-annotate -- \
  uv run --directory /Users/boryant/Projects/svg-annotate-mcp svg-annotate-mcp

Необязательно: ослабьте таймаут MCP-клиента, чтобы один вызов wait_for_annotations мог ждать дольше (можно и без этого, просто цикл будет опрашивать чаще): задайте MCP_TOOL_TIMEOUT=600000 в профиле shell или в env настроек Claude Code.

Related MCP server: Browser Feedback MCP

Поверхность инструментов (4)

Инструмент

Действие

open_svg(svg_path, source_script="", title="")

Открывает SVG в браузере. В source_script передаётся путь к скрипту, который генерирует этот рисунок (например, fig_*.py для matplotlib); затем каждая партия аннотаций возвращается вместе с ним как есть. Если страница уже открыта, вкладка переиспользуется (вызывается session-событие для смены рисунка).

wait_for_annotations(timeout_s=120)

Блокирует выполнение, пока пользователь не нажмёт «Отправить в Claude». Возврат status:"timeout" — это не ошибка — если нужно продолжить, просто вызовите ещё раз немедленно (цикловой протокол, это указано и в описании инструмента).

get_annotations()

Неблокирующий запасной вариант: отдаёт последнюю партию отправленных аннотаций (для восстановления контекста после обрыва цепочки ожидания).

set_status(message)

Отправляет статус в верхнюю панель страницы (например, «правлю fig_xxx.py и перезапускаю…»). После изменения файла вызывать её не нужно — страница обновится автоматически.

Выбор элемента по клику (v2)

По умолчанию работает инструмент «Выбор»: при наведении сразу подсвечивается семантический элемент под курсором (для matplotlib — это группы text_N/line2d_N/legend_N и другие g[id]; берётся минимальная по площади область попадания), на выноске показывается id+текст. Клик открывает инспектор элементов (в боковой панели: id, точный текст, хлебные крошки предков — по ним можно переключиться на родительскую группу, например text_54 → legend_1); аннотация создаётся только после ввода текста в поле «Описание изменения» — обычный клик означает только инспектор и не создаёт мусорных аннотаций. Esc или «Отменить выбор» закрывает инспектор. Элементные аннотации на рисунке отображаются пунктирной рамкой с номером.

Структура возвращаемых аннотаций (расчёт на то, что Claude найдёт объект)

Каждая аннотация содержит:

  • kind (element/rect/arrow/freehand/text), note (пользовательское описание изменения), number (номер на холсте);

  • для kind:"element" также есть target: tag/id/text (точный текст)/ancestors/d_prefix/bbox_svg выбранного элемента — это самый надёжный якорь, используйте его в первую очередь (ищите по id или text в генерирующем скрипте или в SVG);

  • geometry_norm (0–1) и geometry_svg (координаты viewBox, пересчитаны на сервере);

  • hits[]: задетые выделением элементы SVG; каждый содержит tag/id (семантические группы matplotlib, например text_N/line2d_N)/text (точный текст элемента)/ancestors (цепочка родительских id, например ["figure_1", "legend_1", "text_54"])/bbox_svg/coverage/d_prefix (первые 30 символов строки d у path — якорь для grep при прямой правке SVG). Выполнена очистка от шума: фоновые контейнеры отбрасываются, семантические группы имеют приоритет (листья внутри групп не дублируются), не более 10 элементов на запись;

  • text_region_region: все тексты внутри выделенной области (в порядке чтения, без дубликатов) — первая зацепка для поиска по grep в генерирующем скрипте.

Что изменять — решает Claude: если в аннотации есть source_script, сначала изменить скрипт и запустить его заново (изменение SVG-результата будет перезаписано при следующем запуске); если скрипта нет — править файл SVG. Страница не предполагает способа изменений, она отслеживает только изменение mtime файла (опрос каждые 500 мс, проверка стабильности значения, проверка окончания </svg> против записи половины файла).

Жизненный цикл аннотаций

Неотправленные черновики аннотаций сохраняются после обновления страницы; после нажатия «Отправить в Claude» эта аннотация становится полупрозрачной (35%) и остаётся на рисунке (номер сохраняется для сопоставления); следующее обновление, вызванное изменением файла в Claude, удаляет полупрозрачные аннотации.

Типовой цикл

用户: 帮我改 figure11,我来圈
Claude: open_svg("/path/figures/figure11.svg", source_script="/path/fig_tri_complement.py")
        wait_for_annotations()          # 挂起
用户: (浏览器里圈图例写「图例移到右上」,点提交)
Claude: 收到批注 → set_status("正在改 fig_tri_complement.py…")
        → 改脚本 → 重跑出图 → 页面自动刷新
        → wait_for_annotations()        # 等下一轮

Тестирование

uv run python tests/smoke_test.py     # 端到端:握手/HTTP/阻塞等待/坐标换算/SSE reload/复用 tab
uv run python tests/manual_driver.py <svg> [script]   # 起 server 供手动/浏览器自动化测试,批次落盘 tests/out/batches.jsonl

Отладочные параметры страницы: ?nosse=1 — отключить SSE (для headless-скриншотов); ?autotest=x,y,w,h — после загрузки автоматически нарисовать прямоугольную аннотацию и отправить её (координаты нормализованы 0–1); ?autotest_click=x,y — кликнуть по элементу в этой точке и отправить аннотацию (если добавить &autotest_stage=pick, будет только выбор и подсветка — для скриншотов инспектора).

Переменные окружения: SVG_ANNOTATE_NO_OPEN=1 — заставляет open_svg не открывать браузер автоматически (для тестов).

Возвестные ограничения (первая версия)

Одна сессия на рисунок (один рисунок за раз, новый вызов open_svg просто меняет рисунок; несколько сессий Claude работают с независимыми экземплярами сервера, не мешая друг другу); не реализован экспорт annotations.json (аннотации передаются только через память, теряются при перезапуске сервера — надёжный источник сохранности — контекст Claude); внешние ресурсы внутри SVG не проксируются (open_svg выдаст предупреждение; выдача matplotlib всегда встроена, поэтому она не сработает); на macOS только open может открывать браузер; localhost без аутентификации.

Available Tools

4 tools
get_annotationsA

非阻塞地取最近一批已提交的批注(wait_for_annotations 的兜底)。

用于超时链中断后恢复现场;没有批注时返回 status="empty"。
NameRequiredDescriptionDefault

No parameters

TDQS

A3.5/5.0
Behavior2/5

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

No annotations are provided, so the description carries the full burden. It reveals that the operation is non-blocking and mentions the empty status, but does not explain what it returns on a success path (e.g., does it return a list of annotations or a status?), nor whether the fetch consumes the annotations. This is a significant gap since there is no output schema.

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 concise, two sentences, with the core purpose stated first. It fronts the key information (non-blocking fetch, fallback for wait_for_annotations, purpose) and includes an edge-case note. No fluff.

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

Completeness3/5

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

The tool is simple (no parameters, no output schema), so the description needs to explain the return value. It only mentions the empty case (status='empty') and leaves the non-empty case unspecified. Without an output schema, this is a notable gap for an agent that needs to interpret the result. The purpose and context are clear, but return details are incomplete.

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

Parameters4/5

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

The tool has zero parameters and the schema coverage is 100% (vacuous). Since there are no parameters, the description is not required to add any parameter semantics. Baseline of 4 is appropriate.

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

Purpose4/5

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

The description identifies a clear verb (non-blocking fetch), a specific resource (recent committed annotations), and explicitly frames it as a fallback to wait_for_annotations, which distinguishes it from that sibling. However, the terms 'recent batch' and 'committed' are not defined, leaving some ambiguity about scope.

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

Usage Guidelines4/5

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

The description provides a clear usage hint: it is for recovering context after an interrupted timeout chain. It also states the edge case of returning status='empty' when no annotations exist. It does not explicitly rule out other tools like open_svg or set_status, but the context is sufficient.

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

open_svgA

在浏览器中打开一个 SVG 图,供用户圈选区域写批注。

打开后应调用 wait_for_annotations 等待用户提交批注。
svg_path 必须是绝对路径。source_script 可选:该 SVG 的生成脚本路径
(如 matplotlib 的 fig_*.py);之后每批批注都会原样带回该路径,
便于判断是改 SVG 文件还是改脚本重跑。title 可选,显示在页面顶栏。
NameRequiredDescriptionDefault
titleNo
svg_pathYes
source_scriptNo

TDQS

A4.1/5.0
Behavior3/5

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

No annotations are provided, so the description carries the full behavioral burden. It discloses the browser-opening side effect, the requirement to await user annotations, and the behavior that source_script is echoed back with each annotation batch. However, it does not clarify whether the tool mutates the SVG file, what the immediate return value is, or what happens if the user cancels without annotating. The disclosed behaviors are useful but incomplete for a tool with zero annotation coverage.

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 compact and front-loaded, leading with the core purpose before elaborating on parameters. Each sentence adds distinct information: the workflow step, the path requirement, the source_script semantics, and the title behavior. Minor redundancy exists between the opening line and the operational details, but overall it is efficient with no filler.

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

Completeness4/5

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

For a tool with no annotations and no output schema, the description is reasonably complete: it covers purpose, the required follow-up action, parameter semantics, and the round-trip behavior of source_script. Gaps remain around the return value format and error/cancel handling, but these are not critical for an agent determining whether and how to invoke the tool correctly.

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

Parameters4/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 fully compensate. It does: svg_path must be absolute (syntax constraint), source_script is contextualized as the generation script (e.g., matplotlib fig_*.py) with its return behavior explained, and title is described as appearing in the top bar. This adds real meaning beyond the bare property names and types for all three parameters, nearly closing the coverage gap.

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?

The description states a specific verb+resource ('打开一个 SVG 图') with clear intent (供用户圈选区域写批注). It clearly differentiates from sibling tools: wait_for_annotations and get_annotations are about retrieving annotation data, whereas this tool handles the opening/display action. The purpose is unambiguous and contains no tautology.

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

Usage Guidelines4/5

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

Explicitly instructs the agent to call wait_for_annotations after opening, establishing the correct sequential workflow. It also clarifies the conditional choice between editing the SVG vs. re-running the source script via the source_script parameter. It lacks explicit when-not-to-use guidance but provides solid operational direction; the alternating tool routing is implied through sequential instructions rather than named exclusions.

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

set_statusA

向批注页面顶栏推送一条状态文字,如「正在修改 fig_xxx.py 并重跑…」。

修改开始前调用一次,能让用户知道 Claude 正在干活;改完文件后
页面会因文件变化自动刷新,无需再调用本工具通知。
NameRequiredDescriptionDefault
messageYes

TDQS

A4/5.0
Behavior3/5

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

无任何注释,描述须独立承担行为披露责任。它说明了推送状态文字的行为,并解释了自动刷新机制导致无需再次调用,提供了基本行为上下文。但未说明消息的显示时长、是否覆盖旧消息、失败处理等细节,行为透明度有限。

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

Conciseness5/5

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

描述仅两句话:第一句明确动作并给出示例,第二句补充使用时机和自动刷新逻辑。内容紧凑、无冗余,关键信息前置,结构合理,是一份高效规范。

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

Completeness4/5

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

工具简单(单参数,无输出模式),描述涵盖了用途、时机和副作用(自动刷新的自解释)。虽然没有详细的行为细节(如消息清除方式),但鉴于工具的简单性,描述已足够让代理正确调用。

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

Parameters3/5

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

输入模式中message参数仅有标题“Message”,无描述,schema描述覆盖率为0%。描述通过示例「正在修改 fig_xxx.py 并重跑…」暗示了参数应包含的文本内容,这为代理提供了有用的语义补充,但未明确参数格式、长度限制或是否必须为字符串,补偿不完整。

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?

描述明确说明工具是“向批注页面顶栏推送一条状态文字”,并给出具体示例「正在修改 fig_xxx.py 并重跑…」。动词和资源明确,与兄弟工具(open_svg、wait_for_annotations、get_annotations)功能截然不同,区分度高。

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

Usage Guidelines4/5

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

描述给出了明确的使用时机:“修改开始前调用一次”,以及何时不使用:“改完文件后页面会因文件变化自动刷新,无需再调用本工具通知”。这提供了清晰的when和when-not,但没有提及替代工具(尽管兄弟工具功能不同,不需要排除)。

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

wait_for_annotationsA

阻塞等待用户在浏览器里提交批注,提交后立即返回批注内容。

重要协议:返回 status="timeout" 表示用户还没提交,这不是错误——
若仍在等待用户批注,应立即再次调用本工具继续等待,直到拿到
status="submitted" 或用户在对话里明确说不批注了。
返回的每条批注含:kind(rect/arrow/freehand/text)、note(用户文字)、
geometry_svg(viewBox 坐标)、hits(命中的 SVG 元素:id/文字/祖先链,
用于在 SVG 源文件或生成脚本中定位)、texts_in_region(选区内的文字)。
NameRequiredDescriptionDefault
timeout_sNo

TDQS

A4.1/5.0
Behavior5/5

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

With no annotations provided, the description carries full responsibility for behavioral disclosure. It meticulously explains the blocking behavior, the timeout status as non-error, the retry protocol, and the detailed structure of each returned annotation (kind, note, geometry_svg, hits, texts_in_region). It also clarifies that timeout is not an error and how to proceed. This is exceptionally transparent for a wait operation.

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

Conciseness5/5

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

The description is well-organized: it opens with the core purpose and immediate return, then clearly explains the timeout protocol, and finally lists the annotation fields. Every sentence serves a purpose, with no redundant phrasing. It is concise yet comprehensive, front-loading the most important behavioral information.

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

Completeness4/5

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

The description is thorough for a wait tool: it covers the blocking behavior, timeout handling, retry instructions, and the full return payload structure. It does not describe error scenarios (e.g., if the session expires) or what happens if the user submits invalid annotations, but given that there is no output schema and the tool is relatively simple, the provided details are largely sufficient. A small gap prevents a perfect score.

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

Parameters3/5

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

The schema has 0% description coverage for the single parameter timeout_s (default 120), and the description does not explicitly explain this parameter. However, the description mentions status='timeout' and the retry protocol, which implies that the tool waits for a specified period. This indirect inference is not as clear as explicitly stating 'timeout_s is the maximum wait time in seconds.' The description adds some context but doesn't fully compensate for the lack of schema detail, so a 3 is appropriate.

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

Purpose4/5

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

The description clearly states the tool's purpose: '阻塞等待用户在浏览器里提交批注' (blocks waiting for user annotations) and that it returns the annotation content immediately upon submission. It identifies the specific verb 'wait' and the resource 'annotations', making it distinct from siblings like get_annotations (which likely retrieves existing annotations) and open_svg. However, it doesn't explicitly name a sibling alternative, so it stops short of a 5.

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

Usage Guidelines4/5

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

The description provides explicit instructions on when to use this tool: it should be called when waiting for user annotations, and if status='timeout', it should be called again to continue waiting. It also defines a clear stopping condition: until status='submitted' or the user explicitly declines to annotate. It doesn't discuss when not to use it relative to siblings, but the protocol is sufficient for correct usage.

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

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updatesv0.1.0
    • First observedget_annotations
    • First observedopen_svg
    • First observedset_status
    • First observedwait_for_annotations

TDQS

A4.1/5.0

Scored across 4 tools

Disambiguation5/5

每个工具职责清晰唯一:打开、等待、获取、状态推送,互不重叠,边界明确。open_svg 负责启动,wait_for_annotations 阻塞等待,get_annotations 非阻塞兜底,set_status 用于反馈,无混淆可能。

Naming Consistency5/5

所有工具均采用 snake_case 的动词_名词结构(open_svg, wait_for_annotations, get_annotations, set_status),动词清晰且规律一致,无混用风格。

Tool Count5/5

4 个工具覆盖了 SVG 批注交互的完整核心流程,每个工具都有不可替代的作用,没有冗余或缺失,数量恰到好处。

Completeness5/5

工具集覆盖了打开、等待提交、非阻塞获取和状态通知,生命周期闭环。没有明显的缺失操作,且描述了超时续等和兜底恢复机制,足以支持用户与 agent 的完整交互。

Maintenance

ActivityStale
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables visual annotation on web pages for Claude Code, allowing element selection, comment addition, screenshot capture, and structured UI feedback for code fixes via an MCP server.
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Enables visual browser feedback collection directly into Claude Code. Users can point at elements in their browser and send annotated feedback that Claude can act on immediately.
    12
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables drawing annotations directly on local web pages and sending screenshots, DOM data, and annotation context to your IDE agent for precise code edits.
    28 npm
    3
    MIT