Skip to main content
Glama

Fitter — AI 에이전트를 위한 웹 데이터

MCP Toplist

Release License: MIT Go Reference Sponsor

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 데모 — 선언적 구성에서 구조화된 JSON으로

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
  • Docker: Chromium, Firefox 및 WebKit이 사전 설치된 ghcr.io/pxyup/fitter-mcp:playwright 이미지를 사용하세요 ("install": true 불필요).

도구

Tool

Description

fitter_run

인라인으로 전달된 Fitter 구성(JSON 또는 YAML 문자열)을 실행하고 추출된 데이터를 JSON으로 반환합니다. {{{FromInput=.}}} / {{{FromInput=json.path}}}를 통해 구성에서 사용할 수 있는 선택적 input 값을 허용합니다.

fitter_run_file

fitter_run과 동일하지만 로컬 .json/.yaml 파일에서 구성을 읽습니다.

fitter_run_url

fitter_run과 동일하지만 HTTP(S) URL(예: raw GitHub 링크)에서 구성을 다운로드합니다.

fitter_inspect_url

URL을 가져와 간결한 구조 개요와 후보 선택자/경로(JSON의 경우 gjson 경로, HTML의 경우 반복 요소/목록 행 선택자)를 반환하여 모델이 선택자를 추측하고 null을 얻는 대신 첫 시도에 구성을 작성할 수 있게 합니다. 클라이언트 렌더링 SPA를 감지하고 헤드리스 브라우저에서 render할 수 있습니다. 읽기 전용 — 추출하지 않습니다.

fitter_validate_config

구성을 실행하지 않고 검증합니다(구조, response_type, 커넥터 데이터 소스, 모델). 구성을 반복하는 동안 유용합니다.

fitter_config_reference

전체 구성 형식(커넥터, 파서, 모델/필드 스키마, 플레이스홀더, 알리미, 참조, 제한)의 압축된 참조를 작업 예제와 함께 반환하여 모델이 외부 문서 없이 구성을 작성할 수 있게 합니다.

참조는 리소스를 지원하는 클라이언트를 위해 MCP 리소스 fitter://config-reference로도 노출됩니다.

구성 형식은 Fitter_CLI와 정확히 동일합니다: item(필수), limitsreferences가 있는 최상위 객체입니다. 알리미도 작동합니다(결과가 추가로 http/telegram/redis/file/console로 푸시됩니다). trigger_confighttp_server는 서비스 모드 전용이며 MCP 호출에서는 무시됩니다.

원격 / 호스팅 모드 (streamable HTTP)

기본적으로 fitter_mcp는 stdio를 사용합니다. 대신 streamable HTTP 전송을 제공하려면 --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> (env FITTER_MCP_HTTP_ADDR) — 수신 주소; 비어 있으면 stdio 모드

  • FITTER_MCP_AUTH_TOKEN — 설정된 경우 모든 /mcp 요청은 Authorization: Bearer <token>을 보내야 합니다. 설정하지 않으면 엔드포인트가 인증되지 않으므로 localhost에 바인딩하거나 프록시 뒤에 두세요.

  • --stateless (env 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에서 빌드됩니다. 더 작은 Chromium 전용 이미지를 위해 --build-arg PLAYWRIGHT_BROWSERS=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

바인드 마운트(명명된 볼륨이 아닌)를 사용하세요: 컨테이너는 매 실행 후 새로 고쳐진 쿠키를 다시 쓰므로 호스트 복사본이 최신 상태로 유지되며 언제든지 browser-login으로 다시 확장할 수 있습니다.

볼륨은 서버에 대해 쓰기 가능한 상태로 유지되어야 합니다: 순환된 새로 고침 토큰이 매 새로 고침마다 다시 기록됩니다.

환경 변수

  1. FITTER_PLUGINS - string[""] - 플러그인 폴더 경로, Fitter/Fitter_CLI의 --plugins 플래그와 동일

  2. FITTER_MCP_HTTP_ADDR - string[""] - 원격 모드의 수신 주소, --http와 동일

  3. FITTER_MCP_AUTH_TOKEN - string[""] - HTTP 엔드포인트를 보호하는 베어러 토큰

  4. FITTER_MCP_STATELESS - bool[false] - 상태 없는 HTTP 전송, --stateless와 동일

레시피

완전하고 테스트된 설정으로 주요 패턴을 보여줍니다. 모두 Fitter_MCP(fitter_run_file), Fitter_CLI 또는 라이브러리를 통해 수정 없이 실행됩니다 — 자세한 내용은 examples/에서 확인하세요.

API가 없는 페이지를 스크래핑하고, API가 있는 페이지에서 데이터를 보강하기

GitHub trending에는 공식 API가 없습니다 — repo 슬러그를 얻기 위해 HTML을 스크래핑하고(html_attributehref를 읽음), 각 항목을 {PL}로 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-langfRes(현재 항목)에 적용됨)로 꺼냅니다. 도서 검색 → 저자 상세 정보, 검색어는 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)와 표현식이 작동합니다. 비트코인 백서, 페이지 수 및 잘라낸 소개:

examples/config_pdf.json

{
  "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}

정보 수집 방법

  1. Server - 일부 API 또는 http 요청의 응답 파싱(http.Client 사용)

  2. Browser - chromium + docker + playwright/cypress를 사용하여 실제 브라우저를 에뮬레이션하고 DOM 정보 가져오기

  3. Static - 정적 문자열을 데이터로 파싱

파싱 가능한 형식

  1. JSON - 특정 정보를 얻기 위해 JSON 파싱

  2. XML - 특정 정보를 얻기 위해 xml 트리 파싱

  3. HTML - 특정 정보를 얻기 위해 dom 트리 파싱

  4. XPath - xpath로 특정 정보를 얻기 위해 dom 트리 파싱

  5. PDF - PDF 문서에서 텍스트 추출; 콘텐츠는 JSON {"text": "...", "pages": ["..."], "total_pages": N}으로 노출되므로 text 또는 pages.0 같은 일반 JSON 경로가 작동합니다

라이브러리로 사용하기

go get github.com/PxyUp/fitter
package 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를 전달하세요: 취소하면 진행 중인 fetch(HTTP 요청, 헤드리스 브라우저, docker 컨테이너)가 중단되고 데드라인이 종단 간 적용됩니다. lib.Parselib.ParseCtx(context.Background(), ...)와 동일합니다.

Fitter 사용 방법

릴리스 페이지에서 최신 버전 다운로드

또는 로컬에서:

go run cmd/fitter/main.go --path=./examples/config_api.json

인자

  1. --path - string[""] - Fitter 설정 경로

  2. --url - string[""] - Fitter 설정 URL

  3. --verbose - bool[false] - 로깅 활성화

  4. --plugins - string[""] - Fitter 플러그인 경로

  5. --log-level - enum["info", "error", "debug", "fatal"] - 로그 레벨 설정(verbose가 true인 경우에만)

Fitter_CLI 사용 방법

릴리스 페이지에서 최신 버전 다운로드

또는 로컬에서:

go run cmd/cli/main.go --path=./examples/cli/config_cli.json

인자

  1. --path - string[""] - Fitter_CLI 설정 경로

  2. --url - string[""] - Fitter_CLI 설정 URL

  3. --copy - bool[false] - 정보를 클립보드에 복사

  4. --pretty - bool[true] - 읽기 쉬운 결과 생성(복사에도 영향)

  5. --verbose - bool[false] - 로깅 활성화

  6. --omit-error-pretty - bool[false] - pretty가 유효하지 않은 경우 순수 값을 제공

  7. --plugins - string[""] - Fitter 플러그인 경로

  8. --log-level - enum["info", "error", "debug", "fatal"] - 로그 레벨 설정(verbose가 true인 경우에만)

  9. --input - string[""] - 포맷팅을 위한 입력 값 지정. 예: --input=\""124"\" --input=124 --input='{"test": 5}'

./fitter_cli_${VERSION} --path=./examples/cli/config_cli.json --copy=true

fitter_cli auth — OAuth2 계정 연결

oauth2 커넥터 설정을 위한 (refresh) 토큰을 저장하는 일회성 대화형 로그인:

# 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

인자:

  1. --provider - 알려진 엔드포인트가 있는 프리셋: github|google|microsoft|gitlab|spotify

  2. --client-id / --client-secret - OAuth2 앱 자격 증명(일부 device flow는 secret 없이 작동)

  3. --token-file - 수신된 토큰을 저장할 위치(0600 권한); oauth2.token_file에 동일한 경로를 참조

  4. --flow - auto(가능하면 device, 아니면 browser), device(URL 방문 + 코드 입력) 또는 browser(PKCE가 있는 localhost 콜백, 기본 포트 8988 — http://127.0.0.1:8988/callback을 앱 콜백 URL로 등록)

  5. --scopes - 쉼표로 구분된 스코프

  6. --auth-url/--token-url/--device-auth-url/--auth-style - 프리셋이 없는 제공자를 위한 엔드포인트 재정의

  7. --port - int[8988] - browser flow 콜백 포트(env FITTER_AUTH_PORT); 기본값으로 제공자에 등록할 콜백 URL은 http://127.0.0.1:8988/callback입니다

  8. --listen - browser flow 바인드 주소, 기본값 127.0.0.1; 컨테이너 내부에서 0.0.0.0으로 설정하여 게시된 포트가 리스너에 도달하게 합니다(env FITTER_AUTH_LISTEN)

  9. --redirect-url - 리슨 주소와 다를 때 제공자에 등록된 콜백 URL, 예: docker 포트 매핑(env FITTER_AUTH_REDIRECT_URL)

  10. --no-browser - 인증 URL만 출력

Docker 내부에서 실행: Docker의 OAuth2 계정을 참조하세요.

로그인 후 명령은 바로 사용 가능한 oauth2 설정 블록을 출력합니다. 커넥터는 액세스 토큰을 자동으로 갱신하고 회전된 refresh 토큰을 토큰 파일에 다시 쓰므로 로그인은 한 번만 필요합니다.

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

인자:

  1. --url - 열 로그인 페이지(필수)

  2. --storage-state - 세션을 저장할 위치(cookies + localStorage, 0600 권한); playwright.storage_state_file에 동일한 경로를 참조(필수)

  3. --browser - enum["Chromium", "FireFox", "WebKit"] 기본값 "Chromium"; 스크래핑 설정과 동일한 값을 사용 — 사이트가 브라우저 지문에 세션을 바인딩할 수 있음

  4. --install - bool[false] - playwright 브라우저를 먼저 설치

  5. --indexeddb - bool[false] - 스냅샷에 IndexedDB 포함(Firebase Auth 등)

명령을 다시 실행하면 기존 상태를 먼저 로드하므로 처음부터 로그인하지 않고 세션을 확장/갱신할 수 있습니다. 스크래핑 커넥터는 또한 매 실행 후 갱신된 쿠키를 다시 작성하여 정기적으로 사용하는 한 세션을 유지합니다. 디스플레이가 필요합니다: Docker 내부에서는 호스트에서 이 명령을 실행하고 파일을 마운트하세요 — Docker의 브라우저 세션을 참조하세요.

예시:

  1. Server 버전 HackerNews + Quotes + Guardian News - API + HTML + XPath 파싱 사용

  2. Chromium 버전 Guardian News + Quotes - HTML 파싱 + 브라우저 에뮬레이션 사용

  3. Docker 버전 Docker 버전: Guardian News + Quotes - HTML 파싱 + Docker 이미지의 브라우저 사용

  4. Playwright 버전 Playwright 버전: Guardian News + Quotes - HTML 파싱 + Playwright 프레임워크의 브라우저 사용

  5. Playwright 버전 Playwright 버전: England Cities + Weather - HTML + XPath 파싱 + Playwright 프레임워크의 브라우저 사용

  6. JSON 버전 페이지네이션 생성 - 페이지네이션 배열 생성을 위한 static 커넥터 사용

  7. Server 버전 현재 시간 가져오기 - URL에서 시간을 가져와 포맷

Fitter_Agent 사용 방법

Fitter Agent는 AI 기반 CLI로, Claude를 사용하여 자연어 요청을 Fitter 설정으로 변환하고 자동으로 실행합니다.

릴리스 페이지에서 최신 버전 다운로드

또는 로컬에서:

export ANTHROPIC_API_KEY=<your-anthropic-api-key>
go run cmd/agent/main.go

인자

  1. --api-key - string[""] - Anthropic API 키. 키가 셸 기록에 남지 않도록 ANTHROPIC_API_KEY 환경 변수를 선호합니다

  2. --model - string["claude-opus-4-8"] - 사용할 Claude 모델

  3. --effort - enum["low", "medium", "high", "xhigh", "max"] - 추론 노력, 기본값 "high". 더 빠르고 저렴한 설정을 위해 낮추고, 더 어려운 추출을 위해 높이세요

  4. --verbose - bool[false] - 로깅 활성화

  5. --log-level - enum["info", "error", "debug", "fatal"] - 로그 레벨 설정

  6. --plugins - string[""] - Fitter 플러그인 경로

  7. --chromium-limit - uint[0] - 동시 Chromium 인스턴스 제한

  8. --docker-limit - uint[0] - 동시 Docker 컨테이너 제한

  9. --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!

예시 요청

요청

수행 작업

Get Bitcoin price from CoinGecko API

현재 BTC 가격 가져오기

Scrape headlines from news.ycombinator.com with links

CSS 선택자로 HTML 스크래핑

Get top 5 stories from HackerNews with titles

중첩 API 호출

Fetch weather data from wttr.in for London

간단한 API 추출

Scrape product names and prices from example.com

웹 스크래핑

지원 기능

에이전트는 다음에 대한 설정을 생성할 수 있습니다:

  • JSON API - GET/POST 메서드가 있는 REST API

  • HTML 스크래핑 - CSS 선택자 기반 추출

  • XPath 스크래핑 - XPath 기반 추출

  • 중첩 API 호출 - 목록의 각 항목에 대한 세부 정보 가져오기

  • 브라우저 에뮬레이션 - JS 렌더링 페이지용 Playwright

  • 포맷된 필드 - 플레이스홀더가 있는 URL 템플릿

  • 배열 제한 - 결과를 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 - enum["HTML", "json", "xpath", "XML", "pdf"] - 커넥터에서 데이터가 어떤 형식으로 오는지

  • Attempts - 커넥터가 데이터를 가져오기 위해 시도할 횟수

  • Url - 요청할 주소를 정의합니다. 중요: 부모 값의 문자열 주입이 가능합니다 https://api.open-meteo.com/v1/forecast?latitude={{{latitude}}}&longitude={{{longitude}}}&hourly=temperature_2m&forecast_days=1

Config는 다음 중 하나가 될 수 있습니다:

예시:

{
  "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 config

플러그인 빌드 방법

플러그인 빌드

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

references에서 미리 가져온 데이터를 얻을 수 있는 커넥터

type ReferenceConnectorConfig struct {
	Name string `yaml:"name" json:"name"`
}

예시

https://github.com/PxyUp/fitter/blob/master/examples/cli/config_ref.json#L66

IntSequenceConnectorConfig

결과로 정수 시퀀스를 생성하는 static 커넥터의 개선된 버전

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]
}

Config 예시

FileConnectorConfig

제공된 파일에서 데이터를 가져오는 커넥터 유형

type FileConnectorConfig struct {
    Path          string `yaml:"path" json:"path"`
    UseFormatting bool   `yaml:"use_formatting" json:"use_formatting"`
}
  • Path - 파일 경로. 포맷팅 지원

  • UseFormatting[false] - 포맷팅 파일 내용을 사용할지 여부

StaticConnectorConfig

제공된 문자열에서 데이터를 가져오는 커넥터 유형

type StaticConnectorConfig struct {
    Value string `json:"value" yaml:"value"`
    Raw   json.RawMessage `json:"raw" yaml:"raw"`
}
  • Value - 데이터로 사용할 정적 문자열, html 또는 json일 수 있음

  • Raw - raw json 허용. 예시. 포맷팅도 지원

예시:

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 - 요청 중 사용할 사전 정의된 헤더 key/value에 주입 가능

  • Timeout[sec] - 기본 60초 타임아웃 또는 제공된 값 사용

  • Body - 요청 본문, 파싱된 값 주입 가능

  • JsonRawBody - json 형식의 요청 본문; 값 주입 가능

  • ErrorOnStatus - 선택 사항, 기본값 false. true인 경우 HTTP 응답 상태 >= 400은 오류 본문을 파싱하는 대신 가져오기 오류로 처리됩니다(attempts / null_on_error를 통해 흐름) — 실패한 가져오기와 실제로 빈 결과를 구분할 수 있습니다. false로 두면 반환된 본문을 파싱하는 원래 동작이 유지됩니다.

  • Proxy - 요청에 대한 프록시 설정 config

  • OAuth2 - 액세스 토큰을 자동으로 가져오고/새로고침하여 Authorization 헤더로 전송 config

요청은 기본적으로 식별 가능한 User-Agent(fitter (+https://github.com/PxyUp/fitter))를 전송합니다. Headers에서 자체 User-Agent를 설정하여 재정의할 수 있습니다.

예시:

{
  "method": "GET",
  "proxy": {
    "server": "http://localhost:8080",
    "username": "pyx"
  }
}
OAuth2 config

요청 전에 액세스 토큰을 자동으로 획득하여 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 - enum["client_credentials", "refresh_token"], 기본값은 "client_credentials"입니다. 사용자가 한 번 동의한 API(Google, Microsoft 등)에 대해 장기 유효한 refresh token을 보유한 경우 "refresh_token"을 사용하세요

  • ClientId/ClientSecret - 클라이언트 자격 증명. 포맷팅도 지원, 예: {{{FromEnv=CLIENT_SECRET}}}

  • Scopes - 요청된 스코프

  • RefreshToken - "refresh_token" grant에 필요. 포맷팅도 지원

  • EndpointParams - 추가 토큰 엔드포인트 매개변수(예: Auth0의 audience), "client_credentials" grant 전용

  • AuthStyle - enum["", "header", "params"] - 클라이언트 자격 증명이 토큰 엔드포인트에 전달되는 방식: basic auth 헤더 또는 요청 본문; 비어 있으면 자동 감지

  • TokenFile - 선택 사항인 경로(~/ 지원)로 실행 간 토큰을 유지합니다. 저장된 토큰은 RefreshToken보다 우선하며, 회전된 refresh token이 다시 기록됩니다 — 단일 사용 refresh token 제공자(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}}}"
  }
}
Proxy config
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 - 프록시 서버의 스키마가 포함된 주소. 포맷팅도 지원

  • Username - 프록시 사용자 이름(비울 수 있음). 포맷팅도 지원

  • Password - 프록시 비밀번호(비울 수 있음). 포맷팅도 지원

{
  "server": "http://localhost:8080",
  "username": "pyx"
}
환경 변수
  1. 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"`
}

Config는 다음 중 하나가 될 수 있습니다:

  • 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 - 컨테이너 내부에서 실행될 cmd

  • Timeout[sec] - 컨테이너 실행 타임아웃(이미지 풀링 제외)

  • Wait[msec] - 페이지 로딩 타임아웃(Chromium 기반 컨테이너에서만 작동)

  • Flags - 컨테이너 실행을 위한 cmd 인수, Chromium 기반 기본값: "--no-sandbox","--headless", "--proxy-auto-detect", "--temp-profile", "--incognito", "--disable-logging", "--disable-gpu"

  • Purge - 작업 완료 후 컨테이너를 제거할지 여부(docker rm과 같이)

  • NoPull - 이미지 풀링 방지

  • PullTimeout - 풀 컨테이너에 대한 타임아웃 정의

환경 변수
  1. DOCKER_HOST - string - (EnvOverrideHost) docker 서버 URL을 설정합니다.

  2. DOCKER_API_VERSION - string - (EnvOverrideAPIVersion) 사용할 API 버전을 설정합니다. 최신 버전을 사용하려면 비워 두세요.

  3. DOCKER_CERT_PATH - string - (EnvOverrideCertPath) TLS 인증서(ca.pem, cert.pem, key.pem)를 로드할 디렉터리를 지정합니다.

  4. 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 - enum["Chromium", "FireFox", "WebKit"] - 사용할 브라우저

  • Install - 브라우저를 설치할지 여부(첫 사용 시 내장된 playwright-go 버전과 일치하는 드라이버 + 브라우저를 다운로드합니다. 사전 설치된 ghcr.io/pxyup/fitter-mcp:playwright 이미지에서는 필요 없음)

  • Timeout[sec] - playwright 실행 타임아웃

  • Wait[sec] - 페이지 로딩 타임아웃

  • TypeOfWait - enum["load", "domcontentloaded", "networkidle", "commit"] 대기할 페이지 상태, 기본값은 "load"

  • PreRunScript[""] - AddInitScript를 통해 주입되어 페이지 스크립트가 실행되기 전에 실행되는 스크립트(문서 생성 시, 탐색 완료 전). 환경 패치(navigator 재정의, API 스텁)에 유용합니다. 로드된 DOM에는 접근할 수 없습니다. placeholder {PL}도 지원

  • PostRunScript[""] - 페이지 로드 후, 페이지 내용을 읽기 전에 실행되는 스크립트. DOM 상호작용(클릭, 스크롤)에 유용합니다. placeholder {PL}도 지원

  • Stealth[false] - 봇 방어를 통과하기 위한 스크립트 추가 시도

  • StorageStateFile[""] - playwright storage state json(cookies + localStorage) 경로(~/ 지원): 탐색 전에 브라우저 컨텍스트에 로드되고, 매 실행 후 다시 기록되어 새로고침된 세션이 유지됩니다. 헤드리스 실행이 실제 로그인을 재사용할 수 있게 합니다 — fitter_cli browser-login으로 파일을 한 번 생성하세요. 로그인과 스크래핑에 동일한 browser를 사용하세요: 사이트가 세션을 브라우저 지문에 바인딩할 수 있습니다. 포맷팅도 지원

  • IndexedDB[false] - 유지된 storage state에 IndexedDB 포함(일부 SPA, 예: Firebase Auth는 토큰을 여기에 보관)

  • Proxy - 요청에 대한 프록시 설정 config

예시

{
  "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"`
}

Config는 다음 중 하나가 될 수 있습니다:

예시:

{
  "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인 경우 전체 객체가 부모에서 생략됩니다(필드는 전혀 해석되지 않음)

Config는 다음 중 하나가 될 수 있습니다:

  • Fields - 각 필드 정의의 맵; key - 필드 이름, value - 구성

  • 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 - 배열의 고정 크기(생성된 배열 전용, static 아님). 참고: 소스에 limit보다 적은 요소가 있는 경우 배열은 선언된 크기를 유지하기 위해 끝에 null로 채워집니다(의도된 동작) — 대신 정확한 소스 길이를 얻으려면 length_limit을 생략하세요

  • Condition - 선택 사항인 조건 표현식으로, 해석 전에 소스 노드에 대해 평가됩니다. false인 경우 전체 배열이 부모에서 생략됩니다

  • ItemCondition - 선택 사항인 조건 표현식으로, 구성된 모든 항목에 대해 평가됩니다(fRes - 항목 값, fSrc - 소스 요소, fIndex - 항목 인덱스). false로 평가되는 항목은 배열에서 제거됩니다 - 선언적 필터링. static_array에는 적용되지 않음

Config는 다음 중 하나가 될 수 있습니다:

예시:

{
  "root_path": "#content dt.quote > a",
  "item_config": {
    "field": {
      "type": "string"
    }
  }
}

Field

필드의 공통 사항

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"`
}

Config는 다음 중 하나가 될 수 있습니다:

  • 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 - 선택적 조건 표현식으로, 추출된 값(fRes/fResJson/fResRaw, fIndex; fSrc - 필드가 해석된 노드, 형제 포함)에 대해 평가됩니다. false인 경우 필드는 null을 생성하는 대신 부모 객체/배열에서 생략됩니다. Generated보다 먼저 평가되므로, false 조건은 생성 작업(하위 요청, 파일 다운로드)도 건너뜁니다.

중요: 기본적으로 "string" 타입은 트리밍되고 모든 특수 문자가 대체됩니다. 일반 문자열이 필요하면 "raw_string"을 사용하세요.

Config는 다음 중 하나이거나 비어 있을 수 있습니다:

  • Generated - 사용자 지정 설정으로 생성될 수 있는 필드

  • FirstOf - 비어 있지 않은 첫 번째 해석 필드가 선택됩니다

예시

{
  "generated": {
    "uuid": {}
  }
}
{
  "type": "string",
  "path": "text()"
}

조건부 필드

모든 필드는 condition - expr-lang 표현식(사전 정의된 값)을 가질 수 있습니다. true가 아닌 다른 값으로 평가되면 필드는 출력에서 생략됩니다(키/항목이 사라짐). null로 설정되지 않습니다. 잘못된 표현식도 필드를 생략하고 오류를 기록합니다.

조건이 평가되는 위치:

  • BaseField.condition - 추출 후: fRes는 추출된 값, fSrc는 필드가 해석된 노드(형제 포함)입니다 - 따라서 fSrc.on_sale == true는 추출하지 않은 데이터를 기준으로 필드를 제어할 수 있습니다. false 조건은 생성 작업을 완전히 건너뜁니다(하위 요청 없음, 파일 다운로드 없음)

  • 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"
    }
  }
}

특수 사례:

  • 정적 배열에서 생략된 항목은 null로 유지됩니다(위치는 정의상 고정되며 인덱스는 절대 이동하지 않음)

  • 루트 모델 구성이 생략되면 파싱 결과는 null입니다

  • first_of 내부에서 false 조건의 분기는 비어 있는 것으로 간주되어 다음 분기가 시도됩니다

실행 가능한 예시: 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"`
}

Config는 다음 중 하나가 될 수 있습니다:

  • 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]
}

Formatted Field Config

부모 base field의 값을 전달하는 형식화된 필드 생성

type FormattedFieldConfig struct {
	Template string `yaml:"template" json:"template"`
}
  • Template - {PL} 자리 표시자가 있는 템플릿으로, 부모 값이 문자열로 주입됩니다

예시: https://github.com/PxyUp/fitter/blob/master/examples/cli/config_cli.json#L98

{
  "template": "https://news.ycombinator.com/item?id={PL}"
}

File Storage Field

필드 결과를 로컬 파일로 저장하는 데 사용할 수 있는 필드

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 - 파일 저장을 위한 로컬 파일 이름. 기본적으로 헤더에서 FileName을 가져오려고 시도하고, 그 다음 URL에서 가져옵니다. 중요: 부모 값의 문자열 주입이 가능합니다.

  • Path - 파일 저장을 위한 로컬 부모 디렉토리. 기본 경로는 프로세스 디렉토리입니다. 중요: 부모 값의 문자열 주입이 가능합니다

  • Append[false] - 파일에 추가할지 여부

{
  "content": "{{{id}}}, {{{message}}}\n",
  "append": true,
  "file_name": "{{{id}}}.csv",
  "path": "/Users/pxyup/fitter/examples/cli/test/csv"
}

File Field

서버에서 로컬로 파일을 다운로드하는 데 사용할 수 있는 필드

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 - 파일 저장을 위한 로컬 파일 이름. 기본적으로 헤더에서 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"
  }
}

Config 예시:

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

Calculated field

표현식에 따라 다른 타입을 생성할 수 있는 필드

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의 경우 텍스트 콘텐츠). calculated/formatted/notifier 표현식에서는 사용할 수 없습니다

FNewLine - 줄바꿈 구분자

{
  "type": "bool",
  "expression": "fRes > 500"
}

Plugin field

fitter용 외부 플러그인이 될 수 있는 필드

더 보기

type PluginFieldConfig struct {
	Name string `json:"name" yaml:"name"`
	Config json.RawMessage `json:"config" yaml:"config"`
}
  • Name - 플러그인 이름(확장자 없이 이름만)

  • Config - 플러그인의 json 설정

Model Field

modelconnector로 즉석에서 생성할 수 있는 필드 타입

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 - Model의 후처리에 사용할 수 있는 문자열(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"
        }
      }
    }
}

Static Array Config

정적(고정 길이) 배열 생성을 제공합니다

type StaticArrayConfig struct {
    Items map[uint32]*Field `yaml:"items" json:"items"`
    Length uint32            `yaml:"length" json:"length"`
}
  • Items - map[uint32]*Field - 키는 배열의 인덱스, 값은 필드 정의

  • Length - 설정된 경우(1+) 배열의 사용자 지정 길이를 정의하는 데 사용할 수 있습니다

예시:

{
  "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"
    }
  }
}

Placeholder 목록

  1. {PL} - 값 주입용

  2. {INDEX} - 부모 배열의 인덱스 주입용

  3. {HUMAN_INDEX} - 부모 배열의 인덱스를 사람이 읽기 쉬운 방식으로 주입용

  4. {{{json_path}}} - 전파된 "object"/"array" 필드에서 정보를 가져옵니다

  5. {{{RefName=SomeName}}} - 이름으로 reference 값을 가져옵니다. 예시

  6. {{{RefName=SomeName json.path}}} - 이름으로 reference 값을 가져오고 json 경로로 값을 추출합니다. 예시

  7. {{{FromEnv=ENV_KEY}}} - 환경 변수에서 값을 가져옵니다

  8. {{{FromExp=fRes + 5 + fIndex}}} - 표현식에서 값을 가져옵니다. 사전 정의된 값

  9. {{{FromInput=.}}} 또는 {{{FromInput=json.path}}} - 트리거 또는 라이브러리의 입력에서 값을 가져옵니다

  10. {{{FromFile=./test_file.log}}} - 경로로 파일에서 값을 가져옵니다. 파일의 콘텐츠에도 placeholders가 포함될 수 있습니다

  11. {{{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}

References

프리페치된(모든 처리 전에) 특수 맵으로, connector 또는 placeholder에 사용할 수 있습니다

다음 용도로 사용할 수 있습니다:

  1. jwt 토큰을 캐시하고 헤더에 사용

  2. 값 캐시

  3. 기타

Reference

type Reference struct {
    *ModelField
    
    Expire *uint32 `yaml:"expire" json:"expire"`
}
  • ModelField - 임베디드 구조체로, 동일한 필드를 사용할 수 있습니다

  • Expire[sec] - 가져온 후 reference가 만료되는 기간. 설정 안 함 => 영구 캐시. 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"`
}

예시

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"
              }
            }
          }
        }
      }
    }
  }
}

예시

Notifiers

선택적 항목별 설정 item.notifier_config로, 처리 후 파싱 결과를 어딘가로 푸시합니다. 결과는 평소와 같이 반환되며(CLI/MCP 출력, 서비스 로그), notifier가 추가로 전달합니다. 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) > 0

  • Force - 파싱이 오류로 끝나도 알림

  • SendArrayByItem - 결과가 배열인 경우 각 요소를 별도의 알림으로 전송

  • Template - 전송 전 결과에 적용되는 선택적 템플릿, placeholders 허용

  • 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 tools
fitter_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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.2/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYesHTTP(S) URL to fetch and inspect for its structure and candidate selectors.
renderNoRender 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_typeNoOptional hint for how to read the response: json, HTML, xpath or XML. Empty auto-detects from the Content-Type/body.

TDQS

A5/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters5/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
inputNoOptional input value (plain string or JSON), available in the config via {{{FromInput=.}}} or {{{FromInput=json.path}}} placeholders.
configYesFitter CliItem config as a JSON or YAML string. Top-level keys: item (required), limits, references.

TDQS

A4.2/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesAbsolute path to a Fitter config file (.json, .yaml or .yml) with top-level keys: item (required), limits, references.
inputNoOptional input value (plain string or JSON), available in the config via {{{FromInput=.}}} or {{{FromInput=json.path}}} placeholders.

TDQS

A3.7/5.0
Behavior2/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
urlYesHTTP(S) URL of a Fitter config (JSON or YAML) with top-level keys: item (required), limits, references.
inputNoOptional input value (plain string or JSON), available in the config via {{{FromInput=.}}} or {{{FromInput=json.path}}} placeholders.

TDQS

A3.9/5.0
Behavior2/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
configYesFitter CliItem config as a JSON or YAML string to validate without executing it.

TDQS

A4.5/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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. 1 tool updatev1.8.2
    • Addedfitter_inspect_url
  2. 1 tool updatev1.7.0
    • Addedfitter_validate_config
  3. 4 tool updatesv0.1.0
    • First observedfitter_config_reference
    • First observedfitter_run
    • First observedfitter_run_file
    • First observedfitter_run_url

TDQS

A4.4/5.0
Disambiguation5/5

Each tool serves a distinct purpose: reference, inspection, execution (with three source variants), and validation. No overlap or ambiguity between them.

Naming Consistency5/5

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.

Tool Count5/5

Six tools is ideal for a config-driven scraping/parsing workflow: reference, inspect, run (three variants), and validate. Not bloated or sparse.

Completeness5/5

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

ActivityMaintained
ResponsivenessUnresponsive

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

Related MCP Servers

Latest Blog Posts

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