关于 forthling
forthling 是在沙箱中运行 Forth 代码的 MCP 服务,面向 AI Agent 和其他 MCP 客户端。它会在多次调用间保留定义和栈,并返回文本及结构化结果,包括错误、跟踪信息和栈数据。
主要功能
- 01在持久会话中执行 Forth
- 02检查数据栈和浮点栈
- 03列出会话词并查询帮助
- 04加载并保留内存中的文件
- 05返回结构化错误、跟踪和测试结果
- 06限制每次调用的时间和资源
适用场景
- 01通过 Agent 运行并检查 Forth 代码片段
- 02跨调用复用 Forth 定义
- 03根据跟踪信息和源位置诊断栈错误
MCP 相关
通过 stdio 向 MCP 客户端提供 Forth 执行和会话检查工具。每个客户端会话均在沙箱中运行;可选 HTTP 访问仅限明确允许的主机。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
forthling-mcp
一个 MCP 服务,让 AI Agent(Claude Code、 Claude Desktop 和其他 MCP 客户端)在 forthling 中运行 Forth,且始终处于沙盒中。Agent 保留一个会话:它定义的单词和栈会在多次调用之间保持不变。
安装
无需 Rust,作为 MCP bundle 安装:从
最新版本下载 forthling.mcpb,然后在
Claude Desktop(或其他可安装 .mcpb 文件的客户端)中打开。该 bundle 包含适用于 Windows(x64)、macOS(Apple Silicon 和 Intel)以及 Linux(x64)的
服务。
从 crates.io 安装,需要 Rust 1.85 或更高版本:
cargo install forthling-mcp
它会同时构建 SQLite,因此需要 C 编译器(Windows 上使用 Visual Studio 的 C 编译器;Rust 在 Windows 上也会用到它);cargo install forthling-mcp --no-default-features 则不会包含 SQLite。从仓库克隆版本安装:cargo install --path mcp,或
cargo build --release --manifest-path mcp/Cargo.toml,生成的程序位于
mcp/target/release/forthling-mcp。在 Claude Code 中:
claude mcp add forthling -- forthling-mcp
其他客户端也以相同方式启动它:通过 stdio 执行命令 forthling-mcp。
客户端连接时,服务会在指令中向模型介绍基础知识:容易让模型出错的惯用写法、用局部变量而非 ROT、
PICK 和 ROLL、JSON 单词以及各种限制。llms.txt 为预先阅读该文件的模型提供了更详细的相同内容;测试会确保两处的限制保持一致。
工具
| 工具 | 参数 | |
|---|---|---|
forth_eval | code, data, files, trace | 运行 Forth 代码;返回输出、数据栈和浮点栈,以及错误(如果有) |
forth_stack | 显示栈,不运行任何内容 | |
forth_words | 显示此会话中定义的词,最新定义的排在最前 | |
forth_help | word | 显示词的栈效果、功能、示例及所属词表;对于未定义的名称,显示相近名称。会话中的词会在名称后显示 ( ) 注释 |
forth_reset | 开启新会话:所有定义、栈值、数据和文件都会清除 |
代码行(包括 S" 中的字符串)最多为 1024 个字符。更大的输入(例如 JSON 文档)应放入 data:代码使用 DATA ( -- c-addr u ) 读取它,该词会返回一份存储在 ALLOCATE 分配的内存中的副本(记得用 FREE 释放)。数据会保留,供后续调用使用,直到某次调用发送其他数据;数据大小最多可与 Forth 内存相同:
{"name": "forth_eval", "arguments": {"code": "ALSO JSON DATA JSON-LENGTH .", "data": "[[59],[73,41]]"}}
每个会话都有自己的文件,这些文件保存在内存中,不会写入磁盘:INCLUDE、REQUIRE、FILE 词和块词都会使用这些文件,且文件会一直保留,直到调用 forth_reset。代码运行前,files 会以名称和文本组成的对象形式将文件放入会话,并替换同名文件;因此,Agent 可以提供一次库文件,然后使用 INCLUDE 引入,而代码写入的内容也可由后续调用读取。所有文件总大小最多为 4 MiB;超出上限的写入会以该词的 ior 失败,无法放入的 files 也会被拒绝。
{"name": "forth_eval", "arguments": {"code": "INCLUDE square.fs 7 SQUARE .", "files": {"square.fs": ": SQUARE DUP * ;"}}}
每个结果都是 REPL 所显示的文本:
2401 ok
stack: 1 2
结果也会以结构化 JSON 的形式返回(structuredContent,并带有 outputSchema):
{"output": "2401 ", "stack": [1, 2], "fstack": [], "compiling": false, "error": null, "steps": …, "max_depth": …};steps 和 max_depth(仅适用于 forth_eval)分别表示此次调用执行的步数,以及数据栈达到的最大深度;系统运行的词也会计入步数(. 是用 Forth 编写的,因此也会计入)。
发生错误时,栈会清空,因此结果还会显示错误发生时栈中的内容、错误发生位置以及当时正在运行的词;模型可以据此一次性修正问题:
error -10: division by zero
at input, line 2, column 3: MAIN
in: MAIN > STEP > /
stack at the error: 5 1
stack: empty
JSON 中的形式为:"error": {"code": -10, "message": "division by zero", "stack": [5, 1], "fstack": [], "words": ["MAIN", "STEP", "/"], "source": "input", "line": 2, "column": 3, "token": "MAIN", …},并且 isError 为 true。像这里的 / 这样,在失败前已取走参数的词,其参数已被取走。若未定义的词位于搜索顺序之外的词表中,则会提供 hint;文本会在该词后附上提示:error -13: undefined word: JSON@ (it is in the word list JSON; ALSO JSON finds it)。
失控的程序可能在栈上留下十万个单元,或留下同样多的运行中词(无限递归)。此时结果会保留栈顶的 32 个单元和最内层的 32 个词;文本会显示 ... (n more),JSON 中则会在 stack_depth、fstack_depth 和 words_depth 中给出完整深度。若定义尚未结束(compiling 为 true),文本会说明这一点:compiled (a definition is still open; ; ends it)。
若代码运行了 T{ ... -> ... }T 测试(ALSO TESTING),结果还会包含此次调用的测试计数,文本开头会显示 tests: 1 passed, 1 failed。失败行(FAIL input:3 (sums): incorrect result: expected <1> 3, got <1> 2)会出现在输出中。
JSON 中的形式为:"tests": {"passed": 1, "failed": 1, "failures": [{"source": "input", "line": 3, "group": "sums", "expected": [3], "expected_depth": 1, "actual": [2], "actual_depth": 1, "stack": [], "expected_floats": [], "expected_floats_depth": 0, "actual_floats": [], "actual_floats_depth": 0}], "failures_dropped": 0}。最多保留前 32 个失败记录;每个列表最多保留栈顶的 32 个单元和浮点数(深度字段会显示实际数量)。通过 files 提供的文件会将其名称显示为 source。
Agent 遇到典型错误时会看到的内容
每个案例都通过 forth_eval(#47)运行;答案是文本的首几行。
代码从一个全新会话中运行。
| 错误 | 代码 | 答案 |
|---|---|---|
| 未定义的单词 | 1 2 FOO . | error -13: undefined word: FOO,列号,以及出错时的栈 1 2 |
| 单词位于不在搜索顺序中的单词表中 | S" :memory:" DB-OPEN | error -13: undefined word: DB-OPEN (it is in the word list SQLITE; ALSO SQLITE finds it) |
| 定义中的未定义单词 | : sq DUPP * ; | error -13: undefined word: DUPP,以及它所在的列 |
| 栈下溢 | : add2 + ; 1 add2 | error -4: stack underflow,in: ADD2 > +,以及出错时的栈 |
| 消耗过多内容的单词 | : f ( n -- ) DROP ; f | error -4,in: F > DROP |
定义外的 IF、DO、BEGIN | 1 IF 2 THEN | error -14: interpreting a compile-only word: IF |
未闭合的 IF | : foo 1 IF 2 ; | error -22: control structure mismatch,位于 ; 处 |
没有 DO 的 LOOP | : f LOOP ; | error -22: control structure mismatch |
| 未闭合的定义 | : foo 1 2 + | compiled (a definition is still open; ; ends it) |
| 除以零 | 1 0 / | error -10: division by zero,in: /,出错时栈为空(/ 已取走参数) |
| 地址无效 | 12345678 @ | error -9: invalid memory address: 12345678 |
| 步数超限 | : spin BEGIN 1 DROP AGAIN ; spin | error -258: limit exceeded: steps,in: SPIN > DROP |
| 输出超限 | : p BEGIN 65 EMIT AGAIN ; p | 输出达到上限前的内容,然后是 error -258: limit exceeded: output |
| 栈无限增长 | : grow BEGIN 1 AGAIN ; grow | error -3: stack overflow,栈顶 32 个单元以及 ... (n more) |
| 无限递归 | : r RECURSE ; r | error -5: return stack overflow,最内层的 32 个单词 |
| 文件缺失 | S" nofile.fth" INCLUDED | error -38: non-existent file: nofile.fth: no such file |
EVALUATE 内部出错 | S" 1 2 FOO" EVALUATE | at evaluate, line 1, column 5: FOO,栈为 1 2 |
| 行超过 1024 个字符 | S" xxxx…" TYPE | error -18: parsed string overflow: input line too long |
ABORT" | : chk 0= ABORT" zero" ; 0 chk | error -2: aborted: zero |
CATCH | : t 1 0 / ; : u ['] t CATCH . ; u | 输出 -10,没有错误结果 |
以下情况不会报错,因此也不会有消息:未闭合的 S" 或 ( 会取走该行剩余内容(符合标准);: f >R ; 会让返回栈失去平衡,而 1 f 返回时没有单词;负数大小的 ALLOCATE 和重复两次的 FREE 会在栈上返回非零 ior(-59、-60),DB-EXEC 失败时也一样(-261);不存在的 JSON 路径会给出 0 0 0。这些情况符合标准或该单词的栈效应;Agent 必须读取栈。
设置 "trace": true 后,forth_eval 还会返回跟踪信息:每个运行过的单词、嵌套深度,以及它开始运行时的数据栈(最多显示栈顶 8 个单元);最多记录 1000 个单词,其余数量由 trace_dropped 统计。系统自身单词的内部执行过程不会显示。文本以跟踪信息开头,并采用 TRACE-ON 输出的缩进格式:
trace:
F <0>
SQ <1> 3
DUP <1> 3
* <2> 3 3
1+ <1> 9
. <1> 10
end of trace
10 ok
stack: empty
JSON 中还会包含 "trace": [{"word": "F", "depth": 0, "stack": [], "stack_depth": 0}, {"word": "SQ", "depth": 1, "stack": [3], "stack_depth": 1}, …], "trace_dropped": 0。调用失败时的跟踪信息会显示它如何到达错误。在代码本身中,ALSO DEBUG TRACE-ON … TRACE-OFF 会输出相同的行。
BREAK(也可用 ALSO DEBUG)会标记一个检查位置。它不会停止程序,因为没人能在一次调用过程中作答;相反,结果中会包含 breaks,记录程序在每个 BREAK 处的状态(最多 100 条,其余数量由 breaks_dropped 统计),字段与错误信息相同:stack、fstack、words、source、line、column 和 token。文本会以每个断点对应的一行开头:
break 1: in F > BREAK, at input, line 1, column 3: stack <2> 7 9
ALSO TUTORIAL 提供教程:共 20 节 Forth 课程,十节适合初学者,十节进阶课程,Agent 可以引导用户逐步学习(LESSONS、n LESSON、CHECK 用于检查答案、HINT、NEXT)。
JSON 词已安装(ALSO JSON);用于内存中数据库的 SQLite 词(ALSO SQLITE,仅支持 :memory:,SQL 会在时间耗尽时停止,且数据库不能大于 Forth 内存)、正则表达式词(ALSO REGEX,以线性时间进行匹配),以及向量、矩阵、线性代数和特殊函数词(ALSO SCIENCE)也已安装;如果不启用 Cargo 功能 sqlite、regex 和 science(--no-default-features),服务将不会编译这些功能。
HTTP 词(ALSO HTTP,参见 http/README.md)是第三项功能 http,默认关闭,因为它会访问网络。使用该功能构建服务(cargo install forthling-mcp --features http),并为 Forth 代码可能发送请求的主机启动服务,每个主机指定一次:forthling-mcp --allow-host api.example.com(*.example.com 和 * 也可用)。如果没有 --allow-host,网络访问将保持关闭,模型也不会获知这些词。它是唯一能打开沙箱外部访问的选项,且仅限于你指定的主机;Forth 词无法添加主机。
沙箱
每个会话都在 forthling 的沙箱中运行:文件仅存在于内存中,每次调用最多执行 1000 万步、耗时 5 秒,并输出 1 MiB;会话定义等内容总计最多 4 MiB。以下选项可以更改这些限制,但每项都不能超过程序设定的上限:
-m, --memory SIZE Forth memory (default 1M) [64M]
--max-steps N steps per call (default 10000000) [1000000000]
--max-time T time per call, such as 5s or 500ms (default 5s) [60s]
--max-output SIZE output per call (default 1M) [16M]
--max-space SIZE definitions and the like in all (default 4M) [64M]
--allow-host HOST a host that Forth code may send HTTP requests to (repeat)
没有关闭沙箱或允许访问文件的选项,因此更改服务的启动方式也不会开放文件访问。只有 --allow-host 可以开放网络访问,且仅限于它指定的主机(见上文)。
如何强制执行。 沙箱由服务强制执行,而非依赖模型获知或承诺遵守:工具只接受 Forth 代码(其他参数都会被拒绝),且没有 Forth 词能更改限制或权限。用户要求 AI 绕过沙箱,无法通过 forthling 实现。不过,如果 Agent 还拥有其他工具,例如 shell 或文件编辑工具,就可以绕过沙箱:更改 MCP 配置,或启动另一个程序。forthling 无法防范这种情况;请改用 Agent 的权限设置。在 Claude Code 中:拒绝或限制 shell,拒绝编辑 MCP 配置(.mcp.json、~/.claude.json),并通过托管设置仅允许你需要的 MCP 服务。为进一步防范 forthling 中的错误,可在容器中运行服务,或使用权限较少的用户运行服务。
测试
cargo test --manifest-path mcp/Cargo.toml
cargo test --manifest-path mcp/Cargo.toml --no-default-features
cargo test --manifest-path mcp/Cargo.toml --all-features
链接
- forthling 的源代码及其他内容:https://github.com/DeSchaker/forthling
- MCP Registry 将此服务登记为
io.github.DeSchaker/forthling(下面这一行可让它验证此 crate 属于我们)。 - mcp-name: io.github.DeSchaker/forthling
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。