Skip to main content
Glama

Agentic Fabrication Network (AFN)

Server Details

Turn designs into shipped parts: quote 3D printing, CNC, and decals, then check out.

If you are the author of this connector, you can claim ownership with GitHub, an HTTP challenge, or a DNS record. Claimed connector authors can inspect health checks, view analytics, and manage their listing.
Status
Healthy
Uptime
97.5% over 38 days
Last Tested
Transport
Streamable HTTP · MCP 2025-11-25
URL

TDQS

A4.3/5.0

Scored across 13 tools

Disambiguation4/5

Most tools map clearly to distinct resources and actions, but the quote-lifecycle cluster (get_fabrication_quote, finalize_quote, poll_quote, preview_quote, refine_quote) is dense and relies on long descriptions to avoid mis-selection. The guardrails are helpful, but the tool set requires careful reading.

Naming Consistency5/5

Tool names are uniformly lowercase snake_case and almost all follow a verb_noun pattern: get_fabrication_quote, create_checkout, list_orders, refine_quote, leave_review. The only slight deviation, reply_to_maker, still reads naturally and does not introduce naming noise.

Tool Count5/5

13 tools is well within the ideal range, and the breadth fits the domain: capabilities, materials, quoting, refining, checkout, order tracking, and review. The internal-only tools add some surface, but the overall set still feels appropriately scoped.

Completeness4/5

The quote-to-checkout-to-status-to-review lifecycle is well covered, along with supporting material and capability queries. The main missing pieces are post-order management operations like cancellation or updates after checkout, which could leave an agent with a small but plausible dead end.

Available Tools

13 tools
create_checkoutCreate checkoutAInspect

Create the order and get a hosted payment link for a chosen offer. Call this as soon as the user picks an offer + shipping speed — do NOT ask for their address first: the secure payment page collects the shipping address and email. Only pass address fields if the user already volunteered them. Returns checkout_url — give it to the user to pay; UFP places the vendor order automatically after payment.

ParametersJSON Schema
NameRequiredDescriptionDefault
zipNo
cityNo
nameNoRecipient full name (only if the user provided it)
emailNoBuyer email (only if the user provided it)
phoneNo
stateNoTwo-letter US state
street1NoStreet address (only if the user provided it)
street2No
offer_idYes
return_urlNoExact URL of the page the user is on right now, IF the client application knows it (a web app embedding this tool passes its own page URL). The post-payment page shows a 'Return to <site>' button pointing here. Omit when unknown — never invent one.
billing_zipNo
coupon_codeNoCoupon code, only if the user provided one (early-adopter codes from the AFN team). Case-insensitive. The discount appears on the payment page; a 100%-off code makes the total $0 with no card required. Never invent or guess a code.
billing_cityNo
billing_nameNoBilling address, only when the buyer answered the billing question (e.g. said it differs from shipping, or a checkout UI's 'same as shipping' checkbox — then send the shipping values verbatim). Never ask for it; omit and the payment page handles billing.
billing_stateNoTwo-letter US state
billing_street1No
billing_street2No
shipping_option_idYesOne of the offer's shipping option ids

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It states that the secure payment page collects the shipping address/email, that the tool returns a checkout_url, and that UFP places the vendor order automatically after payment — a clear side-effect disclosure for a mutation tool. It could mention auth/error cases, but the core behaviors are transparent and complete.

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?

Five sentences, no wasted words. The core purpose and timing are front-loaded, followed by the address caveat, the return value, and the post-payment behavior. Every sentence earns its place and the structure is easy to scan for an 18-parameter tool.

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 complex 18-param tool with no output schema, the description ties the workflow together: when to call, what to pass, what comes back (checkout_url), and what happens after payment. It lacks a detailed shape of the response beyond the URL, but the essential integration logic an agent needs is all present. Nearly complete.

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 50%, so the description must compensate for the uncovered half. It adds valuable guidance on the address-field philosophy ('Only pass address fields if the user already volunteered them') and implicit rules for return_url ('never invent one'). The schema itself documents the other half (name, email, coupon_code, billing_name, shipping_option_id). The description complements rather than fully compensates for the coverage gap, leaving some params (zip, city, phone, street1) to inference.

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 opens with a specific verb + resource + outcome: 'Create the order and get a hosted payment link for a chosen offer.' It clearly distinguishes from siblings like get_order_status, list_orders, and leave_review, none of which create a checkout or issue a payment link. An agent can immediately tell what this tool does and when it applies.

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?

Explicit timing guidance is given: 'Call this as soon as the user picks an offer + shipping speed — do NOT ask for their address first.' It also states when to pass address fields ('only if the user already volunteered them'). It would earn a 5 by naming an alternative tool to use instead under certain conditions, but the workflow context it provides is concrete and actionable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

finalize_quoteFinalize quote (wait for remaining vendors)AInspect

ONLY for the case where a quote response came back with an EMPTY board and told you to call this: waits for the vendors to answer (up to ~40s) and returns their offers as a full board. Call with just quote_id, immediately, and say nothing substantive before it. NEVER call it on a response that already listed offers — that board is final, and this would add nothing.

ParametersJSON Schema
NameRequiredDescriptionDefault
quote_idYesQuote id from the still-quoting response

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries full burden and meets it: discloses a ~40s blocking behavior, the need for immediate invocation, and the lack of added value if board is already populated. It also implies the tool is safe to call without side effects, though not explicitly stating read-only.

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 dense sentences, each essential: condition+action, execution instructions, and a critical exclusion. Information is front-loaded with the primary purpose and constraint. No filler or repetition.

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 explains the return value ('full board of offers'), the expected wait time, and the exact preconditions. It is sufficiently complete for a single-parameter tool with clear behavior, and it positions itself against sibling tools without needing further context.

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?

The schema already provides 100% coverage with 'Quote id from the still-quoting response', so the baseline is 3. The description adds no substantive parameter meaning beyond reinforcing 'just quote_id' and 'immediately', which are usage directives rather than semantic details.

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 uses a specific verb ('waits for... and returns') and clearly identifies the resource ('vendors' offers') and the trigger (empty board response). It sharply distinguishes from siblings by specifying the exact condition under which this tool is used, unlike generic 'finalize' naming.

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 (only after an empty board response and told to call it), how to use (call immediately, with just quote_id, say nothing substantive), and when NOT to use (never on a response that already listed offers). This provides clear decision-making rules and practical timing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_fabrication_quoteGet fabrication quoteAInspect

Get ranked, purchasable offers (price, ETA, preview image) for fabricating a physical item from a design file. process=fdm_print for 3D printing a model (STL/OBJ/PLY/3MF/AMF/STEP/IGES), process=cnc or process=sheetmetal for machined/bent metal parts (STEP, IGES, DXF), process=decal for stickers/decals from artwork (any common image or design file — PNG/JPG/HEIC/TIFF/GIF/BMP/WEBP/AVIF/SVG/PDF/AI/EPS/PSD/CDR, auto-converted). A .ufp file (UFP part container: the design plus saved spec/constraints in one) is accepted anywhere a design file is — its saved intent applies automatically and anything the user states now wins. If the user just drops a file and asks for a price, omit process — UFP routes it. Provide the design either as design_file (an image/file the user attached or you generated — preferred) or file_url (a public URL). REORDERS: if the user has a UFP part number (from a receipt email or a previous session, looks like UFP-… or part_…), pass it as part_number INSTEAD of any file — the stored design and spec are reused and re-shopped across all current vendors. Locked parts additionally require share_key (from the owner's share link). Returns offers across vendors like Google Flights returns flights.

ParametersJSON Schema
NameRequiredDescriptionDefault
cutNoDecal cut style — pass the user's words verbatim ("triangle", "die cut", "circle"). Known: contour|square|oval|kiss_cut; anything else gets closest-match offers with a substitution note. Omit to compare the main options
sizeNoPrint size — pass the user's words verbatim ("letter", "24x36", "half letter"). Cards are 3.5x2; flyers 8.5x5.5|8.5x11|11x17; posters 12x18 through 36x48. Unknown sizes get closest-match offers
bendsNoSheet-metal bend lines, each as TWO POINTS in the part's own mm frame (flat DXF parts use z=0: a bend from (0,12.7) to (76.2,12.7) is p1 [0,12.7,0], p2 [76.2,12.7,0]). angle_deg is the target bend angle (90 = a right-angle flange), direction "up"/"down" is the fold direction relative to the flat pattern, radius_mm the requested inside radius (omit it — the shop resolves to its tooling and reports what it used). Pass these when the user articulates WHERE the bends go; a bare "it has 2 bends" is bend_count, not this.
colorNoONLY a color the user actually asked for — NEVER pick one for them. fdm_print: Filament color for fdm_print (e.g. black, red); resin_print: Resin color for resin_print (e.g. gray, white, black); powder_print: Powder part color: raw gray/white, or a dye ("black", "dark blue") — vendor-resolved; elastomer_print: Elastomer part color — VCJ parts ship raw; asks resolve with an honest substitution note; cnc: Colour for cnc: with finish anodized it is the anodize colour, otherwise the stock's own colour (black Delrin, clear acrylic). Colour WORDS only; each maker resolves the shade and says what it landed on; laser_cut: Colour of the flat stock for laser_cut (black, clear, natural…). Colour WORDS only; each maker quotes the materials it stocks in that colour and drops the ones that cannot be it; print: Print color ask ("full color", "black and white"). Vendors that only price full color note the substitution; apparel: Garment color for apparel ("black", "heather gray") — vendor-resolved
paperNoPaper stock — free-form ("matte", "glossy", "recycled", "14pt"). Resolved to the closest stock the vendor runs
sidesNosingle|double sided printing (defaults: cards double, flyers/posters single)
unitsNosheetmetal: DXF drawing units: "mm" (default) or "in". STEP files carry their own units; laser_cut: DXF drawing units: "mm" (default) or "in"
finishNocnc: CNC surface finish: standard|anodized|polished|bead_blasted (default standard); sheetmetal: as_cut (default) | deburred | anodized | powder_coat — anodized is aluminum-only; powder coat protects mild steel for outdoor use
insertsNoPEM-style hardware inserts pressed into holes of a sheet-metal part — one record per hole. `insert` is the species (nut | flush_nut | standoff | blind_standoff | stud) and `thread` its size ("M4", "1/4-20"); both are required. When known, add length_mm (standoff/stud post length), the hole's center (located_at_mm, part's own mm frame), its axis, the drilled diameter, and `points` — the signed unit vector the insert's functional side faces (flip = negate). Pass these when the user asks for press-in nuts/standoffs/studs; vendors with a hardware service price them.
processNoWhat to fabricate. If the user just drops a file and asks for a price, OMIT this — UFP detects the file type (artwork, mesh — STL/OBJ/PLY/3MF/AMF, BREP — STEP/IGES, DXF) and routes it to every process that can make it; the response's routing.also_possible lists processes UFP can't quote yet
productNoprint: Print product kind: business_cards|flyers|posters. Omit to quote every kind the artwork fits; apparel: apparel: t_shirt|hoodie|long_sleeve|tank_top (free-form — "tee", "crewneck" resolve to the closest product)
shore_aNoNumeric Shore A durometer ask (10-95, e.g. 40). Resolved to the NEAREST stocked durometer with a substitution note — never a silent swap
tappingNoTapped (threaded) holes for a sheet-metal part — one record per hole the user wants threads cut into. `thread` is the callout in the user's words ("M6", "M4 x 0.7", "1/4-20") and is all that's required; when known, add the hole's center in the part's own mm frame (located_at_mm), its unit axis, the pre-tap drilled diameter, and depth_mm so the shop taps the right hole. Pass these when the user asks for threaded/tapped holes; vendors with a tapping service price them.
vendorsNoOnly these specific vendors/makers ("just quote Slant 3D") — an INCLUDE list of vendor names as they appear on offers. Friendly names accepted ("A3D", "slant 3d"); unmatched names are reported, never an error. Usually OMIT: pass it only when the user explicitly names the vendors they want
calloutsNoDimensions you read off the user's drawing that matter ("hole_diameter 6.5mm ±0.1"). The tightest tolerance prunes vendors that cannot hold it.
deadlineNoLatest acceptable delivery date, ISO YYYY-MM-DD
file_urlNoPublic URL of the design file — only when the design lives at a URL
materialNoONLY a material the user actually asked for — NEVER guess or default one (a silent "pla" on a bare file drop prunes every maker that does not stock it; OMIT instead and each process quotes across its stocked materials so every maker can bid). fdm_print: pla|petg|asa (free-form — "abs", "polycarbonate" asks resolve to the closest stocked filament with a substitution note); resin_print: standard|tough|high_temp|high_detail resin (free-form asks resolve to the closest supported resin); powder_print: Powder-bed nylon: nylon_12|nylon_12_smooth|nylon_11|nylon_12_gf|nylon_12_esd|nylon_12_white|nylon_pa2200|nylon_12_sls|tpu (free-form — "PA12", "glass filled" resolve to the closest stocked powder); elastomer_print: Jetted elastomer: tepu_30a|tepu_50a (free-form — "TPU", "soft rubber" resolve to the closest stocked durometer); cnc: aluminum_6061|aluminum_7075|stainless_304|titanium|brass|acetal|delrin|abs|nylon_pa6|peek|acrylic (free-form asks resolve to the closest supported stock); sheetmetal: mild_steel|aluminum_5052|stainless_304 (free-form — "steel", "5052", "stainless" resolve; unknown asks get closest-match offers). Omit to compare the defaults; laser_cut: acrylic|plywood|mdf|delrin|uhmw|hdpe|g10|carbon_fiber|mild_steel|aluminum_5052|stainless_304 (free-form — "plexiglass", "birch" resolve; unknown asks get closest-match offers); decal: vinyl|holographic|transparent|glitter (free-form — "chrome" etc. gets closest matches)
width_inNoDecal width in inches (default 3)
food_safeNoMust be vendor-certified food safe
height_inNoDecal height in inches (default 3)
high_tempNoMust tolerate sustained heat (vendor heat-resistance claim)
placementNoPrint placement for apparel: front (default) | back | front_back
processesNoOnly quote these fabrication processes — a constraint that narrows the auto-routing fan. Friendly terms accepted ("sheet metal", "3d printing", "cnc", "laser"); unmappable terms are reported, never an error. Usually OMIT: auto-routing quotes every process that can make the file. Pass it only when the user explicitly limits the process
share_keyNoShare key for a LOCKED part — the k=… value from the owner's share link (…/part/UFP-…?k=KEY). Required with part_number when the part is locked; omit otherwise
bend_countNoNumber of bends in the design (bend lines must be in the file). Prices CNC bending; omit for flat parts
quantitiesNoQuantities the user actually wants — pass [1] or [2] if that's the ask. Vendors with a higher minimum quote AT their minimum and the offer notes it (requested_quantity). Default: 25 for decals, 1 for prints; a part_number reorder defaults to the quantity last purchased
ships_fromNoOnly vendors that ship from these countries/regions ("only US vendors", "keep it domestic") — an INCLUDE list. Friendly terms accepted ("US", "Europe", "Germany", "China", "UK"); unmappable terms are reported, never an error. Vendors whose origin is unknown or whose network is worldwide (origin not guaranteed) are excluded, each with a note saying why. Usually OMIT: pass it only when the user explicitly limits where vendors ship from
design_fileNoThe design file itself (user-attached or generated image/STL). ChatGPT supplies the file reference automatically when the user attached a file — just bind the attachment here. Other clients may pass a data: URL (base64) or a public https URL string. Preferred over file_url.
metal_alloyNoMetal AM alloy: stainless_316l|stainless_17_4ph|titanium_ti64|aluminum_alsi10mg|inconel_718|cobalt_chrome|tool_steel_h13|copper (free-form asks like "Ti-6Al-4V" resolve to the closest stocked powder)
part_numberNoUFP part number from a previous paid order (UFP-… or part_…). Reorders: replaces design_file/file_url entirely; any other fields provided override the stored spec
ship_to_zipNoDestination US ZIP code, exactly as the user stated it. OMIT if the user has not given one — NEVER guess or invent a ZIP. Without it, prices come back all-in with shipping to an assumed central-US destination, flagged on routing.ship_to
submersibleNoMust survive submersion in water
metal_finishNoMetal AM post-processing: as_printed|bead_blast|machined_critical|polished|heat_treated (as_printed keeps support witness marks)
requirementsNoVerbatim context terms from the user — materials, finishes, certifications, tolerances ("UV resistant", "anodized: red", "iso 13485", "tolerance: 0.1mm"). UFP applies what it can and reports what it could not; unresolvable terms are logged for vendor sourcing. Do not interrogate the user to fill this — pass what they said.
thickness_inNosheetmetal: Sheet thickness in inches (e.g. 0.063 = 14 ga aluminum). Quoted at the nearest stocked thickness; omit for ~16 ga default; laser_cut: Nominal thickness in inches; quoted at the vendor's nearest stocked thickness. Omit for the material's common stock
outdoor_ratedNoMust survive outdoor exposure
powder_finishNoPowder post-processing: as_printed (raw powder surface) | vapor_polished | polished
max_budget_usdNoHard budget cap in USD, all-in
attachment_urlsNoAdditional files for the SAME part — the PDF drawing next to the STEP, spec sheets, BOMs. Pass everything the user gave you; UFP works out which file is the part and which are supporting documents.
elastomer_finishNoElastomer post-processing: as_printed (VCJ parts ship raw — the whole lane today)
metal_technologyNoMetal AM process: laser_powder_bed (SLM/DMLS/LPBF)|binder_jet|ebm. Omit to let the vendor pick its default for the alloy
min_vendor_starsNoOnly vendors whose displayed review rating is at least this many stars (1-5). Vendors with no reviews yet are excluded — the filter demands demonstrated quality
powder_technologyNoPowder process: mjf (HP Multi Jet Fusion) | sls (laser sintering). Omit to let the vendor pick its default lane for the material
min_vendor_reviewsNoOnly vendors with at least this many verified-purchase reviews
proven_spec_ordersNoOnly vendors with at least N completed orders for this exact process+material — "a vendor that prints PC reliably"
elastomer_technologyNoElastomer process: vapor_cure_jetting (VCJ). Omit to let the vendor pick its default lane for the material

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. It discloses non-obvious behaviors: UFP auto-routing, reorder override semantics, locked-part share_key requirement, closest-match substitution behavior, vendor-minimum quoting, and default quantities. It does not explicitly mention caching, retries, or the response envelope, but it adds substantial transparency beyond what annotations would typically convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but dense — nearly every sentence carries routing logic or process-specific semantics. It front-loads the core purpose and process-to-file-format mapping, then branches into reorders, file sources, and vendor filtering. It could be tightened by moving some enum details to the schema, but given the tool's complexity it is appropriately structured and not padded.

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?

The description covers the main decision paths: which process, which file source, whether to use a part_number, locked-part access, vendor/shipping filters, and shipping destination. It lacks an explicit description of the full output shape beyond 'ranked, purchasable offers (price, ETA, preview image)', but no output schema exists and the tool's core decision logic is well covered.

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?

Schema coverage is 100%, but the description adds high-value guidance beyond the schema: it explains UFP's auto-applied intent, the precedence of part_number over files, the design_file preference, ship_to_zip omission rule, and default behavior for several parameters. For a 47-parameter tool, this strategic guidance is genuinely useful and not redundant with 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 starts with a specific verb phrase — 'Get ranked, purchasable offers (price, ETA, preview image) for fabricating a physical item from a design file' — and clearly identifies the resource (design file) and output (ranked offers). It distinguishes itself from siblings like preview_quote, poll_quote, and finalize_quote by framing this as the entry point that returns purchasable vendor offers.

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?

Gives explicit when-to-use and when-not-to-use guidance for multiple branches: omit process when the user just drops a file, pass part_number instead of a file for reorders, use design_file rather than file_url, and 'usually OMIT' vendors/processes/ships_from unless the user explicitly names them. This routing guidance is unusually rich and specific.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_material_guideGet material guideAInspect

Honest, cited material intelligence for material-choice / strength / durability / heat / outdoor questions ("my PLA part broke, what's stronger?", "will this survive outdoors?"). Returns caveats-FIRST facts: published specs (tensile, heat-deflection, UV/outdoor, chemical) each tagged vendor-cited vs general engineering knowledge, "stronger/tougher/hotter than X" ladders (PLA→PETG→ABS/ASA→nylon/PC→metals), and finish/coating options. Call it BEFORE answering such a question, then relay the facts. It supplies FACTS ONLY — comparative specs and vendor-admitted caveats, never a fitness-for-purpose or safety guarantee (that stays your judgment boundary); name express vendor claims "advertised", not "certified".

ParametersJSON Schema
NameRequiredDescriptionDefault
processNoA UFP process to scope to ("fdm_print", "resin_print", "cnc", "sheetmetal", "laser_cut") — lists the materials that process makes
materialNoA material the user named or you are weighing ("PLA", "6061 aluminum", "stainless") — free-form; a family ask like "stainless" returns the whole family
questionNoThe user's raw question — mined for intent (stronger/tougher, heat/hot, outdoor/UV) so the right ladder is surfaced

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description fully discloses behavior: returns caveats-first facts, tags sources (vendor-cited vs general), provides strength ladders, and explicitly states it never gives safety guarantees. This is comprehensive transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is detailed but well-structured, front-loading the core purpose. It is slightly long, but every sentence adds essential information. Could be tightened, but still efficient for the complexity.

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 no output schema, the description thoroughly explains what is returned. It covers all relevant aspects for a 3-parameter tool, including what the tool does and its limitations. Complete for its purpose.

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% with all parameters documented. The description adds value by explaining how 'question' is used to mine for intent, but does not significantly add beyond schema for 'process' and 'material'. Thus slightly above baseline.

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 provides material intelligence for specific questions (strength, durability, heat, outdoor). It lists concrete outputs like published specs, comparative ladders, and finish options. The purpose is distinct from sibling tools which handle orders, quotes, and reviews.

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?

The description explicitly instructs to call the tool BEFORE answering material questions and to relay facts. It sets boundaries by stating it supplies facts only, not fitness or safety guarantees. While it doesn't mention alternatives, sibling tools are unrelated, so no confusion.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_network_capabilitiesNetwork capabilitiesAInspect

The LIVE catalog of what the fabrication network can do RIGHT NOW — no quote needed. Returns the services ledger (tapping, inserts, welding, bending, finishes… with each shop's own size/material/thickness windows), the network's sheet gauge ladder, the stocked hardware combinations (species x thread) with stocked lengths and shop counts — the most-stocked length is the steering default for an unspecified length — the finish options with their stocked color menus, and per-process manufacturability rules. This is live state, not a spec sheet: it changes as connectors join, leave, or have capability branches toggled, so call it fresh when the user asks what's possible (materials, gauges, hardware, colors, services) rather than answering from memory.

ParametersJSON Schema
NameRequiredDescriptionDefault
processNoAdvisory scope ("sheetmetal") — v1 returns the whole catalog either way; filter what you relay

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden, and it pays off: it discloses that this is live state that changes as connectors join/leave or capability branches toggle, that the process parameter is advisory in v1, and that unspecified lengths default to the most-stocked length. These are non-obvious behaviors that meaningfully affect invocation and interpretation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a dense, front-loaded paragraph that communicates important scoping and behavioral details without irrelevant filler. It is longer than strictly necessary, but the detail is substantive and helps the agent understand a complex, information-rich tool.

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 tool has only one optional parameter and no output schema, the description covers the return surface well: services per shop, size/material/thickness windows, gauge ladder, stocked hardware combinations, finish color menus, and manufacturability rules. It also covers dynamic behavior and usage context, so an agent has enough to invoke and interpret results correctly.

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?

The single parameter is 100% covered by the schema, which already states it is advisory and that v1 returns the whole catalog either way. The description reinforces this but does not add new parameter-level meaning 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 names a specific resource (the live fabrication network capability catalog) and a clear verb (returns/retrieves), with an explicit contrast to quote tools. It enumerates the major content areas (services ledger, gauge ladder, hardware combos, finishes, manufacturability rules), making it easy to distinguish from get_fabrication_quote and get_material_guide.

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?

The description explicitly states when to call: whenever the user asks what's possible in materials, gauges, hardware, colors, or services, and not from memory. It also signals a key exclusion—'no quote needed'—implying that for actual quotations the user should use the quote tools. This is strong, actionable guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_order_statusGet order statusAInspect

Check status, ETA and tracking for a UFP order.

ParametersJSON Schema
NameRequiredDescriptionDefault
order_idYes

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are present, so the description carries the full burden. It discloses that this is a read operation returning status, ETA, and tracking, but lacks details on response structure, potential errors, or required permissions. Adequate for a simple read tool, but not rich.

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 entire description is one concise sentence that front-loads the action and key data points. No unnecessary words or repetition.

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 simple single-parameter lookup, the description covers the key return values (status, ETA, tracking). It does not explain how to obtain order_id, but sibling tools like list_orders likely provide that. The lack of an output schema is partially compensated by listing return items.

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?

The schema has only one parameter, order_id, with no description coverage. The parameter name is self-explanatory, and the description references 'a UFP order,' but does not explain the format or source of order_id. Minimal addition beyond the schema, but the parameter is unambiguous.

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 checks status, ETA, and tracking for a single UFP order. The verb 'check' is specific, and the resource scope distinguishes it from sibling tools like list_orders.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies it is for a single order's status, but does not explicitly state when to use it instead of alternatives like list_orders. No exclusions or when-not guidance is provided.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_shop_gaugesA shop's stocked sheet gaugesAInspect

Every sheet thickness (gauge) ONE named shop stocks right now, per material — read live off the shop's declared catalog, no quote needed. Call it when the user asks what thicknesses/gauges a specific maker carries ("what thicknesses does SendCutSend have in mild steel?"). For the whole network's ladder use get_network_capabilities instead. Never answer a gauge question from memory.

ParametersJSON Schema
NameRequiredDescriptionDefault
shopYesThe shop as the user or the offer cards name it ("SendCutSend", "sendcutsend")
materialNoAdvisory: narrow the relayed list to one material ("mild steel", "5052")

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the behavioral disclosure burden. It clearly states this is a live read off the declared catalog, that no quote is needed, and that answers must not come from memory — which conveys freshness and non-mutating behavior. It could add failure/auth details, but the most important behavioral traits are disclosed.

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 dense sentences with no filler; the core behavior and scope appear first, usage guidance second, and the alternative tool third. Every sentence earns its place.

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?

For a two-parameter lookup with no output schema, the description explains what is returned ('every sheet thickness per material'), how current it is, and when to use it versus the alternative. Nothing essential for invoking the tool correctly is missing.

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%, so the baseline is 3, and the description adds meaningful context: it clarifies that the shop name is matched flexibly as the user or offer cards name it, and that material is an advisory narrowing filter rather than a hard requirement. This helps the agent map user phrasing to parameters beyond what the schema alone provides.

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 names a specific action — returning the sheet thicknesses a single named shop currently stocks — and identifies the targeted resource ('ONE named shop' vs. the whole network). It clearly differentiates from sibling get_network_capabilities by scope, so an agent can select it confidently.

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?

The description gives an explicit when-to-use trigger ('Call it when the user asks what thicknesses/gauges a specific maker carries') and routes the network-wide aggregate case to get_network_capabilities. It also warns against answering from memory, providing actionable guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

leave_reviewLeave vendor reviewAInspect

Record the user's verified-purchase review of how a UFP order turned out. YOUR JOB IS TO STRUCTURE THE FEEDBACK: turn what the user actually said into stars (1-5 overall) and facet scores — "the cut was sloppy" -> quality, "parts arrived 2 days late" -> timeliness, "wrong color" -> accuracy. Keep the optional comment to a short factual summary of their words; never embellish. ALWAYS draft the review (stars, facets, comment) and confirm it with the user BEFORE calling this tool — e.g. "I'll rate this 2 stars with timeliness 1 because it arrived 2 days late — send it?". One review per order: submitting again updates the existing review. Use list_orders first if you need to resolve which order they mean.

ParametersJSON Schema
NameRequiredDescriptionDefault
starsYesOverall rating the user confirmed, 1-5
claimsNoCHECKABLE claims from the user's feedback — the network stamps each against its own records (the ordered spec, polled tracking + delivery events) and attaches evidence chips to the review. Only pass what the user actually asserted.
facetsNoScore only the facets the user actually spoke to
commentNoShort factual summary of the user's feedback, in their spirit — optional
order_idYesThe UFP order being reviewed (ord_…) — see list_orders

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses that the tool structures feedback into stars/facets, updates existing reviews on resubmission, and requires user confirmation. It also warns against embellishing comments. With no annotations provided, the description fully carries the burden of behavioral disclosure.

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 somewhat long but every sentence serves a purpose: purpose, structuring rule, confirmation requirement, update behavior, and reference to list_orders. It's dense but not wasteful, with no redundancy.

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?

For a tool with no annotations and no output schema, the description covers purpose, process, facet mapping, confirmation step, and update semantics. It adequately equips an agent to invoke it correctly, including handling ambiguous order references.

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 schema already provides 100% coverage with descriptions for all parameters. The description adds value by mapping user phrases to facet scores ('the cut was sloppy' -> quality) and clarifying comment brevity. This goes beyond the schema's parameter descriptions.

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 records a verified-purchase review for a UFP order, with a specific verb ('record') and resource ('review'). It distinguishes from siblings like list_orders or get_order_status by focusing on submitting feedback.

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 instructs to confirm the drafted review with the user before calling, and to use list_orders first to resolve which order. It also notes one review per order with update semantics. While it doesn't list alternatives or exclusions, these guidelines are clear and actionable.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_ordersList recent ordersAInspect

List this agent's recent UFP orders (newest first): order id, what was made, vendor, status, total, ETA, created date. Use it to resolve vague references — "my sticker order", "that order from 6 days ago" — to a concrete order_id before calling get_order_status or leave_review.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses the ordering behavior (newest first) and the returned fields. It does not explicitly state it is read-only, but the action of listing without side effects is implied. This is sufficient for a list tool, though a note about no state change would have been more transparent.

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 sentences long, front-loaded with the main purpose, and includes a concrete example of usage. Every sentence provides value without redundancy.

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 no input parameters and no output schema, the description covers the essential return fields, ordering, and a practical use case. It also differentiates from sibling tools, making the context complete for an agent to select and invoke correctly.

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 tool has zero parameters, and the schema coverage is 100% by default. Per rubric, a baseline of 4 is appropriate since there are no parameters to explain and the description adds no param-specific semantics needed.

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 lists the agent's recent UFP orders with a specific set of fields and sorting (newest first). It also explicitly distinguishes its role from siblings by noting it resolves vague references before calling get_order_status or leave_review.

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?

The description gives explicit when-to-use guidance: to resolve vague order references into a concrete order_id. It also names specific alternative tools (get_order_status, leave_review) and indicates this tool should be used before them, providing clear context and alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

poll_quotePoll quote (board internal)AInspect

INTERNAL — the offer board calls this to refresh itself while vendors finish pricing. Never call this yourself. The board you were given is already final for its turn; do not reach for refine_quote to look at it again either, that paints a duplicate board.

ParametersJSON Schema
NameRequiredDescriptionDefault
quote_idYesQuote id the board is watching

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 carries the full burden for behavioral disclosure. It does reveal that the tool is internal and that the board refreshes itself, and it warns that the board is already final. However, it does not specify what happens if the tool is called manually (errors, side effects, return value), leaving some ambiguity about actual runtime 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?

The description is two concise sentences that front-load the INTERNAL warning and immediately give actionable prohibitions. Every clause earns its place, with no filler or repeated schema details.

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 that this is an intentional internal-only tool with a single well-described parameter and no output schema, the description covers the essential context: what the tool is for, who calls it, and why the agent must not call it. It lacks explicit return/error details, but for a tool the agent is explicitly forbidden from invoking, the guardrails are sufficiently complete.

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?

The input schema fully describes quote_id as 'Quote id the board is watching' with 100% coverage, so the description adds no additional parameter semantics. The baseline of 3 applies because the schema already handles the parameter information.

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 that the tool is an internal callback used by the offer board to refresh itself while vendors finish pricing, which goes beyond the title. It also distinguishes itself from refine_quote, warning not to use that tool for re-inspection because it paints a duplicate board.

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?

It gives explicit, non-ambiguous usage rules: 'Never call this yourself' and explicitly warns against using refine_quote to look at the board again. It explains that the provided board is already final for its turn, so calling this tool is unnecessary.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

preview_quotePreview quote routing (soft quote)AInspect

INTERNAL client rail — the routing half of refine_quote with NOTHING committed: takes the same arguments as refine_quote and answers how many distinct fabricators (and which process lanes) the network WOULD ask for the refined part, plus the exclusion notes, without creating a child quote, asking any vendor, superseding in-flight work, or logging demand. An expectation, never a promise — lanes can still decline once asked. Never call this to look at prices; it carries none. Use refine_quote to actually re-price.

ParametersJSON Schema
NameRequiredDescriptionDefault
bendsNoNew bend records for this part — a spec change: sheet lanes requote with exactly these bends (the list REPLACES the previous one, never patches it). Same shape as on get_fabrication_quote: each bend is two points in the part's own mm frame (flat DXF parts use z=0) plus angle_deg, direction up|down, and an optional requested radius_mm. Pass null to REMOVE every articulated bend
clearNoREMOVE constraints entirely ("drop the deadline", "forget the budget", "no more food-safe requirement"): list the constraints to clear and each is removed from the quote — the one deliberate widening besides undo. Clearing a deadline or budget answers instantly from held offers (near-misses convert back); clearing an attribute/reliability/requirements demand re-prices honestly. Same effect as ["any"] on the three filter args, extended to every constraint
colorNoNew color for this part (spec change — lanes requote). Colour WORDS only ('black', 'green', 'clear'); the network resolves them to each maker's stocked shades, dyes, filaments or coatings — a family word ('blue') brings back EVERY stocked shade of it, and the quote's color_shades_available lists them — never pass a material or a shade you invented. Pass null to REMOVE a previously asked color — back to vendor defaults
scaleNoRescale the DESIGN ITSELF before re-quoting: per-axis stretch factors over the file's current geometry ("make it 2x bigger" = {"x":2,"y":2,"z":2}). Mesh designs are genuinely converted — the child quote prices a rescaled file; STEP/IGES designs keep their original file with the dimensions riding as callouts (pass those too). {1,1,1} is a no-op
finishNoNew surface finish ("powder coat", "anodized", "bead blasted") — a spec change: finish-capable lanes (sheet metal, CNC, metal print) requote WITH it; 3D-print lanes have no coating step, so they ignore the finish but keep the COLOR. A colored finish ask ("black powder coat") should set BOTH finish and color, so every lane lands on the buyer's color. Pass null to REMOVE a previously asked finish
insertsNoNew hardware-insert records for this part — a spec change: sheet lanes requote with exactly these inserts (the list REPLACES the previous one, never patches it). Same shape as on get_fabrication_quote: species (nut|flush_nut|standoff|blind_standoff|stud) and thread required, hole geometry optional. Pass null to REMOVE every insert
sort_byNo"Organize by": re-order the quote's offer cards ("sort by cheapest" → "price"; "soonest arrival first" → "arrival"; "best rated" → "rating"; "total_price" = part + cheapest shipping; "recommended" restores the default price+speed rank). PURE PRESENTATION — answers instantly on the same quote, never re-prices or drops offers, and the ordering sticks across re-reads, streaming, and later refines until changed
tappingNoNew tapped-hole records for this part — a spec change: sheet lanes requote with exactly these taps (the list REPLACES the previous one, never patches it). Same shape as on get_fabrication_quote: thread callout ("M6", "1/4-20") required, hole geometry optional. Pass null to REMOVE every tap
vendorsNoOnly these specific vendors/makers ("only show A3D Manufacturing", "just Slant 3D and Fictiv") — an INCLUDE list of vendor names as they appear on offers. A CONSTRAINT like processes: other vendors' offers drop instantly (nothing re-prices), further refines inherit the filter, and ["any"] clears it to show every vendor again. Friendly names accepted ("A3D", "slant 3d"); unmatched names are reported, never an error. This is THE way to answer "show me everything vendor X offers" — the filtered quote lists that vendor's complete lineup
calloutsNoDimensions you read off the user's drawing that matter ("hole_diameter 6.5mm ±0.1"). The tightest tolerance prunes vendors that cannot hold it.
deadlineNoLatest acceptable delivery date, ISO YYYY-MM-DD
materialNoNew material for this part ("I need it in PLA" → "pla"). A spec change: lanes requote with this material through warm vendor sessions; an explicit material here replaces the quote's material fan-out. Free-form — unstocked asks resolve to the closest stocked material with a substitution note. Do NOT pass material changes as requirements terms. Pass null to REMOVE a previously asked material ("forget the aluminum ask") — the ask comes off the record and the process-default material fan returns
quote_idYes
scenarioNoComparison lane label. A labeled refine sits SIDE BY SIDE with the quote's other offers instead of replacing them: refines with the same label replace that scenario, different labels coexist (max 4 per quote), and a refine WITHOUT a scenario resets the baseline and supersedes every lane. "How does X compare to Y?" = one labeled refine per scenario (e.g. scenario "carbon steel" + material "carbon steel", then scenario "aluminum" + material "aluminum"). Keep labels short and human, like "carbon steel"
food_safeNo
high_tempNo
processesNoNarrow this quote to specific fabrication processes ("no, I meant in sheet metal" → ["sheet metal"]). A CONSTRAINT, not a new quote: excluded lanes drop while warm vendor sessions survive, and further refines inherit the filter. Friendly terms accepted ("sheet metal", "3d printing", "cnc", "laser"); pass ["any"] to clear the filter and show every process again. When comparison scenarios are open and the user narrows the process, re-refine EVERY active scenario label with this same arg so all columns prune together
quantitiesNoNew quantities the user wants (spec change — lanes requote at the new quantity). Same rules as on get_fabrication_quote: pass the real ask, never inflate it. Pass null to REMOVE a previously asked quantity — the quote returns to single-part pricing
ships_fromNoOnly vendors that ship from these countries/regions ("only US vendors", "just European shops", "keep it domestic") — an INCLUDE list naming where the user DOES want vendors from. A CONSTRAINT like processes: non-matching vendors drop instantly (nothing re-prices), further refines inherit the filter, and ["any"] clears it to show vendors everywhere again. Friendly terms accepted ("US", "Europe", "Germany", "China", "UK"). Vendors whose origin is unknown or whose network is worldwide (a specific origin cannot be guaranteed) are excluded, each with an honest note. For "nothing from X" asks, pass the regions the user does want instead
sort_labelNoShort human wording for a sort_order, displayed on the board ("most green first") — required with sort_order, since only you know what your order means
sort_orderNoEXPLICIT card order for asks only you can judge ("sort the most green to the top"): look at the offers' preview images, decide the order yourself, and pass the offer ids first-on-top. Offers you leave out (including ones that stream in later) land below the listed ones in the default rank. Pass sort_label with it
ship_to_zipNoDestination US ZIP code, exactly as the user stated it — use this when the user provides their ZIP after a quote priced to the assumed central-US destination (routing.ship_to); the refined prices become theirs. NEVER guess or invent a ZIP
submersibleNo
color_shadesNoNarrow the board to these color SHADES exactly as the quote lists them (color_shades_available / "Colors on this board") — instant, nothing re-prices, the same quote id comes back with only those shades; pass null to show every shade again. Never invent a shade name.
requirementsNoVerbatim context terms from the user — materials, finishes, certifications, tolerances ("UV resistant", "anodized: red", "iso 13485", "tolerance: 0.1mm"). UFP applies what it can and reports what it could not; unresolvable terms are logged for vendor sourcing. Do not interrogate the user to fill this — pass what they said.
thickness_inNoNew sheet thickness in INCHES ("make it in 1/8" → 0.125) — a spec change: sheet lanes requote at the nearest stocked gauge, flagging the substitution when the match isn't close. Pass null to REMOVE a previously asked thickness — back to the material's default gauge
outdoor_ratedNo
max_budget_usdNo
sort_directionNoFlip a sort_by ordering: "desc" reverses the key's natural direction ("most expensive first" = sort_by "price" + "desc"). Only meaningful with sort_by
undo_last_stepNoGO BACK EXACTLY ONE STEP ("undo that", "go back", "put it back how it was"): the network restores the previous quote's stored spec and constraints EXACTLY — never reconstructed from conversation — and re-prices where needed. Send it ALONE (no other args besides quote_id); combining it with changes is rejected. The quote's steps[] names what each undo would take back — steps[0] is the newest. Undo resets the baseline like any unlabeled refine, so open comparison scenarios close. Undoing the original quote is rejected with honest wording — relay it
min_vendor_starsNoOnly vendors whose displayed review rating is at least this many stars (1-5); vendors with no reviews yet are excluded
min_vendor_reviewsNoOnly vendors with at least this many verified-purchase reviews
proven_spec_ordersNoOnly vendors with at least N completed orders for this exact process+material — "a vendor that prints PC reliably"
remove_requirementsNoTake back INDIVIDUAL requirements terms ("drop the anodized ask, keep the rest"): each listed term is removed from the quote's requirements by normalized match, the others stay. Unknown terms are ignored, never an error. Re-stating the requirements list can never drop a term (terms merge as a union) — this is the removal channel

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description bears the full behavioral burden and meets it: nothing is committed, no child quote is created, no vendor is asked, in-flight work is not superseded, demand is not logged, and lanes may still decline. This is exactly the kind of side-effect disclosure an agent needs.

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 dense yet every sentence earns its place: the non-committal nature is front-loaded, the behavioral exclusions are enumerated, and the pricing caveat plus alternative are stated in two final short sentences. No redundant restatement of the title.

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?

Despite no output schema, the description tells the agent what to expect: fabricator count, process lanes, exclusion notes, and no prices or committed quotes. It could add more detail on the exact response shape for the large parameter set, but the core call context is adequately covered.

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?

The tool description contributes only that it takes 'the same arguments as refine_quote'; nearly all parameter meaning is carried by the input schema, which is richly documented at 82% coverage. That meets the baseline, but the description itself adds little per-parameter 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 names a clear operation — preview what routing/refinement would do — and differentiates it from refine_quote by calling it 'the routing half' that answers how many fabricators and process lanes would be asked, plus exclusion notes. It explicitly disclaims pricing, which removes a common misreading.

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?

It states when the tool is appropriate (non-committal routing preview) and when not ('Never call this to look at prices'), and names the alternative: 'Use refine_quote to actually re-price.' This is explicit when/when-not guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

refine_quoteRefine quoteAInspect

Narrow an existing quote with new constraints (destination ZIP the user just provided, deadline, outdoor/waterproof/heat/food-safety requirements, budget, vendor reliability, verbatim requirements terms, drawing callouts, a process filter — "no, I meant in sheet metal" → processes — a ship-from country filter — "only US vendors" → ships_from — or a vendor filter — "only show A3D Manufacturing" → vendors) — or CHANGE its spec: material, color, or quantities. Changing material/quantity is a spec change, not a narrowing — pass it via the material/color/quantities args, NOT as a requirements term; the affected lanes re-price with the new spec through warm vendor sessions. For side-by-side comparisons ("how does carbon steel compare?"), add a scenario label — labeled refines coexist instead of replacing each other (max 4). "Organize by" ("sort by cheapest", "soonest arrival on top", "most green first") is also this tool: sort_by for objective orders, sort_order + sort_label for orders you judged yourself from the previews — presentation only, instant, nothing re-prices. GOING BACK is also this tool: undo_last_step ALONE takes back exactly one refine step (the quote's steps[] names each step, newest first — the network restores the previous stored state exactly); clear removes whole constraints ("drop the deadline" → clear ["deadline"]); remove_requirements takes back individual requirements terms. Call with ONLY quote_id to re-read the quote (e.g. to pick up preview images that finished rendering).

ParametersJSON Schema
NameRequiredDescriptionDefault
bendsNoNew bend records for this part — a spec change: sheet lanes requote with exactly these bends (the list REPLACES the previous one, never patches it). Same shape as on get_fabrication_quote: each bend is two points in the part's own mm frame (flat DXF parts use z=0) plus angle_deg, direction up|down, and an optional requested radius_mm. Pass null to REMOVE every articulated bend
clearNoREMOVE constraints entirely ("drop the deadline", "forget the budget", "no more food-safe requirement"): list the constraints to clear and each is removed from the quote — the one deliberate widening besides undo. Clearing a deadline or budget answers instantly from held offers (near-misses convert back); clearing an attribute/reliability/requirements demand re-prices honestly. Same effect as ["any"] on the three filter args, extended to every constraint
colorNoNew color for this part (spec change — lanes requote). Colour WORDS only ('black', 'green', 'clear'); the network resolves them to each maker's stocked shades, dyes, filaments or coatings — a family word ('blue') brings back EVERY stocked shade of it, and the quote's color_shades_available lists them — never pass a material or a shade you invented. Pass null to REMOVE a previously asked color — back to vendor defaults
scaleNoRescale the DESIGN ITSELF before re-quoting: per-axis stretch factors over the file's current geometry ("make it 2x bigger" = {"x":2,"y":2,"z":2}). Mesh designs are genuinely converted — the child quote prices a rescaled file; STEP/IGES designs keep their original file with the dimensions riding as callouts (pass those too). {1,1,1} is a no-op
finishNoNew surface finish ("powder coat", "anodized", "bead blasted") — a spec change: finish-capable lanes (sheet metal, CNC, metal print) requote WITH it; 3D-print lanes have no coating step, so they ignore the finish but keep the COLOR. A colored finish ask ("black powder coat") should set BOTH finish and color, so every lane lands on the buyer's color. Pass null to REMOVE a previously asked finish
insertsNoNew hardware-insert records for this part — a spec change: sheet lanes requote with exactly these inserts (the list REPLACES the previous one, never patches it). Same shape as on get_fabrication_quote: species (nut|flush_nut|standoff|blind_standoff|stud) and thread required, hole geometry optional. Pass null to REMOVE every insert
sort_byNo"Organize by": re-order the quote's offer cards ("sort by cheapest" → "price"; "soonest arrival first" → "arrival"; "best rated" → "rating"; "total_price" = part + cheapest shipping; "recommended" restores the default price+speed rank). PURE PRESENTATION — answers instantly on the same quote, never re-prices or drops offers, and the ordering sticks across re-reads, streaming, and later refines until changed
tappingNoNew tapped-hole records for this part — a spec change: sheet lanes requote with exactly these taps (the list REPLACES the previous one, never patches it). Same shape as on get_fabrication_quote: thread callout ("M6", "1/4-20") required, hole geometry optional. Pass null to REMOVE every tap
vendorsNoOnly these specific vendors/makers ("only show A3D Manufacturing", "just Slant 3D and Fictiv") — an INCLUDE list of vendor names as they appear on offers. A CONSTRAINT like processes: other vendors' offers drop instantly (nothing re-prices), further refines inherit the filter, and ["any"] clears it to show every vendor again. Friendly names accepted ("A3D", "slant 3d"); unmatched names are reported, never an error. This is THE way to answer "show me everything vendor X offers" — the filtered quote lists that vendor's complete lineup
calloutsNoDimensions you read off the user's drawing that matter ("hole_diameter 6.5mm ±0.1"). The tightest tolerance prunes vendors that cannot hold it.
deadlineNoLatest acceptable delivery date, ISO YYYY-MM-DD
materialNoNew material for this part ("I need it in PLA" → "pla"). A spec change: lanes requote with this material through warm vendor sessions; an explicit material here replaces the quote's material fan-out. Free-form — unstocked asks resolve to the closest stocked material with a substitution note. Do NOT pass material changes as requirements terms. Pass null to REMOVE a previously asked material ("forget the aluminum ask") — the ask comes off the record and the process-default material fan returns
quote_idYes
scenarioNoComparison lane label. A labeled refine sits SIDE BY SIDE with the quote's other offers instead of replacing them: refines with the same label replace that scenario, different labels coexist (max 4 per quote), and a refine WITHOUT a scenario resets the baseline and supersedes every lane. "How does X compare to Y?" = one labeled refine per scenario (e.g. scenario "carbon steel" + material "carbon steel", then scenario "aluminum" + material "aluminum"). Keep labels short and human, like "carbon steel"
food_safeNo
high_tempNo
processesNoNarrow this quote to specific fabrication processes ("no, I meant in sheet metal" → ["sheet metal"]). A CONSTRAINT, not a new quote: excluded lanes drop while warm vendor sessions survive, and further refines inherit the filter. Friendly terms accepted ("sheet metal", "3d printing", "cnc", "laser"); pass ["any"] to clear the filter and show every process again. When comparison scenarios are open and the user narrows the process, re-refine EVERY active scenario label with this same arg so all columns prune together
quantitiesNoNew quantities the user wants (spec change — lanes requote at the new quantity). Same rules as on get_fabrication_quote: pass the real ask, never inflate it. Pass null to REMOVE a previously asked quantity — the quote returns to single-part pricing
ships_fromNoOnly vendors that ship from these countries/regions ("only US vendors", "just European shops", "keep it domestic") — an INCLUDE list naming where the user DOES want vendors from. A CONSTRAINT like processes: non-matching vendors drop instantly (nothing re-prices), further refines inherit the filter, and ["any"] clears it to show vendors everywhere again. Friendly terms accepted ("US", "Europe", "Germany", "China", "UK"). Vendors whose origin is unknown or whose network is worldwide (a specific origin cannot be guaranteed) are excluded, each with an honest note. For "nothing from X" asks, pass the regions the user does want instead
sort_labelNoShort human wording for a sort_order, displayed on the board ("most green first") — required with sort_order, since only you know what your order means
sort_orderNoEXPLICIT card order for asks only you can judge ("sort the most green to the top"): look at the offers' preview images, decide the order yourself, and pass the offer ids first-on-top. Offers you leave out (including ones that stream in later) land below the listed ones in the default rank. Pass sort_label with it
ship_to_zipNoDestination US ZIP code, exactly as the user stated it — use this when the user provides their ZIP after a quote priced to the assumed central-US destination (routing.ship_to); the refined prices become theirs. NEVER guess or invent a ZIP
submersibleNo
color_shadesNoNarrow the board to these color SHADES exactly as the quote lists them (color_shades_available / "Colors on this board") — instant, nothing re-prices, the same quote id comes back with only those shades; pass null to show every shade again. Never invent a shade name.
requirementsNoVerbatim context terms from the user — materials, finishes, certifications, tolerances ("UV resistant", "anodized: red", "iso 13485", "tolerance: 0.1mm"). UFP applies what it can and reports what it could not; unresolvable terms are logged for vendor sourcing. Do not interrogate the user to fill this — pass what they said.
thickness_inNoNew sheet thickness in INCHES ("make it in 1/8" → 0.125) — a spec change: sheet lanes requote at the nearest stocked gauge, flagging the substitution when the match isn't close. Pass null to REMOVE a previously asked thickness — back to the material's default gauge
outdoor_ratedNo
max_budget_usdNo
sort_directionNoFlip a sort_by ordering: "desc" reverses the key's natural direction ("most expensive first" = sort_by "price" + "desc"). Only meaningful with sort_by
undo_last_stepNoGO BACK EXACTLY ONE STEP ("undo that", "go back", "put it back how it was"): the network restores the previous quote's stored spec and constraints EXACTLY — never reconstructed from conversation — and re-prices where needed. Send it ALONE (no other args besides quote_id); combining it with changes is rejected. The quote's steps[] names what each undo would take back — steps[0] is the newest. Undo resets the baseline like any unlabeled refine, so open comparison scenarios close. Undoing the original quote is rejected with honest wording — relay it
min_vendor_starsNoOnly vendors whose displayed review rating is at least this many stars (1-5); vendors with no reviews yet are excluded
min_vendor_reviewsNoOnly vendors with at least this many verified-purchase reviews
proven_spec_ordersNoOnly vendors with at least N completed orders for this exact process+material — "a vendor that prints PC reliably"
remove_requirementsNoTake back INDIVIDUAL requirements terms ("drop the anodized ask, keep the rest"): each listed term is removed from the quote's requirements by normalized match, the others stay. Unknown terms are ignored, never an error. Re-stating the requirements list can never drop a term (terms merge as a union) — this is the removal channel

TDQS

A4.8/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 — and it delivers extensively. It discloses which operations re-price (spec changes, constraint clears) versus which are instant (sorting, vendor/process filters), the max-4 scenario coexistence rule, undo's exact-restore semantics ('never reconstructed from conversation'), substitution notes for unstocked materials, unmatched vendor names being 'reported, never an error', and the ships_from exclusion rule for worldwide/unknown-origin vendors. This is unusually rich behavioral disclosure.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Information-dense but structurally poor: the description is one multi-hundred-word run-on paragraph stuffed with parentheticals ('no, I meant in sheet metal' → processes, 'only show A3D Manufacturing' → vendors). Every sentence carries real content, so nothing is wasted, but the lack of paragraph breaks or bullets, plus the 'GOING BACK is also this tool' section feeling like an afterthought, makes it hard for an agent to scan. For a 34-parameter tool some length is justified, but this could be organized far better.

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?

For an extremely complex tool (34 params, nested objects, no annotations, no output schema), nothing an agent needs is missing. It covers operation semantics, side-effect behavior (instant drops vs re-prices, warm vendor sessions), edge-case handling (undoing the original quote is 'rejected with honest wording'), and cross-references to other quote fields (steps[], color_shades_available, routing.ship_to) that partially compensate for the absent output schema. Remarkably complete.

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?

Schema coverage is 82% (high), so the baseline is 3, but the description adds meaning the schema structurally cannot: it classifies the 34 args into narrowing vs spec-change (material, color, quantities) vs presentation-only (sort_by, sort_order) vs revert (undo, clear, remove_requirements), and explains inter-param coupling (sort_label required with sort_order, undo must be sent alone, requirement terms merge as a union so remove_requirements is the only removal channel). The material-vs-requirements misclassification caution alone prevents a severe mis-invocation.

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+resource — 'Narrow an existing quote' — and enumerates the full operation families: constraint narrowing, spec changes, scenario comparison, sorting, and undo/clear. It distinguishes itself from siblings like get_fabrication_quote (which creates quotes) and finalize_quote/poll_quote by making clear this tool operates on an already-existing quote. An agent can tell exactly what this tool is for.

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?

Extremely explicit about when to use each path and what NOT to do: 'Changing material/quantity is a spec change, not a narrowing — pass it via the material/color/quantities args, NOT as a requirements term'; 'Send it ALONE... combining it with changes is rejected'. It also gives multi-step guidance, such as re-refining every active scenario label when narrowing processes. No other tool in this batch needs this much routing, and it is delivered.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

reply_to_makerReply to the makerAInspect

Send the user's answer to a question the maker (vendor) asked about a UFP order — get_order_status surfaces an open question when one is waiting. Confirm the answer with the user before sending. The network relays it: the maker sees plain text from the network account with the user's contact details and links stripped, so never include emails, phone numbers, or URLs the answer depends on.

ParametersJSON Schema
NameRequiredDescriptionDefault
messageYesThe user's answer, in their words — it is relayed to the maker
order_idYesThe UFP order the maker asked about (ord_…)

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It discloses that the message is relayed via the network account, that contact details and links are stripped, and warns against including them. This is significant behavioral context beyond a simple 'send'.

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, then usage guidance. Every clause adds value: the flow reference, the confirmation step, and the network sanitization warning. No wasted words.

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 absence of output schema, the description still provides enough context: when to use, how to use, and a critical behavioral caveat. It is complete for a two-parameter send action with strong usage guidelines.

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 the schema already documents both parameters. The description reinforces that message is in the user's words and relayed, but adds little beyond what the schema provides.

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 sends the user's answer to a maker's question about a UFP order. It references get_order_status, distinguishing this as the complementary action to surfacing the question.

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 instructs to confirm the answer with the user before sending and ties usage to get_order_status surfacing an open question. Also provides a clear exclusion: never include emails, phone numbers, or URLs the answer depends on.

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.

  1. 1 tool update
    • Addedget_shop_gauges
  2. 2 tool updates
    • Changedpreview_quote2 fields changed
      • changedInput schema / properties / color / description
        Previous value: -"New color for this part (spec change — lanes requote). Colour WORDS only ('black', 'green', 'clear'); the network resolves them to each maker's stocked shade, dye, filament or coating — never pass a material or a shade you invented. Pass null to REMOVE a previously asked color — back to vendor defaults"New value: +"New color for this part (spec change — lanes requote). Colour WORDS only ('black', 'green', 'clear'); the network resolves them to each maker's stocked shades, dyes, filaments or coatings — a family word ('blue') brings back EVERY stocked shade of it, and the quote's color_shades_available lists them — never pass a material or a shade you invented. Pass null to REMOVE a previously asked color — back to vendor defaults"
      • addedInput schema / properties / color_shades
        Added value: +{
        +  "anyOf": [
        +    {
        +      "items": {
        +        "maxLength": 48,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "maxItems": 64,
        +      "type": "array"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Narrow the board to these color SHADES exactly as the quote lists them (color_shades_available / \"Colors on this board\") — instant, nothing re-prices, the same quote id comes back with only those shades; pass null to show every shade again. Never invent a shade name."
        +}
    • Changedrefine_quote2 fields changed
      • changedInput schema / properties / color / description
        Previous value: -"New color for this part (spec change — lanes requote). Colour WORDS only ('black', 'green', 'clear'); the network resolves them to each maker's stocked shade, dye, filament or coating — never pass a material or a shade you invented. Pass null to REMOVE a previously asked color — back to vendor defaults"New value: +"New color for this part (spec change — lanes requote). Colour WORDS only ('black', 'green', 'clear'); the network resolves them to each maker's stocked shades, dyes, filaments or coatings — a family word ('blue') brings back EVERY stocked shade of it, and the quote's color_shades_available lists them — never pass a material or a shade you invented. Pass null to REMOVE a previously asked color — back to vendor defaults"
      • addedInput schema / properties / color_shades
        Added value: +{
        +  "anyOf": [
        +    {
        +      "items": {
        +        "maxLength": 48,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "maxItems": 64,
        +      "type": "array"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Narrow the board to these color SHADES exactly as the quote lists them (color_shades_available / \"Colors on this board\") — instant, nothing re-prices, the same quote id comes back with only those shades; pass null to show every shade again. Never invent a shade name."
        +}
  3. 3 tool updates
    • Changedget_fabrication_quote1 field changed
      • changedInput schema / properties / color / description
        Previous value: -"ONLY a color the user actually asked for — NEVER pick one for them. fdm_print: Filament color for fdm_print (e.g. black, red); resin_print: Resin color for resin_print (e.g. gray, white, black); powder_print: Powder part color: raw gray/white, or a dye (\"black\", \"dark blue\") — vendor-resolved; elastomer_print: Elastomer part color — VCJ parts ship raw; asks resolve with an honest substitution note; print: Print color ask (\"full color\", \"black and white\"). Vendors that only price full color note the substitution; apparel: Garment color for apparel (\"black\", \"heather gray\") — vendor-resolved"New value: +"ONLY a color the user actually asked for — NEVER pick one for them. fdm_print: Filament color for fdm_print (e.g. black, red); resin_print: Resin color for resin_print (e.g. gray, white, black); powder_print: Powder part color: raw gray/white, or a dye (\"black\", \"dark blue\") — vendor-resolved; elastomer_print: Elastomer part color — VCJ parts ship raw; asks resolve with an honest substitution note; cnc: Colour for cnc: with finish anodized it is the anodize colour, otherwise the stock's own colour (black Delrin, clear acrylic). Colour WORDS only; each maker resolves the shade and says what it landed on; laser_cut: Colour of the flat stock for laser_cut (black, clear, natural…). Colour WORDS only; each maker quotes the materials it stocks in that colour and drops the ones that cannot be it; print: Print color ask (\"full color\", \"black and white\"). Vendors that only price full color note the substitution; apparel: Garment color for apparel (\"black\", \"heather gray\") — vendor-resolved"
    • Changedpreview_quote1 field changed
      • changedInput schema / properties / color / description
        Previous value: -"New color for this part (spec change — lanes requote). Pass null to REMOVE a previously asked color — back to vendor defaults"New value: +"New color for this part (spec change — lanes requote). Colour WORDS only ('black', 'green', 'clear'); the network resolves them to each maker's stocked shade, dye, filament or coating — never pass a material or a shade you invented. Pass null to REMOVE a previously asked color — back to vendor defaults"
    • Changedrefine_quote1 field changed
      • changedInput schema / properties / color / description
        Previous value: -"New color for this part (spec change — lanes requote). Pass null to REMOVE a previously asked color — back to vendor defaults"New value: +"New color for this part (spec change — lanes requote). Colour WORDS only ('black', 'green', 'clear'); the network resolves them to each maker's stocked shade, dye, filament or coating — never pass a material or a shade you invented. Pass null to REMOVE a previously asked color — back to vendor defaults"
  4. 3 tool updates
    • Changedget_fabrication_quote2 fields changed
      • addedInput schema / properties / bends / items / properties / face_id
        Added value: +{
        +  "type": "integer"
        +}
      • addedInput schema / properties / bends / items / properties / source
        Added value: +{
        +  "enum": [
        +    "detected",
        +    "user"
        +  ],
        +  "type": "string"
        +}
    • Addedpreview_quote
    • Changedrefine_quote1 field changed
      • changedInput schema / properties / bends / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "not": {}
        -      },
        -      {
        -        "items": {
        -          "additionalProperties": false,
        -          "properties": {
        -            "angle_deg": {
        -              "exclusiveMaximum": 180,
        -              "exclusiveMinimum": 0,
        -              "type": "number"
        -            },
        -            "direction": {
        -              "enum": [
        -                "up",
        -                "down"
        -              ],
        -              "type": "string"
        -            },
        -            "id": {
        -              "maxLength": 32,
        -              "minLength": 1,
        -              "type": "string"
        -            },
        -            "line": {
        -              "additionalProperties": false,
        -              "properties": {
        -                "p1": {
        -                  "items": [
        -                    {
        -                      "type": "number"
        -                    },
        -                    {
        -                      "type": "number"
        -                    },
        -                    {
        -                      "type": "number"
        -                    }
        -                  ],
        -                  "maxItems": 3,
        -                  "minItems": 3,
        -                  "type": "array"
        -                },
        -                "p2": {
        -                  "items": [
        -                    {
        -                      "type": "number"
        -                    },
        -                    {
        -                      "type": "number"
        -                    },
        -                    {
        -                      "type": "number"
        -                    }
        -                  ],
        -                  "maxItems": 3,
        -                  "minItems": 3,
        -                  "type": "array"
        -                }
        -              },
        -              "required": [
        -                "p1",
        -                "p2"
        -              ],
        -              "type": "object"
        -            },
        -            "radius_mm": {
        -              "exclusiveMinimum": 0,
        -              "type": "number"
        -            }
        -          },
        -          "required": [
        -            "line",
        -            "angle_deg",
        -            "direction"
        -          ],
        -          "type": "object"
        -        },
        -        "maxItems": 50,
        -        "type": "array"
        -      }
        -    ],
        -    "description": "Sheet-metal bend lines, each as TWO POINTS in the part's own mm frame (flat DXF parts use z=0: a bend from (0,12.7) to (76.2,12.7) is p1 [0,12.7,0], p2 [76.2,12.7,0]). angle_deg is the target bend angle (90 = a right-angle flange), direction \"up\"/\"down\" is the fold direction relative to the flat pattern, radius_mm the requested inside radius (omit it — the shop resolves to its tooling and reports what it used). Pass these when the user articulates WHERE the bends go; a bare \"it has 2 bends\" is bend_count, not this."
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "anyOf": [
        +      {
        +        "not": {}
        +      },
        +      {
        +        "items": {
        +          "additionalProperties": false,
        +          "properties": {
        +            "angle_deg": {
        +              "exclusiveMaximum": 180,
        +              "exclusiveMinimum": 0,
        +              "type": "number"
        +            },
        +            "direction": {
        +              "enum": [
        +                "up",
        +                "down"
        +              ],
        +              "type": "string"
        +            },
        +            "face_id": {
        +              "type": "integer"
        +            },
        +            "id": {
        +              "maxLength": 32,
        +              "minLength": 1,
        +              "type": "string"
        +            },
        +            "line": {
        +              "additionalProperties": false,
        +              "properties": {
        +                "p1": {
        +                  "items": [
        +                    {
        +                      "type": "number"
        +                    },
        +                    {
        +                      "type": "number"
        +                    },
        +                    {
        +                      "type": "number"
        +                    }
        +                  ],
        +                  "maxItems": 3,
        +                  "minItems": 3,
        +                  "type": "array"
        +                },
        +                "p2": {
        +                  "items": [
        +                    {
        +                      "type": "number"
        +                    },
        +                    {
        +                      "type": "number"
        +                    },
        +                    {
        +                      "type": "number"
        +                    }
        +                  ],
        +                  "maxItems": 3,
        +                  "minItems": 3,
        +                  "type": "array"
        +                }
        +              },
        +              "required": [
        +                "p1",
        +                "p2"
        +              ],
        +              "type": "object"
        +            },
        +            "radius_mm": {
        +              "exclusiveMinimum": 0,
        +              "type": "number"
        +            },
        +            "source": {
        +              "enum": [
        +                "detected",
        +                "user"
        +              ],
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "line",
        +            "angle_deg",
        +            "direction"
        +          ],
        +          "type": "object"
        +        },
        +        "maxItems": 50,
        +        "type": "array"
        +      }
        +    ],
        +    "description": "Sheet-metal bend lines, each as TWO POINTS in the part's own mm frame (flat DXF parts use z=0: a bend from (0,12.7) to (76.2,12.7) is p1 [0,12.7,0], p2 [76.2,12.7,0]). angle_deg is the target bend angle (90 = a right-angle flange), direction \"up\"/\"down\" is the fold direction relative to the flat pattern, radius_mm the requested inside radius (omit it — the shop resolves to its tooling and reports what it used). Pass these when the user articulates WHERE the bends go; a bare \"it has 2 bends\" is bend_count, not this."
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
  5. 3 tool updates
    • Changedget_fabrication_quote4 fields changed
      • addedInput schema / properties / bends
        Added value: +{
        +  "description": "Sheet-metal bend lines, each as TWO POINTS in the part's own mm frame (flat DXF parts use z=0: a bend from (0,12.7) to (76.2,12.7) is p1 [0,12.7,0], p2 [76.2,12.7,0]). angle_deg is the target bend angle (90 = a right-angle flange), direction \"up\"/\"down\" is the fold direction relative to the flat pattern, radius_mm the requested inside radius (omit it — the shop resolves to its tooling and reports what it used). Pass these when the user articulates WHERE the bends go; a bare \"it has 2 bends\" is bend_count, not this.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "angle_deg": {
        +        "exclusiveMaximum": 180,
        +        "exclusiveMinimum": 0,
        +        "type": "number"
        +      },
        +      "direction": {
        +        "enum": [
        +          "up",
        +          "down"
        +        ],
        +        "type": "string"
        +      },
        +      "id": {
        +        "maxLength": 32,
        +        "minLength": 1,
        +        "type": "string"
        +      },
        +      "line": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "p1": {
        +            "items": [
        +              {
        +                "type": "number"
        +              },
        +              {
        +                "type": "number"
        +              },
        +              {
        +                "type": "number"
        +              }
        +            ],
        +            "maxItems": 3,
        +            "minItems": 3,
        +            "type": "array"
        +          },
        +          "p2": {
        +            "items": [
        +              {
        +                "type": "number"
        +              },
        +              {
        +                "type": "number"
        +              },
        +              {
        +                "type": "number"
        +              }
        +            ],
        +            "maxItems": 3,
        +            "minItems": 3,
        +            "type": "array"
        +          }
        +        },
        +        "required": [
        +          "p1",
        +          "p2"
        +        ],
        +        "type": "object"
        +      },
        +      "radius_mm": {
        +        "exclusiveMinimum": 0,
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "line",
        +      "angle_deg",
        +      "direction"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 50,
        +  "type": "array"
        +}
      • changedInput schema / properties / finish / description
        Previous value: -"cnc: CNC surface finish: standard|anodized|polished|bead_blasted (default standard); sheetmetal: as_cut (default) | deburred | powder_coat — powder coat protects mild steel for outdoor use"New value: +"cnc: CNC surface finish: standard|anodized|polished|bead_blasted (default standard); sheetmetal: as_cut (default) | deburred | anodized | powder_coat — anodized is aluminum-only; powder coat protects mild steel for outdoor use"
      • addedInput schema / properties / inserts
        Added value: +{
        +  "description": "PEM-style hardware inserts pressed into holes of a sheet-metal part — one record per hole. `insert` is the species (nut | flush_nut | standoff | blind_standoff | stud) and `thread` its size (\"M4\", \"1/4-20\"); both are required. When known, add length_mm (standoff/stud post length), the hole's center (located_at_mm, part's own mm frame), its axis, the drilled diameter, and `points` — the signed unit vector the insert's functional side faces (flip = negate). Pass these when the user asks for press-in nuts/standoffs/studs; vendors with a hardware service price them.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "axis": {
        +        "items": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "number"
        +          }
        +        ],
        +        "maxItems": 3,
        +        "minItems": 3,
        +        "type": "array"
        +      },
        +      "depth_mm": {
        +        "exclusiveMinimum": 0,
        +        "type": "number"
        +      },
        +      "drilled_diameter_mm": {
        +        "exclusiveMinimum": 0,
        +        "type": "number"
        +      },
        +      "face_id": {
        +        "type": "integer"
        +      },
        +      "hole": {
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "insert": {
        +        "enum": [
        +          "nut",
        +          "flush_nut",
        +          "standoff",
        +          "blind_standoff",
        +          "stud"
        +        ],
        +        "type": "string"
        +      },
        +      "length_mm": {
        +        "exclusiveMinimum": 0,
        +        "type": "number"
        +      },
        +      "located_at_mm": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "x": {
        +            "type": "number"
        +          },
        +          "y": {
        +            "type": "number"
        +          },
        +          "z": {
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "x",
        +          "y",
        +          "z"
        +        ],
        +        "type": "object"
        +      },
        +      "points": {
        +        "items": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "number"
        +          }
        +        ],
        +        "maxItems": 3,
        +        "minItems": 3,
        +        "type": "array"
        +      },
        +      "thread": {
        +        "maxLength": 32,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "insert",
        +      "thread"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 200,
        +  "type": "array"
        +}
      • addedInput schema / properties / tapping
        Added value: +{
        +  "description": "Tapped (threaded) holes for a sheet-metal part — one record per hole the user wants threads cut into. `thread` is the callout in the user's words (\"M6\", \"M4 x 0.7\", \"1/4-20\") and is all that's required; when known, add the hole's center in the part's own mm frame (located_at_mm), its unit axis, the pre-tap drilled diameter, and depth_mm so the shop taps the right hole. Pass these when the user asks for threaded/tapped holes; vendors with a tapping service price them.",
        +  "items": {
        +    "additionalProperties": false,
        +    "properties": {
        +      "axis": {
        +        "items": [
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "number"
        +          },
        +          {
        +            "type": "number"
        +          }
        +        ],
        +        "maxItems": 3,
        +        "minItems": 3,
        +        "type": "array"
        +      },
        +      "depth_mm": {
        +        "exclusiveMinimum": 0,
        +        "type": "number"
        +      },
        +      "drilled_diameter_mm": {
        +        "exclusiveMinimum": 0,
        +        "type": "number"
        +      },
        +      "face_id": {
        +        "type": "integer"
        +      },
        +      "hole": {
        +        "minimum": 1,
        +        "type": "integer"
        +      },
        +      "located_at_mm": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "x": {
        +            "type": "number"
        +          },
        +          "y": {
        +            "type": "number"
        +          },
        +          "z": {
        +            "type": "number"
        +          }
        +        },
        +        "required": [
        +          "x",
        +          "y",
        +          "z"
        +        ],
        +        "type": "object"
        +      },
        +      "thread": {
        +        "maxLength": 32,
        +        "minLength": 1,
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "thread"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 200,
        +  "type": "array"
        +}
    • Addedget_network_capabilities
    • Changedrefine_quote16 fields changed
      • addedInput schema / properties / bends
        Added value: +{
        +  "anyOf": [
        +    {
        +      "anyOf": [
        +        {
        +          "not": {}
        +        },
        +        {
        +          "items": {
        +            "additionalProperties": false,
        +            "properties": {
        +              "angle_deg": {
        +                "exclusiveMaximum": 180,
        +                "exclusiveMinimum": 0,
        +                "type": "number"
        +              },
        +              "direction": {
        +                "enum": [
        +                  "up",
        +                  "down"
        +                ],
        +                "type": "string"
        +              },
        +              "id": {
        +                "maxLength": 32,
        +                "minLength": 1,
        +                "type": "string"
        +              },
        +              "line": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "p1": {
        +                    "items": [
        +                      {
        +                        "type": "number"
        +                      },
        +                      {
        +                        "type": "number"
        +                      },
        +                      {
        +                        "type": "number"
        +                      }
        +                    ],
        +                    "maxItems": 3,
        +                    "minItems": 3,
        +                    "type": "array"
        +                  },
        +                  "p2": {
        +                    "items": [
        +                      {
        +                        "type": "number"
        +                      },
        +                      {
        +                        "type": "number"
        +                      },
        +                      {
        +                        "type": "number"
        +                      }
        +                    ],
        +                    "maxItems": 3,
        +                    "minItems": 3,
        +                    "type": "array"
        +                  }
        +                },
        +                "required": [
        +                  "p1",
        +                  "p2"
        +                ],
        +                "type": "object"
        +              },
        +              "radius_mm": {
        +                "exclusiveMinimum": 0,
        +                "type": "number"
        +              }
        +            },
        +            "required": [
        +              "line",
        +              "angle_deg",
        +              "direction"
        +            ],
        +            "type": "object"
        +          },
        +          "maxItems": 50,
        +          "type": "array"
        +        }
        +      ],
        +      "description": "Sheet-metal bend lines, each as TWO POINTS in the part's own mm frame (flat DXF parts use z=0: a bend from (0,12.7) to (76.2,12.7) is p1 [0,12.7,0], p2 [76.2,12.7,0]). angle_deg is the target bend angle (90 = a right-angle flange), direction \"up\"/\"down\" is the fold direction relative to the flat pattern, radius_mm the requested inside radius (omit it — the shop resolves to its tooling and reports what it used). Pass these when the user articulates WHERE the bends go; a bare \"it has 2 bends\" is bend_count, not this."
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "New bend records for this part — a spec change: sheet lanes requote with exactly these bends (the list REPLACES the previous one, never patches it). Same shape as on get_fabrication_quote: each bend is two points in the part's own mm frame (flat DXF parts use z=0) plus angle_deg, direction up|down, and an optional requested radius_mm. Pass null to REMOVE every articulated bend"
        +}
      • changedInput schema / properties / color / description
        Previous value: -"New color for this part (spec change — lanes requote)"New value: +"New color for this part (spec change — lanes requote). Pass null to REMOVE a previously asked color — back to vendor defaults"
      • changedInput schema / properties / color / type
        Previous value: -"string"New value: +[
        +  "string",
        +  "null"
        +]
      • changedInput schema / properties / finish / description
        Previous value: -"New surface finish (\"powder coat\", \"anodized\", \"bead blasted\") — a spec change: finish-capable lanes (sheet metal, CNC, metal print) requote WITH it; 3D-print lanes have no coating step, so they ignore the finish but keep the COLOR. A colored finish ask (\"black powder coat\") should set BOTH finish and color, so every lane lands on the buyer's color"New value: +"New surface finish (\"powder coat\", \"anodized\", \"bead blasted\") — a spec change: finish-capable lanes (sheet metal, CNC, metal print) requote WITH it; 3D-print lanes have no coating step, so they ignore the finish but keep the COLOR. A colored finish ask (\"black powder coat\") should set BOTH finish and color, so every lane lands on the buyer's color. Pass null to REMOVE a previously asked finish"
      • changedInput schema / properties / finish / type
        Previous value: -"string"New value: +[
        +  "string",
        +  "null"
        +]
      • addedInput schema / properties / inserts
        Added value: +{
        +  "anyOf": [
        +    {
        +      "anyOf": [
        +        {
        +          "not": {}
        +        },
        +        {
        +          "items": {
        +            "additionalProperties": false,
        +            "properties": {
        +              "axis": {
        +                "items": [
        +                  {
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "number"
        +                  }
        +                ],
        +                "maxItems": 3,
        +                "minItems": 3,
        +                "type": "array"
        +              },
        +              "depth_mm": {
        +                "exclusiveMinimum": 0,
        +                "type": "number"
        +              },
        +              "drilled_diameter_mm": {
        +                "exclusiveMinimum": 0,
        +                "type": "number"
        +              },
        +              "face_id": {
        +                "type": "integer"
        +              },
        +              "hole": {
        +                "minimum": 1,
        +                "type": "integer"
        +              },
        +              "insert": {
        +                "enum": [
        +                  "nut",
        +                  "flush_nut",
        +                  "standoff",
        +                  "blind_standoff",
        +                  "stud"
        +                ],
        +                "type": "string"
        +              },
        +              "length_mm": {
        +                "exclusiveMinimum": 0,
        +                "type": "number"
        +              },
        +              "located_at_mm": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "x": {
        +                    "type": "number"
        +                  },
        +                  "y": {
        +                    "type": "number"
        +                  },
        +                  "z": {
        +                    "type": "number"
        +                  }
        +                },
        +                "required": [
        +                  "x",
        +                  "y",
        +                  "z"
        +                ],
        +                "type": "object"
        +              },
        +              "points": {
        +                "items": [
        +                  {
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "number"
        +                  }
        +                ],
        +                "maxItems": 3,
        +                "minItems": 3,
        +                "type": "array"
        +              },
        +              "thread": {
        +                "maxLength": 32,
        +                "minLength": 1,
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "insert",
        +              "thread"
        +            ],
        +            "type": "object"
        +          },
        +          "maxItems": 200,
        +          "type": "array"
        +        }
        +      ],
        +      "description": "PEM-style hardware inserts pressed into holes of a sheet-metal part — one record per hole. `insert` is the species (nut | flush_nut | standoff | blind_standoff | stud) and `thread` its size (\"M4\", \"1/4-20\"); both are required. When known, add length_mm (standoff/stud post length), the hole's center (located_at_mm, part's own mm frame), its axis, the drilled diameter, and `points` — the signed unit vector the insert's functional side faces (flip = negate). Pass these when the user asks for press-in nuts/standoffs/studs; vendors with a hardware service price them."
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "New hardware-insert records for this part — a spec change: sheet lanes requote with exactly these inserts (the list REPLACES the previous one, never patches it). Same shape as on get_fabrication_quote: species (nut|flush_nut|standoff|blind_standoff|stud) and thread required, hole geometry optional. Pass null to REMOVE every insert"
        +}
      • changedInput schema / properties / material / description
        Previous value: -"New material for this part (\"I need it in PLA\" → \"pla\"). A spec change: lanes requote with this material through warm vendor sessions; an explicit material here replaces the quote's material fan-out. Free-form — unstocked asks resolve to the closest stocked material with a substitution note. Do NOT pass material changes as requirements terms"New value: +"New material for this part (\"I need it in PLA\" → \"pla\"). A spec change: lanes requote with this material through warm vendor sessions; an explicit material here replaces the quote's material fan-out. Free-form — unstocked asks resolve to the closest stocked material with a substitution note. Do NOT pass material changes as requirements terms. Pass null to REMOVE a previously asked material (\"forget the aluminum ask\") — the ask comes off the record and the process-default material fan returns"
      • changedInput schema / properties / material / type
        Previous value: -"string"New value: +[
        +  "string",
        +  "null"
        +]
      • addedInput schema / properties / quantities / anyOf
        Added value: +[
        +  {
        +    "items": {
        +      "exclusiveMinimum": 0,
        +      "type": "integer"
        +    },
        +    "maxItems": 5,
        +    "type": "array"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedInput schema / properties / quantities / description
        Previous value: -"New quantities the user wants (spec change — lanes requote at the new quantity). Same rules as on get_fabrication_quote: pass the real ask, never inflate it"New value: +"New quantities the user wants (spec change — lanes requote at the new quantity). Same rules as on get_fabrication_quote: pass the real ask, never inflate it. Pass null to REMOVE a previously asked quantity — the quote returns to single-part pricing"
      • removedInput schema / properties / quantities / items
        Removed value: -{
        -  "exclusiveMinimum": 0,
        -  "type": "integer"
        -}
      • removedInput schema / properties / quantities / maxItems
        Removed value: -5
      • removedInput schema / properties / quantities / type
        Removed value: -"array"
      • addedInput schema / properties / scale
        Added value: +{
        +  "additionalProperties": false,
        +  "description": "Rescale the DESIGN ITSELF before re-quoting: per-axis stretch factors over the file's current geometry (\"make it 2x bigger\" = {\"x\":2,\"y\":2,\"z\":2}). Mesh designs are genuinely converted — the child quote prices a rescaled file; STEP/IGES designs keep their original file with the dimensions riding as callouts (pass those too). {1,1,1} is a no-op",
        +  "properties": {
        +    "x": {
        +      "maximum": 100,
        +      "minimum": 0.01,
        +      "type": "number"
        +    },
        +    "y": {
        +      "maximum": 100,
        +      "minimum": 0.01,
        +      "type": "number"
        +    },
        +    "z": {
        +      "maximum": 100,
        +      "minimum": 0.01,
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "x",
        +    "y",
        +    "z"
        +  ],
        +  "type": "object"
        +}
      • addedInput schema / properties / tapping
        Added value: +{
        +  "anyOf": [
        +    {
        +      "anyOf": [
        +        {
        +          "not": {}
        +        },
        +        {
        +          "items": {
        +            "additionalProperties": false,
        +            "properties": {
        +              "axis": {
        +                "items": [
        +                  {
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "number"
        +                  },
        +                  {
        +                    "type": "number"
        +                  }
        +                ],
        +                "maxItems": 3,
        +                "minItems": 3,
        +                "type": "array"
        +              },
        +              "depth_mm": {
        +                "exclusiveMinimum": 0,
        +                "type": "number"
        +              },
        +              "drilled_diameter_mm": {
        +                "exclusiveMinimum": 0,
        +                "type": "number"
        +              },
        +              "face_id": {
        +                "type": "integer"
        +              },
        +              "hole": {
        +                "minimum": 1,
        +                "type": "integer"
        +              },
        +              "located_at_mm": {
        +                "additionalProperties": false,
        +                "properties": {
        +                  "x": {
        +                    "type": "number"
        +                  },
        +                  "y": {
        +                    "type": "number"
        +                  },
        +                  "z": {
        +                    "type": "number"
        +                  }
        +                },
        +                "required": [
        +                  "x",
        +                  "y",
        +                  "z"
        +                ],
        +                "type": "object"
        +              },
        +              "thread": {
        +                "maxLength": 32,
        +                "minLength": 1,
        +                "type": "string"
        +              }
        +            },
        +            "required": [
        +              "thread"
        +            ],
        +            "type": "object"
        +          },
        +          "maxItems": 200,
        +          "type": "array"
        +        }
        +      ],
        +      "description": "Tapped (threaded) holes for a sheet-metal part — one record per hole the user wants threads cut into. `thread` is the callout in the user's words (\"M6\", \"M4 x 0.7\", \"1/4-20\") and is all that's required; when known, add the hole's center in the part's own mm frame (located_at_mm), its unit axis, the pre-tap drilled diameter, and depth_mm so the shop taps the right hole. Pass these when the user asks for threaded/tapped holes; vendors with a tapping service price them."
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "New tapped-hole records for this part — a spec change: sheet lanes requote with exactly these taps (the list REPLACES the previous one, never patches it). Same shape as on get_fabrication_quote: thread callout (\"M6\", \"1/4-20\") required, hole geometry optional. Pass null to REMOVE every tap"
        +}
      • addedInput schema / properties / thickness_in
        Added value: +{
        +  "anyOf": [
        +    {
        +      "exclusiveMinimum": 0,
        +      "maximum": 1,
        +      "type": "number"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "New sheet thickness in INCHES (\"make it in 1/8\" → 0.125) — a spec change: sheet lanes requote at the nearest stocked gauge, flagging the substitution when the match isn't close. Pass null to REMOVE a previously asked thickness — back to the material's default gauge"
        +}
  6. 1 tool update
    • Changedcreate_checkout1 field changed
      • addedInput schema / properties / coupon_code
        Added value: +{
        +  "description": "Coupon code, only if the user provided one (early-adopter codes from the AFN team). Case-insensitive. The discount appears on the payment page; a 100%-off code makes the total $0 with no card required. Never invent or guess a code.",
        +  "type": "string"
        +}
  7. 1 tool update
    • Changedrefine_quote3 fields changed
      • addedInput schema / properties / clear
        Added value: +{
        +  "description": "REMOVE constraints entirely (\"drop the deadline\", \"forget the budget\", \"no more food-safe requirement\"): list the constraints to clear and each is removed from the quote — the one deliberate widening besides undo. Clearing a deadline or budget answers instantly from held offers (near-misses convert back); clearing an attribute/reliability/requirements demand re-prices honestly. Same effect as [\"any\"] on the three filter args, extended to every constraint",
        +  "items": {
        +    "enum": [
        +      "deadline",
        +      "budget",
        +      "outdoor_rated",
        +      "submersible",
        +      "high_temp",
        +      "food_safe",
        +      "reliability",
        +      "requirements",
        +      "processes",
        +      "ships_from",
        +      "vendors"
        +    ],
        +    "type": "string"
        +  },
        +  "minItems": 1,
        +  "type": "array"
        +}
      • addedInput schema / properties / remove_requirements
        Added value: +{
        +  "description": "Take back INDIVIDUAL requirements terms (\"drop the anodized ask, keep the rest\"): each listed term is removed from the quote's requirements by normalized match, the others stay. Unknown terms are ignored, never an error. Re-stating the requirements list can never drop a term (terms merge as a union) — this is the removal channel",
        +  "items": {
        +    "maxLength": 120,
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "maxItems": 20,
        +  "minItems": 1,
        +  "type": "array"
        +}
      • addedInput schema / properties / undo_last_step
        Added value: +{
        +  "description": "GO BACK EXACTLY ONE STEP (\"undo that\", \"go back\", \"put it back how it was\"): the network restores the previous quote's stored spec and constraints EXACTLY — never reconstructed from conversation — and re-prices where needed. Send it ALONE (no other args besides quote_id); combining it with changes is rejected. The quote's steps[] names what each undo would take back — steps[0] is the newest. Undo resets the baseline like any unlabeled refine, so open comparison scenarios close. Undoing the original quote is rejected with honest wording — relay it",
        +  "type": "boolean"
        +}
  8. 1 tool update
    • Changedget_fabrication_quote6 fields changed
      • changedInput schema / properties / color / description
        Previous value: -"ONLY a color the user actually asked for — NEVER pick one for them. fdm_print: Filament color for fdm_print (e.g. black, red); resin_print: Resin color for resin_print (e.g. gray, white, black); powder_print: Powder part color: raw gray/white, or a dye (\"black\", \"dark blue\") — vendor-resolved; print: Print color ask (\"full color\", \"black and white\"). Vendors that only price full color note the substitution; apparel: Garment color for apparel (\"black\", \"heather gray\") — vendor-resolved"New value: +"ONLY a color the user actually asked for — NEVER pick one for them. fdm_print: Filament color for fdm_print (e.g. black, red); resin_print: Resin color for resin_print (e.g. gray, white, black); powder_print: Powder part color: raw gray/white, or a dye (\"black\", \"dark blue\") — vendor-resolved; elastomer_print: Elastomer part color — VCJ parts ship raw; asks resolve with an honest substitution note; print: Print color ask (\"full color\", \"black and white\"). Vendors that only price full color note the substitution; apparel: Garment color for apparel (\"black\", \"heather gray\") — vendor-resolved"
      • addedInput schema / properties / elastomer_finish
        Added value: +{
        +  "description": "Elastomer post-processing: as_printed (VCJ parts ship raw — the whole lane today)",
        +  "type": "string"
        +}
      • addedInput schema / properties / elastomer_technology
        Added value: +{
        +  "description": "Elastomer process: vapor_cure_jetting (VCJ). Omit to let the vendor pick its default lane for the material",
        +  "type": "string"
        +}
      • changedInput schema / properties / material / description
        Previous value: -"ONLY a material the user actually asked for — NEVER guess or default one (a silent \"pla\" on a bare file drop prunes every maker that does not stock it; OMIT instead and each process quotes across its stocked materials so every maker can bid). fdm_print: pla|petg|asa (free-form — \"abs\", \"polycarbonate\" asks resolve to the closest stocked filament with a substitution note); resin_print: standard|tough|high_temp|high_detail resin (free-form asks resolve to the closest supported resin); powder_print: Powder-bed nylon: nylon_12|nylon_12_smooth|nylon_11|nylon_12_gf|nylon_12_esd|tpu (free-form — \"PA12\", \"glass filled\" resolve to the closest stocked powder); cnc: aluminum_6061|aluminum_7075|stainless_304|titanium|brass|acetal|delrin|abs|nylon_pa6|peek|acrylic (free-form asks resolve to the closest supported stock); sheetmetal: mild_steel|aluminum_5052|stainless_304 (free-form — \"steel\", \"5052\", \"stainless\" resolve; unknown asks get closest-match offers). Omit to compare the defaults; laser_cut: acrylic|plywood|mdf|delrin|uhmw|hdpe|g10|carbon_fiber|mild_steel|aluminum_5052|stainless_304 (free-form — \"plexiglass\", \"birch\" resolve; unknown asks get closest-match offers); decal: vinyl|holographic|transparent|glitter (free-form — \"chrome\" etc. gets closest matches)"New value: +"ONLY a material the user actually asked for — NEVER guess or default one (a silent \"pla\" on a bare file drop prunes every maker that does not stock it; OMIT instead and each process quotes across its stocked materials so every maker can bid). fdm_print: pla|petg|asa (free-form — \"abs\", \"polycarbonate\" asks resolve to the closest stocked filament with a substitution note); resin_print: standard|tough|high_temp|high_detail resin (free-form asks resolve to the closest supported resin); powder_print: Powder-bed nylon: nylon_12|nylon_12_smooth|nylon_11|nylon_12_gf|nylon_12_esd|nylon_12_white|nylon_pa2200|nylon_12_sls|tpu (free-form — \"PA12\", \"glass filled\" resolve to the closest stocked powder); elastomer_print: Jetted elastomer: tepu_30a|tepu_50a (free-form — \"TPU\", \"soft rubber\" resolve to the closest stocked durometer); cnc: aluminum_6061|aluminum_7075|stainless_304|titanium|brass|acetal|delrin|abs|nylon_pa6|peek|acrylic (free-form asks resolve to the closest supported stock); sheetmetal: mild_steel|aluminum_5052|stainless_304 (free-form — \"steel\", \"5052\", \"stainless\" resolve; unknown asks get closest-match offers). Omit to compare the defaults; laser_cut: acrylic|plywood|mdf|delrin|uhmw|hdpe|g10|carbon_fiber|mild_steel|aluminum_5052|stainless_304 (free-form — \"plexiglass\", \"birch\" resolve; unknown asks get closest-match offers); decal: vinyl|holographic|transparent|glitter (free-form — \"chrome\" etc. gets closest matches)"
      • changedInput schema / properties / process / enum
        Previous value: -[
        -  "fdm_print",
        -  "resin_print",
        -  "powder_print",
        -  "metal_print",
        -  "cnc",
        -  "sheetmetal",
        -  "laser_cut",
        -  "decal",
        -  "print",
        -  "apparel"
        -]New value: +[
        +  "fdm_print",
        +  "resin_print",
        +  "powder_print",
        +  "metal_print",
        +  "elastomer_print",
        +  "cnc",
        +  "sheetmetal",
        +  "laser_cut",
        +  "decal",
        +  "print",
        +  "apparel"
        +]
      • addedInput schema / properties / shore_a
        Added value: +{
        +  "description": "Numeric Shore A durometer ask (10-95, e.g. 40). Resolved to the NEAREST stocked durometer with a substitution note — never a silent swap",
        +  "exclusiveMinimum": 0,
        +  "type": "number"
        +}
  9. 1 tool update
    • Changedget_fabrication_quote2 fields changed
      • changedInput schema / properties / color / description
        Previous value: -"fdm_print: Filament color for fdm_print (e.g. black, red); resin_print: Resin color for resin_print (e.g. gray, white, black); powder_print: Powder part color: raw gray/white, or a dye (\"black\", \"dark blue\") — vendor-resolved; print: Print color ask (\"full color\", \"black and white\"). Vendors that only price full color note the substitution; apparel: Garment color for apparel (\"black\", \"heather gray\") — vendor-resolved"New value: +"ONLY a color the user actually asked for — NEVER pick one for them. fdm_print: Filament color for fdm_print (e.g. black, red); resin_print: Resin color for resin_print (e.g. gray, white, black); powder_print: Powder part color: raw gray/white, or a dye (\"black\", \"dark blue\") — vendor-resolved; print: Print color ask (\"full color\", \"black and white\"). Vendors that only price full color note the substitution; apparel: Garment color for apparel (\"black\", \"heather gray\") — vendor-resolved"
      • changedInput schema / properties / material / description
        Previous value: -"fdm_print: pla|petg|asa (free-form — \"abs\", \"polycarbonate\" asks resolve to the closest stocked filament with a substitution note); resin_print: standard|tough|high_temp|high_detail resin (free-form asks resolve to the closest supported resin); powder_print: Powder-bed nylon: nylon_12|nylon_12_smooth|nylon_11|nylon_12_gf|nylon_12_esd|tpu (free-form — \"PA12\", \"glass filled\" resolve to the closest stocked powder); cnc: aluminum_6061|aluminum_7075|stainless_304|titanium|brass|acetal|delrin|abs|nylon_pa6|peek|acrylic (free-form asks resolve to the closest supported stock); sheetmetal: mild_steel|aluminum_5052|stainless_304 (free-form — \"steel\", \"5052\", \"stainless\" resolve; unknown asks get closest-match offers). Omit to compare the defaults; laser_cut: acrylic|plywood|mdf|delrin|uhmw|hdpe|g10|carbon_fiber|mild_steel|aluminum_5052|stainless_304 (free-form — \"plexiglass\", \"birch\" resolve; unknown asks get closest-match offers); decal: vinyl|holographic|transparent|glitter (free-form — \"chrome\" etc. gets closest matches)"New value: +"ONLY a material the user actually asked for — NEVER guess or default one (a silent \"pla\" on a bare file drop prunes every maker that does not stock it; OMIT instead and each process quotes across its stocked materials so every maker can bid). fdm_print: pla|petg|asa (free-form — \"abs\", \"polycarbonate\" asks resolve to the closest stocked filament with a substitution note); resin_print: standard|tough|high_temp|high_detail resin (free-form asks resolve to the closest supported resin); powder_print: Powder-bed nylon: nylon_12|nylon_12_smooth|nylon_11|nylon_12_gf|nylon_12_esd|tpu (free-form — \"PA12\", \"glass filled\" resolve to the closest stocked powder); cnc: aluminum_6061|aluminum_7075|stainless_304|titanium|brass|acetal|delrin|abs|nylon_pa6|peek|acrylic (free-form asks resolve to the closest supported stock); sheetmetal: mild_steel|aluminum_5052|stainless_304 (free-form — \"steel\", \"5052\", \"stainless\" resolve; unknown asks get closest-match offers). Omit to compare the defaults; laser_cut: acrylic|plywood|mdf|delrin|uhmw|hdpe|g10|carbon_fiber|mild_steel|aluminum_5052|stainless_304 (free-form — \"plexiglass\", \"birch\" resolve; unknown asks get closest-match offers); decal: vinyl|holographic|transparent|glitter (free-form — \"chrome\" etc. gets closest matches)"
  10. 1 tool update
    • Changedget_fabrication_quote5 fields changed
      • changedInput schema / properties / color / description
        Previous value: -"fdm_print: Filament color for fdm_print (e.g. black, red); resin_print: Resin color for resin_print (e.g. gray, white, black); print: Print color ask (\"full color\", \"black and white\"). Vendors that only price full color note the substitution; apparel: Garment color for apparel (\"black\", \"heather gray\") — vendor-resolved"New value: +"fdm_print: Filament color for fdm_print (e.g. black, red); resin_print: Resin color for resin_print (e.g. gray, white, black); powder_print: Powder part color: raw gray/white, or a dye (\"black\", \"dark blue\") — vendor-resolved; print: Print color ask (\"full color\", \"black and white\"). Vendors that only price full color note the substitution; apparel: Garment color for apparel (\"black\", \"heather gray\") — vendor-resolved"
      • changedInput schema / properties / material / description
        Previous value: -"fdm_print: pla|petg|asa (free-form — \"abs\", \"polycarbonate\" asks resolve to the closest stocked filament with a substitution note); resin_print: standard|tough|high_temp|high_detail resin (free-form asks resolve to the closest supported resin); cnc: aluminum_6061|aluminum_7075|stainless_304|titanium|brass|acetal|delrin|abs|nylon_pa6|peek|acrylic (free-form asks resolve to the closest supported stock); sheetmetal: mild_steel|aluminum_5052|stainless_304 (free-form — \"steel\", \"5052\", \"stainless\" resolve; unknown asks get closest-match offers). Omit to compare the defaults; laser_cut: acrylic|plywood|mdf|delrin|uhmw|hdpe|g10|carbon_fiber|mild_steel|aluminum_5052|stainless_304 (free-form — \"plexiglass\", \"birch\" resolve; unknown asks get closest-match offers); decal: vinyl|holographic|transparent|glitter (free-form — \"chrome\" etc. gets closest matches)"New value: +"fdm_print: pla|petg|asa (free-form — \"abs\", \"polycarbonate\" asks resolve to the closest stocked filament with a substitution note); resin_print: standard|tough|high_temp|high_detail resin (free-form asks resolve to the closest supported resin); powder_print: Powder-bed nylon: nylon_12|nylon_12_smooth|nylon_11|nylon_12_gf|nylon_12_esd|tpu (free-form — \"PA12\", \"glass filled\" resolve to the closest stocked powder); cnc: aluminum_6061|aluminum_7075|stainless_304|titanium|brass|acetal|delrin|abs|nylon_pa6|peek|acrylic (free-form asks resolve to the closest supported stock); sheetmetal: mild_steel|aluminum_5052|stainless_304 (free-form — \"steel\", \"5052\", \"stainless\" resolve; unknown asks get closest-match offers). Omit to compare the defaults; laser_cut: acrylic|plywood|mdf|delrin|uhmw|hdpe|g10|carbon_fiber|mild_steel|aluminum_5052|stainless_304 (free-form — \"plexiglass\", \"birch\" resolve; unknown asks get closest-match offers); decal: vinyl|holographic|transparent|glitter (free-form — \"chrome\" etc. gets closest matches)"
      • addedInput schema / properties / powder_finish
        Added value: +{
        +  "description": "Powder post-processing: as_printed (raw powder surface) | vapor_polished | polished",
        +  "type": "string"
        +}
      • addedInput schema / properties / powder_technology
        Added value: +{
        +  "description": "Powder process: mjf (HP Multi Jet Fusion) | sls (laser sintering). Omit to let the vendor pick its default lane for the material",
        +  "type": "string"
        +}
      • changedInput schema / properties / process / enum
        Previous value: -[
        -  "fdm_print",
        -  "resin_print",
        -  "metal_print",
        -  "cnc",
        -  "sheetmetal",
        -  "laser_cut",
        -  "decal",
        -  "print",
        -  "apparel"
        -]New value: +[
        +  "fdm_print",
        +  "resin_print",
        +  "powder_print",
        +  "metal_print",
        +  "cnc",
        +  "sheetmetal",
        +  "laser_cut",
        +  "decal",
        +  "print",
        +  "apparel"
        +]
  11. 3 tool updates
    • Changedget_fabrication_quote1 field changed
      • addedInput schema / properties / vendors
        Added value: +{
        +  "description": "Only these specific vendors/makers (\"just quote Slant 3D\") — an INCLUDE list of vendor names as they appear on offers. Friendly names accepted (\"A3D\", \"slant 3d\"); unmatched names are reported, never an error. Usually OMIT: pass it only when the user explicitly names the vendors they want",
        +  "items": {
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "maxItems": 16,
        +  "type": "array"
        +}
    • Changedrefine_quote1 field changed
      • addedInput schema / properties / vendors
        Added value: +{
        +  "description": "Only these specific vendors/makers (\"only show A3D Manufacturing\", \"just Slant 3D and Fictiv\") — an INCLUDE list of vendor names as they appear on offers. A CONSTRAINT like processes: other vendors' offers drop instantly (nothing re-prices), further refines inherit the filter, and [\"any\"] clears it to show every vendor again. Friendly names accepted (\"A3D\", \"slant 3d\"); unmatched names are reported, never an error. This is THE way to answer \"show me everything vendor X offers\" — the filtered quote lists that vendor's complete lineup",
        +  "items": {
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "maxItems": 16,
        +  "type": "array"
        +}
    • Addedreply_to_maker
  12. 2 tool updates
    • Changedget_fabrication_quote1 field changed
      • addedInput schema / properties / ships_from
        Added value: +{
        +  "description": "Only vendors that ship from these countries/regions (\"only US vendors\", \"keep it domestic\") — an INCLUDE list. Friendly terms accepted (\"US\", \"Europe\", \"Germany\", \"China\", \"UK\"); unmappable terms are reported, never an error. Vendors whose origin is unknown or whose network is worldwide (origin not guaranteed) are excluded, each with a note saying why. Usually OMIT: pass it only when the user explicitly limits where vendors ship from",
        +  "items": {
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "maxItems": 8,
        +  "type": "array"
        +}
    • Changedrefine_quote1 field changed
      • addedInput schema / properties / ships_from
        Added value: +{
        +  "description": "Only vendors that ship from these countries/regions (\"only US vendors\", \"just European shops\", \"keep it domestic\") — an INCLUDE list naming where the user DOES want vendors from. A CONSTRAINT like processes: non-matching vendors drop instantly (nothing re-prices), further refines inherit the filter, and [\"any\"] clears it to show vendors everywhere again. Friendly terms accepted (\"US\", \"Europe\", \"Germany\", \"China\", \"UK\"). Vendors whose origin is unknown or whose network is worldwide (a specific origin cannot be guaranteed) are excluded, each with an honest note. For \"nothing from X\" asks, pass the regions the user does want instead",
        +  "items": {
        +    "minLength": 1,
        +    "type": "string"
        +  },
        +  "maxItems": 8,
        +  "type": "array"
        +}
  13. 1 tool update
    • Changedrefine_quote1 field changed
      • addedInput schema / properties / finish
        Added value: +{
        +  "description": "New surface finish (\"powder coat\", \"anodized\", \"bead blasted\") — a spec change: finish-capable lanes (sheet metal, CNC, metal print) requote WITH it; 3D-print lanes have no coating step, so they ignore the finish but keep the COLOR. A colored finish ask (\"black powder coat\") should set BOTH finish and color, so every lane lands on the buyer's color",
        +  "type": "string"
        +}

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    C
    maintenance
    Enables sending local 3D print files to PrintYourDuck for manual quote review, including file discovery, upload, and status checking.
    4
    48 npm
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables agents to request physical-world tasks such as 3D printing, CNC fabrication, assembly, measurement, testing, on-site verification, and receive-repack-ship services from a human operator, with fixed-price quotes, status tracking, and evidence packages.
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    Enables generating parametric 3D-printable parts from OpenSCAD/CadQuery models, exporting STL/3MF files, running DFM checks, and retrieving Bambu X1 Carbon starting profile notes.
    8
    MIT
Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources