Six jobs.
One request, six schemas.
Nothing below needs a different product or a different endpoint. The only thing that changes between them is the shape you ask for — which is the point.
Competitive pricing sweeps
Twenty competitor pricing pages, twenty different layouts, one table at the end of it. Point a batch at the list weekly and diff the objects — the shape can't drift because the shape is yours.
{ "type": "object", "properties": { "plans": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "monthly": { "type": "number" }, "annual": { "type": "number" }, "seats": { "type": ["number", "null"] } }, "required": ["name", "monthly"] } } }, "required": ["plans"] }
Lead enrichment from a website
You have a domain and nothing else. Get the industry, the headcount band, the tech they mention, the contact address and whether they publish pricing — straight into the CRM shape you already use.
{ "type": "object", "properties": { "industry": { "type": "string" }, "employee_band": { "type": "string", "enum": ["1-10","11-50","51-200","201-1000","1000+"] }, "contact_email": { "type": ["string", "null"] }, "has_pricing_page": { "type": "boolean" } }, "required": ["industry"] }
Catalog and inventory sync
Supplier product pages become rows: SKU, title, price, currency, availability, image. Strict mode keeps a half-read page out of your catalog instead of writing a null price into it.
{ "type": "object", "properties": { "sku": { "type": "string" }, "title": { "type": "string" }, "price": { "type": "number", "minimum": 0 }, "currency": { "type": "string", "minLength": 3, "maxLength": 3 }, "in_stock": { "type": "boolean" }, "image_url": { "type": "string" } }, "required": ["sku", "title", "price", "currency"] }
Job-board monitoring
Which roles is a company hiring, where, at what band, and remote or not. Run the same schema across fifty careers pages and you have a hiring signal instead of fifty tabs.
{ "type": "object", "properties": { "roles": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string" }, "location": { "type": "string" }, "remote": { "type": "boolean" }, "salary_min": { "type": ["number", "null"] }, "apply_url": { "type": "string" } }, "required": ["title", "apply_url"] } } }, "required": ["roles"] }
Changelog and release tracking
Turn a vendor's release notes into versioned records with an added/fixed/changed split and a breaking flag, so a breaking change reaches your team as a row rather than as an outage.
{ "type": "object", "properties": { "releases": { "type": "array", "items": { "type": "object", "properties": { "version": { "type": "string" }, "date": { "type": "string" }, "breaking": { "type": "boolean" }, "added": { "type": "array", "items": { "type": "string" } } }, "required": ["version"] } } }, "required": ["releases"] }
A tool your agent can actually trust
An agent that scrapes gets a wall of markdown it has to re-read every turn. An agent with this gets the object it declared — and a valid flag telling it whether to proceed or ask for help. Over MCP it is one tool call.
// MCP · extract_structured { "url": "https://example.com/pricing", "schema": { "type": "object", "properties": { "price": { "type": "number" } }, "required": ["price"] }, "strict": true }
Worth knowing before you spend anything.
The extractor reads what a browser can reach without signing in. It is honest about the rest rather than returning a confident-looking empty object.
No session is carried, so a members-only page returns whatever the logged-out view shows. Not charged when that view is empty.
A field the page never states comes back in missing_fields, not invented. That is deliberate: a plausible guess would pass validation and be wrong.
Only the first stretch of a page is read. For a book-length doc, point the schema at the specific section's URL rather than the index.