Fitter MCP
Fitter — 面向 AI 代理的网页数据
Fitter 以声明方式将任何网站或 API 转换为结构化 JSON。 一个 JSON/YAML 配置描述数据所在位置(HTTP 请求、无头浏览器、文件、静态值)以及要提取的内容(JSON 路径、CSS 选择器、XPath)。无需代码,无需脆弱的抓取脚本。
🚀 在浏览器中试用 — 真正的引擎编译为 WebAssembly:实时示例、可视化配置构建器,无需安装。
由于配置是纯数据,LLM 可以编写它们。内置的 MCP 服务器 让 Claude Code、Claude Desktop 或任何 MCP 客户端按需在您的机器上编写和运行抓取管道:
“获取 HackerNews 前 5 条故事及其标题和分数” → 模型编写 fitter 配置,验证它,在本地运行,并返回干净的 JSON。
一个引擎,五种使用方式:
🤖 Fitter MCP | MCP 服务器,将 fitter 暴露给 Claude Code、Claude Desktop 和任何 MCP 客户端 |
🧠 Fitter Agent | AI 驱动的 CLI:自然语言 → 配置 → 执行结果 |
🖥 Fitter CLI | 在本地运行配置,用于测试/调试/家庭使用 |
📦 Fitter Lib | 将引擎嵌入您自己的 Go 程序 |
⚙️ Fitter | 长时间运行的服务模式,支持调度和通知 |
为什么 AI 代理选择 fitter?
声明式且可审计 — 代理生成一个您可以阅读、保存和重新运行的配置,而不是一次性代码
本地优先 — 所有抓取都在您的机器上进行;没有第三方抓取 API、没有密钥、没有按请求计费
开箱即用 — HTTP 客户端、无头浏览器(Playwright/Chromium/Docker)、JSON/HTML/XML/XPath/PDF 解析、分页、缓存引用、主机速率限制 — 全部包含在一个静态二进制文件中
可复用 — 代理今天编写的配置将成为明天的 cron 作业或服务配置
如何使用 Fitter_MCP
Fitter MCP 是一个 Model Context Protocol 服务器(stdio 传输),它允许任何 MCP 客户端 — Claude Code、Claude Desktop、IDE 助手、自定义代理 — 运行 Fitter 配置并返回结构化 JSON。
快速开始(Claude Desktop — 一键)
从 发布页面 下载 fitter-mcp-<os>-<arch>.mcpb 并打开它 — Claude Desktop 会自动安装服务器。
快速开始(Claude Code)
# 1. get the binary: download fitter_mcp_<version>-<os>-<arch> from the release page
# https://github.com/PxyUp/fitter/releases — or build it from source:
go build -o fitter_mcp ./cmd/mcp
# 2. register it once, available in every project
claude mcp add fitter -s user -- "$(pwd)/fitter_mcp"然后只需询问:
使用 fitter 获取 HackerNews 前 5 条故事及其标题和分数
模型调用 fitter_config_reference,编写配置,可选地使用 fitter_validate_config 检查它,并通过 fitter_run 执行它 — 所有数据抓取都在您的机器上本地进行。对于现成的管道,请尝试 examples/config_morning_briefing.json:
使用 fitter 运行 examples/config_morning_briefing.json 并给我简报
在 Claude Desktop 中注册
{
"mcpServers": {
"fitter": {
"command": "/path/to/fitter_mcp"
}
}
}浏览器支持(Playwright)
.mcpb 捆绑包和原生二进制文件不附带浏览器:HTTP、静态和文件连接器开箱即用,但浏览器配置(playwright 连接器)需要 Playwright 的浏览器。有几种方法可以获取它们:
首次使用(原生二进制 /
.mcpb): 在 playwright 连接器中设置"install": true— fitter 会在首次使用时下载与其内置playwright-go版本匹配的驱动程序和浏览器(一次性,缓存),因此无需单独的安装步骤。提前安装(原生,可选): 为避免首次运行下载,请使用 fitter 构建所针对的相同
playwright-go版本预先安装浏览器(检查go.mod,当前为v0.6100.0):go run github.com/mxschmitt/playwright-go/cmd/playwright@v0.6100.0 install # Linux: append --with-deps to also install the required OS libraries版本必须与
go.mod完全匹配 —playwright-go拒绝在版本不匹配的驱动程序上运行。然后无需"install": true即可运行配置。Docker: 使用
ghcr.io/pxyup/fitter-mcp:playwright镜像,该镜像预装了 Chromium、Firefox 和 WebKit(无需"install": true)。
工具
工具 | 描述 |
| 运行内联传递的 Fitter 配置(JSON 或 YAML 字符串)并返回提取的数据为 JSON。接受可选的 |
| 与 |
| 与 |
| 获取 URL 并返回紧凑的结构大纲 + 候选选择器/路径(JSON 的 gjson 路径;HTML 的重复元素/列表行选择器),以便模型一次尝试就编写配置,而不是猜测选择器并得到 null。检测客户端渲染的 SPA,并可以在无头浏览器中 |
| 验证配置而不执行它(结构、 |
| 返回整个配置格式的简明参考(连接器、解析器、模型/字段模式、占位符、通知器、引用、限制)以及工作示例,以便模型无需外部文档即可编写配置 |
该参考也作为 MCP 资源 fitter://config-reference 暴露给支持资源的客户端。
配置格式与 Fitter_CLI 完全相同:一个顶层对象,包含 item(必需)、limits 和 references。通知器 也有效(结果还会推送到 http/telegram/redis/file/console);trigger_config 和 http_server 仅限服务模式,在 MCP 调用中被忽略。
远程 / 托管模式(streamable HTTP)
默认情况下,fitter_mcp 使用 stdio。传递 --http 以提供 streamable HTTP 传输 — 用于共享团队服务器、容器或任何远程部署:
# serve MCP at http://<host>:8080/mcp (health probe at /healthz)
FITTER_MCP_AUTH_TOKEN=my-secret fitter_mcp --http :8080
# register the remote endpoint in Claude Code
claude mcp add --transport http fitter http://localhost:8080/mcp --header "Authorization: Bearer my-secret"--http <addr>(环境变量FITTER_MCP_HTTP_ADDR)— 监听地址;为空时使用 stdio 模式FITTER_MCP_AUTH_TOKEN— 设置后,每个/mcp请求必须发送Authorization: Bearer <token>;否则端点未认证,因此请绑定到 localhost 或将其放在代理后面--stateless(环境变量FITTER_MCP_STATELESS=true)— 无每会话状态,因此副本可以位于负载均衡器后面而无需粘性会话
服务器在收到 SIGINT/SIGTERM 时优雅关闭。
Docker
每个版本都附带一个精简的多架构镜像(linux/amd64 + linux/arm64):
# hosted HTTP mode
docker run --rm -p 8080:8080 \
-e FITTER_MCP_HTTP_ADDR=:8080 \
-e FITTER_MCP_AUTH_TOKEN=my-secret \
ghcr.io/pxyup/fitter-mcp:latest
# or stdio mode, spawned by the MCP client
claude mcp add fitter -s user -- docker run --rm -i ghcr.io/pxyup/fitter-mcp:latest精简镜像仅包含 fitter 二进制文件和 CA 证书:服务器/静态/文件连接器可用,浏览器连接器(chromium/docker/playwright)不可用。
对于基于浏览器的配置,请使用 playwright 变体,它捆绑了 Playwright 与 Chromium、Firefox 和 WebKit(与 fitter 构建所针对的 playwright-go 版本匹配,因此配置中无需 "install": true):
docker run --rm -i ghcr.io/pxyup/fitter-mcp:playwright # stdio mode
# per-release tag: ghcr.io/pxyup/fitter-mcp:vX.Y.Z-playwright它基于 Dockerfile.mcp-playwright 构建;使用 --build-arg PLAYWRIGHT_BROWSERS=chromium 构建可得到更小的仅 Chromium 镜像。
Docker 中的 OAuth2 账户
两个镜像都附带 fitter_cli,因此一次性 OAuth2 登录 可以在容器内运行。将令牌存储在挂载到 /tokens 的卷上(镜像中预创建可写)并与 MCP 服务器共享:
# one-time login, device flow: no ports needed — open the printed url on any device
docker run --rm -it -v fitter-tokens:/tokens --entrypoint fitter_cli \
ghcr.io/pxyup/fitter-mcp:latest \
auth --provider github --client-id <ID> --client-secret <SECRET> --token-file /tokens/github.json
# or browser flow (device flow not enabled for the app): publish the callback port and
# bind on 0.0.0.0 so the published port reaches the listener; the browser still visits 127.0.0.1
docker run --rm -it -p 8988:8988 -e FITTER_AUTH_LISTEN=0.0.0.0 \
-v fitter-tokens:/tokens --entrypoint fitter_cli ghcr.io/pxyup/fitter-mcp:latest \
auth --provider github --client-id <ID> --client-secret <SECRET> --token-file /tokens/github.json
# then run the MCP server with the same volume; configs reference "token_file": "/tokens/github.json"
# stdio mode (spawned by the MCP client, no port):
docker run --rm -i -v fitter-tokens:/tokens ghcr.io/pxyup/fitter-mcp:latest
# hosted HTTP mode (MCP endpoint on 8080, like the run examples above):
docker run --rm -p 8080:8080 -v fitter-tokens:/tokens \
-e FITTER_MCP_HTTP_ADDR=:8080 \
-e FITTER_MCP_AUTH_TOKEN=my-secret \
ghcr.io/pxyup/fitter-mcp:latest注意:8988 仅用于一次性浏览器流程登录;MCP 服务器本身在 stdio 模式下不需要端口,在托管 HTTP 模式下仅需要 8080。
Docker 中已登录的浏览器会话
浏览器会话 需要 playwright 镜像(精简版没有浏览器)。一次性有头登录需要显示器,因此请在主机上运行它,然后将会话目录绑定挂载到容器中(镜像预创建可写的 /sessions):
# on the host: log in once, save the session
fitter_cli browser-login --url https://example.com/login --storage-state ~/.fitter/sessions/example.json
# run the MCP server with the sessions dir mounted; configs reference "storage_state_file": "/sessions/example.json"
docker run --rm -i -v ~/.fitter/sessions:/sessions ghcr.io/pxyup/fitter-mcp:playwright使用绑定挂载(而不是命名卷):容器在每次运行后写回刷新的 cookie,因此主机副本保持最新,并且可以随时使用 browser-login 重新扩展。
卷必须对服务器保持可写:每次刷新时都会写回轮换的刷新令牌。
环境变量
FITTER_PLUGINS - string[""] - 插件文件夹路径,与 Fitter/Fitter_CLI 的
--plugins标志相同FITTER_MCP_HTTP_ADDR - string[""] - 远程模式 的监听地址,与
--http相同FITTER_MCP_AUTH_TOKEN - string[""] - 保护 HTTP 端点的 bearer 令牌
FITTER_MCP_STATELESS - bool[false] - 无状态 HTTP 传输,与
--stateless相同
示例
完整且经过测试的配置,展示了主要模式。所有这些都可以通过 Fitter_MCP(fitter_run_file)、Fitter_CLI 或库原样运行——更多内容见 examples/。
抓取没有 API 的页面,并从有 API 的页面丰富数据
GitHub trending 没有官方 API——抓取 HTML 获取仓库 slug(html_attribute 读取 href),然后使用 {PL} 将每个 slug 分发到 GitHub REST API:
examples/config_github_trending.json
{
"item": {
"connector_config": {
"response_type": "HTML",
"url": "https://github.com/trending",
"server_config": { "method": "GET", "headers": { "User-Agent": "Mozilla/5.0 (fitter demo)" } }
},
"model": {
"array_config": {
"root_path": "article.Box-row h2 a",
"length_limit": 5,
"item_config": {
"field": {
"type": "string",
"html_attribute": "href",
"generated": { "model": {
"type": "object",
"connector_config": {
"response_type": "json",
"url": "https://api.github.com/repos{PL}",
"server_config": { "method": "GET", "headers": { "User-Agent": "fitter-demo" } },
"null_on_error": true
},
"model": { "object_config": { "fields": {
"repo": { "base_field": { "type": "string", "path": "full_name" } },
"stars": { "base_field": { "type": "int", "path": "stargazers_count" } },
"language": { "base_field": { "type": "string", "path": "language" } }
} } }
} }
}
}
}
}
},
"limits": { "host_request_limiter": { "api.github.com": 2 } }
}[{"repo": "block/buzz", "stars": 6214, "language": "Rust"}, {"repo": "koala73/worldmonitor", "stars": 71179, "language": "TypeScript"}]使用表达式在 JSON 字段上连接
当数组项是对象时,连接键位于对象内部——使用 {{{FromExp=...}}} 将其取出(expr-lang 作用于 fRes,即当前项)。图书搜索 → 作者详情,搜索查询通过 input 提供:
examples/config_book_authors.json
"url": "https://openlibrary.org/authors/{{{FromExp=fromJSON(fRes).author_key[0]}}}.json"./fitter_cli --path=examples/config_book_authors.json --input=dune[{"title": "Dune", "year": 1965, "author": {"name": "Frank Herbert", "born": "8 October 1920", "died": "11 February 1986"}}]将结果写入本地文件
file_storage 生成字段将字段转换为写入操作——前 5 大加密货币追加到 CSV,每个项目一行。裸 {{{json.path}}} 占位符读取当前项目;{HUMAN_INDEX} 标记从 1 开始的排名(项目并行处理,因此追加按完成顺序落盘——按排名列排序):
examples/config_crypto_csv.json
"file_storage": {
"content": "{HUMAN_INDEX},{{{name}}},{{{current_price}}},{{{price_change_percentage_24h}}}\n",
"file_name": "coins.csv",
"path": "/tmp/fitter-report",
"append": true
}$ sort -n /tmp/fitter-report/coins.csv
1,Bitcoin,64778,-2.3
2,Ethereum,1881.01,-3.4
3,Tether,0.999265,0从 PDF 中提取文本
response_type: "pdf" 将任何获取的 PDF 转换为 JSON 文档——{"text": "...", "pages": ["..."], "total_pages": N}——因此常规 JSON 路径(text、pages.0)和表达式都可以在其上工作。比特币白皮书、页数加上修剪后的简介:
{
"item": {
"connector_config": {
"response_type": "pdf",
"url": "https://bitcoin.org/bitcoin.pdf",
"server_config": { "method": "GET" }
},
"model": {
"object_config": {
"fields": {
"total_pages": { "base_field": { "type": "int", "path": "total_pages" } },
"intro": {
"base_field": {
"type": "string",
"path": "pages.0",
"generated": {
"calculated": {
"type": "string",
"expression": "trim(fRes[:100]) + \"...\""
}
}
}
}
}
}
}
}
}{"intro": "Bitcoin: A Peer-to-Peer Electronic Cash SystemSatoshi Nakamotosatoshin@gmx.comwww.bitcoin.orgAbstrac...", "total_pages": 9}收集信息的方式
Server - 解析来自某些 API 或 http 请求的响应(使用 http.Client)
Browser - 使用 chromium + docker + playwright/cypress 模拟真实浏览器并获取 DOM 信息
Static - 将静态字符串解析为数据
可解析的格式
JSON - 解析 JSON 以获取特定信息
XML - 解析 xml 树以获取特定信息
HTML - 解析 dom 树以获取特定信息
XPath - 解析 dom 树以获取特定信息,但使用 xpath
PDF - 从 PDF 文档中提取文本;内容以 JSON
{"text": "...", "pages": ["..."], "total_pages": N}形式暴露,因此像text或pages.0这样的常规 JSON 路径可以工作
像库一样使用
go get github.com/PxyUp/fitterpackage main
import (
"fmt"
"github.com/PxyUp/fitter/lib"
"github.com/PxyUp/fitter/pkg/config"
"log"
"net/http"
)
func main() {
res, err := lib.Parse(&config.Item{
ConnectorConfig: &config.ConnectorConfig{
ResponseType: config.Json,
Url: "https://random-data-api.com/api/appliance/random_appliance",
ServerConfig: &config.ServerConnectorConfig{
Method: http.MethodGet,
},
},
Model: &config.Model{
ObjectConfig: &config.ObjectConfig{
Fields: map[string]*config.Field{
"my_id": {
BaseField: &config.BaseField{
Type: config.Int,
Path: "id",
},
},
"generated_id": {
BaseField: &config.BaseField{
Generated: &config.GeneratedFieldConfig{
UUID: &config.UUIDGeneratedFieldConfig{},
},
},
},
"generated_array": {
ArrayConfig: &config.ArrayConfig{
RootPath: "@this|@keys",
ItemConfig: &config.ObjectConfig{
Field: &config.BaseField{
Type: config.String,
},
},
},
},
},
},
},
}, nil, nil, nil, nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(res.ToJson())
}
输出:
{
"generated_array": ["id","uid","brand","equipment"],
"my_id": 6000,
"generated_id": "26b08b73-2f2e-444d-bcf2-dac77ac3130e"
}使用 lib.ParseCtx(ctx, ...) 传递 context.Context:取消它会中止进行中的获取(HTTP 请求、无头浏览器、docker 容器),并端到端应用截止时间。lib.Parse 等同于 lib.ParseCtx(context.Background(), ...)。
如何使用 Fitter
或在本地:
go run cmd/fitter/main.go --path=./examples/config_api.json参数
--path - string[""] - Fitter 配置的路径
--url - string[""] - Fitter 配置的 url
--verbose - bool[false] - 启用日志记录
--plugins - string[""] - Fitter 插件的路径
--log-level - enum["info", "error", "debug", "fatal"] - 设置日志级别(仅在 verbose 设置为 true 时)
如何使用 Fitter_CLI
或在本地:
go run cmd/cli/main.go --path=./examples/cli/config_cli.json参数
--path - string[""] - Fitter_CLI 配置的路径
--url - string[""] - Fitter_CLI 配置的 url
--copy - bool[false] - 将信息复制到剪贴板
--pretty - bool[true] - 使结果可读(也影响复制)
--verbose - bool[false] - 启用日志记录
--omit-error-pretty - bool[false] - 如果 pretty 无效则提供纯值
--plugins - string[""] - Fitter 插件的路径
--log-level - enum["info", "error", "debug", "fatal"] - 设置日志级别(仅在 verbose 设置为 true 时)
--input - string[""] - 为格式化指定输入值。示例:
--input=\""124"\"--input=124--input='{"test": 5}'
./fitter_cli_${VERSION} --path=./examples/cli/config_cli.json --copy=truefitter_cli auth — 连接 OAuth2 账户
一次性交互式登录,为 oauth2 连接器配置存储(刷新)令牌:
# device flow (default when the provider supports it): no callback, works headless
./fitter_cli_${VERSION} auth --provider github --client-id <ID> --client-secret <SECRET> --token-file ~/.fitter/tokens/github.json
# custom provider without preset
./fitter_cli_${VERSION} auth --auth-url https://.../authorize --token-url https://.../token --client-id <ID> --token-file ./token.json参数:
--provider - 预设已知端点:
github|google|microsoft|gitlab|spotify--client-id / --client-secret - OAuth2 应用凭据(某些设备流程无需 secret 即可工作)
--token-file - 存储接收到的令牌的位置(0600 权限);在
oauth2.token_file中引用相同的路径--flow -
auto(如果可用则使用设备,否则使用浏览器)、device(访问 url + 输入代码)或browser(带 PKCE 的 localhost 回调,默认端口 8988——将http://127.0.0.1:8988/callback注册为应用回调 url)--scopes - 逗号分隔的 scopes
--auth-url/--token-url/--device-auth-url/--auth-style - 为没有预设的提供者覆盖端点
--port - int[8988] - 浏览器流程回调端口(环境变量
FITTER_AUTH_PORT);使用默认值时,在提供者处注册的回调 url 是http://127.0.0.1:8988/callback--listen - 浏览器流程绑定地址,默认
127.0.0.1;在容器内设置为0.0.0.0,以便发布的端口到达监听器(环境变量FITTER_AUTH_LISTEN)--redirect-url - 当回调 url 与监听地址不同时,在提供者处注册的回调 url,例如 docker 端口映射(环境变量
FITTER_AUTH_REDIRECT_URL)--no-browser - 仅打印授权 url
在 Docker 内运行:参见 Docker 中的 OAuth2 账户。
登录后,该命令会打印可直接使用的 oauth2 配置块。连接器会自动刷新访问令牌,并将轮换后的刷新令牌写回令牌文件,因此只需登录一次。
fitter_cli browser-login — 复用真实的登录会话
对于没有 API/OAuth 的网站:在真实的(有头)浏览器窗口中手动登录一次——任何认证方案都可以,包括密码、2FA、SSO 和验证码——并通过 storage_state_file 保存会话用于无头抓取:
./fitter_cli_${VERSION} browser-login --url https://example.com/login --storage-state ~/.fitter/sessions/example.json
# a browser window opens; log in, then press Enter in the terminal to save the session参数:
--url - 要打开的登录页面(必填)
--storage-state - 保存会话的位置(cookies + localStorage,0600 权限);在
playwright.storage_state_file中引用相同的路径(必填)--browser - enum["Chromium", "FireFox", "WebKit"] 默认 "Chromium";使用与抓取配置相同的值——网站可能会将会话绑定到浏览器指纹
--install - bool[false] - 首先安装 playwright 浏览器
--indexeddb - bool[false] - 在快照中包含 IndexedDB(Firebase Auth 等)
重新运行该命令会先加载现有状态,因此您可以扩展/刷新会话而无需从头登录。抓取连接器还会在每次运行后将刷新后的 cookies 写回,只要定期使用就能保持会话有效。需要显示器:在 Docker 内,请在主机上运行此命令并挂载文件——参见 Docker 中的浏览器会话。
示例:
Server 版本 HackerNews + Quotes + Guardian News - 使用 API + HTML + XPath 解析
Chromium 版本 Guardian News + Quotes - 使用 HTML 解析 + 浏览器模拟
Docker 版本 Docker 版本:Guardian News + Quotes - 使用 HTML 解析 + 来自 Docker 镜像的浏览器
Playwright 版本 Playwright 版本:Guardian News + Quotes - 使用 HTML 解析 + 来自 Playwright 框架的浏览器
Playwright 版本 Playwright 版本:England Cities + Weather - 使用 HTML + XPath 解析 + 来自 Playwright 框架的浏览器
JSON 版本 生成分页 - 使用静态连接器生成分页数组
Server 版本 获取当前时间 - 从 url 获取时间并格式化
如何使用 Fitter_Agent
Fitter Agent 是一个由 AI 驱动的 CLI,使用 Claude 将自然语言请求转换为 Fitter 配置并自动执行。
或在本地:
export ANTHROPIC_API_KEY=<your-anthropic-api-key>
go run cmd/agent/main.go参数
--api-key - string[""] - Anthropic API 密钥。优先使用
ANTHROPIC_API_KEY环境变量,这样密钥不会出现在您的 shell 历史中--model - string["claude-opus-4-8"] - 要使用的 Claude 模型
--effort - enum["low", "medium", "high", "xhigh", "max"] - 推理努力程度,默认 "high"。降低以获得更快/更便宜的配置,提高以应对更难的提取
--verbose - bool[false] - 启用日志记录
--log-level - enum["info", "error", "debug", "fatal"] - 设置日志级别
--plugins - string[""] - Fitter 插件的路径
--chromium-limit - uint[0] - 限制并发 Chromium 实例数
--docker-limit - uint[0] - 限制并发 Docker 容器数
--playwright-limit - uint[0] - 限制并发 Playwright 实例数
工作原理
┌─────────────────────────────────────────────────────────────────┐
│ 1. User enters natural language request │
│ "Get top 5 HackerNews stories with titles and scores" │
│ ↓ │
│ 2. Claude returns a config in a schema-constrained response │
│ ↓ │
│ 3. Agent validates it; on failure the error is handed back │
│ to Claude to repair (up to 3 attempts) │
│ ↓ │
│ 4. Agent displays config and asks for confirmation │
│ ↓ │
│ 5. On confirmation, executes via lib.Parse() │
│ ↓ │
│ 6. Returns structured JSON result │
└─────────────────────────────────────────────────────────────────┘优化配置
代理会保留对话,因此在生成配置后,您只需说出要更改的内容,而无需重新陈述整个请求:
> Get top 3 HackerNews stories with titles and scores
refine> Only return 5 items and also include the article URL使用 new 忘记当前配置并开始新的会话。
交互式 REPL 命令
help - 显示帮助消息
new/reset - 忘记当前配置并重新开始
clear - 清除屏幕
exit/quit/q - 退出代理
示例会话
$ export ANTHROPIC_API_KEY=sk-ant-...
$ ./fitter_agent
╔══════════════════════════════════════════════════════════════╗
║ Fitter Agent - AI-Powered Data Extraction ║
╚══════════════════════════════════════════════════════════════╝
Describe what you want to extract. Follow-up messages refine the
previous config. Type 'help' for commands.
> Get top 3 HackerNews stories with titles and scores
┌─ Generated Fitter Config ───────────────────────────────────────
{
"item": {
"connector_config": {
"response_type": "json",
"url": "https://hacker-news.firebaseio.com/v0/topstories.json",
"server_config": { "method": "GET" }
},
"model": {
"array_config": {
"root_path": "@this",
"length_limit": 3,
"item_config": {
"fields": {
"id": { "base_field": { "type": "int" } },
"story": {
"base_field": {
"type": "int",
"generated": {
"model": {
"type": "object",
"connector_config": {
"response_type": "json",
"url": "https://hacker-news.firebaseio.com/v0/item/{PL}.json",
"server_config": { "method": "GET" }
},
"model": {
"object_config": {
"fields": {
"title": { "base_field": { "type": "string", "path": "title" } },
"score": { "base_field": { "type": "int", "path": "score" } }
}
}
}
}
}
}
}
}
}
}
}
}
}
└──────────────────────────────────────────────────────────────────
Execute this config? [y/n]: y
┌─ Result ────────────────────────────────────────────────────────
[
{
"id": 46740029,
"story": { "title": "Show HN: Open-source project", "score": 161 }
},
{
"id": 46737630,
"story": { "title": "Interesting article", "score": 237 }
},
{
"id": 46735644,
"story": { "title": "New technology release", "score": 192 }
}
]
└──────────────────────────────────────────────────────────────────
> exit
Goodbye!示例请求
请求 | 功能 |
| 获取当前 BTC 价格 |
| 使用 CSS 选择器进行 HTML 抓取 |
| 嵌套 API 调用 |
| 简单的 API 提取 |
| 网页抓取 |
支持的功能
代理可以为以下内容生成配置:
JSON APIs - 支持 GET/POST 方法的 REST API
HTML Scraping - 基于 CSS 选择器的提取
XPath Scraping - 基于 XPath 的提取
Nested API Calls - 获取列表中每个项目的详细信息
Browser Emulation - 使用 Playwright 处理 JS 渲染的页面
Formatted Fields - 带占位符的 URL 模板
Array Limiting - 将结果限制为 N 个项目
配置
连接器
这是您获取数据的方式
type ConnectorConfig struct {
ResponseType ParserType `json:"response_type" yaml:"response_type"`
Url string `json:"url" yaml:"url"`
Attempts uint32 `json:"attempts" yaml:"attempts"`
NullOnError bool `yaml:"null_on_error" json:"null_on_error"`
StaticConfig *StaticConnectorConfig `json:"static_config" yaml:"static_config"`
IntSequenceConfig *IntSequenceConnectorConfig `json:"int_sequence_config" yaml:"int_sequence_config"`
ServerConfig *ServerConnectorConfig `json:"server_config" yaml:"server_config"`
BrowserConfig *BrowserConnectorConfig `yaml:"browser_config" json:"browser_config"`
PluginConnectorConfig *PluginConnectorConfig `json:"plugin_connector_config" yaml:"plugin_connector_config"`
ReferenceConfig *ReferenceConnectorConfig `yaml:"reference_config" json:"reference_config"`
FileConfig *FileConnectorConfig `json:"file_config" yaml:"file_config"`
}NullOnError[false] - 如果设为 true,则所有错误都会被忽略
ResponseType - 枚举["HTML", "json", "xpath", "XML", "pdf"] - 连接器返回数据的格式
Attempts - 连接器获取数据时尝试的次数
Url - 定义要请求的地址。重要提示:可以注入父级值作为字符串
https://api.open-meteo.com/v1/forecast?latitude={{{latitude}}}&longitude={{{longitude}}}&hourly=temperature_2m&forecast_days=1
配置可以是以下之一:
示例:
{
"response_type": "xpath",
"attempts": 3,
"url": "https://openweathermap.org/find?q={PL}",
"browser_config": {
"playwright": {
"timeout": 30,
"wait": 30,
"install": false,
"browser": "Chromium"
}
}
}PluginConnectorConfig
连接器可以通过插件系统定义。要使用它,你需要为 Fitter/Cli 应用以下标志(插件的位置):
... --plugins=./examples/plugin--plugins - 在提供的文件夹中查找所有扩展名为 ".so" 的文件(不包含子目录)
type PluginConnectorConfig struct {
Name string `json:"name" yaml:"name"`
Config json.RawMessage `json:"config" yaml:"config"`
}{
"name": "connector",
"config": {
"name": "Elon"
}
}Name - 插件名称
Config - 插件的 json 配置
如何构建插件
构建插件
go build -buildmode=plugin -gcflags="all=-N -l" -o examples/plugin/connector.so examples/plugin/connector/connector.go确保你导出了实现 pl.ConnectorPlugin 接口的 Plugin 变量
CLI 示例:
https://github.com/PxyUp/fitter/blob/master/examples/cli/config_plugin.json#L5
插件示例:
package main
import (
"context"
"encoding/json"
"fmt"
"github.com/PxyUp/fitter/pkg/config"
"github.com/PxyUp/fitter/pkg/logger"
"github.com/PxyUp/fitter/pkg/builder"
pl "github.com/PxyUp/fitter/pkg/plugins/plugin"
)
var (
_ pl.ConnectorPlugin = &plugin{}
Plugin plugin
)
type plugin struct {
log logger.Logger
Name string `json:"name" yaml:"name"`
}
func (pl *plugin) Get(ctx context.Context, parsedValue builder.Interfacable, index *uint32, input builder.Interfacable) ([]byte, error) {
return []byte(fmt.Sprintf(`{"name": "%s"}`, pl.Name)), nil
}
func (pl *plugin) SetConfig(cfg *config.PluginConnectorConfig, logger logger.Logger) {
pl.log = logger
if cfg.Config != nil {
err := json.Unmarshal(cfg.Config, pl)
if err != nil {
pl.log.Errorw("cant unmarshal plugin configuration", "error", err.Error())
return
}
}
}ReferenceConnectorConfig
允许从引用获取预取数据的连接器
type ReferenceConnectorConfig struct {
Name string `yaml:"name" json:"name"`
}示例
https://github.com/PxyUp/fitter/blob/master/examples/cli/config_ref.json#L66
Name - 来自引用映射的引用名称
IntSequenceConnectorConfig
静态连接器的改进版本,生成整数序列作为结果
type IntSequenceConnectorConfig struct {
Start int `json:"start" yaml:"start"`
End int `json:"end" yaml:"end"`
Step int `json:"step" yaml:"step"`
}Start[0] - 生成的起始点(包含)
End[0] - 生成的结束点(不包含在最终结果中,类似于任何语言中的 range)
Step[1] - 序列的间隔
示例
{
"start": 0,
"end": 2
// Generate [0, 1]
}FileConnectorConfig
从提供的文件获取数据的连接器类型
type FileConnectorConfig struct {
Path string `yaml:"path" json:"path"`
UseFormatting bool `yaml:"use_formatting" json:"use_formatting"`
}StaticConnectorConfig
从提供的字符串获取数据的连接器类型
type StaticConnectorConfig struct {
Value string `json:"value" yaml:"value"`
Raw json.RawMessage `json:"raw" yaml:"raw"`
}示例:
https://github.com/PxyUp/fitter/blob/master/examples/cli/config_static_connector.json#L5
{
"value": "[1,2,3,4,5]"
}ServerConnectorConfig
使用 golang http.Client(类似 curl 的服务端请求)获取数据的连接器类型
type ServerConnectorConfig struct {
Method string `json:"method" yaml:"method"`
Headers map[string]string `yaml:"headers" json:"headers"`
Timeout uint32 `yaml:"timeout" json:"timeout"`
JsonRawBody json.RawMessage `json:"json_raw_body" yaml:"json_raw_body"`
Body string `yaml:"body" json:"body"`
ErrorOnStatus bool `json:"error_on_status" yaml:"error_on_status"`
Proxy *ProxyConfig `yaml:"proxy" json:"proxy"`
OAuth2 *OAuth2Config `yaml:"oauth2" json:"oauth2"`
}Method - 支持所有 http 方法:GET、POST、PUT、DELETE、PATCH、OPTIONS、HEAD
Headers - 预定义请求时使用的请求头可注入到键/值中
Timeout[sec] - 默认 60 秒超时,或使用提供的值
Body - 请求体,解析后的值可注入
JsonRawBody - json 格式的请求体;值可注入
ErrorOnStatus - 可选,默认
false。当为true时,HTTP 响应状态码>= 400被视为获取错误(通过attempts/null_on_error处理),而不是解析错误响应体——这样你可以区分获取失败与真正空结果的情况。保持false则保留原始行为,即解析返回的任何响应体。Proxy - 为请求设置代理配置
OAuth2 - 自动获取/刷新访问令牌,并将其作为
Authorization请求头发送配置
请求默认发送可识别的
User-Agent(fitter (+https://github.com/PxyUp/fitter));在Headers中设置你自己的User-Agent可覆盖它。
示例:
{
"method": "GET",
"proxy": {
"server": "http://localhost:8080",
"username": "pyx"
}
}OAuth2 配置
在请求前自动获取访问令牌,并将其作为 Authorization 请求头注入(覆盖通过 headers 设置的请求头)。令牌缓存在内存中,并在过期前刷新;当收到 401 响应时,缓存的令牌会被丢弃,并使用新令牌重试一次请求。
type OAuth2Config struct {
TokenUrl string `json:"token_url" yaml:"token_url"`
GrantType OAuth2GrantType `json:"grant_type" yaml:"grant_type"`
ClientId string `json:"client_id" yaml:"client_id"`
ClientSecret string `json:"client_secret" yaml:"client_secret"`
Scopes []string `json:"scopes" yaml:"scopes"`
RefreshToken string `json:"refresh_token" yaml:"refresh_token"`
EndpointParams map[string]string `json:"endpoint_params" yaml:"endpoint_params"`
AuthStyle string `json:"auth_style" yaml:"auth_style"`
TokenFile string `json:"token_file" yaml:"token_file"`
}TokenUrl - 令牌端点 URL。也支持格式化
GrantType - 枚举["client_credentials", "refresh_token"],默认为 "client_credentials"。对于用户已一次性授权的 API(Google、Microsoft 等)且你持有长期有效的刷新令牌时,使用 "refresh_token"
ClientId/ClientSecret - 客户端凭据。也支持格式化,例如
{{{FromEnv=CLIENT_SECRET}}}Scopes - 请求的作用域
RefreshToken - "refresh_token" 授权类型必需。也支持格式化
EndpointParams - 额外的令牌端点参数(例如 Auth0 的
audience),仅适用于 "client_credentials" 授权类型AuthStyle - 枚举["", "header", "params"] - 客户端凭据如何传递给令牌端点:basic auth 请求头或请求体;空表示自动检测
TokenFile - 可选路径(支持
~/),用于在运行之间持久化令牌;存储的令牌优先于 RefreshToken,轮换后的刷新令牌会写回——对于使用一次性刷新令牌的提供商(GitHub Apps 等)是必需的。使用 fitter_cli auth 创建它
示例:
{
"method": "GET",
"oauth2": {
"token_url": "https://oauth2.googleapis.com/token",
"grant_type": "refresh_token",
"client_id": "{{{FromEnv=GOOGLE_CLIENT_ID}}}",
"client_secret": "{{{FromEnv=GOOGLE_CLIENT_SECRET}}}",
"refresh_token": "{{{FromEnv=GOOGLE_REFRESH_TOKEN}}}"
}
}代理配置
type ProxyConfig struct {
// Proxy to be used for all requests. HTTP and SOCKS proxies are supported, for example
// `http://myproxy.com:3128` or `socks5://myproxy.com:3128`. Short form `myproxy.com:3128`
// is considered an HTTP proxy.
Server string `json:"server" yaml:"server"`
// Optional username to use if HTTP proxy requires authentication.
Username string `json:"username" yaml:"username"`
// Optional password to use if HTTP proxy requires authentication.
Password string `json:"password" yaml:"password"`
}{
"server": "http://localhost:8080",
"username": "pyx"
}环境变量
FITTER_HTTP_WORKER - int[1000] - 默认并发 HTTP 工作线程数
BrowserConnectorConfig
模拟通过浏览器获取数据的连接器类型
type BrowserConnectorConfig struct {
Chromium *ChromiumConfig `json:"chromium" yaml:"chromium"`
Docker *DockerConfig `json:"docker" yaml:"docker"`
Playwright *PlaywrightConfig `json:"playwright" yaml:"playwright"`
}配置可以是以下之一:
Chromium - 使用本地安装的 Chromium 获取数据
Docker - 使用 docker 作为服务来启动容器获取数据
Playwright - 使用 playwright 框架获取数据
示例:
{
"docker": {
"wait": 10000,
"image": "docker.io/zenika/alpine-chrome:with-node",
"entry_point": "chromium-browser",
"purge": true
}
}Chromium
使用本地安装的 Chromium 获取数据
type ChromiumConfig struct {
Path string `yaml:"path" json:"path"`
Timeout uint32 `yaml:"timeout" json:"timeout"`
Wait uint32 `yaml:"wait" json:"wait"`
Flags []string `yaml:"flags" json:"flags"`
}Path - Chromium 二进制文件的路径
Timeout[sec] - 执行 chromium 的超时时间
Wait[msec] - 页面加载的超时时间
Flags - Chromium 的标志,默认值:"--headless", "--proxy-auto-detect", "--temp-profile", "--incognito", "--disable-logging", "--disable-extensions", "--no-sandbox"
示例:
{
"path": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
"wait": 10000
}Docker
使用 Docker 启动容器获取数据
type DockerConfig struct {
Image string `yaml:"image" json:"image"`
EntryPoint string `json:"entry_point" yaml:"entry_point"`
Timeout uint32 `yaml:"timeout" json:"timeout"`
Wait uint32 `yaml:"wait" json:"wait"`
Flags []string `yaml:"flags" json:"flags"`
Purge bool `json:"purge" yaml:"purge"`
NoPull bool `yaml:"no_pull" json:"no_pull"`
PullTimeout uint32 `yaml:"pull_timeout" json:"pull_timeout"`
}Docker 默认镜像:docker.io/zenika/alpine-chrome
Image - docker 注册表的镜像(需提供注册表主机)
EntryPoint - 在容器内运行的命令
Timeout[sec] - 运行容器的超时时间(不包括拉取镜像)
Wait[msec] - 页面加载的超时时间(仅适用于基于 Chromium 的容器)
Flags - 运行容器的命令参数,基于 Chromium 的默认值:"--no-sandbox","--headless", "--proxy-auto-detect", "--temp-profile", "--incognito", "--disable-logging", "--disable-gpu"
Purge - 工作完成后是否移除容器(类似 docker rm)
NoPull - 阻止拉取镜像
PullTimeout - 定义拉取容器的超时时间
环境变量
DOCKER_HOST - string - (EnvOverrideHost) 设置 docker 服务器的 URL。
DOCKER_API_VERSION - string - (EnvOverrideAPIVersion) 设置要使用的 API 版本,留空表示使用最新版本。
DOCKER_CERT_PATH - string - (EnvOverrideCertPath) 指定加载 TLS 证书的目录(ca.pem、cert.pem、key.pem)。
DOCKER_TLS_VERIFY - bool - (EnvTLSVerify) 启用或禁用 TLS 验证(默认关闭)
示例:
{
"wait": 10000,
"image": "docker.io/zenika/alpine-chrome:with-node",
"entry_point": "chromium-browser",
"purge": true
}Playwright
通过 playwright 框架运行浏览器
type PlaywrightConfig struct {
Browser PlaywrightBrowser `json:"browser" yaml:"browser"`
Install bool `yaml:"install" json:"install"`
Timeout uint32 `yaml:"timeout" json:"timeout"`
Wait uint32 `yaml:"wait" json:"wait"`
TypeOfWait *playwright.WaitUntilState `json:"type_of_wait" yaml:"type_of_wait"`
PreRunScript string `json:"pre_run_script" yaml:"pre_run_script"`
PostRunScript string `json:"post_run_script" yaml:"post_run_script"`
Stealth bool `json:"stealth" yaml:"stealth"`
StorageStateFile string `json:"storage_state_file" yaml:"storage_state_file"`
IndexedDB bool `json:"indexed_db" yaml:"indexed_db"`
Proxy *ProxyConfig `yaml:"proxy" json:"proxy"`
}Browser - 枚举["Chromium", "FireFox", "WebKit"] - 使用哪个浏览器
Install - 是否安装浏览器(首次使用时下载与内置
playwright-go版本匹配的驱动程序和浏览器;使用ghcr.io/pxyup/fitter-mcp:playwright镜像时不需要,该镜像已预装)Timeout[sec] - 运行 playwright 的超时时间
Wait[sec] - 页面加载的超时时间
TypeOfWait - 枚举["load", "domcontentloaded", "networkidle", "commit"] 我们等待页面的哪个状态,默认为 "load"
PreRunScript[""] - 通过 AddInitScript 注入并在任何页面脚本运行之前执行的脚本(在文档创建时、导航完成之前执行)。用于修补环境(navigator 覆盖、API 桩)。无法访问已加载的 DOM。也支持占位符 {PL}
PostRunScript[""] - 页面加载后、读取页面内容之前执行的脚本。用于 DOM 交互(点击、滚动)。也支持占位符 {PL}
Stealth[false] - 添加脚本以尝试通过机器人防御
StorageStateFile[""] - playwright 存储状态 json(cookies + localStorage)的路径(支持
~/):在导航前加载到浏览器上下文中,每次运行后写回,以便刷新后的会话保持有效。让无头运行可以复用真实登录——使用 fitter_cli browser-login 创建一次该文件。登录和抓取时使用相同的browser:网站可能会将会话绑定到浏览器指纹。也支持格式化IndexedDB[false] - 在持久化的存储状态中包含 IndexedDB(某些 SPA,例如 Firebase Auth,将令牌存储在其中)
Proxy - 为请求设置代理配置
示例
{
"timeout": 30,
"wait": 30,
"install": false,
"browser": "Chromium"
}Related MCP server: MCP Server Fetch Python
Model
通过 Model 我们定义抓取的结果
type Model struct {
ObjectConfig *ObjectConfig `yaml:"object_config" json:"object_config"`
ArrayConfig *ArrayConfig `json:"array_config" yaml:"array_config"`
BaseField *BaseField `json:"base_field" yaml:"base_field"`
IsArray bool `json:"is_array" yaml:"is_array"`
}配置可以是以下之一:
ObjectConfig - 对象格式的配置
ArrayConfig - 数组格式的配置
BaseField - 单个/生成字段的配置
示例:
{
"object_config": {}
}ObjectConfig
对象和字段的配置
type ObjectConfig struct {
Fields map[string]*Field `json:"fields" yaml:"fields"`
Field *BaseField `json:"field" yaml:"field"`
ArrayConfig *ArrayConfig `json:"array_config" yaml:"array_config"`
Condition string `json:"condition" yaml:"condition"`
}Condition - 可选的条件表达式,在解析之前针对源节点求值;为 false 时整个对象从父级中省略(字段完全不解析)
配置可以是以下之一:
Fields - 每个字段定义的映射;键 - 字段名,值 - 配置
Field - 用于数组元素;将被反序列化为基本类型(如 "string"、"int" 等)的字段(此处用于基本类型数组的情况)
ArrayConfig - 用于数组元素;数组的数组的反序列化
示例:
{
"fields": {
"title": {
"base_field": {
"type": "string",
"path": "type"
}
}
}
}ArrayConfig
数组和字段的配置
type ArrayConfig struct {
RootPath string `json:"root_path" yaml:"root_path"`
Reverse bool `yaml:"reverse" json:"reverse"`
ItemConfig *ObjectConfig `json:"item_config" yaml:"item_config"`
LengthLimit uint32 `json:"length_limit" yaml:"length_limit"`
Condition string `json:"condition" yaml:"condition"`
ItemCondition string `json:"item_condition" yaml:"item_condition"`
StaticConfig *StaticArrayConfig `json:"static_array" yaml:"static_array"`
}RootPath - 用于查找数组根元素或 html 解析中重复元素的选择器,数组大小将是根元素下子元素的数量
Reverse - bool[false] - 指示需要使用反向迭代(n 到 1)
LengthLimit - 数组的固定大小(仅适用于生成的数组;不适用于静态数组)。注意:当源中的元素少于限制时,数组会用尾部的
null填充以保持声明的大小(这是有意为之)——省略length_limit则获取与源完全相同的长度Condition - 可选的条件表达式,在解析之前针对源节点求值;为 false 时整个数组从父级中省略
ItemCondition - 可选的条件表达式,针对每个构建的项目求值(fRes - 项目值,fSrc - 源元素,fIndex - 项目索引);解析为 false 的项目会从数组中删除 - 声明式过滤。不适用于 static_array
配置可以是以下之一:
ItemConfig - 数组中每个元素的配置
StaticConfig - 静态数组的配置
示例:
{
"root_path": "#content dt.quote > a",
"item_config": {
"field": {
"type": "string"
}
}
}字段
字段的通用配置
type Field struct {
BaseField *BaseField `json:"base_field" yaml:"base_field"`
ObjectConfig *ObjectConfig `json:"object_config" yaml:"object_config"`
ArrayConfig *ArrayConfig `json:"array_config" yaml:"array_config"`
FirstOf []*Field `json:"first_of" yaml:"first_of"`
}配置可以是以下之一:
BaseField - 将像"string"、"int"等基本类型一样反序列化的字段
ObjectConfig - 当字段位于嵌套对象中时
ArrayConfig - 当字段位于数组中时
FirstOf - 将选择第一个非空解析字段
示例:
{
"base_field": {
"type": "string",
"path": "div.current-temp span.heading"
}
}BaseField
当我们想要获取一些静态信息或生成新信息时
type BaseField struct {
Type FieldType `yaml:"type" json:"type"`
Path string `yaml:"path" json:"path"`
HTMLAttribute string `json:"html_attribute" yaml:"html_attribute"`
Condition string `json:"condition" yaml:"condition"`
Generated *GeneratedFieldConfig `yaml:"generated" json:"generated"`
FirstOf []*BaseField `json:"first_of" yaml:"first_of"`
}FieldType - enum["null", "boolean", "string", "int", "int64", "float", "float64", "array", "object", "html", "raw_string"] - 用于解析的静态字段。重要:html 类型仅适用于返回 HTML 的连接器(在这种情况下 HTMLAttribute 无效)。示例
Path - 用于解析的选择器(如果是数组子元素则为相对路径)
HTMLAttribute - 额外值,仅通过 goquery 在 HTML 解析中生效。这里可以指定需要解析的属性。
Condition - 可选的 condition 表达式,针对提取的值(fRes/fResJson/fResRaw、fIndex;fSrc - 字段解析来源的节点,包含兄弟节点)求值;当为 false 时,该字段从父对象/数组中省略,而不是生成 null。在 Generated 之前求值,因此 false 条件也会跳过生成工作(子请求、文件下载)
重要:默认情况下"string"类型会被修剪并替换所有特殊字符,如果需要纯字符串请使用"raw_string"
配置可以是以下之一或为空:
示例
{
"generated": {
"uuid": {}
}
}{
"type": "string",
"path": "text()"
}条件字段
每个字段都可以携带一个 condition - 一个 expr-lang 表达式(预定义值)。当它求值为除 true 之外的任何值时,该字段将从输出中省略(键/项消失),而不是设置为 null。无效表达式也会省略该字段并记录错误。
条件求值的位置:
BaseField.
condition- 提取之后:fRes是提取的值,fSrc是字段解析来源的节点(包含其兄弟节点)- 因此fSrc.on_sale == true可以根据未提取的数据来门控字段。false 条件会完全跳过 generated 工作(无子请求、无文件下载)ObjectConfig.
condition/ ArrayConfig.condition- 解析之前:fRes/fSrc是源节点(json 为解析值,html 为文本内容)ArrayConfig.
item_condition- 针对每个已构建的项:fRes是该项,fSrc是构建该项的源元素,fIndex是其索引;false 的项会被丢弃 - 声明式数组过滤。使用fSrc可以根据源属性进行过滤,而无需将它们添加到输出中
过滤数组项 - fSrc.in_stock 读取源元素(未提取到输出中),fRes.price 读取构建的项:
{
"array_config": {
"root_path": "products",
"item_condition": "fSrc.in_stock && fRes.price > 0",
"item_config": {
"fields": {
"title": { "base_field": { "type": "string", "path": "title" } },
"price": { "base_field": { "type": "float", "path": "price" } }
}
}
}
}除非值通过检查,否则省略键:
{
"discount": {
"base_field": {
"type": "float",
"path": "discount_pct",
"condition": "fRes > 0"
}
}
}特殊情况:
在 static array 中,被省略的项保持
null(位置由定义固定,索引永远不会移动)如果根模型配置被省略,解析结果为
null
可运行示例:examples/config_conditions.json
GeneratedFieldConfig
提供动态生成字段的功能
type GeneratedFieldConfig struct {
UUID *UUIDGeneratedFieldConfig `yaml:"uuid" json:"uuid"`
Static *StaticGeneratedFieldConfig `yaml:"static" json:"static"`
Formatted *FormattedFieldConfig `json:"formatted" yaml:"formatted"`
Plugin *PluginFieldConfig `yaml:"plugin" json:"plugin"`
Calculated *CalculatedConfig `yaml:"calculated" json:"calculated"`
File *FileFieldConfig `yaml:"file" json:"file"`
Model *ModelField `yaml:"model" json:"model"`
FileStorageField *FileStorageField `json:"file_storage" yaml:"file_storage"`
}配置可以是以下之一:
UUID - 生成随机 UUID V4
Static - 生成静态字段
Formatted - 格式化字段
Model - 由其他连接器和模型生成的模型
Plugin - 插件字段
Calculated - 计算字段
File - 文件字段(用于从服务器下载文件)
FileStorage - 可以保存到本地文件的文件字段
示例:
{
"uuid": {}
}https://github.com/PxyUp/fitter/blob/master/examples/cli/config_cli.json#L58
{
"model": {
"type": "array",
"model": {
"array_config": {
"root_path": "#content dt.quote > a",
"item_config": {
"field": {
"type": "string"
}
}
}
},
"connector_config": {
"response_type": "HTML",
"url": "http://www.quotationspage.com/random.php",
"attempts": 3,
"browser_config": {
"chromium": {
"path": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
"wait": 10000
}
}
}
}
}UUID
动态生成随机 UUID V4,可用于生成唯一 ID
type UUIDGeneratedFieldConfig struct {
Regexp string `yaml:"regexp" json:"regexp"`
}Regexp - 提供匹配器,可用于获取生成的 UUID 的一部分
Static
生成静态字段
type StaticGeneratedFieldConfig struct {
Type FieldType `yaml:"type" json:"type"`
Value string `json:"value" yaml:"value"`
Raw json.RawMessage `json:"raw" yaml:"raw"`
}Type - enum["null", "boolean", "string", "int","int64","float","float64", "array", "object"] - 字段类型
Value - 字段的字符串值
Raw - 字段的纯 JSON 值
示例
{
"type": "int",
"value": "65"
}{
"type": "array",
"value": "[65,45]"
}{
"type": "array",
"raw": [65,45]
}格式化字段配置
生成格式化字段,将值从父级 base field 传递
type FormattedFieldConfig struct {
Template string `yaml:"template" json:"template"`
}示例: https://github.com/PxyUp/fitter/blob/master/examples/cli/config_cli.json#L98
{
"template": "https://news.ycombinator.com/item?id={PL}"
}文件存储字段
字段可用于将字段结果存储为本地文件
type FileStorageField struct {
Content string `json:"content" yaml:"content"`
Raw json.RawMessage `yaml:"raw" yaml:"raw"`
FileName string `json:"file_name" yaml:"file_name"`
Path string `json:"path" yaml:"path"`
Append bool `json:"append" yaml:"append"`
}Content - 内容的模板字符串。重要:可以包含父值作为字符串注入
Raw - 字段的原始 JSON 内容。重要:可以包含父值作为字符串注入
FileName - 用于存储文件的本地文件名。默认情况下,会尝试从 header 获取 FileName,然后从 url 获取。重要:可以包含父值作为字符串注入。
Path - 用于存储文件的本地父目录。默认路径是进程目录。重要:可以包含父值作为字符串注入
Append[false] - 是否追加到文件
{
"content": "{{{id}}}, {{{message}}}\n",
"append": true,
"file_name": "{{{id}}}.csv",
"path": "/Users/pxyup/fitter/examples/cli/test/csv"
}文件字段
字段可用于从服务器本地下载文件
type FileFieldConfig struct {
Config *ServerConnectorConfig `yaml:"config" json:"config"`
Url string `yaml:"url" json:"url"`
FileName string `json:"file_name" yaml:"file_name"`
Path string `json:"path" yaml:"path"`
}Config - ServerConfig 使用默认的 fitter http.Client 发送请求
Url - 图片的 URL。重要:连接器中的 URL 可以包含父值作为字符串注入
FileName - 用于存储文件的本地文件名。默认情况下,会尝试从 header 获取 FileName,然后从 url 获取。重要:可以包含父值作为字符串注入。
Path - 用于存储文件的本地父目录。默认路径是进程目录。重要:可以包含父值作为字符串注入
字段的结果将是本地文件路径字符串
{
"url": "https://images.shcdn.de/resized/w680/p/dekostoff-gobelinstoff-panel-oriental-cat-46-x-46_P19-KP_2.jpg",
"path": "/Users/pxyup/fitter/bin",
"config": {
"method": "GET"
}
}使用传播的 URL(父值作为字符串注入)
{
"url": "https://picsum.photos{PL}",
"path": "/Users/pxyup/fitter/bin",
"config": {
"method": "GET"
}
}配置示例:
https://github.com/PxyUp/fitter/blob/master/examples/cli/config_image.json
https://github.com/PxyUp/fitter/blob/master/examples/cli/config_image_multiple.json
计算字段
字段可以根据表达式生成不同类型
type CalculatedConfig struct {
Type FieldType `yaml:"type" json:"type"`
Expression string `yaml:"expression" json:"expression"`
}Type - 表达式的结果类型\
Expression - 用于计算的表达式(我们使用这个库进行表达式计算)
预定义值
FNull - builder.Nullvalue 的别名
FNil - nil 的别名
isNull(value T) - 用于检查值是否为 FNull 的函数
fRes - 来自 base field 解析的原始(具有正确类型)结果
fIndex - 父数组中的索引(仅当父级是数组字段时)
fResJson - 原始结果的 JSON 字符串表示
fResRaw - 字节格式的结果
fSrc - 仅在 condition/item_condition 表达式中可用:值解析来源的源节点(json 为解析值 - 包含兄弟节点,html 为文本内容)。在计算/格式化/通知器表达式中不可用
FNewLine - 换行符
{
"type": "bool",
"expression": "fRes > 500"
}插件字段
字段可以是 fitter 的某个外部插件
type PluginFieldConfig struct {
Name string `json:"name" yaml:"name"`
Config json.RawMessage `json:"config" yaml:"config"`
}Name - 插件名称(不带扩展名,仅名称)
Config - 插件的 json 配置
模型字段
可以通过新的 model 和 connector 动态生成的字段类型
type ModelField struct {
// Type of parsing
ConnectorConfig *ConnectorConfig `yaml:"connector_config" json:"connector_config"`
// Model of the response
Model *Model `yaml:"model" json:"model"`
Type FieldType `yaml:"type" json:"type"`
Path string `yaml:"path" json:"path"`
Expression string `yaml:"expression" json:"expression"`
}ConnectorConfig - 使用哪个连接器。重要:连接器中的 URL 可以包含父值作为字符串注入
Model - 底层模型的配置
Type - enum["null", "boolean", "string", "int", "int64", "float", "float64", "array", "object"] - 生成字段的类型
Path - 如果我们无法从生成的字段中提取某些信息,可以使用 json 选择器进行提取
Expression - 可用于模型后处理的字符串(忽略 path 字段)
示例:
https://github.com/PxyUp/fitter/blob/master/examples/cli/config_cli.json#L60
{
"type": "array",
"model": {
"array_config": {
"root_path": "#content dt.quote > a",
"item_config": {
"field": {
"type": "string"
}
}
}
}
}https://github.com/PxyUp/fitter/blob/master/examples/cli/config_weather.json#L37
{
"type": "string",
"path": "temp.temp",
"model": {
"object_config": {
"fields": {
"temp": {
"base_field": {
"type": "string",
"path": "//div[@id='forecast_list_ul']//td/b/a/@href",
"generated": {
"model": {
"type": "string",
"model": {
"object_config": {
"fields": {
"temp": {
"base_field": {
"type": "string",
"path": "div.current-temp span.heading"
}
}
}
}
},
"connector_config": {
"response_type": "HTML",
"attempts": 4,
"url": "https://openweathermap.org{PL}",
"browser_config": {
"playwright": {
"timeout": 30,
"wait": 30,
"install": false,
"browser": "FireFox",
"type_of_wait": "networkidle"
}
}
}
}
}
}
}
}
}
},
"connector_config": {
"response_type": "xpath",
"attempts": 3,
"url": "https://openweathermap.org/find?q={PL}",
"browser_config": {
"playwright": {
"timeout": 30,
"wait": 30,
"install": false,
"browser": "Chromium"
}
}
}
}静态数组配置
提供静态(固定长度)数组生成
type StaticArrayConfig struct {
Items map[uint32]*Field `yaml:"items" json:"items"`
Length uint32 `yaml:"length" json:"length"`
}示例:
{
"0": {
"base_field": {
"type": "string",
"path": "div.current-temp span.heading"
}
}
}{
"length": 4,
"0": {
"base_field": {
"type": "string",
"path": "div.current-temp span.heading"
}
}
}{
"length": 4,
"2": {
"base_field": {
"type": "string",
"path": "div.current-temp span.heading"
}
}
}占位符列表
{PL} - 用于注入值
{INDEX} - 用于注入父数组中的索引
{HUMAN_INDEX} - 用于以人类可读方式注入父数组中的索引
{{{json_path}}} - 将从传播的"object"/"array"字段中获取信息
{{{RefName=SomeName json.path}}} - 按名称获取 reference 值并通过 json path 提取值。示例
{{{FromEnv=ENV_KEY}}} - 从环境变量获取值
{{{FromExp=fRes + 5 + fIndex}}} - 从 expression 获取值。预定义值
{{{FromInput=.}}} 或 {{{FromInput=json.path}}} - 从触发器或库的输入获取值
{{{FromFile=./test_file.log}}} - 按路径从文件获取值。文件内容也可以包含占位符
{{{FromURL=http://localhost:8081}}} - 从 URL 获取响应
示例:
{{{FromExp="{{{FromEnv=TEST_VAL}}}" + "hello"}}}Current time is: {PL} with token from TokenRef={{{RefName=TokenRef}}} and TokenObjectRef={{{RefName=TokenObjectRef token}}}Current time is: {PL} with token from TokenRef={{{RefName=TokenRef}}} and TokenObjectRef={{{RefName=TokenObjectRef token}}}TokenRef={{{RefName=TokenRef}}} and TokenObjectRef={{{RefName=TokenObjectRef token}}} Object={{{value}}} {PL} Env={{{FromEnv=TEST_VAL}}} {INDEX} {HUMAN_INDEX}引用
特殊的映射,预取(在任何处理之前)并且可以用于 connector 或 placeholder
可用于:
缓存 jwt token 并在 headers 中使用它们
缓存值
等等
引用
type Reference struct {
*ModelField
Expire *uint32 `yaml:"expire" json:"expire"`
}ModelField - 是嵌入结构体,可以使用相同的字段
Expire[sec] - 引用获取后过期的时间。未设置 => 永久缓存。设置为 0 => 每次重新获取。设置为 n > 0 => 缓存 n 秒
对于 Fitter
type RefMap map[string]*Reference
type Config struct {
// Other Config Fields
Limits *Limits `yaml:"limits" json:"limits"`
References RefMap `json:"references" yaml:"references"`
}对于 Fitter Cli
type RefMap map[string]*Reference
type CliItem struct {
// Other Config Fields
Limits *Limits `yaml:"limits" json:"limits"`
References RefMap `json:"references" yaml:"references"`
}References - map[string]*Reference - 对象,其中键是 ReferenceName(可用于 connector 或 placeholder),值是 Reference
示例
https://github.com/PxyUp/fitter/blob/master/examples/cli/config_ref.json#L2
{
"references": {
"TokenRef": {
"expire": 10,
"connector_config": {
"response_type": "json",
"static_config": {
"value": "\"plain token\""
}
},
"model": {
"base_field": {
"type": "string"
}
}
},
"TokenObjectRef": {
"connector_config": {
"response_type": "json",
"static_config": {
"value": "{\"token\":\"token from object\"}"
}
},
"model": {
"object_config": {
"fields": {
"token": {
"base_field": {
"type": "string",
"path": "token"
}
}
}
}
}
}
}
}通知器
可选的每项配置 item.notifier_config,在处理后将解析结果推送到某处。结果仍然照常返回(CLI/MCP 输出、服务日志);通知器额外传递它。适用于 Fitter(服务模式)、Fitter_CLI 和 Fitter_MCP。
type NotifierConfig struct {
Expression string `yaml:"expression" json:"expression"`
Force bool `json:"force" yaml:"force"`
SendArrayByItem bool `yaml:"send_array_by_item" json:"send_array_by_item"`
Template string `yaml:"template" json:"template"`
// exactly ONE destination:
Console *ConsoleConfig `yaml:"console" json:"console"`
TelegramBot *TelegramBotConfig `yaml:"telegram_bot" json:"telegram_bot"`
Http *HttpConfig `yaml:"http" json:"http"`
Redis *RedisNotifierConfig `json:"redis" yaml:"redis"`
File *FileStorageField `json:"file" yaml:"file"`
}Expression - 可选 expr-lang 条件:仅当其计算结果为 true 时通知。解析结果可通过
fRes(解析值)、fResRaw(原始字节)、fResJson(JSON 字符串)获取,例如len(fResRaw) > 0Force - 即使解析出错也发送通知
SendArrayByItem - 如果结果是数组,则将每个元素作为单独的通知发送
Template - 可选模板,在发送前应用于结果,允许使用 占位符
Destination - 必须且只能为
console、telegram_bot、http、redis、file之一
目标配置:
type HttpConfig struct {
Url string `yaml:"url" json:"url"`
Method string `json:"method" yaml:"method"`
Headers map[string]string `yaml:"headers" json:"headers"`
Timeout uint32 `yaml:"timeout" json:"timeout"`
}
type TelegramBotConfig struct {
Token string `json:"token" yaml:"token"`
UsersId []int64 `json:"users_id" yaml:"users_id"`
Pretty bool `json:"pretty" yaml:"pretty"`
OnlyMsg bool `json:"only_msg" yaml:"only_msg"`
}
type RedisNotifierConfig struct {
Addr string `json:"addr" yaml:"addr"`
Password string `json:"password" yaml:"password"`
DB int `json:"db" yaml:"db"`
Channel string `json:"channel" yaml:"channel"`
}
type ConsoleConfig struct {
OnlyResult bool `json:"only_result" yaml:"only_result"`
}file 目标使用与文件字段类型相同的 FileStorageField。
示例(examples/config_telegram.json):
{
"item": {
"connector_config": { "...": "..." },
"model": { "...": "..." },
"notifier_config": {
"expression": "len(fResRaw) > 0",
"telegram_bot": {
"token": "{{{FromEnv=TG_TOKEN}}}",
"users_id": [123456],
"pretty": true
}
}
}
}限制
提供限制以防止 DDOS、内存大量占用
type Limits struct {
HostRequestLimiter HostRequestLimiter `yaml:"host_request_limiter" json:"host_request_limiter"`
ChromiumInstance uint32 `yaml:"chromium_instance" json:"chromium_instance"`
DockerContainers uint32 `yaml:"docker_containers" json:"docker_containers"`
PlaywrightInstance uint32 `yaml:"playwright_instance" json:"playwright_instance"`
}HostRequestLimiter - map[string]int64 - 按主机名的限制,键为主机,值为并行请求数量(用于 server connector)
ChromiumInstance - 并行 chromium 实例数量
DockerContainers - 并行 docker 实例数量
PlaywrightInstance - 并行 playwright 实例数量
https://github.com/PxyUp/fitter/blob/master/examples/cli/config_cli.json#L2
{
"limits": {
"host_request_limiter": {
"hacker-news.firebaseio.com": 5
},
"chromium_instance": 3,
"docker_containers": 3,
"playwright_instance": 3
}
}Available Tools
6 toolsfitter_config_referenceA
Return a condensed reference of the Fitter config format (connectors, parsers, model/field schema, placeholders, notifiers, references, limits) with working examples. Use it before authoring a config for fitter_run.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations provided, so description carries burden. Describes output but does not explicitly state that tool is read-only or has no side effects, though context implies safe operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with purpose, no fluff. Every part earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no parameters or output schema, description sufficiently covers purpose and usage. Could mention response format but not critical for a reference tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
No parameters, schema coverage is 100% trivially. Baseline 4 applies, and description adds value by listing what the reference includes.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it returns a condensed reference of the Fitter config format with working examples, and distinguishes itself from sibling run tools by advising use before authoring a config for fitter_run.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly recommends using before authoring a config for fitter_run, providing clear context. However, it does not mention exclusions or alternatives, but siblings are run tools making differentiation obvious.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fitter_inspect_urlA
Fetch a URL and return a compact structure outline plus candidate selectors/paths, so you can author a fitter config that matches on the first try instead of guessing selectors and getting nulls. For JSON it lists gjson paths with types and sample values; for HTML it lists repeated elements (candidate array_config root_path / list rows) and link/heading selectors. For client-rendered SPAs (content built by JavaScript), a plain fetch sees only an empty shell — the output warns when it detects one; pass render:true to render it in a headless browser first (mirrors what a browser_config scrape would see). Read-only helper that does NOT extract data — use it before fitter_run, then fitter_run to actually extract.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | HTTP(S) URL to fetch and inspect for its structure and candidate selectors. | |
| render | No | Render the page in a headless browser (Playwright/Chromium) before inspecting — needed for client-rendered SPAs whose content is built by JavaScript and is absent from the raw HTML. Requires browser support (the fitter-mcp:playwright image or a local Playwright install). | |
| response_type | No | Optional hint for how to read the response: json, HTML, xpath or XML. Empty auto-detects from the Content-Type/body. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It clearly states the tool is read-only and does not extract data, and explains behavior for different content types (JSON, HTML, SPAs) and the render option.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is detailed but each sentence adds unique value, covering purpose, output, parameter usage, and distinctions from execution tools. It is front-loaded with the primary purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite no output schema, the description describes the output as a 'compact structure outline plus candidate selectors/paths' and gives specifics for JSON and HTML. It also covers the render behavior for SPAs, making the tool's behavior well understood.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description expands on each parameter beyond the schema: url as the target, render for SPAs, and response_type as an optional hint with auto-detection. It explains why the parameters matter and how they affect the output.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Fetch a URL and return a compact structure outline') and differentiates from sibling tools by positioning it as an inspection step before fitter_run. Clearly identifies the tool's role.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use it ('before fitter_run') and what it does not do ('does NOT extract data'), plus provides guidance on when to set render:true for SPAs. Also mentions the response_type hint.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fitter_runA
Run a Fitter scraping/parsing config passed inline (JSON or YAML) and return the extracted data as JSON. Fitter fetches data via a connector (HTTP request, headless browser, static value, file, ...) and extracts structured data using json/HTML/XML/xpath selectors described by a declarative model. Call fitter_config_reference first if you are unsure about the config format.
| Name | Required | Description | Default |
|---|---|---|---|
| input | No | Optional input value (plain string or JSON), available in the config via {{{FromInput=.}}} or {{{FromInput=json.path}}} placeholders. | |
| config | Yes | Fitter CliItem config as a JSON or YAML string. Top-level keys: item (required), limits, references. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must disclose behaviors. It mentions fetching data via connectors and extracting data, implying network access. However, it omits potential side effects like rate limits, authentication needs, or error scenarios, which would strengthen transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is brief, with a clear structure: first sentence states the tool's purpose, second explains the underlying Fitter mechanism, third gives a usage tip. Every sentence contributes directly to understanding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with two parameters, no output schema, and no annotations, the description provides sufficient context: config format, supported selectors, and a reference to the config spec tool. It could be more complete by noting potential timeouts or result size limitations, but overall it covers the essential information.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% (both parameters described). The description adds context beyond the schema by explaining that config is JSON/YAML, highlighting top-level keys (item, limits, references), and stating that output is JSON. This adds meaningful value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the action ('Run a Fitter scraping/parsing config passed inline') and the resource (inline config). It distinguishes from siblings by specifying 'inline', contrasting with file- and URL-based tools. The purpose is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description advises calling fitter_config_reference first if unsure about the config format, providing clear guidance. However, it does not explicitly compare this tool to fitter_run_file or fitter_run_url, leaving the selection of the appropriate sibling somewhat implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fitter_run_fileA
Run a Fitter scraping/parsing config from a local JSON or YAML file and return the extracted data as JSON. Same as fitter_run but reads the config from disk.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | Absolute path to a Fitter config file (.json, .yaml or .yml) with top-level keys: item (required), limits, references. | |
| input | No | Optional input value (plain string or JSON), available in the config via {{{FromInput=.}}} or {{{FromInput=json.path}}} placeholders. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations exist, so the description must fully disclose behavioral traits. It states the tool returns extracted data as JSON but does not mention whether modifications occur, required permissions, or error handling (e.g., file not found). The description is minimal and lacks transparency beyond the basic operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise with two sentences, front-loading the primary purpose. Every sentence adds value: first defines the tool, second clarifies the difference from a sibling. No fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has 2 parameters and no output schema, the description covers the basic purpose but omits important context like what happens if the file is invalid, permissions needed, or error scenarios. It is adequate for simple use but has gaps compared to a fully transparent description.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds minimal additional meaning beyond the schema; it only reiterates that 'input' is optional and used with placeholders, which the schema already covers. No further value is added for the 'path' parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states the verb (Run), the resource (Fitter config file), and distinguishes it from fitter_run by specifying 'reads the config from disk.' It also indicates the output format (JSON). This differentiates it from sibling tools like fitter_config_reference, fitter_run, and fitter_run_url.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly notes 'Same as fitter_run but reads the config from disk,' which helps users decide between this tool and fitter_run. However, it does not provide explicit when-not-to-use scenarios or mention other alternatives besides the direct sibling comparison.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fitter_run_urlA
Run a Fitter scraping/parsing config downloaded from an HTTP(S) URL (JSON or YAML) and return the extracted data as JSON. Same as fitter_run but fetches the config from a remote location, e.g. a raw GitHub link.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | HTTP(S) URL of a Fitter config (JSON or YAML) with top-level keys: item (required), limits, references. | |
| input | No | Optional input value (plain string or JSON), available in the config via {{{FromInput=.}}} or {{{FromInput=json.path}}} placeholders. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must fully disclose behavior. It states the tool downloads config from a URL and returns JSON, but omits important details such as network error handling, timeout limits, authentication, size restrictions, or what happens with invalid configs. This lack of transparency could lead to unexpected failures.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two concise sentences with no unnecessary words. It front-loads the action and result, then adds the key distinction from 'fitter_run'. Every sentence provides useful information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool involves remote fetching and parsing, but the description does not detail the return format beyond 'extracted data as JSON', nor does it explain error conditions or required permissions. With no output schema, more detail would be beneficial for an agent to anticipate the response structure.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already covers both parameters with descriptions (100% coverage). The description adds value by specifying the required top-level keys of the config ('item', 'limits', 'references'), which aids in understanding the expected structure beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool runs a Fitter config from an HTTP(S) URL and returns JSON data. It explicitly distinguishes itself from 'fitter_run' by noting the remote fetching behavior, making the purpose specific and differentiated from siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description indicates when to use this tool over 'fitter_run' (remote vs local config) and gives an example (raw GitHub link). However, it does not explicitly mention when not to use it or alternatives like 'fitter_run_file', though the context from the name and sibling list provides some guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fitter_validate_configA
Validate a Fitter config (JSON or YAML) without executing it. Checks the structural rules: item/connector_config/model presence, valid response_type, that the connector has a data source, and compiles every condition/item_condition expression in the model. Returns "valid" or the validation error. Cheap and safe — use it while iterating on a config before calling fitter_run.
| Name | Required | Description | Default |
|---|---|---|---|
| config | Yes | Fitter CliItem config as a JSON or YAML string to validate without executing it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description fully carries the burden, detailing what it checks (structural rules, condition compilation), that it is cheap and safe, and that it returns 'valid' or error. This comprehensively discloses behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, each earning its place: purpose, checks, and usage advice. Front-loaded and succinct with no redundancies.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the single parameter and no output schema, the description fully covers purpose, behavior, usage context, and return type. It is complete for effective tool selection.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description reinforces the config parameter but adds no new parameter-level details beyond the schema description.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states 'Validate a Fitter config (JSON or YAML) without executing it,' clearly specifying the verb and resource. It distinguishes from sibling tools like fitter_run by advising use before calling fitter_run.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly advises using this tool while iterating on a config before calling fitter_run, providing clear when-to-use context. However, it does not explicitly state when not to use it or mention alternatives for different scenarios.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
1 tool update
v1.8.2- Added
fitter_inspect_url
1 tool update
v1.7.0- Added
fitter_validate_config
4 tool updates
v0.1.0- First observed
fitter_config_reference - First observed
fitter_run - First observed
fitter_run_file - First observed
fitter_run_url
TDQS
Each tool serves a distinct purpose: reference, inspection, execution (with three source variants), and validation. No overlap or ambiguity between them.
All tools follow the 'fitter_' prefix with snake_case, and the action part is consistently descriptive (inspect, run, validate). The naming pattern is uniform and predictable.
Six tools is ideal for a config-driven scraping/parsing workflow: reference, inspect, run (three variants), and validate. Not bloated or sparse.
The toolset covers the full lifecycle: learning the format (reference), inspecting target structure (inspect), validating configs (validate), and executing from inline, file, or URL sources. No missing functionality apparent.
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
MCP server for Riveter's enrichment, scraping, and monitoring API
MCP server for web extraction and rendering via AceDataCloud WebExtrator
One MCP server for 180+ live web-data APIs returning clean JSON from sites that block scrapers.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceMCP server for interacting with Prometheus metrics and data.17MIT
- AlicenseAqualityCmaintenanceAn MCP server for fetching and transforming web content into various formats.48MIT
- FlicenseBqualityDmaintenanceAn MCP Server for Web scraping and Crawling, built using Crawl4AI224-
- AlicenseAqualityCmaintenanceMCP server for web scraping — extract clean markdown, links, and metadata from any URL. Free Firecrawl alternative.51575MIT
Appeared in Searches
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/PxyUp/fitter'
If you have feedback or need assistance with the MCP directory API, please join our Discord server