
Eclipse Feedforge
Converts a merchant's messy catalog into an agent-grade product feed with per-attribute provenance: every attribute records {value, source_field, rule_id, source_value} and verify_feed recomputes each byte-for-byte from the source rows and the documented deterministic rule set. LOCAL/fixture scope only — local engine over caller-supplied rows/CSV/JSON + bundled fixtures; deterministic transforms only, no LLM calls, no network calls; attributes no rule can produce are absent, never invented, and unmapped source fields are reported.
status: in-developmentclass: mcpTrust & ReceiptsCommerce Readiness
Vendor: Cyan Eclipse Technologies
What it does
- Novel mechanism — provenance-pointer attributes with byte-for-byte recompute (SPEC §1.1): every generated attribute carries {value, source_field, rule_id, source_value}, so any auditor can recompute why the feed claims what it claims — take the source row, apply the named rule (SPEC §3, machine-readable in rules.json, stable ids R01–R12) to source_value, and the result must equal value byte-for-byte; verify_feed does exactly this recompute over every attribute. Bench: independent recompute (written from SPEC §3/§4 + rules.json only, builder code never imported) reproduces the JSON fixture feed byte-for-byte — catalog cat_5820376e0fc71b86, feed feed_18337452aa65cc76, 9 entries, 85 attributes, every attribute with exactly the 4 provenance keys, rule_id present in rules.json with matching target, source_value byte-identical to the raw row; CSV fixture feed also deep-equals recompute; both feeds verify_feed → VERIFIED (P1 11/11).
- Absent-never-invented + unmapped honesty (P2 14/14): an attribute no rule can produce is ABSENT — never invented, never defaulted, never LLM-guessed. The crafted no-rule row (price "call for price in JPY", weight "heavy", stock "maybe", no category field, keyword-free title) yields exactly {id, title}; fixture WID-008 carries exactly {id, title, brand} and explain_attribute on each absent attribute returns ATTRIBUTE_ABSENT by name. A source field consumed by no rule is reported in unmapped_fields with occurrence count + row indices (all 4 fixture unmapped fields — Legacy Code, Supplier Notes, internal_code, warehouse_bin — plus crafted fields), and provenance never points at an unmapped field. The target attribute set is closed (11 attributes) — nothing outside it can appear. Tamper naming (P3 6/6): value edits, provenance-only edits (source_value $129.99→$999.99), provenance swapped between products, invented extra attributes, and attribute deletion + unmapped-report wipe all return MISMATCH naming product + attribute; determinism (P4 3/3): identical catalog/feed hashes across fresh processes for JSON + CSV inputs.
- Crash-proof supplied-feed path (v0.1.1 fix for bench defect D1, re-bench PASS): verify_feed's feed-object form — precisely the surface meant to receive untrusted feeds — now structurally validates supplied feeds (catalog_id non-empty string; entries a list of objects; attributes objects whose values are provenance objects; unmapped_fields a list) before recompute, with non-string id guards and dispatch-level inputSchema enforcement for all 5 tools plus last-resort exception guards in the handler and stdio loop. Re-bench: full suite 98/98 (P5 55/55) + expanded fuzz 156/156 on one persistent process with liveness after every vector (23 supplied-feed deep shapes, 80 wrong-type argument vectors across all 5 tools, raw protocol attacks) — every malformed input is a clean ToolError, no process death; tamper semantics preserved (missing entries/attributes/hash = MISMATCH, not validation errors). Explain sweep (P6 6/6): 99 explain_attribute calls (9 products × closed 11-attribute set) — every presented attribute is explainable and resolvable, every absent one ATTRIBUTE_ABSENT; no opaque-but-present attribute exists — the exact delta vs an LLM feed generator.
- Honest scope — LOCAL/fixture ONLY: the local engine ingests caller-supplied rows (JSON), csv_text, or json_text plus the bundled fixtures (messy_catalog.json 9 products in per-row field-name dialects; messy_catalog.csv 8 products under one messy header). Deterministic transforms only — NO LLM calls, NO network calls; Python 3 standard library only (csv, hashlib, io, json, os, re, decimal, sys — hygiene P7 3/3); MCP over stdio; exactly 5 tools (unknown names return NO_SUCH_TOOL); every response carries scope: "LOCAL/fixture". No payment, checkout, hosting, account, or API-key code exists — the $49/mo figure is pricing metadata in SPEC §6/README only (future hosted form). Informational bench notes (non-blocking): currency tokenization is a substring match (SPEC silent; engine + recompute agree on every documented/standard form); duplicate product ids are both kept, explain resolves to the first entry; ragged-CSV extra cells are discarded by DictReader (no field name to report).
Tools
ingest_catalog · list_rules · transform_feed · verify_feed · explain_attribute
Platforms
- MCP over stdio
Certification
Bench verdict: CERTIFIED (local, fixture)
Certified scope: CERTIFIED (local, fixture) — Verity independent re-bench 2026-10-26, REBENCH-1 of the v0.1.1 Bench Fix D1 round (repo @ 1e41e3f): full prior suite 98/98 PASS, 0 FAIL (P1 11/11 · P2 14/14 · P3 6/6 · P4 3/3 · P5 55/55 · P6 6/6 · P7 3/3), defects list empty, plus expanded wrong-type fuzz 156/156 PASS on one persistent server process with a liveness ping (list_rules → 12 rules) after every vector. D1 (HIGH — the verify_feed supplied-feed path performed no type validation; five malformed feed objects raised unhandled TypeError/AttributeError and killed the server process) CLOSED: the 5 original crash vectors (list/dict catalog_id; entries:[123]; entries:"abc"; attributes-as-string) all return clean ToolErrors with no process death, verified in the prior suite AND verbatim in the expanded fuzz (supplied-feed deep shapes 23 vectors; 8 wrong value types × every argument of all 5 tools = 80 vectors; raw protocol attacks — non-string tool names, non-dict arguments, malformed/truncated JSON lines — server keeps answering after each). Behavior preservation PASS: fixture transform seals to feed_18337452aa65cc76 (full hash 18337452aa65cc76eb57c986e0d8f3ff58f2d6b389a09cf16df9d33cee9e94a5) over catalog cat_5820376e0fc71b86 — exactly SPEC §4.1 — and deep-equals the bench's independent recompute (85 attributes, 9 entries; CSV fixture also deep-equals + VERIFIED); spot recompute of SHOE-001/price_cents, MUG-002/availability, BAG-009/category, LAP-003/weight_grams, TEE-004/category matches feed values + explain_attribute provenance; tamper semantics preserved 9/9 (missing entries/attributes/unmapped_fields/feed_hash and partial provenance records are MISMATCH, never validation errors; untampered copies by-object and by-feed_id VERIFIED). Prior verdict on v0.1.0 (VERDICT.md): CONDITIONAL (local, fixture), 93/98 — the novel mechanism itself passed without exception (byte-for-byte independent recompute of all 85 fixture attributes, provenance always resolving to the real raw source value, absent-never-invented, tamper naming on value AND provenance, determinism, complete 99-call explain sweep); the sole condition was the D1 fix + P5 re-bench, now closed. Informational carry-overs, non-blocking (unchanged from v0.1): currency tokenization is a substring match ("100 EURO" yields EUR; SPEC does not define tokenization — recommend SPEC v0.2 state the token rule explicitly); duplicate product ids are both kept and explain_attribute resolves a duplicated product_key to the first entry; ragged-CSV extra cells beyond the header are discarded by the csv.DictReader restkey path (no field name, nothing to report). Scope = LOCAL/fixture only: local engine over caller-supplied rows/CSV/JSON + bundled fixtures; deterministic transforms only — no LLM calls, no network calls; no live catalogs benched or implied; $49/mo is a pricing term for the future hosted form only — no payment/checkout/hosting code.
Not tested:
- Live merchant catalogs or marketplace/catalog API sync (Shopify etc.) — not in v0.1.1 by design (SPEC §7): local engine over caller-supplied rows/CSV/JSON + bundled fixtures only
- Hosted or remote serving — v0.1.1 is local stdio only; the $49/mo hosted bundle form is a future commercial shape, not a v0.1 feature, and no hosted service is live or sold in v0.1
- LLM or network calls of any kind — none exist in v0.1.1 by design: deterministic documented rules (R01–R12, rules.json) only; Python 3 standard library only
- Payment, checkout, hosting, accounts, or billing — none exists in v0.1.1 by design: the $49/mo figure is commercial metadata / a stated pricing term for the future hosted form only
- Feed publishing or submission to any platform (Google/UCP endpoints etc.) — none exists in v0.1.1; feeds are sealed locally and verified by recompute only
Live state note: Bench evidence: argus-batch-20261026/bench/feedforge/VERDICT.md + REBENCH-1.md (Verity, independent bench over stdio JSON-RPC only, never importing builder code; recompute.py written from SPEC §3/§4 + rules.json alone; builder suite 29/29). This bench issued no test-bench/results scorecard; scorecard_ref is null and no scorecard is claimed or hosted for this product.
Pricing
PRICED — $49/mo hosted bundle pattern, via the Eclipse Bazaar bench-order path only. No checkout, payment, or buy-now link exists for this product, and no hosted service is being sold as live in v0.1: v0.1.1 is the local engine and contains no payment, checkout, hosting, metering, or billing code (the price is a stated term for the future hosted form only). Repository is PRIVATE (priced-product policy).
Install / verify
No install command is published for this product in the catalog or its registry record.
Official MCP Registry name: io.github.CYAN-ECLIPSE-TECHNOLOGIES-LLC/eclipse-feedforge-mcp
Registry listing: https://registry.modelcontextprotocol.io/v0.1/servers/io.github.CYAN-ECLIPSE-TECHNOLOGIES-LLC%2Feclipse-feedforge-mcp/versions/0.1.1
Repository: https://github.com/CYAN-ECLIPSE-TECHNOLOGIES-LLC/eclipse-feedforge-mcp
Verify any MCP server in your client configs against this catalog with bazaar check (Eclipse Bazaar MCP / CLI — see llms.txt).