geogebra-mcp-bridge
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
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__*下载
内容 | 地址 |
本仓库(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: Enhanced GeoGebra MCP
要求
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,用来获得「数学模式 / 数学模式+」两个 preset; 不装 DSH 也能作为普通 MCP server 使用
程序不启动浏览器,也不跑 GeoGebra 内核:canvas_create 立即返回画布地址,
模型把地址告诉用户,用户自己在浏览器里打开。桥只监听 127.0.0.1,浏览器、
agent 客户端与 MCP 服务器在同一台设备上。
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 端口,默认 |
| state/export 的输出目录,默认 |
| 本地回答,不启动任何服务 |
桥只监听 127.0.0.1。用 canvas_create 建画布时,它立即返回 id:cN 与 url:http://127.0.0.1:<端口>/?canvas=cN&app=…;把地址交给用户在浏览器打开,页面加载完 GeoGebra 就会自动连上桥。
查看器页面
页面参数都在 URL 查询串里:
参数 | 说明 |
|
|
|
|
|
|
|
|
| 界面语言,默认 |
| 初始布局串(如 |
页面右上角有个连接状态小徽章,显示 GeoGebra 版本与对象数;控制台里
window.__GGB_BRIDGE__ 暴露 clientId、api() 与 events() 便于手工排查。
页面侧只做四件事:保证 applet 就绪、把方法名映射到 API、把异常变成可读文本、 把构造与用户交互记成事件流。所有业务判断与排版都在 MCP 进程里。
工具(14 个)
工具 | 说明 |
| 自检:HTTP 服务、离线资源、画布清单(id / 界面 / 地址 / 是否连上);不碰页面,随时可跑 |
| 建画布:立即返回 |
| 释放画布:让页面 |
| 五段说明: |
| 对象清单(名称/类型/可见/颜色/值/定义),可按类型过滤 |
| 单个对象详情(定义、非本地化写法、LaTeX、坐标、样式…) |
| 用户操作与构造变化,读取即清空 |
| 出图给用户看: |
| 读:工具、可见坐标范围、网格/坐标轴、视口像素、布局;写:范围/网格/轴/布局/工具/缩放 |
| 执行 GeoGebra 命令(主力); |
| 按属性名设对象样式或数值(19 种属性) |
|
|
| 整份构造的 |
| PNG / SVG / PDF,写文件或直接返回内容; |
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:不阻塞,直接给地址
canvas_create 只接受 app,不会等待页面连接,也不会启动浏览器。它立即返回两行:
id:c1
url:http://127.0.0.1:3460/?canvas=c1&app=classic模型拿到后把 url 原样告诉用户,请用户用浏览器打开,然后结束本轮。
用户下一条消息时,模型再用 status 看页面是否连上;连上后就能用 objects / eval / ...。
不要在同一个回合里反复轮询 status,也不要重复建画布。
画布会一直保留到 canvas_release 或桥进程退出,没有超时自动释放。页面刷新会重新连回
同一个画布;页面断开后画布记录仍然保留,只是 status 显示未连接。
桥只监听 127.0.0.1,没有 --host 选项:浏览器、agent 客户端与 MCP 服务器必须在
同一台设备上。若 HTTP 服务启动失败,canvas_create 会释放刚建的画布并报错。
画布(canvas):显式句柄
一个「画布」= 一个浏览器里跑着的 GeoGebra 页面,用短 id 指代(c1、c2…)。
这是为了消掉「同时开着好几个页面时,工具到底操作哪一个」的歧义——以前按「最近活跃」
猜,现在由调用方明确指定:
canvas_create {app: "3d"} → id:c1
url:http://127.0.0.1:3460/?canvas=c1&app=3d
(立即返回;把 url 告诉用户,请用户打开)
status → 看 c1 是否已连接
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()(真正回收内核内存)再删记录; 页面也是在结果回投送达之后才拆通道。
文件输出目录
state save/load 与 export 只接受文件名(name),不接受目录或绝对路径。
文件统一落在桥进程当前工作目录的 exports/ 下,可用 GGB_EXPORT_DIR 覆盖:
state save {name: "sine_wave_demo"} → exports/sine_wave_demo.ggb
state save {name: "demo.xml"} → exports/demo.xml
export {format: "png", name: "plot"} → exports/plot.png
export {format: "pdf", name: "plot"} → exports/plot.pdf没写扩展名时会按格式自动补;写了但与格式不符则报错。文件名拒绝 /、\、..、
绝对路径、前导点、控制字符、Windows 保留名;读写时拒绝符号链接。export 的 PNG/SVG
省略 name 时仍然直接返回内容,PDF 必须给 name。
界面: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 |
| 立即返回,没有等待 |
挂到 DSH 时 toolCallTimeoutMs 要大于这里最长的那一项(bundle 里用的是 180000),
否则长调用会先被宿主掐断。
HTTP 接口(调试用)
方法 | 路径 | 说明 |
GET |
| 查看器页面 |
GET |
| 页面侧的桥 |
GET |
| GeoGebra 离线包(严格限制在该目录内) |
GET |
| SSE 下行通道,页面在这里收命令 |
POST |
| 页面自报身份 |
POST |
| 页面回投命令结果 |
GET |
| 纯 HTTP 自检( |
curl -s http://127.0.0.1:3460/api/status | head -c 400桥只监听 127.0.0.1,没有 /api/pending;画布地址由 canvas_create 直接返回。
当库用
exports 指向 src/server.mjs:
import { createServer, start, SERVER_INFO, DEFAULT_GGB_ROOT } from 'geogebra-mcp-bridge';
// 只要 MCP server 实例(自己接传输)。
const server = createServer({ hub, viewerUrl: () => 'http://127.0.0.1:3460/' });
// 或完整启动(HTTP 查看器 + stdio MCP)。
// exportDir 是 state/export 的输出目录,默认 <cwd>/exports。
await start({ port: 3460, exportDir: '/path/to/exports' });自检
node test/files.mjs # 纯单元:文件名、固定目录、扩展名、符号链接
node test/list-tools.mjs # 离线:不需要浏览器与 GeoGebra 内核
node test/e2e-browser.mjs # 真机:无界面 Firefox + 真 GeoGebra,产物写到 ./verify/test/files.mjs:不启动桥,检查文件名白名单、exports/目录、扩展名推断与符号链接拒绝。test/list-tools.mjs:检查命令行开关;按 stdio 启动桥并列出 14 个工具,把每个inputSchema送进 DSH 的 schema 子集校验器(宿主只支持type/oneOf/properties/required/additionalProperties/items/enum/const+ 注解, 多一个关键字就整体注册失败);再起一个「假页面」按同一份协议回投结果, 覆盖成功路径、错误路径、文件读写、页面断线、非阻塞canvas_create、name文件规则, 以及旧browser参数被 schema 丢弃的安全回归。test/e2e-browser.mjs:用无界面 Firefox 打开canvas_create返回的地址,让真 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.
A remote MCP server to convert HTML documents (URL or raw source) to PDF or screenshots
QuLab MCP remote server (Streamable HTTP) for computational science and lab tools.
Related MCP Servers
- 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
- AlicenseAqualityDmaintenanceA 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.1240 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables local CLI and desktop MCP clients to control the MazeBench 3D game engine via stdio, with real-time browser viewing, action recording, and post-run summaries and replays.MIT
- AlicenseNot gradedqualityBmaintenanceA standalone stdio MCP server that exposes 13 resources, 3 prompts and 7 tools for assembling interactive, replayable HTML interfaces such as calculators, charts, maps, flowcharts and small apps. It returns the generated HTML document for the calling client to decide whether and how to display.68 npmMIT