geogebra-mcp-bridge
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@geogebra-mcp-bridgecreate a GeoGebra canvas and plot y = x^2, then export it as PNG"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
geogebra-mcp-bridge
独立程序:MCP over stdio,把浏览器里的 GeoGebra 交给任何支持 stdio 的 MCP 客户端。 不依赖 DeepSeek Harness。
GeoGebra 是浏览器里的 GWT 应用,只认页面上的 ggbApplet JS API,没有跨进程接口。
所以本程序自己托管一个查看器页面,页面加载完 GeoGebra 后经 SSE 连回来,
页面上的 API 就是全部可操作能力:
MCP client (stdio) ──► geogebra-mcp-bridge ──► 127.0.0.1:3460
│ ├─ / 查看器页面
│ ├─ /client.js 页面侧的桥
│ ├─ /GeoGebra/** GeoGebra 离线包
│ ├─ /events SSE 下行(发命令)
│ ├─ /rpc 页面回投结果
└────── MCP tools ───────┴─ /api/status 自检
mcp__geogebra__* /api/pending 等用户确认「已打开」
/api/pending/confirm 用户的选择下载
内容 | 地址 |
本仓库(MCP server) | |
最新源码 ZIP | https://github.com/myLiLingyun/GeoGebraMCPServer/archive/refs/heads/main.zip |
DSH 插件仓库 |
git clone https://github.com/myLiLingyun/GeoGebraMCPServer.git本仓库不包含 GeoGebra 离线包。GeoGebra 官方离线包约 32 MB、解压后 100 MB 以上, 按 GeoGebra 自己的非商业许可分发,所以请从官方地址单独下载(见下)。
Related MCP server: lunar
要求
Node.js ≥ 20(
node --version确认)Git(或直接下载上面的 ZIP)
一个本机浏览器:Firefox / Chromium / Edge 均可,用来打开查看器页面
GeoGebra 离线包 5.4.932.1:解压后含
GeoGebra/deployggb.js与GeoGebra/HTML5/5.0/web3d/可选:DeepSeek Harness,用来获得「数学模式 / 数学模式+」和网页确认框; 不装 DSH 也能作为普通 MCP server 使用
程序不启动浏览器,也不跑 GeoGebra 内核:没有页面连上来时,工具返回一句可读的
中文,并给出查看器地址。canvas_create 会先把地址交给用户的网页界面(确认框),
本机有图形环境时也可以自己把浏览器拉起来(见下)。
MCP 客户端断开(stdin 收到 EOF/close)或进程收到 SIGTERM / SIGINT / SIGHUP 时, 桥会关掉 HTTP 服务并退出,把查看器端口放掉——HTTP 监听会把事件循环撑住,不主动退出 就会留下一个仍占着端口的孤儿进程。
安装
推荐把两个仓库和离线包放在同一个父目录里,这样桥的默认路径能直接找到离线包:
geogebra/
├── GeoGebraMCPServer/ ← 本仓库
├── GeoGebraDSHPlug/ ← DSH 插件(可选)
└── geogebra-math-apps-bundle/ ← GeoGebra 官方离线包
├── README.txt
└── GeoGebra/
├── deployggb.js
└── HTML5/5.0/web3d/1. 下载两个仓库
mkdir -p ~/geogebra && cd ~/geogebra
git clone https://github.com/myLiLingyun/GeoGebraMCPServer.git
git clone https://github.com/myLiLingyun/GeoGebraDSHPlug.git # 只用 MCP server 时可跳过只想用 MCP server 时,也可以把 ZIP 解压到任意目录,后面的路径按实际位置替换。
2. 下载并解压 GeoGebra 离线包
官方下载地址(当前指向 geogebra-math-apps-bundle-5-4-932-1.zip):
cd ~/geogebra
curl -L -o geogebra-math-apps-bundle.zip \
https://download.geogebra.org/package/geogebra-math-apps-bundle
unzip geogebra-math-apps-bundle.zip -d geogebra-math-apps-bundle也可以从 https://www.geogebra.org/download 的 “GeoGebra Math Apps Bundle” 下载。 解压后确认这一层文件存在:
test -f ~/geogebra/geogebra-math-apps-bundle/GeoGebra/deployggb.js && echo OK离线包放在别处也可以,只要启动时用
--ggb-root或GGB_ROOT指过去。 仓库的.gitignore已排除它,不要把离线包提交进 git。
3. 安装 Node 依赖
cd ~/geogebra/GeoGebraMCPServer
npx --yes pnpm@12 install没有 pnpm 时 npm install 也可以(会生成 package-lock.json,已被忽略)。
运行时依赖只有 @modelcontextprotocol/server 与 zod。
4. 自检
node test/list-tools.mjs这条不需要浏览器和 GeoGebra 内核,会按 stdio 启动桥、列出 14 个工具、跑完协议断言。 要连真浏览器和真 GeoGebra 再跑:
node test/e2e-browser.mjs # 需要 firefox;产物写到 ./verify/接到 MCP 客户端
任何支持 stdio 的 MCP 客户端都可以直接用。配置里的路径换成你机器上的绝对路径:
{
"mcpServers": {
"geogebra": {
"command": "node",
"args": ["/home/you/geogebra/GeoGebraMCPServer/bin/geogebra-mcp-bridge.mjs"],
"env": {
"GGB_ROOT": "/home/you/geogebra/geogebra-math-apps-bundle"
}
}
}
}按上面的推荐布局安装时,
GGB_ROOT可以省略(桥默认找仓库上一级的geogebra-math-apps-bundle/)。Windows 把
command改成node.exe的绝对路径,路径分隔符用\\或/。客户端连上后会出现
mcp__geogebra__*工具;先调canvas_create,再打开它返回的地址。接 DeepSeek Harness 不用手写这段配置,装 GeoGebraDSHPlug 即可, 它会在「数学模式 / 数学模式+」里自动挂载本桥。
运行
cd ~/geogebra/GeoGebraMCPServer
node bin/geogebra-mcp-bridge.mjs # 在 stdin/stdout 上提供 MCP
node bin/geogebra-mcp-bridge.mjs --help # 用法
node bin/geogebra-mcp-bridge.mjs --version # 版本
node bin/geogebra-mcp-bridge.mjs --port 3461 --ggb-root /path/to/geogebra-math-apps-bundle选项 / 环境变量 | 说明 |
| GeoGebra 离线包目录,默认与本仓库同级的 |
| 查看器 HTTP 端口,默认 |
| 监听地址,默认 |
| 本地回答,不启动任何服务 |
启动后按 stderr 上打印的地址打开查看器,页面加载完 GeoGebra 就会自动连上桥。
用 canvas_create 工具建画布时,工具返回里会带上该画布专属的地址(?canvas=cN&app=…)。
查看器页面
页面参数都在 URL 查询串里:
参数 | 说明 |
|
|
|
|
|
|
|
|
| 界面语言,默认 |
| 初始布局串(如 |
页面右上角有个连接状态小徽章,显示 GeoGebra 版本与对象数;控制台里
window.__GGB_BRIDGE__ 暴露 clientId、api() 与 events() 便于手工排查。
页面侧只做四件事:保证 applet 就绪、把方法名映射到 API、把异常变成可读文本、 把构造与用户交互记成事件流。所有业务判断与排版都在 MCP 进程里。
工具(14 个)
工具 | 说明 |
| 自检:HTTP 服务、离线资源、画布清单(id / 界面 / 地址 / 是否连上);不碰页面,随时可跑 |
| 建画布:返回 id + 要打开的地址; |
| 释放画布:让页面 |
| 五段说明: |
| 对象清单(名称/类型/可见/颜色/值/定义),可按类型过滤 |
| 单个对象详情(定义、非本地化写法、LaTeX、坐标、样式…) |
| 用户操作与构造变化,读取即清空 |
| 出图给用户看: |
| 读:工具、可见坐标范围、网格/坐标轴、视口像素、布局;写:范围/网格/轴/布局/工具/缩放 |
| 执行 GeoGebra 命令(主力); |
| 按属性名设对象样式或数值(19 种属性) |
|
|
| 整份构造的 |
| PNG / SVG / PDF,写文件或直接返回内容;png 可用 |
GeoGebra 没有「成功/失败」信号,eval 用的是「有没有变化」
这一点值得单独说清楚,因为它决定了 eval 的返回怎么写:
evalCommand(cmd)对SetColor/Delete/ZoomIn这类不新建对象的命令返回false, 哪怕它确实执行成功了;evalCommandGetLabels(cmd)对这类命令与真正的语法错误返回的都是null。
所以页面侧的判据是「有没有产生可观察的变化」:新建了对象,或者构造/视图 XML 变了,
就算成功;什么都没变,才报「没有产生任何变化,多半是语法或参数错了」。
构造 XML 超过 1 MB(比如内嵌了图片)时放弃比对,返回「无法判断」,让模型自己用
objects 复核。代价是每次 eval 多取一次 getXML(),对正常规模的构造可以忽略。
另一个实测结论:自动命名会撞车。Segment(A,B) 会自己挑一个空闲小写字母
(常常正好是 f),此后 f(x)=x^2 会把那条线段改写成函数。eval 的返回里会列出
新建对象的真实名字,照它往下写就不会错;要更稳就给对象显式命名(s=Segment(A,B))。
CAS 需要先打开一次 CAS 视图
evalCommandCAS 在 CAS 视图从未打开过时一律返回 "?"。查看器因此在加载时做一次
预热:短暂打开 CAS 视图,探到引擎就绪(用 evalCommandCAS("1+1") 探)再切回目标布局。
只有 classic / suite 带 CAS;3d / geometry 会明确报「CAS 没有返回结果」。
另外 CAS 会把结果行(例如积分常数 c_{1})作为对象放进构造,返回里会列出这些新对象名。
canvas_create 不说假话
它默认分两步:先在用户的网页界面弹确认框(登记请求 → 等用户打开地址 → 等用户 点「已打开」),确认之后才返回 id;没人能点确认时退回老路径。老路径的判据是结果:
本进程没有图形环境(linux 且
DISPLAY/WAYLAND_DISPLAY都没设)→ 立刻告诉你 弹不出窗口、请手动打开地址,不去做注定失败的尝试;否则依次试
browser(命令行,可带参数,如"firefox --new-window",默认firefox、xdg-open),再用最多 8 秒等页面连上来:连上了才算成功,没连上 就报错并给出地址与退出码。
浏览器进程「启动成功」不等于「有窗口看得见」:在没有 DISPLAY 的进程里,firefox
会立刻退出,spawn 却不会报错。这条是实测改出来的:DSH 进程没有 DISPLAY,早期
实现回了「已用 firefox 打开」,模型为此白跑了 5 步、最后只能问用户要地址。
确认框(等用户把画布打开)
canvas_create 建好画布之后默认不立刻返回,而是登记一条请求并挂住这次调用,
让用户真的把画布打开、再确认已经打开,然后才把 id 交给模型:
Agent: canvas_create
│ 桥建好 c1,登记一条等待请求(默认最多等 5 分钟)
│
├─ 浏览器界面(DSH 的 geogebra-bridge-ui 插件)轮询 GET /api/pending
├─ 弹窗里给出蓝色可点的画布地址;页面连上之前「已打开,继续」是灰的
├─ 用户点开地址 → 页面连回桥 → 弹窗状态变「页面已连上」
└─ 用户点「已打开,继续」→ POST /api/pending/confirm {id, action:"opened"}
→ 挂住的调用解除,工具返回「用户已在…确认框里点过「已打开」」工具参数:
参数 | 说明 |
| 是否弹确认框,默认 |
| 等用户点确认的上限,默认 |
| 自动化路径:用无界面浏览器打开,同时等于关掉确认框 |
三条兜底(都不会把模型永久卡住):
情况 |
| 结果 |
用户点「跳过,先继续」/ 按 Esc |
| 立刻返回 id,说明用户跳过了 |
等了一小段(默认 4 秒)仍没有任何界面在轮询;或界面已经超过 10 秒没来问过 |
| 走老路径:自己试 |
界面在,但用户一直没点 |
| 超时返回 id,提示用 |
期间画布被 |
| 返回「请求作废」 |
「界面在不在」是实际观测出来的:GET /api/pending 每被问一次就刷新一次时间戳。
所以脱离 DSH 单独用这个桥(没有界面插件)时,行为就是老行为,不会白等。
挂到 DSH 时 toolCallTimeoutMs 要大于 confirmTimeoutMs,否则等确认的调用会先被
宿主掐断(bundle 里用 600000)。
画布(canvas):显式句柄
一个「画布」= 一个浏览器里跑着的 GeoGebra 页面,用短 id 指代(c1、c2…)。
这是为了消掉「同时开着好几个页面时,工具到底操作哪一个」的歧义——以前按「最近活跃」
猜,现在由调用方明确指定:
canvas_create {app: "3d"} → 画布 c1 已建好(3d 界面)。
地址:http://127.0.0.1:3460/?canvas=c1&app=3d
默认先在网页界面的确认框里等用户点「已打开」;
没人能点确认时退回「自己拉起浏览器 / 把地址给用户」
objects {id: "c1"} → 读 c1 的画布
eval {id: "c1", command: "A=(1,2)"}
canvas_release {id: "c1"} → 页面里的 applet 被真正拆除,记录删除页面通过 URL 上的
?canvas=c1认领画布;/events、/hello都把 id 带回来, 桥据此把 SSE 通道绑到画布上。一个画布同时只认最后一条连接(页面刷新会重连)。地址里没有
canvas参数的手工页面会被自动分配auto-1、auto-2…,也能用。画布在页面断开后记录保留(用户刷新后还能接回来),只有
canvas_release才删。 释放时桥会先让页面自己调ggbApplet.remove()(真正回收内核内存)再删记录; 页面也是在结果回投送达之后才拆通道。
界面:classic 与新版
同一个离线包里装着两套界面,用查看器 URL 的 ?app=(工具的 app 参数)选:
app | 界面 |
| 3D 计算器(新版界面里专门画 3D 的那个);需要可用的 WebGL |
| 几何应用:网格与坐标轴默认关闭,命令面是「几何 + 无 CAS」 |
| 计算器套件(新版现代界面):函数、数列、统计、表格、符号计算,带 CAS |
| 老式 Classic:顶部一整条工具栏、左侧代数区、菜单挤在顶上一行,多视图布局最全 |
推荐的选择流程(按顺序判断,命中就停;插件提示词里也要求模型照此执行):
需要 3D 绘图 / 立体 →
3d不需要坐标网格的几何问题 →
geometry可以只用 suite 完成任务 →
suite其它(要经典多视图布局、构形协议,或用户点名要经典界面)→
classic
选错 app 只能 canvas_release 后重建(appName 在页面加载时定死),所以建画布前先定下来。
带 CAS 的只有 classic / suite;3d / geometry 的符号计算会明确报「CAS 没有返回结果」。
appName 只能在页面加载时决定,换 app 就是新开一个页面:那是一份空构造,而且之后的
工具会操作新页面。所以要换界面之前先 state save,切过去再 state load,或者干脆
canvas_create 建第二个画布(各个画布互不干扰),换完用 canvas_release 收掉旧的。
3d 就是 3D 计算器(新版界面里专门画 3D 的那个)。它和 3D 视图一样依赖浏览器有可用的
WebGL:没有 WebGL 时页面根本起不来(appName: "3d" 实测 180 秒也连不上桥),
suite/classic 里的 3D 视图则会渲染成一片空白。status 与 view 会直接把这件事报出来
(3D 渲染:不可用(…) / 浏览器 WebGL:不可用(…)),不要靠猜。
关于 3D:先看 WebGL,再谈别的
3D 视图、3D 计算器(?app=3d)、以及 3D 内容的导出,前提都是浏览器有可用的 WebGL。
本机的无界面 Firefox 实测就是 WebGL:不可用(about:config 里 webgl.disabled 或驱动被禁),
所以在这个环境里:?app=3d 连不上、3D 视图像一片空白、导出也拿不到 3D 内容。
在真实浏览器里请先确认:
打开
about:support,看 Graphics → WebGL 1 Driver Renderer 是不是正常值(不是 “WebGL is disabled / unavailable”);或者访问 https://get.webgl.org/,它直接告诉你浏览器支不支持;
被禁了就在
about:config里把webgl.disabled设为false、webgl.force-enabled设为true再重启浏览器(无 GPU 的虚拟机/远程桌面通常还要软件渲染兜底)。
WebGL 可用之后,?app=3d 才是真正的 3D 计算器,view(perspective: "3D") 才会真的画出 3D。
导出 3D 内容(在无 WebGL 环境下的结论,有 WebGL 时未复测)
在没有 WebGL 的环境里,导出接口拿到的是图形视图(2D)的画布:
为什么 3D 出不了图
实测结论:GeoGebra 的导出接口只能读图形视图(2D)的画布,3D 视图(WebGL 画布)的内容 拿不到。 三条路径都验证过:
调用 | 在无 WebGL 环境里的结果 |
| 只有图形区,参数里没有选视图的余地 |
| 整个 applet 的布局(代数面板 + 图形面板),3D 面板位置是空的 |
| 同样是图形视图的渲染 |
在 perspective: "3D"(视图 XML 确认「视图 1 关、视图 16 开」,即只剩 3D)下截图,出来的
仍然是那张 2D 网格,平面与法向量都不在图里。
注意这个结论的适用范围:它是在没有 WebGL 的环境(本机无界面 Firefox)里得到的——3D 面板
本来就没渲染出东西,自然也无从抓取。用户的真实浏览器已确认支持 WebGL,那里的表现尚未
定论;切布局后不重算画布是另一个很可能的原因,现在 view 工具会补
recalculateEnvironments,待复测。
WebGL 可用时这里没有复测过,不能断言 GeoGebra 一定抓不到 3D。所以 screenshot /
export 的说明只写「本环境下 3D 面板拿不到」,并让你先用 status 看 WebGL 那一行。
给 3D 内容出图的实际做法:先确认 WebGL 可用并复测导出;不行再把 3D 几何投影到 2D 重画, 或者让用户自己截窗口。
超时
情况 | 上限 |
观测类(objects / object / events / view / set) | 20s |
| 60s |
| 120s |
| 60s |
| 默认 300s( |
挂到 DSH 时 toolCallTimeoutMs 要大于这里最长的那一项(bundle 里用的是 600000),
否则长调用会先被宿主掐断。
HTTP 接口(调试用)
方法 | 路径 | 说明 |
GET |
| 查看器页面 |
GET |
| 页面侧的桥 |
GET |
| GeoGebra 离线包(严格限制在该目录内) |
GET |
| SSE 下行通道,页面在这里收命令 |
POST |
| 页面自报身份 |
POST |
| 页面回投命令结果 |
GET |
| 纯 HTTP 自检( |
GET |
| 现在有哪些画布在等用户确认打开;被问一次就刷新「有人在看弹窗」的时间戳 |
POST |
| 用户在弹窗里的选择: |
curl -s http://127.0.0.1:3460/api/status | head -c 400
curl -s http://127.0.0.1:3460/api/pending
curl -s -X POST -H 'content-type: application/json' \
-d '{"id":"o1","action":"opened"}' http://127.0.0.1:3460/api/pending/confirmDSH 侧的界面插件通过同源路由 /api/dsh-geogebra-bridge/{pending,confirm,status}
访问这几条(见 GeoGebraDSHPlug);
桥自身仍然只监听回环地址。
当库用
exports 指向 src/server.mjs:
import { createServer, start, OpenRequests, SERVER_INFO, DEFAULT_GGB_ROOT } from 'geogebra-mcp-bridge';
// 只要 MCP server 实例(自己接传输)。不传 openRequests 时确认框永远走「没人看」的分支,
// 也就是老行为:自己拉起浏览器 / 把地址交给用户。
const server = createServer({ hub, viewerUrl: () => 'http://127.0.0.1:3460/' });
// 想自己接了确认界面,就把登记表也传进去(HTTP 侧的 /api/pending 也用它):
const openRequests = new OpenRequests({ timeoutMs: 300_000 });
const server2 = createServer({ hub, openRequests, viewerUrl: () => 'http://127.0.0.1:3460/' });
// 或完整启动(HTTP 查看器 + stdio MCP + 确认接口)。
// confirmTimeoutMs 是等用户点「已打开」的上限,默认 300000。
await start({ port: 3460, confirmTimeoutMs: 300_000 });自检
node test/list-tools.mjs # 离线:不需要浏览器与 GeoGebra 内核
node test/e2e-browser.mjs # 真机:无界面 Firefox + 真 GeoGebra,产物写到 ./verify/test/list-tools.mjs:检查命令行开关;按 stdio 启动桥并列出 14 个工具,把每个inputSchema送进 DSH 的 schema 子集校验器(宿主只支持type/oneOf/properties/required/additionalProperties/items/enum/const+ 注解, 多一个关键字就整体注册失败);再起一个「假页面」按同一份协议回投结果, 跑完 97 条断言,覆盖成功路径、错误路径、文件读写、页面断线,以及确认框的 全流程(登记 → 不存在/非法动作被拒 → 确认「已打开」→ 确认「跳过」→ 超时 →headless不登记)。test/e2e-browser.mjs:用无界面 Firefox 打开查看器,让真 GeoGebra 5.4.932.1 连上来, 再用 MCP 工具画图、读对象、改样式、算 CAS、导出 PNG/SVG/PDF、存取构造、撤销重做, 产物落在./verify/(已在.gitignore里)。
schema 子集校验器取自 DSH 安装目录(DSH_CHECKOUT 可覆盖),没有就自动跳过那一步。
许可证
代码(
src/、bin/、web/、test/、package.json):GPL-3.0-only,见 LICENSE文档(
README.md):CC BY-NC-SA 4.0,见 LICENSE.CC-BY-NC-SA-4.0
GeoGebra 离线包本身为非商业用途许可,见 https://www.geogebra.org/license。
This server cannot be deployed
Maintenance
Related MCP Connectors
MCP server to assist with JxBrowser development.
Headless CAD engine & MCP server for 2D/3D drafting, solids, DXF/SVG export, and automation.
QuLab MCP remote server (Streamable HTTP) for computational science and lab tools.
Official Browserless MCP server: browser automation, scraping, screenshots and PDFs for AI agents.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceExposes any stdio-based MCP server to the internet via HTTP/SSE transport, enabling remote agents to access MCP tools over a network.12 npmMIT
- AlicenseNot gradedqualityDmaintenanceBrowser-based geometry processing server that enables AI agents to create geometry, run analysis and operators, inspect results, and take screenshots via MCP.48 npm6MIT
- AlicenseAqualityDmaintenanceLets Claude Code, Codex, and other MCP clients control GeoGebra to create geometric constructions, function graphs, 3D graphics, dynamic mechanisms, and save .ggb or export .png.155MIT
- AlicenseAqualityCmaintenanceA local stdio MCP server for a self-hosted GeoGebra 5.0 Web bundle. It enables executing GeoGebra commands with structured feedback, querying commands, evaluating CAS, managing state, and exporting images using headless Chromium.1225 npmMIT