Skip to main content
Glama

Fitter — Webdaten für KI-Agenten

MCP Toplist

Release License: MIT Go Reference Sponsor

Fitter verwandelt jede Website oder API deklarativ in strukturiertes JSON. Eine JSON/YAML-Konfiguration beschreibt, wo die Daten liegen (HTTP-Anfrage, Headless-Browser, Datei, statischer Wert) und was extrahiert werden soll (JSON-Pfade, CSS-Selektoren, XPath). Kein Code, keine fragilen Scraping-Skripte.

🚀 Probieren Sie es im Browser aus — die echte Engine, kompiliert zu WebAssembly: Live-Beispiele, ein visueller Konfigurations-Builder, keine Installation.

Da Konfigurationen reine Daten sind, können LLMs sie erstellen. Der eingebaute MCP-Server ermöglicht es Claude Code, Claude Desktop oder jedem MCP-Client, Scraping-Pipelines auf Ihrem Rechner on demand zu schreiben und auszuführen:

"Hole die Top-5-HackerNews-Geschichten mit Titeln und Punktzahlen" → das Modell erstellt eine Fitter-Konfiguration, validiert sie, führt sie lokal aus und erhält sauberes JSON zurück.

Eine Engine, fünf Einsatzmöglichkeiten:

🤖 Fitter MCP

MCP-Server, der Fitter für Claude Code, Claude Desktop und jeden MCP-Client bereitstellt

🧠 Fitter Agent

KI-gestützte CLI: natürliche Sprache → Konfiguration → ausgeführtes Ergebnis

🖥 Fitter CLI

Konfigurationen lokal ausführen für Test/Debug/Heimgebrauch

📦 Fitter Lib

Die Engine in Ihr eigenes Go-Programm einbetten

⚙️ Fitter

Langlaufender Dienstmodus mit Zeitplanung und Benachrichtigungen

Warum Fitter für KI-Agenten?

  • Deklarativ & nachvollziehbar — der Agent erstellt eine Konfiguration, die Sie lesen, speichern und erneut ausführen können, keinen Wegwerf-Code

  • Lokal zuerst — alle Abrufe erfolgen auf Ihrem Rechner; keine Drittanbieter-Scraping-API, keine Schlüssel, keine Abrechnung pro Anfrage

  • Alles inklusive — HTTP-Client, Headless-Browser (Playwright/Chromium/Docker), JSON/HTML/XML/XPath/PDF-Parsing, Paginierung, gecachte Referenzen, Host-Ratenbegrenzungen — in einer einzigen statischen Binärdatei

  • Wiederverwendbar — was der Agent heute erstellt, wird morgen zum Cron-Job oder zur Dienstkonfiguration

Fitter-Demo — deklarative Konfiguration zu strukturiertem JSON

So verwenden Sie Fitter_MCP

Fitter MCP ist ein Model Context Protocol-Server (stdio-Transport), der es jedem MCP-Client — Claude Code, Claude Desktop, IDE-Assistenten, benutzerdefinierten Agenten — ermöglicht, Fitter-Konfigurationen auszuführen und strukturiertes JSON zurückzuerhalten.

Schnellstart (Claude Desktop — ein Klick)

Laden Sie fitter-mcp-<os>-<arch>.mcpb von der Release-Seite herunter und öffnen Sie es — Claude Desktop installiert den Server automatisch.

Schnellstart (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"

Dann fragen Sie einfach:

Hole die Top-5-HackerNews-Geschichten mit Titeln und Punktzahlen mit Fitter

Das Modell ruft fitter_config_reference auf, erstellt eine Konfiguration, prüft sie optional mit fitter_validate_config und führt sie über fitter_run aus — alle Datenabrufe erfolgen lokal auf Ihrem Rechner. Für eine fertige Pipeline probieren Sie examples/config_morning_briefing.json:

Führe examples/config_morning_briefing.json mit Fitter aus und gib mir das Briefing

In Claude Desktop registrieren

{
  "mcpServers": {
    "fitter": {
      "command": "/path/to/fitter_mcp"
    }
  }
}

Browser-Unterstützung (Playwright)

Das .mcpb-Bundle und die native Binärdatei werden ohne Browser ausgeliefert: HTTP-, statische und Datei-Connectors funktionieren sofort, aber Browser-Konfigurationen (der playwright-Connector) benötigen Playwrights Browser. Einige Möglichkeiten, sie zu erhalten:

  • Bei der ersten Verwendung (native Binärdatei / .mcpb): Setzen Sie "install": true im Playwright-Connector — Fitter lädt den Treiber + Browser passend zu seiner eingebauten playwright-go-Version bei der ersten Verwendung herunter (einmalig, gecacht), sodass kein separater Installationsschritt erforderlich ist.

  • Im Voraus (nativ, optional): Um den Download beim ersten Start zu vermeiden, installieren Sie die Browser vorab mit derselben playwright-go-Version, gegen die Fitter gebaut ist (siehe go.mod, aktuell 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

    Die Version muss exakt mit go.mod übereinstimmen — playwright-go weigert sich, mit einem nicht passenden Treiber zu laufen. Führen Sie dann Konfigurationen ohne "install": true aus.

  • Docker: Verwenden Sie das ghcr.io/pxyup/fitter-mcp:playwright-Image, das Chromium, Firefox und WebKit vorinstalliert enthält (kein "install": true erforderlich).

Werkzeuge

Tool

Beschreibung

fitter_run

Führt eine inline übergebene Fitter-Konfiguration (JSON- oder YAML-String) aus und gibt die extrahierten Daten als JSON zurück. Akzeptiert einen optionalen input-Wert, der in der Konfiguration über {{{FromInput=.}}} / {{{FromInput=json.path}}} verfügbar ist

fitter_run_file

Wie fitter_run, liest die Konfiguration jedoch aus einer lokalen .json/.yaml-Datei

fitter_run_url

Wie fitter_run, lädt die Konfiguration jedoch von einer HTTP(S)-URL herunter, z. B. einem rohen GitHub-Link

fitter_inspect_url

Ruft eine URL ab und gibt eine kompakte Strukturübersicht + Kandidaten-Selektoren/Pfade zurück (gjson-Pfade für JSON; wiederholte Element-/Listenzeilen-Selektoren für HTML), damit das Modell eine Konfiguration beim ersten Versuch erstellt, statt Selektoren zu raten und null zu erhalten. Erkennt clientgerenderte SPAs und kann sie in einem Headless-Browser renderen. Schreibgeschützt — extrahiert nicht

fitter_validate_config

Validiert eine Konfiguration ohne Ausführung (Struktur, response_type, Connector-Datenquelle, Modell). Nützlich beim Iterieren an einer Konfiguration

fitter_config_reference

Gibt eine komprimierte Referenz des gesamten Konfigurationsformats zurück (Connectors, Parser, Modell-/Feld-Schema, Platzhalter, Notifier, Referenzen, Limits) mit funktionierenden Beispielen, damit das Modell Konfigurationen ohne externe Dokumentation erstellen kann

Die Referenz ist auch als MCP-Ressource fitter://config-reference für Clients verfügbar, die Ressourcen unterstützen.

Das Konfigurationsformat ist genau dasselbe wie für Fitter_CLI: ein Objekt der obersten Ebene mit item (erforderlich), limits und references. Notifier funktionieren ebenfalls (das Ergebnis wird zusätzlich an http/telegram/redis/file/console gesendet); trigger_config und http_server sind nur für den Dienstmodus und werden bei MCP-Aufrufen ignoriert.

Remote-/gehosteter Modus (streamable HTTP)

Standardmäßig kommuniziert fitter_mcp über stdio. Übergeben Sie --http, um den streamable HTTP transport zu bedienen — für einen gemeinsamen Team-Server, einen Container oder jede Remote-Bereitstellung:

# 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> (Umgebungsvariable FITTER_MCP_HTTP_ADDR) — Listen-Adresse; stdio-Modus, wenn leer

  • FITTER_MCP_AUTH_TOKEN — wenn gesetzt, muss jede /mcp-Anfrage Authorization: Bearer <token> senden; ohne dies ist der Endpunkt nicht authentifiziert, also binden Sie ihn an localhost oder stellen Sie ihn hinter einen Proxy

  • --stateless (Umgebungsvariable FITTER_MCP_STATELESS=true) — kein Pro-Sitzungs-Zustand, sodass Replikate hinter einem Load Balancer ohne Sticky Sessions stehen können

Der Server fährt bei SIGINT/SIGTERM sauber herunter.

Docker

Ein schlankes Multi-Arch-Image (linux/amd64 + linux/arm64) wird mit jedem Release ausgeliefert:

# 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

Das schlanke Image enthält nur die Fitter-Binärdatei und CA-Zertifikate: Server-/statische-/Datei-Connectors funktionieren, Browser-Connectors (chromium/docker/playwright) nicht.

Für browserbasierte Konfigurationen verwenden Sie die playwright-Variante, die Playwright mit Chromium, Firefox und WebKit bündelt (passend zur playwright-go-Version, gegen die Fitter gebaut ist, sodass kein "install": true in Konfigurationen erforderlich ist):

docker run --rm -i ghcr.io/pxyup/fitter-mcp:playwright        # stdio mode
# per-release tag: ghcr.io/pxyup/fitter-mcp:vX.Y.Z-playwright

Es wird aus Dockerfile.mcp-playwright gebaut; bauen Sie mit --build-arg PLAYWRIGHT_BROWSERS=chromium für ein kleineres Chromium-only-Image.

OAuth2-Konten in Docker

Beide Images enthalten fitter_cli, sodass der einmalige OAuth2-Login im Container ausgeführt werden kann. Speichern Sie das Token auf einem Volume, das unter /tokens gemountet ist (im Image vorerstellt und beschreibbar), und teilen Sie es mit dem MCP-Server:

# 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

Hinweis: 8988 ist nur für den einmaligen Browser-Flow-Login; der MCP-Server selbst benötigt im stdio-Modus keinen Port und im gehosteten HTTP-Modus nur 8080.

Angemeldete Browser-Sitzungen in Docker

Browser-Sitzungen benötigen das playwright-Image (das schlanke hat keine Browser). Der einmalige Login mit Anzeige benötigt ein Display, führen Sie ihn also auf dem Host aus und mounten Sie dann das Sitzungsverzeichnis in den Container (das Image erstellt vorab ein beschreibbares /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

Verwenden Sie einen Bind-Mount (kein benanntes Volume): Der Container schreibt nach jedem Lauf aktualisierte Cookies zurück, sodass die Host-Kopie aktuell bleibt und jederzeit mit browser-login erweitert werden kann.

Das Volume muss für den Server beschreibbar bleiben: Rotierte Refresh-Tokens werden bei jeder Aktualisierung zurückgeschrieben.

Umgebungsvariablen

  1. FITTER_PLUGINS - string[""] - Pfad für den Plugins-Ordner, wie das --plugins-Flag von Fitter/Fitter_CLI

  2. FITTER_MCP_HTTP_ADDR - string[""] - Listen-Adresse für den Remote-Modus, wie --http

  3. FITTER_MCP_AUTH_TOKEN - string[""] - Bearer-Token, das den HTTP-Endpunkt schützt

  4. FITTER_MCP_STATELESS - bool[false] - zustandsloser HTTP-Transport, wie --stateless

Rezepte

Vollständige, getestete Konfigurationen, die die wichtigsten Muster zeigen. Alle laufen unverändert über Fitter_MCP (fitter_run_file), Fitter_CLI oder die Bibliothek – mehr in examples/.

Eine Seite ohne API scrapen und mit einer API anreichern

GitHub Trending hat keine offizielle API – scrapen Sie das HTML nach Repo-Slugs (html_attribute liest das href), und fächern Sie dann jeden einzelnen in die GitHub-REST-API mit {PL} auf:

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

Join über ein JSON-Feld mit einem Ausdruck

Wenn Array-Elemente Objekte sind, liegt der Join-Schlüssel in ihnen – extrahieren Sie ihn mit {{{FromExp=...}}} (expr-lang über fRes, das aktuelle Element). Buchsuche → Autorendetails, Suchanfrage über input bereitgestellt:

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

Ergebnisse in eine lokale Datei schreiben

Das generierte Feld file_storage verwandelt Felder in Schreibvorgänge – die Top-5-Krypto-Coins werden an eine CSV angehängt, eine Zeile pro Element. Nackte {{{json.path}}}-Platzhalter lesen das aktuelle Element; {HUMAN_INDEX} stempelt den 1-basierten Rang (Elemente werden parallel verarbeitet, daher landen Anhänge in der Reihenfolge des Abschlusses – sortieren Sie nach der Rangspalte):

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

Text aus einer PDF-Datei extrahieren

response_type: "pdf" verwandelt jedes abgerufene PDF in ein JSON-Dokument – {"text": "...", "pages": ["..."], "total_pages": N} – sodass reguläre JSON-Pfade (text, pages.0) und Ausdrücke darauf funktionieren. Das Bitcoin-Whitepaper, Seitenzahl plus eine gekürzte Einleitung:

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}

Möglichkeiten zur Informationssammlung

  1. Server – Parsen der Antwort von APIs oder HTTP-Anfragen (Verwendung von http.Client)

  2. Browser – Emulation eines echten Browsers mit Chromium + Docker + Playwright/Cypress und Abrufen von DOM-Informationen

  3. Statisch – Parsen eines statischen Strings als Daten

Formate, die geparst werden können

  1. JSON – Parsen von JSON, um spezifische Informationen zu erhalten

  2. XML – Parsen des XML-Baums, um spezifische Informationen zu erhalten

  3. HTML – Parsen des DOM-Baums, um spezifische Informationen zu erhalten

  4. XPath – Parsen des DOM-Baums, um spezifische Informationen zu erhalten, aber per XPath

  5. PDF – Extrahieren von Text aus PDF-Dokumenten; der Inhalt wird als JSON {"text": "...", "pages": ["..."], "total_pages": N} bereitgestellt, sodass reguläre JSON-Pfade wie text oder pages.0 funktionieren

Als Bibliothek verwenden

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())
}

Ausgabe:

{
  "generated_array": ["id","uid","brand","equipment"],
  "my_id": 6000,
  "generated_id": "26b08b73-2f2e-444d-bcf2-dac77ac3130e"
}

Verwenden Sie lib.ParseCtx(ctx, ...), um einen context.Context zu übergeben: Das Abbrechen bricht laufende Abrufe ab (HTTP-Anfragen, Headless-Browser, Docker-Container) und wendet Fristen durchgängig an. lib.Parse entspricht lib.ParseCtx(context.Background(), ...).

So verwenden Sie Fitter

Laden Sie die neueste Version von der Release-Seite herunter

oder lokal:

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

Argumente

  1. --path – string[""] – Pfad für die Konfiguration des Fitters

  2. --url – string[""] – URL für die Konfiguration des Fitters

  3. --verbose – bool[false] – Protokollierung aktivieren

  4. --plugins – string[""] – Pfad für Plugins für Fitter

  5. --log-level – enum["info", "error", "debug", "fatal"] – Protokollstufe festlegen (nur wenn verbose auf true gesetzt ist)

So verwenden Sie Fitter_CLI

Laden Sie die neueste Version von der Release-Seite herunter

oder lokal:

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

Argumente

  1. --path – string[""] – Pfad für die Konfiguration des Fitter_CLI

  2. --url – string[""] – URL für die Konfiguration des Fitter_CLI

  3. --copy – bool[false] – Informationen in die Zwischenablage kopieren

  4. --pretty – bool[true] – lesbares Ergebnis erzeugen (wirkt sich auch auf das Kopieren aus)

  5. --verbose – bool[false] – Protokollierung aktivieren

  6. --omit-error-pretty – bool[false] – reinen Wert liefern, wenn pretty ungültig ist

  7. --plugins – string[""] – Pfad für Plugins für Fitter

  8. --log-level – enum["info", "error", "debug", "fatal"] – Protokollstufe festlegen (nur wenn verbose auf true gesetzt ist)

  9. --input – string[""] – Eingabewert für Formatierung angeben. Beispiele: --input=\""124"\" --input=124 --input='{"test": 5}'

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

fitter_cli auth – ein OAuth2-Konto verbinden

Einmaliger interaktiver Login, der ein (Refresh-)Token für die OAuth2-Connector-Konfiguration speichert:

# 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

Argumente:

  1. --provider – voreingestellt mit bekannten Endpunkten: github|google|microsoft|gitlab|spotify

  2. --client-id / --client-secret – OAuth2-App-Anmeldedaten (einige Device-Flows funktionieren ohne Secret)

  3. --token-file – wo das empfangene Token gespeichert wird (Berechtigungen 0600); verweisen Sie in oauth2.token_file auf denselben Pfad

  4. --flowauto (Device, falls verfügbar, sonst Browser), device (URL besuchen + Code eingeben) oder browser (localhost-Callback mit PKCE, Standard-Port 8988 – registrieren Sie http://127.0.0.1:8988/callback als App-Callback-URL)

  5. --scopes – durch Kommas getrennte Scopes

  6. --auth-url/--token-url/--device-auth-url/--auth-style – Endpunkt-Überschreibungen für Anbieter ohne Voreinstellung

  7. --port – int[8988] – Callback-Port für den Browser-Flow (env FITTER_AUTH_PORT); mit dem Standardwert ist die beim Anbieter zu registrierende Callback-URL http://127.0.0.1:8988/callback

  8. --listen – Bind-Adresse für den Browser-Flow, Standard 127.0.0.1; setzen Sie 0.0.0.0 in einem Container, damit der veröffentlichte Port den Listener erreicht (env FITTER_AUTH_LISTEN)

  9. --redirect-url – Callback-URL, die beim Anbieter registriert ist, wenn sie von der Listen-Adresse abweicht, z. B. Docker-Portzuordnung (env FITTER_AUTH_REDIRECT_URL)

  10. --no-browser – nur die Autorisierungs-URL ausgeben

Ausführung in Docker: siehe OAuth2-Konten in Docker.

Nach dem Login gibt der Befehl den gebrauchsfertigen oauth2-Konfigurationsblock aus. Der Connector aktualisiert das Zugriffstoken automatisch und schreibt rotierte Refresh-Tokens zurück in die Token-Datei, sodass der Login nur einmal benötigt wird.

fitter_cli browser-login – eine echte Login-Sitzung wiederverwenden

Für Websites ohne API/OAuth: Melden Sie sich einmal manuell in einem echten (sichtbaren) Browserfenster an – jedes Authentifizierungsschema funktioniert, einschließlich Passwörter, 2FA, SSO und Captchas – und speichern Sie die Sitzung für Headless-Scraping über 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

Argumente:

  1. --url – zu öffnende Login-Seite (erforderlich)

  2. --storage-state – wo die Sitzung gespeichert wird (Cookies + localStorage, Berechtigungen 0600); verweisen Sie in playwright.storage_state_file auf denselben Pfad (erforderlich)

  3. --browser – enum["Chromium", "FireFox", "WebKit"] Standard "Chromium"; verwenden Sie denselben Wert wie in der Scraping-Konfiguration – Websites können Sitzungen an den Browser-Fingerprint binden

  4. --install – bool[false] – zuerst Playwright-Browser installieren

  5. --indexeddb – bool[false] – IndexedDB in den Snapshot aufnehmen (Firebase Auth und Ähnliches)

Ein erneutes Ausführen des Befehls lädt zuerst den vorhandenen Zustand, sodass Sie eine Sitzung erweitern/aktualisieren können, ohne sich von Grund auf anzumelden. Der Scraping-Connector schreibt nach jedem Lauf auch aktualisierte Cookies zurück und hält die Sitzung am Leben, solange sie regelmäßig verwendet wird. Benötigt ein Display: Führen Sie diesen Befehl in Docker auf dem Host aus und mounten Sie die Datei – siehe Browser-Sitzungen in Docker.

Beispiele:

  1. Server-Version HackerNews + Quotes + Guardian News – mit API + HTML + XPath-Parsing

  2. Chromium-Version Guardian News + Quotes – mit HTML-Parsing + Browser-Emulation

  3. Docker-Version Docker-Version: Guardian News + Quotes – mit HTML-Parsing + Browser aus Docker-Image

  4. Playwright-Version Playwright-Version: Guardian News + Quotes – mit HTML-Parsing + Browser aus dem Playwright-Framework

  5. Playwright-Version Playwright-Version: England Cities + Weather – mit HTML + XPath-Parsing + Browser aus dem Playwright-Framework

  6. JSON-Version Paginierung generieren – mit statischem Connector zum Generieren eines Paginierungs-Arrays

  7. Server-Version Aktuelle Zeit abrufen – Zeit von URL abrufen und formatieren

So verwenden Sie Fitter_Agent

Fitter Agent ist eine KI-gestützte CLI, die Claude verwendet, um natürliche Sprachbefehle in Fitter-Konfigurationen umzuwandeln und sie automatisch auszuführen.

Laden Sie die neueste Version von der Release-Seite herunter

oder lokal:

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

Argumente

  1. --api-key – string[""] – Anthropic-API-Schlüssel. Bevorzugen Sie die Umgebungsvariable ANTHROPIC_API_KEY, damit der Schlüssel nicht in Ihrer Shell-Historie landet

  2. --model – string["claude-opus-4-8"] – zu verwendendes Claude-Modell

  3. --effort – enum["low", "medium", "high", "xhigh", "max"] – Denkaufwand, Standard "high". Senken Sie ihn für schnellere/günstigere Konfigurationen, erhöhen Sie ihn für schwierigere Extraktionen

  4. --verbose – bool[false] – Protokollierung aktivieren

  5. --log-level – enum["info", "error", "debug", "fatal"] – Protokollstufe festlegen

  6. --plugins – string[""] – Pfad für Plugins für Fitter

  7. --chromium-limit – uint[0] – gleichzeitige Chromium-Instanzen begrenzen

  8. --docker-limit – uint[0] – gleichzeitige Docker-Container begrenzen

  9. --playwright-limit – uint[0] – gleichzeitige Playwright-Instanzen begrenzen

So funktioniert es

┌─────────────────────────────────────────────────────────────────┐
│  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                             │
└─────────────────────────────────────────────────────────────────┘

Eine Konfiguration verfeinern

Der Agent behält das Gespräch, sodass Sie nach der Generierung einer Konfiguration einfach sagen können, was geändert werden soll, anstatt die gesamte Anfrage zu wiederholen:

> Get top 3 HackerNews stories with titles and scores
refine> Only return 5 items and also include the article URL

Verwenden Sie new, um die aktuelle Konfiguration zu verwerfen und eine neue Sitzung zu starten.

Interaktive REPL-Befehle

  • help – Hilfemeldung anzeigen

  • new/reset – aktuelle Konfiguration verwerfen und neu starten

  • clear – Bildschirm löschen

  • exit/quit/q – Agent beenden

Beispielsitzung

$ 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!

Beispielanfragen

Anfrage

Was es tut

Get Bitcoin price from CoinGecko API

Ruft aktuellen BTC-Preis ab

Scrape headlines from news.ycombinator.com with links

HTML-Scraping mit CSS-Selektoren

Get top 5 stories from HackerNews with titles

Verschachtelte API-Aufrufe

Fetch weather data from wttr.in for London

Einfache API-Extraktion

Scrape product names and prices from example.com

Web-Scraping

Unterstützte Funktionen

Der Agent kann Konfigurationen generieren für:

  • JSON-APIs – REST-APIs mit GET/POST-Methoden

  • HTML-Scraping – Extraktion basierend auf CSS-Selektoren

  • XPath-Scraping – Extraktion basierend auf XPath

  • Verschachtelte API-Aufrufe – Details für jedes Element in einer Liste abrufen

  • Browser-Emulation – Playwright für JS-gerenderte Seiten

  • Formatierte Felder – URL-Vorlagen mit Platzhaltern

  • Array-Begrenzung – Ergebnisse auf N Elemente begrenzen

Konfiguration

Connector

Es ist die Art und Weise, wie Sie die Daten abrufen.

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] – wenn auf true gesetzt, werden alle Fehler ignoriert

  • ResponseType – enum["HTML", "json", "xpath", "XML", "pdf"] – in welchem Format die Daten vom Connector kommen

  • Attempts – wie viele Versuche zum Abrufen der Daten durch den Connector verwendet werden

  • Url – definiert, welche Adresse angefragt werden soll. Wichtig: kann mit Injektion des übergeordneten Werts als String verwendet werden https://api.open-meteo.com/v1/forecast?latitude={{{latitude}}}&longitude={{{longitude}}}&hourly=temperature_2m&forecast_days=1

Die Konfiguration kann eine der folgenden sein:

Beispiel:

{
  "response_type": "xpath",
  "attempts": 3,
  "url": "https://openweathermap.org/find?q={PL}",
  "browser_config": {
    "playwright": {
      "timeout": 30,
      "wait": 30,
      "install": false,
      "browser": "Chromium"
    }
  }
}

PluginConnectorConfig

Der Connector kann über das Plugin-System definiert werden. Dafür müssen Sie die folgenden Flags auf Fitter/Cli anwenden (Speicherort der Plugins):

... --plugins=./examples/plugin

--plugins – sucht nach allen Dateien mit der Erweiterung ".so" im angegebenen Ordner (Unterordner ausgeschlossen)

type PluginConnectorConfig struct {
	Name   string          `json:"name" yaml:"name"`
	Config json.RawMessage `json:"config" yaml:"config"`
}
{
    "name": "connector",
    "config": {
      "name": "Elon"
    }
}
  • Name – Name des Plugins

  • Config – JSON-Konfiguration des Plugins

So erstellen Sie ein Plugin

Plugin erstellen

go build -buildmode=plugin -gcflags="all=-N -l" -o examples/plugin/connector.so examples/plugin/connector/connector.go

Stellen Sie sicher, dass Sie die Variable Plugin exportieren, die das Interface pl.ConnectorPlugin implementiert.

Beispiel für CLI:

https://github.com/PxyUp/fitter/blob/master/examples/cli/config_plugin.json#L5

Plugin-Beispiel:

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

Connector, der das Abrufen von vorab geladenen Daten aus references ermöglicht

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

Beispiel

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

IntSequenceConnectorConfig

Verbesserte Version des Static-Connectors, die eine Integer-Sequenz als Ergebnis generiert

type IntSequenceConnectorConfig struct {
	Start int `json:"start" yaml:"start"`
	End   int `json:"end" yaml:"end"`
	Step  int `json:"step" yaml:"step"`
}
  • Start[0] – Startpunkt für die Generierung (eingeschlossen)

  • End[0] – Endpunkt für die Generierung (ausgeschlossen vom Endergebnis wie range in jeder Sprache)

  • Step[1] – Intervall für die Sequenz

Beispiel

{
    "start": 0,
    "end": 2 
    // Generate [0, 1]
}

Konfigurationsbeispiel

FileConnectorConfig

Connector-Typ, der Daten aus der angegebenen Datei abruft

type FileConnectorConfig struct {
    Path          string `yaml:"path" json:"path"`
    UseFormatting bool   `yaml:"use_formatting" json:"use_formatting"`
}
  • Path – Dateipfad. Unterstützt formatting

  • UseFormatting[false] – formatting des Dateiinhalts verwenden oder nicht

StaticConnectorConfig

Connector-Typ, der Daten aus dem angegebenen String abruft

type StaticConnectorConfig struct {
    Value string `json:"value" yaml:"value"`
    Raw   json.RawMessage `json:"raw" yaml:"raw"`
}
  • Value – statischer String als Daten, kann HTML oder JSON sein

  • Raw – akzeptiert rohes JSON. Beispiel. Unterstützt auch formatting

Beispiel:

https://github.com/PxyUp/fitter/blob/master/examples/cli/config_static_connector.json#L5

{
  "value": "[1,2,3,4,5]"
}

ServerConnectorConfig

Connector-Typ, der Daten mit dem golang http.Client abruft (serverseitige Anfrage wie 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 – unterstützt alle HTTP-Methoden: GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD

  • Headers – vordefinierte Header für die Anfrage kann in Schlüssel/Wert injiziert werden

  • Timeout[sec] – Standard-Timeout 60 Sekunden oder der angegebene Wert

  • Body – Body der Anfrage, geparster Wert kann injiziert werden

  • JsonRawBody – Body der Anfrage im JSON-Format; Wert kann injiziert werden

  • ErrorOnStatus – optional, Standard false. Wenn true, wird ein HTTP-Antwortstatus >= 400 als Abruffehler behandelt (durchläuft attempts / null_on_error), anstatt den Fehler-Body zu parsen – so können Sie einen fehlgeschlagenen Abruf von einem wirklich leeren Ergebnis unterscheiden. Wenn Sie es auf false lassen, bleibt das ursprüngliche Verhalten erhalten, bei dem der zurückgegebene Body geparst wird.

  • Proxy – Proxy für die Anfrage einrichten config

  • OAuth2 – ein Zugriffstoken automatisch abrufen/aktualisieren und als Authorization-Header senden config

Anfragen senden standardmäßig einen identifizierbaren User-Agent (fitter (+https://github.com/PxyUp/fitter)); setzen Sie Ihren eigenen User-Agent in Headers, um ihn zu überschreiben.

Beispiel:

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

Ruft automatisch ein Zugriffstoken vor der Anfrage ab und injiziert es als Authorization-Header (überschreibt einen über headers gesetzten). Tokens werden im Speicher zwischengespeichert und vor Ablauf aktualisiert; bei einer 401-Antwort wird das zwischengespeicherte Token verworfen und die Anfrage einmal mit einem neuen Token wiederholt.

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 – Endpunkt-URL für das Token. Unterstützt auch formatting

  • GrantType – enum["client_credentials", "refresh_token"], Standard ist "client_credentials". Verwenden Sie "refresh_token" für APIs, bei denen der Benutzer einmal zugestimmt hat (Google, Microsoft, ...) und Sie ein langlebiges Refresh-Token besitzen

  • ClientId/ClientSecret – Client-Anmeldedaten. Unterstützen auch formatting, z. B. {{{FromEnv=CLIENT_SECRET}}}

  • Scopes – angeforderte Scopes

  • RefreshToken – erforderlich für den Grant "refresh_token". Unterstützt auch formatting

  • EndpointParams – zusätzliche Parameter für den Token-Endpunkt (z. B. audience für Auth0), nur für Grant "client_credentials"

  • AuthStyle – enum["", "header", "params"] – wie Client-Anmeldedaten an den Token-Endpunkt übergeben werden: Basic-Auth-Header oder Anfrage-Body; leer bedeutet automatische Erkennung

  • TokenFile – optionaler Pfad (unterstützt ~/) zum Speichern von Tokens zwischen Läufen; das gespeicherte Token wird gegenüber RefreshToken bevorzugt und rotierte Refresh-Tokens werden zurückgeschrieben – erforderlich für Anbieter mit Einmal-Refresh-Tokens (GitHub Apps und ähnliche). Erstellen Sie es mit fitter_cli auth

Beispiel:

{
  "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-Konfiguration
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 – Adresse mit Schema des Proxy-Servers. Unterstützt auch formatting

  • Username – Benutzername für den Proxy (kann leer sein). Unterstützt auch formatting

  • Password – Passwort für den Proxy (kann leer sein). Unterstützt auch formatting

{
  "server": "http://localhost:8080",
  "username": "pyx"
}
Umgebungsvariablen
  1. FITTER_HTTP_WORKER – int[1000] – Standard-Anzahl gleichzeitiger HTTP-Worker

BrowserConnectorConfig

Connector-Typ, der das Abrufen von Daten über einen Browser emuliert

type BrowserConnectorConfig struct {
	Chromium   *ChromiumConfig   `json:"chromium" yaml:"chromium"`
	Docker     *DockerConfig     `json:"docker" yaml:"docker"`
	Playwright *PlaywrightConfig `json:"playwright" yaml:"playwright"`
}

Die Konfiguration kann eine der folgenden sein:

  • Chromium – lokal installiertes Chromium zum Abrufen von Daten verwenden

  • Docker – Docker als Dienst zum Starten eines Containers zum Abrufen von Daten verwenden

  • Playwright – Playwright-Framework zum Abrufen von Daten verwenden

Beispiel:

{
    "docker": {
      "wait": 10000,
      "image": "docker.io/zenika/alpine-chrome:with-node",
      "entry_point": "chromium-browser",
      "purge": true
    }
}

Chromium

Verwendet lokal installiertes Chromium zum Abrufen der Daten

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 – Pfad zur Chromium-Binärdatei

  • Timeout[sec] – Timeout für die Ausführung von Chromium

  • Wait[msec] – Timeout für das Laden der Seite

  • Flags – Flags für Chromium, Standard: "--headless", "--proxy-auto-detect", "--temp-profile", "--incognito", "--disable-logging", "--disable-extensions", "--no-sandbox"

Beispiel:

{
  "path": "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
  "wait": 10000
}

Docker

Verwendet Docker zum Starten eines Containers zum Abrufen von Daten

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-Standardimage: docker.io/zenika/alpine-chrome

  • Image – Image für die Docker-Registry (mit Registry-Host angeben)

  • EntryPoint – Befehl, der im Container ausgeführt wird

  • Timeout[sec] – Timeout für das Ausführen des Containers (ohne Image-Pull)

  • Wait[msec] – Timeout für das Laden der Seite (funktioniert nur bei Chromium-basierten Containern)

  • Flags – Befehlsargumente zum Ausführen von Containern, Standard für Chromium-basiert: "--no-sandbox","--headless", "--proxy-auto-detect", "--temp-profile", "--incognito", "--disable-logging", "--disable-gpu"

  • Purge – soll der Container nach Abschluss der Arbeit entfernt werden (wie docker rm)

  • NoPull – verhindert das Pull des Images

  • PullTimeout – definiert das Timeout für den Image-Pull

Umgebungsvariablen
  1. DOCKER_HOST – string – (EnvOverrideHost) zum Festlegen der URL zum Docker-Server.

  2. DOCKER_API_VERSION – string – (EnvOverrideAPIVersion) zum Festlegen der zu verwendenden API-Version, für die neueste Version leer lassen.

  3. DOCKER_CERT_PATH – string – (EnvOverrideCertPath) zum Festlegen des Verzeichnisses, aus dem die TLS-Zertifikate geladen werden (ca.pem, cert.pem, key.pem).

  4. DOCKER_TLS_VERIFY – bool – (EnvTLSVerify) zum Aktivieren oder Deaktivieren der TLS-Verifizierung (standardmäßig deaktiviert)

Beispiel:

{
  "wait": 10000,
  "image": "docker.io/zenika/alpine-chrome:with-node",
  "entry_point": "chromium-browser",
  "purge": true
}

Playwright

Browser über das Playwright-Framework ausführen

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"] – welcher Browser verwendet werden soll

  • Install – soll der Browser installiert werden (lädt beim ersten Gebrauch den Treiber + Browser passend zur eingebauten playwright-go-Version herunter; nicht erforderlich mit dem ghcr.io/pxyup/fitter-mcp:playwright-Image, das sie vorinstalliert enthält)

  • Timeout[sec] – Timeout für die Ausführung von Playwright

  • Wait[sec] – Timeout für das Laden der Seite

  • TypeOfWait – enum["load", "domcontentloaded", "networkidle", "commit"] – auf welchen Zustand der Seite gewartet wird, Standard ist "load"

  • PreRunScript[""] – Skript, das über AddInitScript injiziert und vor der Ausführung von Seitenskripten ausgeführt wird (bei Dokumenterstellung, vor Abschluss der Navigation). Nützlich zum Patchen der Umgebung (navigator-Überschreibungen, API-Stubs). Kann nicht auf das geladene DOM zugreifen. Unterstützt auch Platzhalter {PL}

  • PostRunScript[""] – Skript, das nach dem Laden der Seite, vor dem Lesen des Seiteninhalts, ausgeführt wird. Nützlich für DOM-Interaktionen (Klicks, Scrollen). Unterstützt auch Platzhalter {PL}

  • Stealth[false] – Skript hinzufügen, um Bot-Abwehr zu umgehen

  • StorageStateFile[""] – Pfad (unterstützt ~/) zu einer Playwright-Storage-State-JSON (Cookies + localStorage): wird vor der Navigation in den Browser-Kontext geladen und nach jedem Lauf zurückgeschrieben, sodass aktualisierte Sitzungen erhalten bleiben. Ermöglicht Headless-Läufen die Wiederverwendung eines echten Logins – erstellen Sie die Datei einmal mit fitter_cli browser-login. Verwenden Sie denselben browser für Login und Scraping: Websites können Sitzungen an den Browser-Fingerprint binden. Unterstützt auch formatting

  • IndexedDB[false] – IndexedDB in den gespeicherten Storage-State einbeziehen (einige SPAs, z. B. Firebase Auth, speichern Tokens dort)

  • Proxy – Proxy für die Anfrage einrichten config

Beispiel

{
  "timeout": 30,
  "wait": 30,
  "install": false,
  "browser": "Chromium"
}

Related MCP server: MCP Server Fetch Python

Model

Mit Model definieren wir das Ergebnis des Scrapings

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

Die Konfiguration kann eine der folgenden sein:

  • ObjectConfig – Konfiguration des Objektformats

  • ArrayConfig – Konfiguration des Array-Formats

  • BaseField – Konfiguration eines einzelnen/generierten Felds

  • IsArray – bool[false] – erzwingt die Angabe, dass das Feld ein Array ist (verwendbar im Fall von model field mit base field)

Beispiel:

{
  "object_config": {}
}

ObjectConfig

Konfiguration des Objekts und der Felder

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 – optionaler condition-Ausdruck, der vor der Auflösung gegen den Quellknoten ausgewertet wird; wenn false, wird das gesamte Objekt vom übergeordneten Element weggelassen (Felder werden überhaupt nicht aufgelöst)

Die Konfiguration kann eine der folgenden sein:

  • Fields – Map der Felddefinitionen; Schlüssel – Feldname, Wert – Konfiguration

  • Field – für Elemente eines Arrays verwendet; Felder, die wie Basistypen wie "string", "int" usw. deserialisiert werden (hier für den Fall von Arrays mit Basistypen verwendet)

  • ArrayConfig – für Elemente eines Arrays verwendet; Deserialisierung von Array von Arrays

Beispiel:

{
  "fields": {
    "title": {
      "base_field": {
        "type": "string",
        "path": "type"
      }
    }
  }
}

ArrayConfig

Konfiguration des Arrays und der Felder

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 – Selektor zum Finden des Wurzelelements des Arrays oder des wiederholten Elements bei HTML-Parsing; die Größe des Arrays entspricht der Anzahl der untergeordneten Elemente unter der Wurzel

  • Reverse – bool[false] – gibt an, dass die Iteration in umgekehrter Reihenfolge verwendet werden soll (n bis 1)

  • LengthLimit – feste Größe des Arrays (nur für generierte Arrays; nicht für statische). Hinweis: Wenn die Quelle weniger Elemente als das Limit enthält, wird das Array mit nachgestellten nulls aufgefüllt, um die deklarierte Größe beizubehalten (dies ist beabsichtigt) – lassen Sie length_limit weg, um stattdessen exakt die Quelllänge zu erhalten

  • Condition – optionaler condition-Ausdruck, der vor der Auflösung gegen den Quellknoten ausgewertet wird; wenn false, wird das gesamte Array vom übergeordneten Element weggelassen

  • ItemCondition – optionaler condition-Ausdruck, der gegen jedes erstellte Element ausgewertet wird (fRes – Elementwert, fSrc – Quellelement, fIndex – Elementindex); Elemente, die false ergeben, werden aus dem Array entfernt – deklarative Filterung. Wird nicht auf static_array angewendet

Die Konfiguration kann eine der folgenden sein:

Beispiel:

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

Feld

Gemeinsame Eigenschaften des Felds

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 kann eines der folgenden sein:

  • BaseField – Felder, die wie Basistypen wie „string", „int" usw. deserialisiert werden

  • ObjectConfig – falls unser Feld ein verschachteltes Objekt ist

  • ArrayConfig – falls unser Feld ein Array ist

  • FirstOf – das erste nicht leere aufgelöste Feld wird ausgewählt

Beispiel:

{
  "base_field": {
    "type": "string",
    "path": "div.current-temp span.heading"
  }
}

BaseField

Falls wir statische Informationen erhalten oder neue generieren möchten

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"] – statisches Feld zum Parsen. Wichtig: Der Typ html funktioniert nur mit einem Connector, der HTML zurückgibt (HTMLAttribute hat in diesem Fall keine Wirkung). Beispiel

  • Path – Selektor (relativ, falls es ein Array-Kind ist) zum Parsen

  • HTMLAttribute – zusätzlicher Wert, der nur beim HTML-Parsing über goquery wirkt. Hier kannst du angeben, welches Attribut geparst werden soll.

  • Condition – optionale Bedingung, die gegen den extrahierten Wert ausgewertet wird (fRes/fResJson/fResRaw, fIndex; fSrc – der Knoten, aus dem das Feld aufgelöst wurde, einschließlich Geschwister); wenn false, wird das Feld aus dem übergeordneten Objekt/Array weggelassen, statt null zu erzeugen. Wird vor Generated ausgewertet, sodass eine false-Bedingung auch generierte Arbeit überspringt (Unteranfragen, Dateidownloads)

Wichtig: Standardmäßig wird der Typ „string" getrimmt und alle Sonderzeichen werden ersetzt. Wenn du einen einfachen String benötigst, verwende „raw_string".

Config kann eines der folgenden sein oder leer:

  • Generated – Feld kann generiert werden, mit benutzerdefinierter Konfiguration

  • FirstOf – das erste nicht leere aufgelöste Feld wird ausgewählt

Beispiele

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

Bedingte Felder

Jedes Feld kann eine condition tragen – einen expr-lang-Ausdruck (vordefinierte Werte). Wenn er zu etwas anderem als true ausgewertet wird, wird das Feld aus der Ausgabe weggelassen (der Schlüssel/das Element verschwindet), nicht auf null gesetzt. Ein ungültiger Ausdruck lässt das Feld ebenfalls weg und protokolliert einen Fehler.

Wo die Bedingung ausgewertet wird:

  • BaseField.conditionnach der Extraktion: fRes ist der extrahierte Wert, fSrc der Knoten, aus dem das Feld aufgelöst wurde (einschließlich seiner Geschwister) – so kann fSrc.on_sale == true ein Feld an Daten koppeln, die du nicht extrahiert hast. Eine false-Bedingung überspringt die generierte Arbeit vollständig (keine Unteranfrage, kein Dateidownload)

  • ObjectConfig.condition / ArrayConfig.conditionvor der Auflösung: fRes/fSrc sind der Quellknoten (geparster Wert für JSON, Textinhalt für HTML)

  • ArrayConfig.item_condition – gegen jedes erstellte Element: fRes ist das Element, fSrc das Quell-Element, aus dem es erstellt wurde, fIndex sein Index; false-Elemente werden verworfen – deklarative Array-Filterung. Verwende fSrc, um nach Quellattributen zu filtern, ohne sie in die Ausgabe aufzunehmen

Array-Elemente filtern – fSrc.in_stock liest das Quell-Element (nicht in die Ausgabe extrahiert), fRes.price das erstellte Element:

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

Einen Schlüssel weglassen, es sei denn, der Wert besteht eine Prüfung:

{
  "discount": {
    "base_field": {
      "type": "float",
      "path": "discount_pct",
      "condition": "fRes > 0"
    }
  }
}

Sonderfälle:

  • in einem statischen Array bleibt ein weggelassenes Element null (Positionen sind per Definition fest, Indizes verschieben sich nie)

  • wenn die Root-Modell-Config weggelassen wird, ist das Parse-Ergebnis null

  • innerhalb von first_of zählt ein Zweig mit false-Bedingung als leer, sodass der nächste Zweig versucht wird

Ausführbares Beispiel: examples/config_conditions.json

GeneratedFieldConfig

Bietet die Funktionalität, Felder im laufenden Betrieb zu generieren

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 kann eines der folgenden sein:

  • UUID – zufällige UUID V4 generieren

  • Static – statisches Feld generieren

  • Formatted – Feld formatieren

  • Model – Modell, das aus einem anderen Connector und Modell generiert wird

  • Plugin – Plugin-Feld

  • Calculated – berechnetes Feld

  • File – Dateifeld (zum Herunterladen einer Datei vom Server)

  • FileStorage – Dateifeld, das in einer lokalen Datei gespeichert werden kann

Beispiele:

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

Generiert im laufenden Betrieb eine zufällige UUID V4, kann zur Erzeugung einer eindeutigen ID verwendet werden

type UUIDGeneratedFieldConfig struct {
	Regexp string `yaml:"regexp" json:"regexp"`
}
  • Regexp – stellt einen Matcher bereit, der verwendet werden kann, um einen Teil der generierten UUID zu erhalten

Static

Generiert ein statisches Feld

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"] – Typ des Felds

  • Value – String-Wert des Felds

  • Raw – reiner JSON-Wert des Felds

Beispiel

{
  "type": "int",
  "value": "65"
}
{
  "type": "array",
  "value": "[65,45]"
}
{
  "type": "array",
  "raw": [65,45]
}

Formatierte Feld-Config

Generiert ein formatiertes Feld, das den Wert vom übergeordneten Basisfeld übernimmt

type FormattedFieldConfig struct {
	Template string `yaml:"template" json:"template"`
}
  • Template – Vorlage mit Platzhalter {PL}, in die der übergeordnete Wert als String eingefügt wird

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

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

Dateispeicher-Feld

Feld kann verwendet werden, um das Feldergebnis als lokale Datei zu speichern

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": "{{{id}}}, {{{message}}}\n",
  "append": true,
  "file_name": "{{{id}}}.csv",
  "path": "/Users/pxyup/fitter/examples/cli/test/csv"
}

Dateifeld

Feld kann verwendet werden, um eine Datei lokal vom Server herunterzuladen

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

Das Ergebnis des Felds ist der lokale Dateipfad als String

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

Mit weitergegebener URL (Einfügung des übergeordneten Werts als String)

{
  "url": "https://picsum.photos{PL}",
  "path": "/Users/pxyup/fitter/bin",
  "config": {
    "method": "GET"
  }
}

Config-Beispiel:

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

Berechnetes Feld

Feld kann je nach Ausdruck verschiedene Typen generieren

type CalculatedConfig struct {
	Type       FieldType `yaml:"type" json:"type"`
	Expression string    `yaml:"expression" json:"expression"`
}
  • Type – resultierender Typ des Ausdrucks

  • Expression – Ausdruck zur Berechnung (wir verwenden diese Bibliothek für berechnete Ausdrücke)

Vordefinierte Werte

FNull – Alias für builder.Nullvalue

FNil – Alias für nil

isNull(value T) – Funktion zum Prüfen, ob der Wert FNull ist

fRes – rohes (mit korrektem Typ) Ergebnis aus dem Parsen des Basisfelds

fIndex – Index im übergeordneten Array (nur wenn das übergeordnete Element ein Array-Feld war)

fResJson – JSON-String-Darstellung des rohen Ergebnisses

fResRaw – Ergebnis im Byte-Format

fSrc – nur in condition/item_condition-Ausdrücken: der Quellknoten, aus dem der Wert aufgelöst wurde (geparster Wert für JSON – einschließlich Geschwister, Textinhalt für HTML). Nicht verfügbar in berechneten/formatierten/Notifier-Ausdrücken

FNewLine – Zeilenumbruch-Trennzeichen

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

Plugin-Feld

Feld kann ein externes Plugin für fitter sein

Mehr

type PluginFieldConfig struct {
	Name string `json:"name" yaml:"name"`
	Config json.RawMessage `json:"config" yaml:"config"`
}
  • Name – Name des Plugins (ohne Erweiterung, nur Name)

  • Config – JSON-Config des Plugins

Modell-Feld

Feldtyp, der im laufenden Betrieb durch ein neues Modell und Connector generiert werden kann

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 – welcher Connector verwendet werden soll. Wichtig: URL im Connector kann mit Einfügung des übergeordneten Werts als String verwendet werden

  • Model – Konfiguration des zugrunde liegenden Modells

  • Type – enum["null", "boolean", "string", "int", "int64", "float", "float64", "array", "object"] – Typ des generierten Felds

  • Path – falls wir keine Informationen aus dem generierten Feld extrahieren können, können wir einen JSON-Selektor zur Extraktion verwenden

  • Expression – String, der zur Nachbearbeitung des Modells verwendet werden kann (ignoriert das Path-Feld)

Beispiele:

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

Bietet die Generierung eines statischen (festen Länge) Arrays

type StaticArrayConfig struct {
    Items map[uint32]*Field `yaml:"items" json:"items"`
    Length uint32            `yaml:"length" json:"length"`
}
  • Items – map[uint32]*Field – Schlüssel ist der Index im Array, Wert ist die Felddefinition

  • Length – wenn gesetzt (1+), kann zur Definition einer benutzerdefinierten Array-Länge verwendet werden

Beispiele:

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

Platzhalterliste

  1. {PL} – zum Einfügen eines Werts

  2. {INDEX} – zum Einfügen des Index im übergeordneten Array

  3. {HUMAN_INDEX} – zum Einfügen des Index im übergeordneten Array auf menschliche Weise

  4. {{{json_path}}} – erhält Informationen aus dem weitergegebenen „object"/„array"-Feld

  5. {{{RefName=SomeName}}} – Referenz-Wert nach Name abrufen. Beispiel

  6. {{{RefName=SomeName json.path}}} – Referenz-Wert nach Name abrufen und Wert per JSON-Pfad extrahieren. Beispiel

  7. {{{FromEnv=ENV_KEY}}} – Wert aus einer Umgebungsvariable abrufen

  8. {{{FromExp=fRes + 5 + fIndex}}} – Wert aus dem Ausdruck abrufen. Vordefinierte Werte

  9. {{{FromInput=.}}} oder {{{FromInput=json.path}}} – Wert aus der Eingabe des Triggers oder der Bibliothek abrufen

  10. {{{FromFile=./test_file.log}}} – Wert aus einer Datei per Pfad abrufen. Der Dateiinhalt kann ebenfalls Platzhalter enthalten

  11. {{{FromURL=http://localhost:8081}}} – Antwort von einer URL abrufen

Beispiele:

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

Referenzen

Spezielle Map, die vorab abgerufen (vor jeder Verarbeitung) wird und für Connector oder Platzhalter verwendet werden kann

Kann verwendet werden für:

  1. JWT-Token cachen und in Headern verwenden

  2. Werte cachen

  3. usw.

Referenz

type Reference struct {
    *ModelField
    
    Expire *uint32 `yaml:"expire" json:"expire"`
}
  • ModelField – ist eine eingebettete Struktur, du kannst dieselben Felder verwenden

  • Expire[sec] – Dauer, nach der die Referenz nach dem Abrufen abläuft. Nicht gesetzt => für immer gecacht. Auf 0 gesetzt => jedes Mal neu abrufen. Auf n > 0 gesetzt => für n Sekunden gecacht

Für Fitter

type RefMap map[string]*Reference

type Config struct {
    // Other Config Fields

    Limits     *Limits `yaml:"limits" json:"limits"`
    References RefMap  `json:"references" yaml:"references"`
}

Für 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 – Objekt, in dem der Schlüssel der Referenzname ist (kann für Connector oder Platzhalter verwendet werden) und der Wert eine Referenz ist

  • Limits

Beispiel

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

Beispiel

Notifier

Optionale Pro-Element-Config item.notifier_config, die das Parse-Ergebnis nach der Verarbeitung irgendwohin überträgt. Das Ergebnis wird weiterhin wie gewohnt zurückgegeben (CLI/MCP-Ausgabe, Dienstprotokolle); der Notifier liefert es zusätzlich. Funktioniert in Fitter (Dienstmodus), Fitter_CLI und 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 - optionale expr-lang-Bedingung: nur benachrichtigen, wenn sie wahr ist. Das Parsing-Ergebnis ist verfügbar als fRes (geparster Wert), fResRaw (Rohbytes), fResJson (JSON-String), z. B. len(fResRaw) > 0

  • Force - auch benachrichtigen, wenn das Parsing mit einem Fehler abgeschlossen wurde

  • SendArrayByItem - wenn das Ergebnis ein Array ist, jedes Element als separate Benachrichtigung senden

  • Template - optionale Vorlage, die auf das Ergebnis angewendet wird, bevor es gesendet wird, Platzhalter erlaubt

  • Destination - genau eines von console, telegram_bot, http, redis, file

Destination-Konfigurationen:

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

Das file-Destination verwendet dasselbe FileStorageField wie der Dateifeldtyp.

Beispiel (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
      }
    }
  }
}

Grenzen

Stellt Begrenzungen bereit, um DDOS und hohe Speichernutzung zu verhindern.

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 - Begrenzung pro Hostname, Schlüssel ist der Host, Wert ist die Anzahl paralleler Anfragen (Verwendung für Server-Connector)

  • ChromiumInstance - Anzahl paralleler chromium-Instanzen

  • DockerContainers - Anzahl paralleler docker-Instanzen

  • PlaywrightInstance - Anzahl paralleler playwright-Instanzen

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