svg-annotate-mcp
svg-annotate-mcp
SVG-Artikelabbildungen direkt im Browser annotieren und senden – auf ein Element zeigen? No, translate properly:
SVG-Abbildungen von Papers im Browser annotieren – Elemente anklicken (Hover hebt das semantische Element unter dem Cursor hervor, im Claude‑Design-Stil) oder Bereiche auswählen. Die Annotationen (einschließlich der getroffenen SVG-Element-Informationen) werden per MCP an Claude Code zurückgegeben, woraufhin Claude Code die Quelldatei (SVG oder Generierungsskript) verändert; die Seite überwacht Dateiänderungen und aktualisiert sich automatisch – so entsteht ein geschlossener Kreislauf „Annotation → Änderung → Refresh → erneute Annotation“.
Backend: Python + offizielles
mcpSDK (MCPServer, stdio); im selben Prozess läuft zusätzlich ein stdlib-HTTP-Thread (temporärer Port auf 127.0.0.1).Frontend: eine einzelne Datei
src/svg_annotate_mcp/web/index.html. Das SVG wird perfetch+DOMParserin Shadow DOM injiziert (beidseitig isoliert von Seiten-CSS undid-Werten), und die Annotationen werden auf ein separates Overlay gezeichnet; die Element-Treffererkennung läuft beim Absenden im Browser.
Installation und Registrierung
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-mcpOptional: Den Timeout des MCP-Clients erhöhen, damit ein einzelner wait_for_annotations-Aufruf länger warten kann (Ohne Einstellung funktioniert es weiterhin, der Loop läuft häufiger.)Oder: In der Shell-Profile oder den Claude Code Settings unter env die Variable MCP_TOOL_TIMEOUT=600000 setzen.
Werkzeuge (4)
Werkzeug | Funktion |
| Öffnet das SVG im Browser. |
| Blockiert und wartet darauf, bis der Benutzer „An Claude Code senden“ klickt. Ein Timeout mit |
| Nicht blockierender Fallback: Holt den zuletzt übermittelten Batch (zur Wiederherstellung, wenn die Timeout-Kette abgebrochen ist). |
| Schiebt eine Statusmeldung in die Kopfleiste der Seite (z. B. „ fig_xxx.py ändere ich gerade, –”). Nach dem Ändern der Datei nicht aufrufen nötig; die Seite aktualisiert sich selbst. |
Elementgenaue Auswahl (v2)
Im Standardwerkzeug „Auswahl": Hover hebt das semantische Element unter dem Cursor live hervor (bei matplotlib z. B. die g[id]-Gruppen text_N/line2d_N/legend_N, es wird die kleinstflächige Treffer immer verwendet; der Chip zeigt id+Text). Ein Klick öffnet den Element-Inspektor (Seitenleiste mit id,, wörtlichen Text, Vorfahren-Brotkrumen – Klick auf die Krume wählt die übergeordnete Gruppe neu aus, z.B. text_54 → legend_1). Erst wenn im „Änderungshinweis“ ein Text eingegeben wird, wird eine Annotation erzeugt (reines Klicken = Inspektor, keinerlei Nullannotationen); Esc oder „Auswahl aufheben“ beendet. Element Annotationen werden auf dem Bild als gestrichelte Box undigerung der Nummer angezeigt.
Rückgabestruktur der Annotationen (für Claude Code geschaffen)
Jede Annotation enthält:
kind(element/rect/arrow/freehand/text),note(die Änderungsbeschreibung des Nutzers),number(die Nummer auf dem Canvas);Bei
kind:"element"zusätzlich dertarget: zugewiesen... :bei
kind:"element"gibt estarget:tag/id/text(wörtlich)/ancestors/d_prefix/bbox_svgdes Elementebes der angeklickten Elements – das ist die stärkste Verankerung; bevorzugt verwenden (id oder text direkt pergrepauf das Generation Skript/ SVG suchen);geometry_norm(0–1) undgeometry_svg(viewBox-Koordinaten, serverseitig bereits konvertiert);hits[]: die vom Auswahlbereich getroffenen SVG-Elemente; jedes mittag/id(semantische Gruppen wie matplotlibtext_N/line2d_N) /text(Element um Text unnötig? Elementtext, wörtlich) /ancestors(Vorfahren-id-Kette, z. B.["figure_1","legend_1","text_54"]) /bbox_svg/coverage/d_prefix(die ersten 30 Zeichen desd-Attributs des Pfades, ein grep-Anker beim direkten Ändern des SVG). Schon geRauschen: Hinter–Container entfernt, semantische Gruppen prioritär (Blätter in der Gruppe nicht doppelt), je Annotation max. 10 Einträge;texts_in_region: alle Texte im Auswahlbereich (im Kursübrigen, deduplikt) – der erste Hinweis für eine grep- Suche im Generierungsskript.
Wo geändert wird, entscheidet Claude Code: Wenn die Annotation source_script enthält, sollte zuerst das Skript und die Abbildung neu generiert werden (die SVG-Datei als Prodikat würde beim nächsten Lauf überschrieben); wenn kein Skript existiert, direkt die SVG-Datei bearbeiten. Die Seite macht keine Annahmen über die Änderungsmethode, sondern überwacht nur die Datei-mtime (500ms-Pollings, stabil über zweifache Zeitreihe, </svg> am Ende als Schreibschutz).
Lifecycle
Nicht mehr übernommen – Wording:
Nicht übermittelte (unkommittete) Entwürfe bleiben auch nach dem Refresh erhalten. Nach dem Klick auf „An Claude Code senden“ wird dieser (diesen) Stapel zu 35 % halbtransparent auf dem Bild behon (Nummer bleibt, damit man zuordnen kann); Die nächste Aktualisierung, die ausgelöst wird, weil Claude Code Dateien geändert hat, entfernt die halbtransparenten Annotationen.
Typischer Kreislauf
用户: 帮我改 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() # 等下一轮Tests
uv run python tests/smoke_test.py # 端到端:握手/HTTP/阻塞等待/坐标换算/SSE reload/复用 tab
uv run python tests/manual_driver.py <svg> [script] # 起 server 供手动/浏览器自动化测试,批次落盘 tests/out/batches.jsonlDebug-Parameter für die Seite: ?nosse=1 überspringt SSE (für Headless-Screenshots); ?autotest=x,y,w,h zeichnet und drückt nach dem Laden automatisch ein VB-Rechteck (0–1 normalisierte Koordinaten); ?autotest_click=x,y wählt das Element in diesem Punkt und drückt es automatisch ab (mit &autotest_stage=pick nur klick it den Hover, zum Screenshoten des Inspektors).
Umgebungsvariablen: SVG_ANNOTATE_NO_OPEN=1 sorgt dafür, dass open_svg den Browser nicht automatisch aufruft (für Tests).
Bekannte Grenken (der ersten Version)
Einzelsitzung (ein Bild zur Zeit; erneutes open wechselt das Bild); keine Konkurrenz (mehrere Claude-Concurrent-Sitzungen behindern sich nicht, da getrennte Server); keine Export von annotations.json (Annotationen werden nur im Speicher übergeben, gehen beim Server-Neustart verloren, Rückhalt komplett über die Claude-Kontext); externen Bilder/Ressourcen in SVG werden nicht proxied (open_svg gibt eine Warnung aus; matplotlib-Outputs sind alle eingebettet, lösen das nicht aus); nur macOS open öffnet Browser; localhost ist ohne Authentifizierung.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Real-time collaborative whiteboard — AI agents and humans edit the same board live over MCP.
Live browser debugging for AI assistants — DOM, console, network via MCP.
Cross-agent artifact workspace with provenance across Claude Code, Codex, Cursor, LangGraph.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/sunjianbo-123/svg-annotate-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server