@pipeworx/california-tax-appeals
Connect: https://pipeworx.io/mcp — every tool in the catalog, including @pipeworx/california-tax-appeals’s. Install: one-click buttons
Connect to just the @pipeworx/california-tax-appeals pack
https://gateway.pipeworx.io/california-tax-appeals/mcp — only @pipeworx/california-tax-appeals’s own tools, nothing else in the catalog.
No MCP client? Skip the connection: POST https://gateway.pipeworx.io/v1/tools/search_packs {"query":"..."} to find a tool below, GET /v1/tools/<name> for its schema, POST the same URL with arguments for the data — see For AI agents.
Tools: 2
California Office of Tax Appeals (OTA) opinions — search by statute citation or topic across 4,254 issued opinions (precedential and nonprecedential, 2018–2026), or retrieve one specific opinion’s full text and cited provisions by its OTA citation.
Tools
ca_ota_search(query, category?, precedential_only?, limit?)— find opinions by topic keyword (e.g. “residency”, “innocent spouse”) or statute citation (e.g. “17014”). Returns citation, title, date, tax category (Franchise/Income Tax vs Business Tax), precedential status, and OTA’s own one-line “Issues” tag, most recent first. Searches listing metadata only (title + Issues tag) — OTA publishes no full-text search.ca_ota_opinion_lookup(cite)— fetch one opinion by its OTA citation (e.g. “2020-OTA-263P”), live. Returns the full opinion text, exact date issued, OTA’s internal case number, tax category, precedential status, and statute citations found in the text (best-effort R&TC/Cal. Code Regs./IRC).
Auth
Keyless. No signup — this is a read of OTA’s own published, public opinions.
Data sources
- https://ota.ca.gov/opinions/ — the landing page this pack’s bake script
(
scripts/bake-index.mjs) scrapes to discover every per-year and all-precedential opinion listing page. - Per-year listing pages, e.g. https://ota.ca.gov/2024-franchise-income-tax-opinions/ and https://ota.ca.gov/2024-business-tax-opinions/ — every opinion issued that year/category, precedential and nonprecedential alike.
- All-years precedential pages, e.g. https://ota.ca.gov/all-precedential-franchise-and-income-tax-opinions/ — fetched too, to cover any year a per-year page might omit.
- Individual opinion PDFs (e.g.
https://ota.ca.gov/wp-content/uploads/sites/54/2021/06/19064883_Mazer_Opinion_Revised_090420_P.pdf) — fetched live perca_ota_opinion_lookupcall, text extracted withshared/src/pdf-text.ts.
Shape and known limits
ota.ca.gov (WordPress/WP Engine, TablePress tables) has no JSON search
backend — every opinion-listing page renders its whole table as static
HTML; the DataTables plugin paginates it client-side only (confirmed live:
every DataTable('#tablepress-NNN', {...}) init call on these pages carries
no ajax/serverSide option). So this pack bakes a citation-indexed table
from OTA’s own listing pages rather than proxying a search endpoint — see
scripts/bake-index.mjs’s own header for exactly which pages it fetches and
how it discovers new years without a code change.
Per root CLAUDE.md’s standing rule on baked data (fleet #2754), the index
(4,254 rows, ~1.6MB) lives in KV, never gateway module scope — uploaded by
scripts/sync-gateway-static-json.mjs and injected as args._bakedIndex
(registered in workers/gateway/src/pack-baked-indexes.json).
ca_ota_search searches listing metadata only — the opinion title and
OTA’s own one-line “Issues” tag (e.g. “Residency (R&TC 17014; Reg. 17014)”).
A statute cited only in an opinion’s full body text, and not in its Issues
tag, will not be found by search; use ca_ota_opinion_lookup on a specific
citation to read that opinion’s full text.
“Case number” = OTA’s own citation (e.g. “2020-OTA-263P”, the trailing “P”
marking Precedential status) — what OTA itself cites opinions by, not the
PDF’s internal 8-digit “OTA Case No.” docket number (which only appears
inside the PDF body and is surfaced in ca_ota_opinion_lookup’s response as
ota_case_no, read live, not indexed). The trailing precedential marker may
be omitted when looking up a citation; ca_ota_opinion_lookup tries both
forms before reporting a miss. Some opinions carry other OTA suffix letters
(e.g. ”…SCP” for a Summary Conclusion of Proceedings) — those must be
typed exactly.
A transport failure (non-200) or a listing/PDF mismatch (a 404 for a
citation the index says has a PDF) throws loudly naming the upstream status
— never a silent found: false. A PDF that exists but fails to extract
(rare; e.g. a scanned, non-text PDF) degrades to full_text: null with a
warning rather than throwing, since the opinion’s metadata (title, date,
decision type, Issues tag) is still valid from the listing page.
Re-run node scripts/bake-index.mjs > src/ca-ota-index-data.ts periodically
to pick up newly issued opinions — it refuses to write a suspiciously small
index (fewer than 2,000 opinions or fewer than 15 listing pages fetched),
so a silent partial bake from an OTA markup change is caught rather than
shipped.
Tools
- ca_ota_search — Find California Office of Tax Appeals (OTA) opinions by statute citation or topic keyword (e.g. “residency”, “innocent spouse”, “17014”, “17951-4”) — returns citation, title, date, tax category (Fran
- ca_ota_opinion_lookup — Look up a California Office of Tax Appeals opinion by its OTA citation (e.g. “2020-OTA-263P” for a Precedential opinion, “2020-OTA-374” for a Nonprecedential one) — fetches the opinion PDF live and r
Tools
ca_ota_opinion_lookup— Look up a California Office of Tax Appeals opinion by its OTA citation (e.g. 2020-OTA-263P for a Precedential opinion, 2020-OTA-374 for a Nonprecedential one) -- fetches the opinion PDF live and returca_ota_search— Find California Office of Tax Appeals (OTA) opinions by statute citation or topic keyword (e.g. residency , innocent spouse , 17014 , 17951-4 ) -- returns citation, title, date, tax category (Franchis