{"serverId":"mcp-registry/com.formulasignal/record","tools":[{"name":"ingredients.regulatory","fixed":{"name":"ingredients_regulatory","description":"Return regulatory records and documented cautions for named ingredients, each carrying the class of record it actually is.\n\nWhen to use: Use when you need to know what filings, advisories, label warnings, interactions, or enforcement actions FormulaSignal holds for an ingredient.\n\nWhat it cannot provide: A regulatory filing is never returned as an approval, a warning, or a finding of harm. Nothing here is medical clearance.\n\nLimits: Pass ingredient_ids (at most 5) or one product_id, not both. Yo","inputSchema":{"type":"object","required":[],"properties":{"product_id":{"type":"string","description":"A canonical product id, to read the ingredients that product declares. Pass this or ingredient_ids, not both."},"ingredient_ids":{"type":"array","items":{"type":"string","maxLength":120},"maxItems":5,"minItems":1,"description":"Up to five canonical ingredient ids. Pass these or product_id, not both."}},"additionalProperties":false},"annotations":{"title":"Get regulatory context","readOnlyHint":true,"openWorldHint":false,"idempotentHint":true},"title":"Get regulatory context"},"changes":[{"kind":"name","detail":"Renamed \"ingredients.regulatory\" → \"ingredients_regulatory\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":277,"tokensAfter":277},{"name":"ingredients.research","fixed":{"name":"ingredients_research","description":"Return the dose range used in the selected evidence set for named ingredients, with the citation and its limitations.\n\nWhen to use: Use to place a declared amount against published work. Pass ingredient ids, or a product_id to read the ingredients that product declares.\n\nWhat it cannot provide: A dose comparison is not evidence of effectiveness, safety, or suitability for any person, and the response says so on every record.\n\nLimits: Pass ingredient_ids (at most 5) or one product_id, not both. Y","inputSchema":{"type":"object","required":[],"properties":{"product_id":{"type":"string","description":"A canonical product id, to read the ingredients that product declares. Pass this or ingredient_ids, not both."},"ingredient_ids":{"type":"array","items":{"type":"string","maxLength":120},"maxItems":5,"minItems":1,"description":"Up to five canonical ingredient ids. Pass these or product_id, not both."}},"additionalProperties":false},"annotations":{"title":"Get research context","readOnlyHint":true,"openWorldHint":false,"idempotentHint":true},"title":"Get research context"},"changes":[{"kind":"name","detail":"Renamed \"ingredients.research\" → \"ingredients_research\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":276,"tokensAfter":276},{"name":"ledger.get","fixed":{"name":"ledger_get","description":"Return one Category Ledger edition: the executive summary, confirmed changes released in the period, category benchmarks with their cohorts, serving economics, the product comparison, and the limitations.\n\nWhen to use: Use when an agent needs the month's category intelligence with every denominator attached, or needs to cite a figure a customer is reading on the web edition.\n\nWhat it cannot provide: It never returns an unreviewed candidate, a Signal the publication gate refuses, a preserved-sour","inputSchema":{"type":"object","required":["edition_id"],"properties":{"edition_id":{"type":"string","description":"A Category Ledger edition id, as returned by ledger.list."}},"additionalProperties":false},"annotations":{"title":"Get ledger edition","readOnlyHint":true,"openWorldHint":false,"idempotentHint":true},"title":"Get ledger edition"},"changes":[{"kind":"name","detail":"Renamed \"ledger.get\" → \"ledger_get\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":209,"tokensAfter":209},{"name":"ledger.list","fixed":{"name":"ledger_list","description":"List the published Category Ledger editions: period, status, data-as-of date and the count released in each.\n\nWhen to use: Call this first to find which edition covers a period, then fetch that edition by id.\n\nWhat it cannot provide: It returns no figures from inside an edition and no product data. A closed edition's identity never changes, so this list is safe to cache.\n\nLimits: Identities only. A frozen edition never changes, so its listing and its content are both safe to cache; an in-progres","inputSchema":{"type":"object","required":[],"properties":{},"additionalProperties":false},"annotations":{"title":"List ledger editions","readOnlyHint":true,"openWorldHint":false,"idempotentHint":true},"title":"List ledger editions"},"changes":[{"kind":"name","detail":"Renamed \"ledger.list\" → \"ledger_list\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":177,"tokensAfter":177},{"name":"products.compare","fixed":{"name":"products_compare","description":"Compare two or three covered products on consistent FormulaSignal criteria.\n\nWhen to use: Use when a user asks how covered products differ on formula, serving economics, stimulant load, or record depth.\n\nWhat it cannot provide: It returns no overall winner and no suitability judgement. A product whose depth is REGISTERED is refused rather than compared, because a guessed label beside a measured one implies a precision the Record does not have.\n\nLimits: At most 3 products per call, and every prod","inputSchema":{"type":"object","required":["product_ids"],"properties":{"product_ids":{"type":"array","items":{"type":"string","maxLength":120},"maxItems":3,"minItems":2,"description":"Two or three canonical product ids to compare. Resolve names with products.resolve first."}},"additionalProperties":false},"annotations":{"title":"Compare products","readOnlyHint":true,"openWorldHint":false,"idempotentHint":true},"title":"Compare products"},"changes":[{"kind":"name","detail":"Renamed \"products.compare\" → \"products_compare\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":239,"tokensAfter":239},{"name":"products.get","fixed":{"name":"products_get","description":"Return the controlled current Record for one covered product: identity, serving configuration, declared ingredients, captured price context, and freshness.\n\nWhen to use: Use when you need what a product declares right now, with the dates and limitations attached.\n\nWhat it cannot provide: It returns no preserved source bytes, no internal capture identifiers, no review notes, and no verdict about whether the product is good or suitable.\n\nLimits: Your plan has a daily limit on how many distinct pro","inputSchema":{"type":"object","required":["product_id"],"properties":{"product_id":{"type":"string","description":"A canonical FormulaSignal product id, such as the product_id returned by products.resolve. Not a display name."}},"additionalProperties":false},"annotations":{"title":"Get product record","readOnlyHint":true,"openWorldHint":false,"idempotentHint":true},"title":"Get product record"},"changes":[{"kind":"name","detail":"Renamed \"products.get\" → \"products_get\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":224,"tokensAfter":224},{"name":"products.history","fixed":{"name":"products_history","description":"Return the controlled historical timeline for one covered product, with each state classified by what it can actually support.\n\nWhen to use: Use to find out whether a product has changed, how deep the recoverable history is, and which states are comparable to each other.\n\nWhat it cannot provide: It never presents an observation window as an exact reformulation date, and it never reports an unreviewed candidate as a confirmed change.\n\nLimits: Your plan has a daily limit on how many distinct produ","inputSchema":{"type":"object","required":["product_id"],"properties":{"product_id":{"type":"string","description":"A canonical FormulaSignal product id, such as the product_id returned by products.resolve. Not a display name."}},"additionalProperties":false},"annotations":{"title":"Get formula history","readOnlyHint":true,"openWorldHint":false,"idempotentHint":true},"title":"Get formula history"},"changes":[{"kind":"name","detail":"Renamed \"products.history\" → \"products_history\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":225,"tokensAfter":225},{"name":"products.resolve","fixed":{"name":"products_resolve","description":"Resolve a brand, product name, or alias to one canonical covered product.\n\nWhen to use: Call this first whenever you hold a user-supplied product name and need the canonical product_id every other capability takes.\n\nWhat it cannot provide: It never guesses. An ambiguous or generic name returns the candidate list and no match, and an uncovered product returns no match at all.\n\nLimits: Your plan has a daily limit on how many distinct products, Signals and ingredients you may read. Repeating a ques","inputSchema":{"type":"object","required":["identifier"],"properties":{"identifier":{"type":"string","maxLength":120,"description":"A brand, product name or alias as the user wrote it, for example \"C4 Original\"."}},"additionalProperties":false},"annotations":{"title":"Resolve product","readOnlyHint":true,"openWorldHint":false,"idempotentHint":true},"title":"Resolve product"},"changes":[{"kind":"name","detail":"Renamed \"products.resolve\" → \"products_resolve\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":222,"tokensAfter":222},{"name":"products.serving_economics","fixed":{"name":"products_serving_economics","description":"Return the captured commercial facts and the deterministic price arithmetic for one covered product.\n\nWhen to use: Use for package price, price basis, serving count, price per serving, and the date each was observed.\n\nWhat it cannot provide: It never calls an observed price a list price unless the Record recorded it as one, and it never reports a promotional-versus-list difference as a price change.\n\nLimits: Your plan has a daily limit on how many distinct products, Signals and ingredients you m","inputSchema":{"type":"object","required":["product_id"],"properties":{"product_id":{"type":"string","description":"A canonical FormulaSignal product id, such as the product_id returned by products.resolve. Not a display name."}},"additionalProperties":false},"annotations":{"title":"Get serving economics","readOnlyHint":true,"openWorldHint":false,"idempotentHint":true},"title":"Get serving economics"},"changes":[{"kind":"name","detail":"Renamed \"products.serving_economics\" → \"products_serving_economics\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":228,"tokensAfter":228},{"name":"record.search","fixed":{"name":"record_search","description":"Answer one specific, bounded question from FormulaSignal's covered pre-workout Record.\n\nWhen to use: Use for a single natural-language question about a covered product: what it declares now, whether it changed, what it costs per serving, or which covered products meet one stated numeric condition.\n\nWhat it cannot provide: It cannot list the database, export products, answer medical or suitability questions, or answer about a product FormulaSignal does not cover.\n\nLimits: One question, at most 30","inputSchema":{"type":"object","required":["query"],"properties":{"query":{"type":"string","maxLength":300,"description":"One plain-language question about covered pre-workout products, for example \"How much caffeine is in C4 Original?\". Ask once; rewording the same question returns the same answer and costs quota."}},"additionalProperties":false},"annotations":{"title":"Search record","readOnlyHint":true,"openWorldHint":false,"idempotentHint":true},"title":"Search record"},"changes":[{"kind":"name","detail":"Renamed \"record.search\" → \"record_search\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":250,"tokensAfter":250},{"name":"record.version","fixed":{"name":"record_version","description":"Return the public Record version, the methodology version, the supported category, coverage counts, and source freshness.\n\nWhen to use: Call this to state which version of FormulaSignal intelligence an answer came from, or to detect that coverage has moved.\n\nWhat it cannot provide: It exposes no implementation detail, no internal scoring, and no proprietary methodology text.\n\nLimits: Your plan has a daily limit on how many distinct products, Signals and ingredients you may read. Repeating a ques","inputSchema":{"type":"object","required":[],"properties":{},"additionalProperties":false},"annotations":{"title":"Get record version","readOnlyHint":true,"openWorldHint":false,"idempotentHint":true},"title":"Get record version"},"changes":[{"kind":"name","detail":"Renamed \"record.version\" → \"record_version\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":178,"tokensAfter":178},{"name":"signals.explain","fixed":{"name":"signals_explain","description":"Explain one approved FormulaSignal Signal: a confirmed, reviewed change between two comparable product states.\n\nWhen to use: Use when a product record or history response named a signal_id and you need the before state, the after state, the observation window, and the evidence.\n\nWhat it cannot provide: It has no access to unreviewed candidates, review deliberation, or the internal review queue. A signal_id that is not approved returns not found.\n\nLimits: Your plan has a daily limit on how many d","inputSchema":{"type":"object","required":["signal_id"],"properties":{"signal_id":{"type":"string","description":"A Signal id, as named by a product record, a formula history, or signals.list."}},"additionalProperties":false},"annotations":{"title":"Explain signal","readOnlyHint":true,"openWorldHint":false,"idempotentHint":true},"title":"Explain signal"},"changes":[{"kind":"name","detail":"Renamed \"signals.explain\" → \"signals_explain\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":216,"tokensAfter":216},{"name":"signals.list","fixed":{"name":"signals_list","description":"Return approved FormulaSignal Signals in release order, newest first, for incremental polling.\n\nWhen to use: Use to keep a system in step with the Record. Pass `since` with the release date you last saw, or follow `next_cursor`, and filter by product, brand, dimension or category.\n\nWhat it cannot provide: It returns no unreviewed candidate and no change event that fails the publication gate, and it is not an export of the product table.\n\nLimits: At most 25 Signals per page, newest release first.","inputSchema":{"type":"object","required":[],"properties":{"brand":{"type":"string","description":"Only Signals for this brand, matched on the full brand name, case-insensitive."},"limit":{"type":"integer","maximum":25,"minimum":1,"description":"Signals per page, 1 to 25. Defaults to the plan's page size."},"since":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Only Signals released on or after this date, YYYY-MM-DD. Pass the newest release date you have already seen to poll for what is new."},"until":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Only Signals released on or before this date, YYYY-MM-DD."},"cursor":{"type":"string","description":"The next_cursor value from the previous page. Omit it for the first page."},"category":{"type":"string","description":"Only Signals whose change category matches this value, case-insensitive, as shown in a Signal's change.category field."},"dimension":{"type":"string","description":"Only Signals of this kind of change: FORMULA, FORMULA_DOSE, SERVING, PRICE, CLAIMS, CERTIFICATION, LIFECYCLE or OTHER."},"product_id":{"type":"string","description":"Only Signals for this canonical product id."}},"additionalProperties":false},"annotations":{"title":"List signal changes","readOnlyHint":true,"openWorldHint":false,"idempotentHint":true},"title":"List signal changes"},"changes":[{"kind":"name","detail":"Renamed \"signals.list\" → \"signals_list\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":492,"tokensAfter":492},{"name":"signals.snapshot","fixed":{"name":"signals_snapshot","description":"Return a bounded summary of approved Signals and coverage state across the covered pre-workout set for a date window.\n\nWhen to use: Use for 'what changed in the category recently'. Pass from and to dates; the window is capped and the page size is capped.\n\nWhat it cannot provide: It is not an export. It returns approved Signals inside one bounded window, never the product table and never the underlying Record.\n\nLimits: Bounded window of at most 400 days and at most 25 items per page. Follow next_","inputSchema":{"type":"object","required":[],"properties":{"to":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"End of the window, YYYY-MM-DD. Defaults to today (UTC)."},"from":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Start of the window, YYYY-MM-DD. Defaults to the widest window the plan allows before `to`."},"limit":{"type":"integer","maximum":25,"minimum":1,"description":"Signals per page, 1 to 25. Defaults to the plan's page size."},"cursor":{"type":"string","description":"The next_cursor value from the previous page. Omit it for the first page."}},"additionalProperties":false},"annotations":{"title":"Get category snapshot","readOnlyHint":true,"openWorldHint":false,"idempotentHint":true},"title":"Get category snapshot"},"changes":[{"kind":"name","detail":"Renamed \"signals.snapshot\" → \"signals_snapshot\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":329,"tokensAfter":329},{"name":"watchlist.add","fixed":{"name":"watchlist_add","description":"Add one covered product to the bound account's watchlist.\n\nWhen to use: Use when a person asks to start watching a product. Resolve the product first if you were given a name rather than an id.\n\nWhat it cannot provide: It cannot add a product outside the covered set, exceed the account's watch limit, or act on an account this key is not bound to. It refuses a covered product FormulaSignal cannot monitor yet and says why in the refusal. It does not start a subscription and refuses when the accoun","inputSchema":{"type":"object","required":["product_id"],"properties":{"product_id":{"type":"string","maxLength":120,"description":"The canonical product id to start watching. Resolve a name with products.resolve first."}},"additionalProperties":false},"annotations":{"title":"Watch product","readOnlyHint":false,"openWorldHint":false,"idempotentHint":true,"destructiveHint":false},"title":"Watch product"},"changes":[{"kind":"name","detail":"Renamed \"watchlist.add\" → \"watchlist_add\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":222,"tokensAfter":222},{"name":"watchlist.list","fixed":{"name":"watchlist_list","description":"Return the watchlist of the one Founding Pro account this key is bound to, with each product's monitoring state.\n\nWhen to use: Use to answer what a person is watching, when each product was last read, when the next check is due, and whether anything is currently unreadable.\n\nWhat it cannot provide: It reaches exactly one account, the one bound to this key, and no other. It returns no candidate detail, no source URL and no internal identifier, and it is not a way to read the covered set.\n\nLimits:","inputSchema":{"type":"object","required":[],"properties":{},"additionalProperties":false},"annotations":{"title":"List watched products","readOnlyHint":true,"openWorldHint":false,"idempotentHint":true},"title":"List watched products"},"changes":[{"kind":"name","detail":"Renamed \"watchlist.list\" → \"watchlist_list\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":178,"tokensAfter":178},{"name":"watchlist.receipt","fixed":{"name":"watchlist_receipt","description":"Return the monitoring receipt for one period: valid checks, attempts that returned nothing, recoveries, and confirmed Signals.\n\nWhen to use: Use to answer whether anything a person watches changed in a period, and what monitoring did in the period whether or not anything did.\n\nWhat it cannot provide: A count of valid checks is not a claim that a product held still. It reports no candidate, no source URL and no internal identifier, and a period the monitoring ledger does not reach is reported as ","inputSchema":{"type":"object","required":[],"properties":{"period":{"type":"string","maxLength":7,"description":"A calendar month, YYYY-MM. Defaults to the current month (UTC)."}},"additionalProperties":false},"annotations":{"title":"Get watch receipt","readOnlyHint":true,"openWorldHint":false,"idempotentHint":true},"title":"Get watch receipt"},"changes":[{"kind":"name","detail":"Renamed \"watchlist.receipt\" → \"watchlist_receipt\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":212,"tokensAfter":212},{"name":"watchlist.remove","fixed":{"name":"watchlist_remove","description":"Remove one product from the bound account's watchlist.\n\nWhen to use: Use when a person asks to stop watching a product. Future alerts stop; everything already delivered stays.\n\nWhat it cannot provide: It cannot delete an account, cancel a subscription, or remove history. Removing a watch never removes what was already sent.\n\nLimits: Your plan has a daily limit on how many distinct products, Signals and ingredients you may read. Repeating a question about the same product costs nothing extra; rea","inputSchema":{"type":"object","required":["product_id"],"properties":{"product_id":{"type":"string","maxLength":120,"description":"The canonical product id to stop watching."}},"additionalProperties":false},"annotations":{"title":"Unwatch product","readOnlyHint":false,"openWorldHint":false,"idempotentHint":true,"destructiveHint":true},"title":"Unwatch product"},"changes":[{"kind":"name","detail":"Renamed \"watchlist.remove\" → \"watchlist_remove\" (letters, digits, _ and - only; max 64). Keep the old name as an alias for a release if clients already call it.","verify":true}],"tokensBefore":211,"tokensAfter":211}],"toolsChanged":18,"tokensSaved":0,"todo":[],"note":"Deterministic fixes. Changes marked verify need a human look before shipping (renames, inferred annotations, inferred types, removed text). Parameter descriptions in `todo` need to be written by someone who knows the API."}