使用说明
工具脚本
将OpenAPI规范和MCP服务器转化为可脚本化的运行时环境。一次往返,而不是多次往返。
问题
在复杂的API上使用MCP工具的AI代理浪费了资源。每个API调用都成为一个单独的工具调用,即使在不需要判断的情况下,LLM round-tips也会处理所有中间状态。LLM变成了一个昂贵的数据穿梭机。
解决方案
toolscript为LLM提供了 Luau 使用强类型SDK编写运行时脚本。SDK可以从OpenAPI规范自动生成,从上游MCP服务器填充,或两者兼而有之。LLM编写一个脚本,将多个调用链接起来,发送执行,并返回结果。一次往返,而不是多次往返。
快速开始
cargo install --path .
指向OpenAPI规范并提供您的API密钥:
export MY_TOKEN=your-token-here
toolscript run petstore=https://petstore3.swagger.io/api/v3/openapi.json \
--auth petstore:MY_TOKEN
或者使用配置文件(toolscript.toml):
[apis.petstore]
spec = "https://petstore3.swagger.io/api/v3/openapi.json"
auth = "your-token-here"
toolscript run
或者连接到上游MCP服务器,而不是(或与OpenAPI规范一起):
# MCP-only
toolscript run --mcp filesystem='npx -y @modelcontextprotocol/server-filesystem /tmp'
# Mixed: OpenAPI + MCP
toolscript run petstore=petstore.yaml \
--auth petstore:MY_TOKEN \
--mcp filesystem='npx -y @modelcontextprotocol/server-filesystem /tmp'
将服务器添加到MCP客户端配置中:
{
"mcpServers": {
"petstore": {
"command": "toolscript",
"args": ["run", "petstore=https://petstore3.swagger.io/api/v3/openapi.json", "--auth", "petstore:PETSTORE_TOKEN"],
"env": {
"PETSTORE_TOKEN": "your-token-here"
}
}
}
}
运作原理
- 代理连接到MCP服务器。
- 它使用文档工具探索SDK(
list_apis,list_functions,get_function_docs,search_docs)或通过浏览资源(sdk://petstore/overview,sdk://petstore/functions等等)。 - 它编写了一个链接SDK调用的Luau脚本。
- 它将脚本发送到
execute_script. - 它在一个响应中返回结果并捕获日志。
LLM可能编写的示例脚本:
-- OpenAPI calls
local pets = sdk.list_pets({ limit = 5 })
local first = pets[1]
local details = sdk.get_pet({ pet_id = first.id })
return { pet = details, total = #pets }
脚本还可以调用同一命名空间中的上游MCP工具:
-- MCP tool call (filesystem server)
local content = sdk.filesystem.read_file({ path = "/tmp/data.txt" })
return json.decode(content)
OpenAPI函数和MCP工具在 sdk.* 并且可以在单个脚本中自由混合。响应包括JSON格式的返回值,任何 print() 以日志形式捕获的输出,以及 files_touched 数组汇总通过沙盒写入或删除的文件 io 图书馆。
CLI参考
toolscript run
一步生成和服务。这是最常见的子命令。
toolscript run [SPECS]... [OPTIONS]
| 标志 | 默认值 | 描述 |
|---|---|---|
--config |
-- | TOML配置文件的路径 |
--auth |
-- | API授权: name:ENV_VAR 或 ENV_VAR |
--mcp |
-- | 上游MCP服务器: name=command 或 name=url |
--transport |
stdio |
运输类型(stdio, sse) |
--port |
8080 |
HTTP/SSE传输端口 |
--timeout |
30 |
脚本执行超时(秒) |
--memory-limit |
64 |
Luau VM内存限制(MB) |
--max-api-calls |
100 |
每个脚本的最大上行调用数(API+MCP) |
--io-dir |
-- | 用于沙盒文件访问的I/O目录 |
--auth-authority |
-- | OAuth颁发者URL(启用JWT身份验证) |
--auth-audience |
-- | 预计JWT观众 |
--auth-jwks-uri |
-- | 显式JWKS URI覆盖 |
规格在以下情况下是可选的 --mcp 或 [mcp_servers] config至少提供一个源。如果没有规格,就没有 --mcp,而且没有 --config 提供, toolscript run 寻找 toolscript.toml 在当前目录中。
toolscript generate
仅用于代码生成。在不启动服务器的情况下生成清单和SDK注释。
toolscript generate <SPECS>... [-o <DIR>] [--config <FILE>]
输出目录默认为 ./output。生成 manifest.json 和 sdk/*.luau.使用 --config 从TOML配置文件而不是位置参数加载规范。
toolscript serve
从预先生成的输出目录启动MCP服务器。
toolscript serve <DIR> [OPTIONS]
接受与相同的选项 run (--auth, --mcp, --transport, --port, --timeout, --memory-limit, --max-api-calls, --io-dir, --auth-authority, --auth-audience, --auth-jwks-uri).
认证
有两个单独的身份验证层。
上游API证书
这些是toolscript用来调用SDK后面的API的凭据。
命令行界面 --auth 旗帜 (快速启动):
# Named: --auth name:ENV_VAR
toolscript run petstore=spec.yaml --auth petstore:MY_TOKEN
# Unnamed (single-spec only): --auth ENV_VAR
toolscript run spec.yaml --auth MY_TOKEN
该工具在启动时读取环境变量的值。秘密永远不会出现在命令本身。
配置文件 (toolscript.toml):
[apis.petstore]
spec = "https://petstore.example.com/spec.json"
auth = "sk-my-token"
[apis.stripe]
spec = "./stripe.yaml"
auth = "sk_live_abc123"
[apis.legacy]
spec = "./legacy.yaml"
[apis.legacy.auth]
type = "basic"
username = "admin"
password = "secret"
使用 auth_env 而不是 auth 引用环境变量:
[apis.stripe]
spec = "./stripe.yaml"
auth_env = "STRIPE_KEY"
使用配置文件运行:
toolscript run --config toolscript.toml
# Or just have toolscript.toml in the current directory:
toolscript run
根据请求,通过 _meta.auth (对于托管模式,覆盖全部):
{
"method": "tools/call",
"params": {
"name": "execute_script",
"arguments": { "script": "return sdk.list_pets()" },
"_meta": {
"auth": {
"petstore": { "type": "bearer", "token": "sk-runtime-token" }
}
}
}
}
解析顺序 (首场比赛获胜):
- 命令行界面
--auth旗帜 - 配置文件
auth/auth_env - 根据请求
_meta.auth
MCP层身份验证
这控制了谁可以连接到工具脚本服务器本身。它仅适用于使用HTTP/SSE传输时。
- 使用OIDC发现进行JWT验证
- 启用
--auth-authority和--auth-audience - 可选地用以下命令覆盖JWKS端点
--auth-jwks-uri - 出版
/.well-known/oauth-protected-resource用于客户端发现
对于本地stdio的使用,不需要这一层——MCP客户端和服务器共享相同的信任边界。
冻结参数
冻结参数是在请求时注入API调用的服务器端固定值。它们完全隐藏在LLM之外——从工具模式、文档和搜索结果中剥离出来。使用它们来硬编码值,如API版本、租户ID或特定于环境的设置。
在中配置冻结参数 toolscript.toml 在两个层面上:
# Global — applies to every API
[frozen_params]
api_version = "v2"
# Per-API — applies only to this API's operations
[apis.petstore]
spec = "petstore.yaml"
[apis.petstore.frozen_params]
tenant_id = "abc-123"
优先: 当两个参数名称相同时,Per-API值将覆盖全局值。不匹配的参数名称(操作中不存在的参数)将被自动忽略。
它是如何工作的: 在代码生成过程中,冻结的参数保留其完整的元数据(名称、位置、类型),但用固定值标记。在运行时,服务器将配置的值注入到正确的位置(路径、查询字符串或标头),而LLM不需要知道这些位置。
上游MCP服务器
toolscript可以连接到外部MCP服务器,并将它们的工具作为可调用的Luau函数与OpenAPI生成的函数一起公开。来自上游MCP服务器的工具出现在 sdk.<server>.<tool>() 命名空间。
命令行界面 --mcp 旗帜
# Stdio: name=command with args
toolscript run --mcp filesystem='npx -y @modelcontextprotocol/server-filesystem /tmp'
# HTTP: name=url (uses streamable-http transport)
toolscript run --mcp remote=https://mcp.example.com/mcp
# Multiple servers
toolscript run --mcp filesystem='npx -y @modelcontextprotocol/server-filesystem /tmp' \
--mcp db='npx -y @modelcontextprotocol/server-sqlite db.sqlite'
如果该值以开头 http:// 或 https://,它被视为一个URL。否则,它被拆分为空格:第一个标记是命令,其余的是参数。
配置文件
# Stdio-based (spawns a child process)
[mcp_servers.filesystem]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
env = { HOME = "/tmp" }
# HTTP-based (streamable-http transport)
[mcp_servers.remote]
url = "https://mcp.example.com/mcp"
每个条目必须恰好有一个 command 或 urlThe args 和 env 字段仅在以下情况下有效 command基于URL的服务器使用可流式传输的http。不支持传统SSE传输。
命令行界面 --mcp 标志与配置文件条目合并。如果两者定义了相同的服务器名称,则CLI标志获胜。
MCP工具的外观
MCP工具已完全集成到发现工具和资源中。 list_apis 包括MCP服务器和OpenAPI API。 list_functions 返回MCP工具和OpenAPI函数,可按服务器名称过滤。 get_function_docs 返回任何MCP工具的完整Luau类型注释。 search_docs 在MCP工具名称、描述和参数之间进行搜索。
在Luau脚本中,MCP工具在服务器名称下以命名空间排列:
-- Call an MCP tool
local result = sdk.filesystem.read_file({ path = "/tmp/data.txt" })
-- MCP tool results: text content is returned as a string,
-- structured content as a table. Parse JSON yourself if needed:
local data = json.decode(result)
执行限制
| 标志 | 默认值 | 控件 |
|---|---|---|
--timeout |
30s | 每个脚本执行的挂钟截止日期 |
--memory-limit |
64 MB | 最大Luau VM内存分配 |
--max-api-calls |
100 | 每个脚本的最大上行调用数(API+MCP) |
OpenAPI HTTP请求和MCP工具调用都计入相同的限制。CPU受到挂钟超时的间接限制。没有单独的指令计数限制。
MCP工具和资源
工具
| 工具 | 说明 |
|---|---|
list_apis |
列出加载的API和MCP服务器,包括名称、描述和计数 |
list_functions |
列出SDK功能和MCP工具,可通过API/服务器或标签进行筛选 |
get_function_docs |
函数或MCP工具的完整Luau类型注释,带有引用的模式 |
search_docs |
在所有SDK和MCP工具文档中进行全文搜索 |
execute_script |
对SDK执行Luau脚本 |
资源
可浏览的SDK文档,可通过以下方式访问 resources/read:
| URI模式 | 内容 |
|---|---|
sdk://{api}/overview |
API或MCP服务器概述 |
sdk://{api}/functions |
所有功能/工具签名 |
sdk://{api}/schemas |
所有类型定义(仅限OpenAPI) |
sdk://{api}/functions/{name} |
单个函数文档(仅限OpenAPI) |
sdk://{api}/schemas/{name} |
单个模式文档(仅限OpenAPI) |
这 overview 和 functions 为OpenAPI API和上游MCP服务器生成资源。
沙盒安全
脚本在沙盒Luau VM中执行。以下是可用和不可用的内容。
允许:
- 标准库:
string,table,math os.clock()(仅限挂钟计时)os.remove()(删除I/O目录中的文件)print()(捕获到日志中,不写入stdout)json.encode()/json.decode()sdk.*功能(来自OpenAPI规范和上游MCP服务器)io.open(),io.lines(),io.list(),io.type()(沙盒文件I/O,见下文)
有条件可用--沙盒 io:
这 io 库是Lua标准的沙盒子集 io。所有路径都是相对于单个I/O目录解析的(默认 ./toolscript-files,用以下命令覆盖 --io-dir).此目录外的路径遍历被拒绝。在stdio模式下, io 默认情况下启用。在托管(HTTP/SSE)模式下,除非通过以下方式明确启用,否则它将被禁用 --io-dir 或 [io] 配置部分。
此 路 不通:
os.execute(外壳访问)loadfile,dofile,require(模块加载)debug图书馆string.dump(字节码访问)load(动态代码加载)- 原始网络访问
- 非沙盒文件系统访问
执行机制:
- Luau原生沙盒模式(只读全局变量,按脚本隔离环境)
- 可配置的内存限制
- 通过Luau中断回调实现挂钟超时
- 每次执行API调用计数器
- 每次执行新的VM(脚本之间没有状态泄漏)
- 凭据从未暴露给Luau——注入服务器端
关于托管的说明。 如果您通过HTTP为多个用户部署toolscript,则您将计算作为代码沙箱提供。沙盒限制了滥用表面,但您应该在适当的资源约束和网络策略之后进行部署。对于大多数用例,使用自己的凭据在stdio上本地运行是最简单、最安全的选择。
码头工人
构建并运行:
docker build -t toolscript .
docker run toolscript https://api.example.com/openapi.json
对于HTTP传输:
docker run -p 8080:8080 toolscript \
https://api.example.com/openapi.json \
--transport sse --port 8080
Docker和MCP服务器
Docker镜像构建自 scratch --它只包含静态链接的二进制和CA证书。这意味着它是为 基于HTTP的托管部署 其中下游传输(客户端如何连接到工具脚本)和任何上游MCP服务器都使用HTTP。
HTTP上游MCP服务器开箱即用:
docker run -p 8080:8080 toolscript \
--mcp remote=https://mcp.example.com/mcp \
--transport sse --port 8080
Stdio上游MCP服务器将无法工作 在默认图像中。Stdio模式生成子进程(例如。 npx, python),并且这些运行时间不存在于划痕图像中。这是设计上的——stdio MCP服务器适用于单用户本地场景,其中工具脚本直接在主机上运行,而不是用于托管的多用户部署。
如果需要容器中的stdio MCP服务器,请使用所需的运行时扩展映像:
FROM node:20-slim
COPY --from=toolscript:latest /toolscript /toolscript
RUN npm install -g @modelcontextprotocol/server-filesystem
ENTRYPOINT ["/toolscript", "run"]
在实践中,大多数容器化部署都应该使用基于HTTP的上游MCP服务器。如果上游服务器只支持stdio,可以考虑在HTTP适配器后面运行它,或者将其作为暴露HTTP端点的sidecar运行。
从源头构建
git clone https://github.com/alenna/toolscript.git
cd toolscript
cargo build --release
cargo test
需要Rust 1.85+(使用2024版)。
许可证
麻省理工学院