이 MCP로 할 수 있는 일
Calculates parametric civil-engineering quantities and Bills of Quantities for drainage, earthworks, retaining walls, pavements, foundations, and related infrastructure assemblies.
도구
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'quantity': {'type': 'integer', 'default': 1}, 'wall_form': {'enum': ['insitu_rc', 'king_post', 'sheet_piled'], 'type': 'string', 'default': 'insitu_rc', 'description': 'Structural form of the anchored retaining wall.\n\nINSITU_RC â\x80\x94 Continuous in-situ reinforced concrete stem with a\n continuous waling beam (typically at the wall head;\n multi-row anchored walls have a waling at each anchor\n level). Anchors penetrate the stem and are stressed\n against the waling. Routes the stem to CESMM4 F.6.4 /\n NRM2 11.3.4 / MMHW 1700.4.3 / SMM7 E10.3.3.\n\nKING_POST â\x80\x94 Steel H-section (UC or UB) "king posts" or "soldier\n piles" driven or socketed at regular centres\n (typically 2.0-3.0 m c/c), with horizontal timber\n or precast concrete lagging panels between. A\n continuous RC waling beam runs at the head (and at\n each anchor row if multi-row) transferring the anchor\n loads to the king posts. King posts â\x86\x92 CESMM4 P.5 /\n NRM2 7.3 / MMHW 1600.3 / SMM7 D32. Lagging â\x86\x92\n CESMM4 O.3 (timber) or F.6.4 (precast concrete) /\n NRM2 16.4 (timber) or 13 (precast) / MMHW 2500.7\n (timber) or 1700.4.3 (precast) / SMM7 G20.1 (timber)\n or E50 (precast).\n\nSHEET_PILED â\x80\x94 Driven steel sheet piles (Larssen LX, AZ, GU\n profiles) forming a continuous wall, with a\n continuous RC waling at the head. Sheet pile toe\n drives below the excavation formation to provide\n passive resistance; anchor loads at the head are\n restrained back. Sheet piles â\x86\x92 CESMM4 P.4 /\n NRM2 7.4 / MMHW 1600.4 / SMM7 D31.'}, 'toe_length': {'type': 'number', 'default': 0.0}, 'anchor_rows': {'type': 'integer', 'default': 1}, 'stem_height': {'type': 'number', 'default': 6.0}, 'wall_length': {'type': 'number', 'default': 25.0}, 'lagging_type': {'enum': ['timber', 'precast_conc'], 'type': 'string', 'default': 'timber', 'description': 'For KING_POST variant: timber or precast concrete lagging.\n\nTIMBER â\x80\x94 Horizontal timber boards (C24 or similar) between\n king-post flanges. Lower cost; permitted only for\n temporary works and certain permanent applications\n where durability allows (creosote treatment etc.).\nPRECAST_CONC â\x80\x94 Precast concrete lagging panels between king-post\n flanges. Used for permanent works where timber\n is not acceptable. More expensive than timber.\n\nOnly relevant when wall_form == KING_POST. Ignored otherwise.'}, 'backfill_class': {'type': 'string', 'default': 'Class 6N'}, 'base_thickness': {'type': 'number', 'default': 0.0}, 'blinding_grade': {'type': 'string', 'default': 'C8/10'}, 'concrete_grade': {'type': 'string', 'default': 'C32/40'}, 'drain_diameter': {'type': 'number', 'default': 0.15}, 'stem_thickness': {'type': 'number', 'default': 0.5}, 'king_post_grade': {'type': 'string', 'default': 'S355'}, 'retained_height': {'type': 'number', 'default': 5.5}, 'anchor_test_type': {'type': 'string', 'default': 'proof'}, 'include_drainage': {'type': 'boolean', 'default': True}, 'sheet_pile_grade': {'type': 'string', 'default': 'S355GP'}, 'anchor_permanence': {'enum': ['permanent', 'temporary'], 'type': 'string', 'default': 'permanent', 'description': 'Permanent or temporary anchor classification per BS EN 1537.\n\nPERMANENT â\x80\x94 Design life >= 2 years; tendons require double\n corrosion protection (DCP) per BS EN 1537 Table 1.\n Stressing forces locked off and retained for life.\nTEMPORARY â\x80\x94 Design life < 2 years (typically supporting basement\n excavation until permanent structure is built).\n Single corrosion protection (SCP) acceptable.\n Often de-stressed and tendons cropped on completion.'}, 'excavation_batter': {'type': 'number', 'default': 0.0}, 'king_post_section': {'type': 'string', 'default': 'UC 305Ã\x97305Ã\x9797'}, 'anchor_tendon_type': {'type': 'string', 'default': 'strand'}, 'excavation_support': {'enum': ['open_batter', 'vertical'], 'type': 'string', 'default': 'vertical', 'description': 'Excavation support strategy for below-ground assemblies.\n\nConsumed by retaining walls (cantilever, gravity, counterfort,\nanchored, bored pile), foundation assemblies, and drainage chambers\nthat involve a battered or vertical-supported pit. The enum value is\nsurfaced in the description text of the relevant excavation BoQ line\nand in some standards (CESMM4 E.4.4 et seq.) drives a separate code.'}, 'include_geotextile': {'type': 'boolean', 'default': True}, 'sheet_pile_profile': {'type': 'string', 'default': 'Larssen LX-20'}, 'king_post_spacing_m': {'type': 'number', 'default': 2.5}, 'anchor_free_length_m': {'type': 'number', 'default': 6.0}, 'formation_below_base': {'type': 'number', 'default': 0.15}, 'lagging_preservative': {'type': 'string', 'default': 'creosote'}, 'lagging_thickness_mm': {'type': 'integer', 'default': 75}, 'lagging_timber_grade': {'type': 'string', 'default': 'C24'}, 'anchor_fixed_length_m': {'type': 'number', 'default': 4.0}, 'lagging_precast_grade': {'type': 'string', 'default': 'C40/50'}, 'waling_concrete_grade': {'type': 'string', 'default': 'C40/50'}, 'anchor_inclination_deg': {'type': 'number', 'default': 20.0}, 'anchor_working_load_kN': {'type': 'number', 'default': 300.0}, 'waling_section_width_m': {'type': 'number', 'default': 0.4}, 'anchor_test_load_factor': {'type': 'number', 'default': 1.25}, 'king_post_penetration_m': {'type': 'number', 'default': 3.0}, 'reinforcement_kg_per_m3': {'type': 'number', 'default': 150.0}, 'waling_section_height_m': {'type': 'number', 'default': 0.5}, 'anchor_drill_diameter_mm': {'type': 'integer', 'default': 150}, 'excavation_working_space': {'type': 'number', 'default': 0.6}, 'sheet_pile_total_length_m': {'type': 'number', 'default': 10.0}, 'anchor_corrosion_protection': {'enum': ['single', 'double'], 'type': 'string', 'default': 'single', 'description': 'Anchor corrosion protection level per BS EN 1537.\n\nSINGLE â\x80\x94 Grease-and-sheath protection of free length;\n grouted-only fixed length. Acceptable for temporary\n anchors and benign permanent environments.\nDOUBLE â\x80\x94 Grease-and-sheath PLUS a continuous corrugated plastic\n duct over the full free length, AND a corrugated duct\n over the fixed length. Mandatory for permanent anchors\n in aggressive ground per BS EN 1537 Table 1.'}, 'anchor_horizontal_spacing_m': {'type': 'number', 'default': 2.5}, 'anchor_row_levels_below_top_m': {'type': 'array', 'items': {'type': 'number'}, 'default': [1.0]}, 'waling_reinforcement_kg_per_m3': {'type': 'number', 'default': 180.0}}, 'description': 'Parameter form for an anchored retaining wall.\n\nA single dataclass that â\x80\x94 through combinations of its fields and the\n``wall_form`` discriminator â\x80\x94 produces all eight VARIANT_PRESETS plus\narbitrary user-specified geometries across all three structural\nvariants (INSITU_RC, KING_POST, SHEET_PILED). Sensible defaults\nyield a 6m in-situ RC wall with a single row of permanent anchors.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'freeboard': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'tank_type': {'enum': ['crate', 'pipes'], 'type': 'string', 'default': 'crate'}, 'pipe_count': {'type': 'integer', 'default': 3}, 'crate_width': {'type': 'number', 'default': 6.0}, 'tank_length': {'type': 'number', 'default': 30.0}, 'crate_height': {'type': 'number', 'default': 1.2}, 'pipe_diameter': {'type': 'number', 'default': 1.5}, 'crate_void_ratio': {'type': 'number', 'default': 0.95}, 'bedding_thickness': {'type': 'number', 'default': 0.15}, 'cover_to_tank_top': {'type': 'number', 'default': 0.8}, 'excavation_batter': {'type': 'number', 'default': 0.5}, 'surround_material': {'type': 'string', 'default': '20mm single-size aggregate'}, 'excavation_support': {'enum': ['open_batter', 'vertical'], 'type': 'string', 'default': 'open_batter'}, 'pipe_clear_spacing': {'type': 'number', 'default': 0.4}, 'pipe_wall_thickness': {'type': 'number', 'default': 0.11}, 'cover_material_class': {'type': 'string', 'default': 'Class 6N'}, 'geotextile_full_wrap': {'type': 'boolean', 'default': True}, 'working_space_each_side': {'type': 'number', 'default': 0.6}, 'formation_prep_thickness': {'type': 'number', 'default': 0.15}, 'granular_surround_thickness': {'type': 'number', 'default': 0.3}, 'sheet_pile_depth_below_formation': {'type': 'number', 'default': 1.5}}}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'quantity': {'type': 'integer', 'default': 1}, 'overlap_mm': {'type': 'integer', 'default': 100}, 'basement_use': {'enum': ['basement_below_ground', 'highway_cutting', 'rail_box', 'shaft_lining', 'cofferdam', 'utility_trench'], 'type': 'string', 'default': 'basement_below_ground', 'description': 'Intended use of the wall (drives concrete cover and crack-width\nrequirements, not the geometry).'}, 'cage_cover_mm': {'type': 'integer', 'default': 75}, 'wall_length_m': {'type': 'number', 'default': 20.0}, 'face_treatment': {'enum': ['shotcrete_and_mesh', 'precast_lagging_panels', 'exposed', 'architectural_finish'], 'type': 'string', 'default': 'shotcrete_and_mesh', 'description': 'Face treatment between / over piles.'}, 'bored_pile_form': {'enum': ['contiguous', 'secant_hard_soft', 'secant_hard_hard', 'king_post_and_lagging_rc'], 'type': 'string', 'default': 'contiguous', 'description': 'Structural form of the bored pile retaining wall.'}, 'cut_off_depth_mm': {'type': 'integer', 'default': 400}, 'pile_diameter_mm': {'type': 'integer', 'default': 600}, 'retained_height_m': {'type': 'number', 'default': 6.0}, 'cage_link_pitch_mm': {'type': 'integer', 'default': 200}, 'cage_main_bar_count': {'type': 'integer', 'default': 12}, 'cage_mass_kg_per_m3': {'type': 'number', 'default': 220.0}, 'pile_concrete_grade': {'type': 'string', 'default': 'C32/40'}, 'capping_beam_width_m': {'type': 'number', 'default': 0.8}, 'include_capping_beam': {'type': 'boolean', 'default': True}, 'shotcrete_mesh_grade': {'type': 'string', 'default': 'A142 mesh per BS 4483'}, 'cage_link_diameter_mm': {'type': 'integer', 'default': 12}, 'capping_beam_cover_mm': {'type': 'integer', 'default': 50}, 'capping_beam_height_m': {'type': 'number', 'default': 0.9}, 'working_space_width_m': {'type': 'number', 'default': 1.0}, 'pile_spacing_centres_m': {'type': 'number', 'default': 0.9}, 'shotcrete_thickness_mm': {'type': 'integer', 'default': 100}, 'soft_pile_concrete_grade': {'type': 'string', 'default': 'C8/10'}, 'cage_main_bar_diameter_mm': {'type': 'integer', 'default': 25}, 'capping_beam_link_pitch_mm': {'type': 'integer', 'default': 200}, 'capping_beam_main_bars_top': {'type': 'integer', 'default': 4}, 'capping_beam_concrete_grade': {'type': 'string', 'default': 'C32/40'}, 'embedment_below_formation_m': {'type': 'number', 'default': 4.0}, 'capping_beam_link_diameter_mm': {'type': 'integer', 'default': 12}, 'capping_beam_main_bars_bottom': {'type': 'integer', 'default': 4}, 'include_working_space_excavation': {'type': 'boolean', 'default': False}, 'capping_beam_main_bar_diameter_mm': {'type': 'integer', 'default': 25}, 'capping_beam_reinforcement_kg_per_m3': {'type': 'number', 'default': 180.0}}, 'description': 'Parameter form for a bored pile retaining wall.\n\nA single dataclass that â\x80\x94 through combinations of its fields and\nthe ``bored_pile_form`` discriminator â\x80\x94 produces all eight\nVARIANT_PRESETS plus arbitrary user-specified geometries across\nall four BoredPileForm options. Sensible defaults yield a 6m\nbasement-wall CONTIGUOUS bored pile wall.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'size': {'enum': ['BC_600', 'BC_900', 'BC_1200', 'BC_1500x1200', 'BC_1800x1500', 'BC_2400x1800', 'BC_2400x2000', 'BC_3000x2000'], 'type': 'string', 'default': 'BC_1500x1200', 'description': 'Standard UK precast concrete box culvert sizes. Drawn from the\nMarshalls / FP McCann / CPM published ranges; values are the\nnominal clear span Ã\x97 clear height in millimetres. BS EN 14844 /\nBS 5911-3.\n\nEight catalogue sizes spanning the practical range:\n\n BC_600 â\x80\x94 600 Ã\x97 600 (smallest; small watercourses)\n BC_900 â\x80\x94 900 Ã\x97 900 (small; minor streams)\n BC_1200 â\x80\x94 1200 Ã\x97 1200 (small; agricultural)\n BC_1500x1200 â\x80\x94 1500 Ã\x97 1200 (medium; equine / accommodation)\n BC_1800x1500 â\x80\x94 1800 Ã\x97 1500 (medium; main watercourses)\n BC_2400x1800 â\x80\x94 2400 Ã\x97 1800 (large; pedestrian / livestock subway)\n BC_2400x2000 â\x80\x94 2400 Ã\x97 2000 (large; pedestrian subway)\n BC_3000x2000 â\x80\x94 3000 Ã\x97 2000 (largest practical without bespoke\n order; vehicular accommodation\n culvert / small bridge alternative)'}, 'span_mm': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'integer', 'default': 1}, 'height_mm': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None}, 'project_ref': {'type': 'string', 'default': 'Box culvert'}, 'unit_mass_t': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit_length_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'chainage_label': {'type': 'string', 'default': ''}, 'invert_depth_m': {'type': 'number', 'default': 2.5}, 'total_length_m': {'type': 'number', 'default': 12.0}, 'invert_gradient': {'type': 'number', 'default': 0.005}, 'excavation_batter': {'type': 'number', 'default': 0.5}, 'surround_material': {'type': 'string', 'default': 'Class 6N selected granular fill'}, 'wall_thickness_mm': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None}, 'bedding_overhang_m': {'type': 'number', 'default': 0.15}, 'excavation_support': {'enum': ['open_batter', 'vertical'], 'type': 'string', 'default': 'open_batter', 'description': 'Excavation support method. OPEN_BATTER assumes side slopes per the\n``excavation_batter`` parameter (H:V); VERTICAL_SUPPORTED assumes\nsheet piles or trench boxes and emits EXCAVATION_SUPPORT m² items.'}, 'has_upstream_headwall': {'type': 'boolean', 'default': True}, 'bedding_blinding_grade': {'type': 'string', 'default': 'C20/25'}, 'upstream_headwall_size': {'enum': ['PHW_300', 'PHW_375', 'PHW_450', 'PHW_600', 'PHW_750', 'PHW_900', 'PHW_1050', 'PHW_1200', 'PHW_1500'], 'type': 'string', 'default': 'PHW_900', 'description': 'Standard UK precast headwall sizes, by outfall pipe internal diameter.\n\nThese bracket the offerings from Marshalls CPM, FP McCann, and\nStanton Bonna. The unit size determines the CESMM4 Class H sub-code\n(H.7.1 â\x89¤ 1200mm, H.7.2 > 1200mm), the typical mass for handling\nplant requirements, and the bedding footprint.'}, 'upstream_stone_size_mm': {'type': 'integer', 'default': 200}, 'has_downstream_headwall': {'type': 'boolean', 'default': True}, 'downstream_headwall_size': {'enum': ['PHW_300', 'PHW_375', 'PHW_450', 'PHW_600', 'PHW_750', 'PHW_900', 'PHW_1050', 'PHW_1200', 'PHW_1500'], 'type': 'string', 'default': 'PHW_900', 'description': 'Standard UK precast headwall sizes, by outfall pipe internal diameter.\n\nThese bracket the offerings from Marshalls CPM, FP McCann, and\nStanton Bonna. The unit size determines the CESMM4 Class H sub-code\n(H.7.1 â\x89¤ 1200mm, H.7.2 > 1200mm), the typical mass for handling\nplant requirements, and the bedding footprint.'}, 'downstream_stone_size_mm': {'type': 'integer', 'default': 200}, 'cover_to_top_of_culvert_m': {'type': 'number', 'default': 0.6}, 'upstream_headwall_bedding': {'enum': ['concrete_bed', 'granular_bed'], 'type': 'string', 'default': 'concrete_bed', 'description': 'Bedding type beneath a precast headwall.\n\nCONCRETE_BED uses mass concrete blinding (typically C8/10 or C16/20)\nunder the unit, providing a level rigid surface and tying the unit\nto the formation. Common for soft cohesive ground and where flow\nerosion under the unit is a risk.\n\nGRANULAR_BED uses imported Class 6N or 6P granular material per\nSHW Cl. 803, compacted and levelled. Common for non-erodible\ngranular soils where a concrete bed is unnecessary.'}, 'upstream_scour_protection': {'enum': ['rock_armour', 'gabion_mattress', 'concrete_apron', 'none'], 'type': 'string', 'default': 'rock_armour', 'description': 'Scour protection variant downstream of the headwall outfall.\n\nROCK_ARMOUR is the existing headwall_precast variant (granular fill,\nrock armour blanket). GABION_MATTRESS and CONCRETE_APRON are the\nnew S21 extensions for higher-energy or longer-lasting requirements.\nNONE skips scour protection entirely (rare; only suitable for\ndischarge into a robust receiving channel like a piled concrete\nweir basin).'}, 'working_space_each_side_m': {'type': 'number', 'default': 0.6}, 'geotextile_separator_grade': {'type': 'string', 'default': '200 g/m²'}, 'downstream_headwall_bedding': {'enum': ['concrete_bed', 'granular_bed'], 'type': 'string', 'default': 'concrete_bed', 'description': 'Bedding type beneath a precast headwall.\n\nCONCRETE_BED uses mass concrete blinding (typically C8/10 or C16/20)\nunder the unit, providing a level rigid surface and tying the unit\nto the formation. Common for soft cohesive ground and where flow\nerosion under the unit is a risk.\n\nGRANULAR_BED uses imported Class 6N or 6P granular material per\nSHW Cl. 803, compacted and levelled. Common for non-erodible\ngranular soils where a concrete bed is unnecessary.'}, 'downstream_scour_protection': {'enum': ['rock_armour', 'gabion_mattress', 'concrete_apron', 'none'], 'type': 'string', 'default': 'rock_armour', 'description': 'Scour protection variant downstream of the headwall outfall.\n\nROCK_ARMOUR is the existing headwall_precast variant (granular fill,\nrock armour blanket). GABION_MATTRESS and CONCRETE_APRON are the\nnew S21 extensions for higher-energy or longer-lasting requirements.\nNONE skips scour protection entirely (rare; only suitable for\ndischarge into a robust receiving channel like a piled concrete\nweir basin).'}, 'include_outlet_flow_control': {'type': 'boolean', 'default': False}, 'upstream_apron_thickness_mm': {'type': 'integer', 'default': 300}, 'upstream_scour_apron_width_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'bedding_blinding_thickness_mm': {'type': 'integer', 'default': 150}, 'downstream_apron_thickness_mm': {'type': 'integer', 'default': 300}, 'upstream_scour_apron_length_m': {'type': 'number', 'default': 2.0}, 'downstream_scour_apron_width_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'surround_thickness_each_side_m': {'type': 'number', 'default': 0.3}, 'downstream_scour_apron_length_m': {'type': 'number', 'default': 2.5}, 'upstream_headwall_bedding_grade': {'type': 'string', 'default': 'C8/10'}, 'downstream_headwall_bedding_grade': {'type': 'string', 'default': 'C8/10'}, 'sheet_pile_depth_below_formation_m': {'type': 'number', 'default': 1.0}}, 'description': "Parameter form for a precast concrete box culvert run.\n\nCatalogue-driven: pick a ``size`` and the section's nominal\nspan / height / mass / wall thickness are read from ``_CATALOGUE``.\nOverride individual fields if a specific manufacturer differs.\n\nThe run is composed of ``ceil(total_length_m / unit_length_m)``\nprecast sections of the chosen size. Headwalls at each end are\noptional and each independently selectable, with the\nheadwall_attenuation_outlet sub-assembly owning its size, bedding,\noutlet ironmongery, and scour protection. Per the S23 spec, the\nheadwalls are emitted as fully separate sub-assemblies â\x80\x94 their\nWorkItems carry their own ``source_assembly`` tag."}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'toe_length': {'type': 'number', 'default': 0.8}, 'heel_length': {'type': 'number', 'default': 1.7}, 'stem_height': {'type': 'number', 'default': 4.0}, 'wall_length': {'type': 'number', 'default': 25.0}, 'backfill_class': {'type': 'string', 'default': 'Class 6N'}, 'base_thickness': {'type': 'number', 'default': 0.5}, 'blinding_grade': {'type': 'string', 'default': 'C8/10'}, 'concrete_grade': {'type': 'string', 'default': 'C32/40'}, 'drain_diameter': {'type': 'number', 'default': 0.15}, 'excavation_batter': {'type': 'number', 'default': 1.0}, 'stem_thickness_top': {'type': 'number', 'default': 0.3}, 'drain_surround_width': {'type': 'number', 'default': 0.4}, 'formation_below_base': {'type': 'number', 'default': 0.15}, 'drain_surround_height': {'type': 'number', 'default': 0.4}, 'stem_thickness_bottom': {'type': 'number', 'default': 0.45}, 'reinforcement_kg_per_m3': {'type': 'number', 'default': 130.0}, 'excavation_working_space': {'type': 'number', 'default': 0.6}, 'backfill_height_above_base': {'type': 'number', 'default': 3.8}}}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'freeboard': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'use': {'enum': ['housing lateral', 'estate carrier', 'site carrier', 'district trunk', 'urban trunk', 'combined sewer main', 'rising main'], 'type': 'string', 'default': 'estate carrier', 'description': 'Functional use of the carrier pipe â\x80\x94 informs description text.\nDoes NOT change the BoQ code (the codes are governed by material,\nbore and depth only). Use is reflected in the description so the\nQS reading the priced bill can see which run is which.'}, 'jointing': {'enum': ['flexible elastomeric', 'electrofusion', 'push-fit gasket', 'solvent weld'], 'type': 'string', 'default': 'flexible elastomeric', 'description': 'How sections of the run are jointed end-to-end.'}, 'material': {'enum': ['vitrified clay', 'concrete', 'hdpe', 'ductile iron', 'upvc'], 'type': 'string', 'default': 'vitrified clay', 'description': 'Carrier pipe material families per BS EN standards. Maps to the\nClass I material sub-class digits 1-6 in the CESMM4 renderer\n(see _CESMM4_CLASS_I_MATERIAL_DIGIT).'}, 'diameter_mm': {'type': 'integer', 'default': 225}, 'run_length_m': {'type': 'number', 'default': 30.0}, 'invert_depth_m': {'type': 'number', 'default': 1.8}, 'description_override': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}}, 'description': 'Parameters for a carrier pipe run.\n\nGeometric defaults yield a DN225 vitrified clay carrier at 1.8 m\naverage invert depth over a 30 m run â\x80\x94 the textbook small-civils\nfoul carrier described in the QS measurement examples.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'size': {'enum': ['CP_900', 'CP_1050', 'CP_1200', 'CP_1350', 'CP_1500', 'CP_1800'], 'type': 'string', 'default': 'CP_1200', 'description': 'Standard UK precast catchpit chamber internal diameters per\nBS 5911-3. Catalogued by CPM, FP McCann, Stanton Bonna, and\nCPM Group. CP_900 is the smallest commonly stocked precast\ncatchpit; CP_1800 is the largest practical without bespoke\norder (used for industrial heavy-silt loading or where the\ncatchpit also serves as a silt-removal pre-treatment chamber\nupstream of a Class 1 petrol interceptor).'}, 'quantity': {'type': 'integer', 'default': 1}, 'access_type': {'enum': ['step_irons', 'ladder', 'none'], 'type': 'string', 'default': 'step_irons'}, 'project_ref': {'type': 'string', 'default': ''}, 'ring_mass_t': {'type': 'number', 'default': None}, 'bedding_type': {'enum': ['granular', 'concrete'], 'type': 'string', 'default': 'granular', 'description': 'Bedding layer beneath a precast catchpit base.'}, 'invert_depth': {'type': 'number', 'default': 2.5}, 'cover_loading': {'enum': ['A15', 'B125', 'C250', 'D400', 'E600', 'F900'], 'type': 'string', 'default': 'D400', 'description': 'BS EN 124 cover-and-frame loading classes.'}, 'ring_height_m': {'type': 'number', 'default': None}, 'chainage_label': {'type': 'string', 'default': ''}, 'wall_thickness': {'type': 'number', 'default': None}, 'base_unit_mass_t': {'type': 'number', 'default': None}, 'cover_slab_grade': {'type': 'string', 'default': 'C40/50'}, 'excavation_batter': {'type': 'number', 'default': 0.5}, 'internal_diameter': {'type': 'number', 'default': None}, 'silt_sump_depth_m': {'type': 'number', 'default': None}, 'step_iron_spacing': {'type': 'number', 'default': 0.3}, 'surround_material': {'type': 'string', 'default': '20mm single-size aggregate'}, 'base_unit_height_m': {'type': 'number', 'default': None}, 'bedding_overhang_m': {'type': 'number', 'default': 0.15}, 'excavation_support': {'enum': ['open_batter', 'vertical'], 'type': 'string', 'default': 'open_batter'}, 'surround_thickness': {'type': 'number', 'default': 0.15}, 'cover_clear_opening': {'type': 'number', 'default': 0.6}, 'bedding_thickness_mm': {'type': 'integer', 'default': 150}, 'cover_slab_thickness': {'type': 'number', 'default': 0.2}, 'cover_to_top_of_slab': {'type': 'number', 'default': 0.075}, 'geotextile_full_wrap': {'type': 'boolean', 'default': True}, 'seating_rings_height': {'type': 'number', 'default': 0.15}, 'bedding_concrete_grade': {'type': 'string', 'default': 'C8/10'}, 'bedding_granular_class': {'type': 'string', 'default': '6N'}, 'working_space_each_side': {'type': 'number', 'default': 0.5}, 'is_pretreatment_for_interceptor': {'type': 'boolean', 'default': False}, 'sheet_pile_depth_below_formation': {'type': 'number', 'default': 1.0}}, 'description': "Parameter form for a precast concrete catchpit / silt trap.\n\nCatalogue-driven: pick a ``size`` and the chamber's nominal\ndimensions, masses, and silt-sump depth are read from\n``_CATALOGUE``. Override individual fields if a specific\nmanufacturer differs.\n\nThe catchpit is treated as a **manhole-family chamber** (same\nWorkCategory.MANHOLE) discriminated on chamber_type='catchpit'."}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'services': {'type': 'array', 'items': {'type': 'object', 'required': ['service_type'], 'properties': {'cover_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'material': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pipe_od_mm': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None}, 'njug_colour': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'service_type': {'enum': ['water', 'gas_lp', 'gas_mp', 'electricity_lv', 'electricity_hv', 'telecoms', 'fibre', 'street_lighting'], 'type': 'string', 'description': 'Utility service categories per NJUG Volume 1.'}, 'warning_tape': {'type': 'boolean', 'default': True}, 'bedding_class': {'enum': ['N', 'F', 'B', 'S', 'A', 'Z'], 'type': 'string', 'default': 'S', 'description': 'Geometric bedding class per HA 40/01 / BS EN 1610.\n\nListed in ascending order of structural support.'}, 'bedding_thickness_m': {'type': 'number', 'default': 0.1}, 'surround_above_crown_m': {'type': 'number', 'default': 0.15}, 'tape_height_above_crown_m': {'type': 'number', 'default': 0.3}}, 'description': 'One utility within the shared trench. The QS specifies the service\ntype; the assembly resolves NJUG defaults for cover, colour, OD and\nmaterial. Any of these can be overridden.'}}, 'project_ref': {'type': 'string', 'default': 'Combined Services Trench'}, 'support_type': {'enum': ['none', 'trench_box', 'sheet_pile', 'timber_board'], 'type': 'string', 'default': 'none', 'description': 'How the trench sides are supported during installation.'}, 'chainage_label': {'type': 'string', 'default': ''}, 'trench_width_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'bedding_context': {'enum': ['highway', 'building'], 'type': 'string', 'default': 'highway', 'description': 'Specification context for pipe bedding measurement.\n\nHIGHWAY â\x80\x94 MMHW Series 500 / HA 40/01. Bedding clause references\n SHW Cl. 503. Class N/F/B/A common; Class S less so.\nBUILDING â\x80\x94 NRM2 §33 / BS EN 1610. Class S is the typical default;\n Class A and Z used for deep or structural locations.'}, 'trench_length_m': {'type': 'number', 'default': 50.0}, 'geotextile_grade': {'type': 'string', 'default': '200 g/m² non-woven'}, 'service_spacing_mm': {'type': 'integer', 'default': 100}, 'use_geotextile_separators': {'type': 'boolean', 'default': False}, 'working_space_below_bed_mm': {'type': 'integer', 'default': 100}, 'surface_reinstatement_thickness_m': {'type': 'number', 'default': 0.0}}}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'method': {'enum': ['saddle connection', 'wye junction fitting', 'cut-in junction', 'core-drilled breakthrough', 'level outfall'], 'type': 'string', 'default': 'core-drilled breakthrough', 'description': 'How the physical connection is made â\x80\x94 informs the description\nbut does not change the BoQ code (the code is governed by the\nconnection_type discriminator + bore digit).'}, 'diameter_mm': {'type': 'integer', 'default': 225}, 'connection_type': {'enum': ['existing_manhole', 'existing_pipeline', 'existing_outfall'], 'type': 'string', 'default': 'existing_manhole', 'description': "The type of existing asset the new pipe run connects to.\n\nThe discriminator that routes through to the four standards'\nsub-codes:\n existing_manhole â\x86\x92 CESMM4 I.7.1 / NRM2 33.6.1 / MMHW 500.5.1\n / SMM7 R12.4.1\n existing_pipeline â\x86\x92 CESMM4 I.7.2 / NRM2 33.6.2 / MMHW 500.5.2\n / SMM7 R12.4.2\n existing_outfall â\x86\x92 CESMM4 I.7.3 / NRM2 33.6.3 / MMHW 500.5.3\n / SMM7 R12.4.3"}, 'existing_asset_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}}, 'description': 'Parameters for a single connection-to-existing extra-over item.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'quantity': {'type': 'integer', 'default': 1}, 'toe_length': {'type': 'number', 'default': 0.6}, 'heel_length': {'type': 'number', 'default': 3.0}, 'stem_height': {'type': 'number', 'default': 5.0}, 'wall_length': {'type': 'number', 'default': 25.0}, 'backfill_class': {'type': 'string', 'default': 'Class 6N'}, 'base_thickness': {'type': 'number', 'default': 0.6}, 'blinding_grade': {'type': 'string', 'default': 'C8/10'}, 'concrete_grade': {'type': 'string', 'default': 'C32/40'}, 'drain_diameter': {'type': 'number', 'default': 0.15}, 'counterfort_shape': {'enum': ['parallel', 'tapered'], 'type': 'string', 'default': 'parallel', 'description': 'Counterfort fin shape in elevation (side view).\n\nPARALLEL â\x80\x94 counterfort thickness constant from base to top of stem.\nTAPERED â\x80\x94 counterfort tapers from full thickness at base to a\n fraction (default 0.5) of full thickness at top. The\n mass-efficient form; the structural moment at the top is\n small, so the section can taper.'}, 'curtain_thickness': {'type': 'number', 'default': 0.35}, 'excavation_batter': {'type': 'number', 'default': 1.0}, 'shear_key_depth_m': {'type': 'number', 'default': 0.0}, 'shear_key_width_m': {'type': 'number', 'default': 0.0}, 'excavation_support': {'enum': ['open_batter', 'vertical'], 'type': 'string', 'default': 'open_batter', 'description': 'Excavation support strategy for below-ground assemblies.\n\nConsumed by retaining walls (cantilever, gravity, counterfort,\nanchored, bored pile), foundation assemblies, and drainage chambers\nthat involve a battered or vertical-supported pit. The enum value is\nsurfaced in the description text of the relevant excavation BoQ line\nand in some standards (CESMM4 E.4.4 et seq.) drives a separate code.'}, 'foundation_profile': {'enum': ['level', 'stepped'], 'type': 'string', 'default': 'level', 'description': 'Foundation formation profile â\x80\x94 level or stepped.\n\nConsumed by retaining walls and foundation assemblies built on\nsloping ground. STEPPED foundation reuses the v10 cross-cutting\nEXCAVATION_FOUNDATION stepping discrimination upgrade (originally\nadded for strip_foundation S8). The stepping branch in the standards\nhandlers detects ``is_stepped=True`` on EXCAVATION_FOUNDATION items\nand routes to the stepped-foundation codes.'}, 'include_geotextile': {'type': 'boolean', 'default': True}, 'counterfort_spacing': {'type': 'number', 'default': 4.0}, 'drain_surround_width': {'type': 'number', 'default': 0.4}, 'formation_below_base': {'type': 'number', 'default': 0.15}, 'counterfort_thickness': {'type': 'number', 'default': 0.4}, 'drain_surround_height': {'type': 'number', 'default': 0.4}, 'foundation_step_count': {'type': 'integer', 'default': 0}, 'counterfort_taper_ratio': {'type': 'number', 'default': 0.5}, 'reinforcement_kg_per_m3': {'type': 'number', 'default': 145.0}, 'excavation_working_space': {'type': 'number', 'default': 0.6}, 'foundation_step_height_m': {'type': 'number', 'default': 0.0}, 'backfill_height_above_base': {'type': 'number', 'default': 4.7}}, 'description': 'Parameter form for an in-situ RC counterfort retaining wall.\n\nA single dataclass that â\x80\x94 through combinations of its fields â\x80\x94\nproduces all eight VARIANT_PRESETS plus arbitrary user-specified\ngeometries. Sensible defaults yield a 5 m high standard highway\ncounterfort wall with counterforts at 4.0 m centres.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'freeboard': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'depth_mm': {'type': 'integer', 'default': 600}, 'lining_type': {'enum': ['unlined', 'geotextile', 'granular', 'concrete'], 'type': 'string', 'default': 'unlined', 'description': "The lining material of the ditch (or unlined).\n\nThe discriminator that routes through to the four standards'\nsub-codes:\n unlined -> CESMM4 E.4.x.1 / NRM2 34.10.1 / MMHW 500.4.1\n / SMM7 R13.4.1\n geotextile -> CESMM4 E.4.x.2 / NRM2 34.10.2 / MMHW 500.4.2\n / SMM7 R13.4.2\n granular -> CESMM4 E.4.x.3 / NRM2 34.10.3 / MMHW 500.4.3\n / SMM7 R13.4.3\n concrete -> CESMM4 E.4.x.4 / NRM2 34.10.4 / MMHW 500.4.4\n / SMM7 R13.4.4"}, 'run_length_m': {'type': 'number', 'default': 100.0}, 'top_width_mm': {'type': 'integer', 'default': 1700}, 'bottom_width_mm': {'type': 'integer', 'default': 500}, 'side_slope_h_per_v': {'type': 'number', 'default': 1.0}, 'lining_thickness_mm': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None}}, 'description': 'Parameters for a single open-ditch primary measurement.\n\nThe geometry is a trapezoidal cross-section run linearly along the\nditch alignment. side_slope_h_per_v is the side slope expressed as\nhorizontal-per-vertical (1.0 = 45 deg, 1.5 = ~34 deg, 0.5 = ~63 deg).'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'pipe_type': {'enum': ['hdpe_twin_wall', 'clay_perforated'], 'type': 'string', 'default': 'hdpe_twin_wall', 'description': 'Perforated carrier â\x80\x94 same enum as French drain for consistency.'}, 'drain_length': {'type': 'number', 'default': 100.0}, 'invert_depth': {'type': 'number', 'default': 0.8}, 'has_filter_wrap': {'type': 'boolean', 'default': True}, 'cover_above_crown': {'type': 'number', 'default': 0.35}, 'excavation_batter': {'type': 'number', 'default': 1.0}, 'has_top_separator': {'type': 'boolean', 'default': True}, 'trench_width_extra': {'type': 'number', 'default': 0.3}, 'top_separator_grade': {'type': 'string', 'default': '200 g/m² non-woven separator (SHW Cl. 624)'}, 'filter_aggregate_type': {'enum': ['type_b_6f2', 'type_a_6f1'], 'type': 'string', 'default': 'type_b_6f2', 'description': 'Filter aggregate per SHW Series 500 / SHW Cl. 513.'}, 'pipe_wall_thickness_mm': {'type': 'integer', 'default': 25}, 'filter_geotextile_grade': {'type': 'string', 'default': '200 g/m² non-woven (SHW Cl. 513)'}, 'working_space_each_side': {'type': 'number', 'default': 0.1}, 'pipe_internal_diameter_mm': {'type': 'integer', 'default': 150}, 'excavation_support_required': {'type': 'boolean', 'default': True}, 'bedding_thickness_below_pipe': {'type': 'number', 'default': 0.15}}}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'method': {'enum': ['simpsons', 'trapezoidal', 'prismoidal'], 'type': 'string', 'default': 'simpsons', 'description': 'Integration method preference. The actual method applied may\ndiffer â\x80\x94 see VolumeResult.method_used.'}, 'bulking': {'anyOf': [{'type': 'object', 'properties': {'bulk_factor': {'type': 'number', 'default': 1.2}, 'shrink_factor': {'type': 'number', 'default': 0.9}}, 'description': 'SHW Series 600 Cl. 605 bulking/shrinkage factors.\n\nbulk_factor â\x80\x94 multiplier applied to the in-situ cut volume to get\n the loose volume that needs haulage. Typical values:\n 1.10 for granular (Class 1x)\n 1.20 for cohesive (Class 2x)\n 1.30 for chalk (Class 3)\n 1.50 for rock (Class 8)\n Default = 1.20 (conservative average for mixed cut).\nshrink_factor â\x80\x94 multiplier applied to the in-situ fill volume to\n get the volume of cut required to produce it.\n Typical values:\n 0.95 for granular\n 0.85 for cohesive\n 0.80 for stabilised\n Default = 0.90 (conservative average for mixed fill).'}, {'type': 'null'}], 'default': None}, 'cut_class': {'enum': ['1A', '1B', '1C', '2A', '2B', '2C', '2D', '2E', '3', '4', '5A', '5B', '6A', '6B', '6C', '6D', '6E', '6F1', '6F2', '6F3', '6F4', '6F5', '6I', '6J', '6N', '6P', '6Q', '7A', '7B', '7C', '7D', '7E', '7F', '8', '9A', '9B', 'U1A', 'U1B', 'U2'], 'type': 'string', 'default': '2C', 'description': 'Full SHW Series 600 Table 6/1 acceptable material class set, plus the\nTable 6/2 unacceptable classes.\n\nThe enum value is the SHW designator. Use `family` and `default_use`\nproperties for routing in the assembly and renderer code.'}, 'fill_class': {'enum': ['1A', '1B', '1C', '2A', '2B', '2C', '2D', '2E', '3', '4', '5A', '5B', '6A', '6B', '6C', '6D', '6E', '6F1', '6F2', '6F3', '6F4', '6F5', '6I', '6J', '6N', '6P', '6Q', '7A', '7B', '7C', '7D', '7E', '7F', '8', '9A', '9B', 'U1A', 'U1B', 'U2'], 'type': 'string', 'default': '1A', 'description': 'Full SHW Series 600 Table 6/1 acceptable material class set, plus the\nTable 6/2 unacceptable classes.\n\nThe enum value is the SHW designator. Use `family` and `default_use`\nproperties for routing in the assembly and renderer code.'}, 'reach_name': {'type': 'string', 'default': 'Embankment Ch 0+000 to Ch 0+200'}, 'capping_class': {'enum': ['1A', '1B', '1C', '2A', '2B', '2C', '2D', '2E', '3', '4', '5A', '5B', '6A', '6B', '6C', '6D', '6E', '6F1', '6F2', '6F3', '6F4', '6F5', '6I', '6J', '6N', '6P', '6Q', '7A', '7B', '7C', '7D', '7E', '7F', '8', '9A', '9B', 'U1A', 'U1B', 'U2'], 'type': 'string', 'default': '6F2', 'description': 'Full SHW Series 600 Table 6/1 acceptable material class set, plus the\nTable 6/2 unacceptable classes.\n\nThe enum value is the SHW designator. Use `family` and `default_use`\nproperties for routing in the assembly and renderer code.'}, 'crest_width_m': {'type': 'number', 'default': 10.0}, 'height_profile': {'type': 'array', 'items': {'type': 'object', 'required': ['chainage', 'height_m'], 'properties': {'chainage': {'type': 'number'}, 'height_m': {'type': 'number'}}, 'description': 'A single point on the embankment height profile.\n\n`height_m` is the embankment height above the existing ground at this\nchainage. Zero means the embankment has zero height (the alignment\nhas reached existing ground level â\x80\x94 the embankment toe).'}}, 'sub_base_class': {'enum': ['1A', '1B', '1C', '2A', '2B', '2C', '2D', '2E', '3', '4', '5A', '5B', '6A', '6B', '6C', '6D', '6E', '6F1', '6F2', '6F3', '6F4', '6F5', '6I', '6J', '6N', '6P', '6Q', '7A', '7B', '7C', '7D', '7E', '7F', '8', '9A', '9B', 'U1A', 'U1B', 'U2'], 'type': 'string', 'default': '1A', 'description': 'Full SHW Series 600 Table 6/1 acceptable material class set, plus the\nTable 6/2 unacceptable classes.\n\nThe enum value is the SHW designator. Use `family` and `default_use`\nproperties for routing in the assembly and renderer code.'}, 'topsoil_source': {'type': 'string', 'default': 'site-won'}, 'topsoil_replace': {'type': 'boolean', 'default': True}, 'left_slope_h_per_v': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'side_slope_h_per_v': {'type': 'number', 'default': 2.0}, 'right_slope_h_per_v': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'method_statement_ref': {'type': 'string', 'default': ''}, 'selected_import_class': {'enum': ['1A', '1B', '1C', '2A', '2B', '2C', '2D', '2E', '3', '4', '5A', '5B', '6A', '6B', '6C', '6D', '6E', '6F1', '6F2', '6F3', '6F4', '6F5', '6I', '6J', '6N', '6P', '6Q', '7A', '7B', '7C', '7D', '7E', '7F', '8', '9A', '9B', 'U1A', 'U1B', 'U2'], 'type': 'string', 'default': '1A', 'description': 'Full SHW Series 600 Table 6/1 acceptable material class set, plus the\nTable 6/2 unacceptable classes.\n\nThe enum value is the SHW designator. Use `family` and `default_use`\nproperties for routing in the assembly and renderer code.'}, 'topsoil_strip_depth_m': {'type': 'number', 'default': 0.15}, 'strip_envelope_offset_m': {'type': 'number', 'default': 0.5}, 'unacceptable_proportion': {'type': 'number', 'default': 0.0}, 'topsoil_replace_depth_mm': {'type': 'integer', 'default': 150}, 'founding_depth_below_ground_m': {'type': 'number', 'default': 0.0}}, 'description': 'Inputs for a geometry-driven embankment cross-section assembly.\n\nThe assembly generates a `CrossSection` list from the profile +\ngeometry parameters, builds an `EndAreaEarthworksParameters` from\nthe result + the material/method parameters carried here, and\ndelegates compute to `EndAreaEarthworks.compute(...)`.\n\nPer Session 12 Q2 decision: left and right slopes are exposed\nseparately, both defaulting to `side_slope_h_per_v` so the common\nsymmetric case is a single-parameter call.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'method': {'enum': ['simpsons', 'trapezoidal', 'prismoidal'], 'type': 'string', 'default': 'simpsons', 'description': 'Integration method preference. The actual method applied may\ndiffer â\x80\x94 see VolumeResult.method_used.'}, 'bulking': {'anyOf': [{'type': 'object', 'properties': {'bulk_factor': {'type': 'number', 'default': 1.2}, 'shrink_factor': {'type': 'number', 'default': 0.9}}, 'description': 'SHW Series 600 Cl. 605 bulking/shrinkage factors.\n\nbulk_factor â\x80\x94 multiplier applied to the in-situ cut volume to get\n the loose volume that needs haulage. Typical values:\n 1.10 for granular (Class 1x)\n 1.20 for cohesive (Class 2x)\n 1.30 for chalk (Class 3)\n 1.50 for rock (Class 8)\n Default = 1.20 (conservative average for mixed cut).\nshrink_factor â\x80\x94 multiplier applied to the in-situ fill volume to\n get the volume of cut required to produce it.\n Typical values:\n 0.95 for granular\n 0.85 for cohesive\n 0.80 for stabilised\n Default = 0.90 (conservative average for mixed fill).'}, {'type': 'null'}], 'default': None}, 'cut_class': {'enum': ['1A', '1B', '1C', '2A', '2B', '2C', '2D', '2E', '3', '4', '5A', '5B', '6A', '6B', '6C', '6D', '6E', '6F1', '6F2', '6F3', '6F4', '6F5', '6I', '6J', '6N', '6P', '6Q', '7A', '7B', '7C', '7D', '7E', '7F', '8', '9A', '9B', 'U1A', 'U1B', 'U2'], 'type': 'string', 'default': '2C', 'description': 'Full SHW Series 600 Table 6/1 acceptable material class set, plus the\nTable 6/2 unacceptable classes.\n\nThe enum value is the SHW designator. Use `family` and `default_use`\nproperties for routing in the assembly and renderer code.'}, 'fill_class': {'enum': ['1A', '1B', '1C', '2A', '2B', '2C', '2D', '2E', '3', '4', '5A', '5B', '6A', '6B', '6C', '6D', '6E', '6F1', '6F2', '6F3', '6F4', '6F5', '6I', '6J', '6N', '6P', '6Q', '7A', '7B', '7C', '7D', '7E', '7F', '8', '9A', '9B', 'U1A', 'U1B', 'U2'], 'type': 'string', 'default': '2C', 'description': 'Full SHW Series 600 Table 6/1 acceptable material class set, plus the\nTable 6/2 unacceptable classes.\n\nThe enum value is the SHW designator. Use `family` and `default_use`\nproperties for routing in the assembly and renderer code.'}, 'reach_name': {'type': 'string', 'default': 'Mainline cutting Ch 0+000 to Ch 0+100'}, 'capping_class': {'enum': ['1A', '1B', '1C', '2A', '2B', '2C', '2D', '2E', '3', '4', '5A', '5B', '6A', '6B', '6C', '6D', '6E', '6F1', '6F2', '6F3', '6F4', '6F5', '6I', '6J', '6N', '6P', '6Q', '7A', '7B', '7C', '7D', '7E', '7F', '8', '9A', '9B', 'U1A', 'U1B', 'U2'], 'type': 'string', 'default': '6F2', 'description': 'Full SHW Series 600 Table 6/1 acceptable material class set, plus the\nTable 6/2 unacceptable classes.\n\nThe enum value is the SHW designator. Use `family` and `default_use`\nproperties for routing in the assembly and renderer code.'}, 'cross_sections': {'type': 'array', 'items': {'type': 'object', 'required': ['chainage'], 'properties': {'notes': {'type': 'string', 'default': ''}, 'cap_area': {'type': 'number', 'default': 0.0}, 'chainage': {'type': 'number'}, 'cut_area': {'type': 'number', 'default': 0.0}, 'fill_area': {'type': 'number', 'default': 0.0}, 'attributes': {'type': 'object', 'additionalProperties': True}, 'sub_base_area': {'type': 'number', 'default': 0.0}, 'topsoil_strip_area': {'type': 'number', 'default': 0.0}}, 'description': 'A single surveyed cross-section at a known chainage.\n\nAll areas are in m² (the planar cross-section area). The chainage\nis in m along the centreline.\n\nThe optional `notes` field carries any inspector commentary that\nshould appear in the audit trail (e.g. "soft spot, U2 material\nexpected below formation"). The optional `attributes` carries any\nfurther structured data that downstream consumers may want (per-class\ncut splits, designer\'s identifier, etc.).'}}, 'sub_base_class': {'enum': ['1A', '1B', '1C', '2A', '2B', '2C', '2D', '2E', '3', '4', '5A', '5B', '6A', '6B', '6C', '6D', '6E', '6F1', '6F2', '6F3', '6F4', '6F5', '6I', '6J', '6N', '6P', '6Q', '7A', '7B', '7C', '7D', '7E', '7F', '8', '9A', '9B', 'U1A', 'U1B', 'U2'], 'type': 'string', 'default': '1A', 'description': 'Full SHW Series 600 Table 6/1 acceptable material class set, plus the\nTable 6/2 unacceptable classes.\n\nThe enum value is the SHW designator. Use `family` and `default_use`\nproperties for routing in the assembly and renderer code.'}, 'topsoil_source': {'type': 'string', 'default': 'site-won'}, 'topsoil_replace': {'type': 'boolean', 'default': True}, 'method_statement_ref': {'type': 'string', 'default': ''}, 'selected_import_class': {'enum': ['1A', '1B', '1C', '2A', '2B', '2C', '2D', '2E', '3', '4', '5A', '5B', '6A', '6B', '6C', '6D', '6E', '6F1', '6F2', '6F3', '6F4', '6F5', '6I', '6J', '6N', '6P', '6Q', '7A', '7B', '7C', '7D', '7E', '7F', '8', '9A', '9B', 'U1A', 'U1B', 'U2'], 'type': 'string', 'default': '1A', 'description': 'Full SHW Series 600 Table 6/1 acceptable material class set, plus the\nTable 6/2 unacceptable classes.\n\nThe enum value is the SHW designator. Use `family` and `default_use`\nproperties for routing in the assembly and renderer code.'}, 'topsoil_strip_depth_m': {'type': 'number', 'default': 0.15}, 'unacceptable_proportion': {'type': 'number', 'default': 0.0}, 'topsoil_replace_depth_mm': {'type': 'integer', 'default': 150}, 'typical_excavation_depth_m': {'type': 'number', 'default': 2.0}}, 'description': 'Inputs for a linear earthworks reach measured by the end-area method.\n\nThe five area streams in each `CrossSection` are integrated independently\nalong the chainage axis. `topsoil_strip_area` is the planar (m²)\nstrip area at each section; the volume is computed as\n`trap-integrate(topsoil_strip_area) Ã\x97 topsoil_strip_depth_m / strip_area_mean`\nâ\x80\x94 i.e. we multiply the integrated planar strip area by the strip depth\nto get a volume in m³. Conventionally `topsoil_strip_area` per the\ndesigner is planar in m² per running metre (m² of plan area per metre\nof chainage = m of width), but to keep CrossSection symmetric with the\nother four area streams we treat it as a true area (m²) at that station\nand apply the depth multiplication here.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'width': {'type': 'number', 'default': 6.0}, 'length': {'type': 'number', 'default': 100.0}, 'base_material': {'anyOf': [{'enum': ['HRA_30/14F', 'SMA_10_surf', 'SMA_14_surf', 'AC_10_close_surf', 'AC_6_dense_surf', 'TSCS', 'surf_dress', 'AC_20_dense_bin', 'AC_32_dense_bin', 'HRA_60/20', 'AC_32_dense_base', 'AC_20_dense_base', 'HRA_60/32', 'CBGM_A_C8/10', 'CBGM_B_C12/15', 'PBP_concrete_block', 'PA_open_graded', 'PC_no_fines'], 'type': 'string', 'description': 'Canonical UK flexible pavement materials. The enum value is the\nBS EN 13108 designation; legacy SHW Cl. names are carried as the\n`legacy_designation` field in PavementInfo.'}, {'type': 'null'}], 'default': None}, 'capping_class': {'enum': ['1A', '1B', '1C', '2A', '2B', '2C', '2D', '2E', '3', '4', '5A', '5B', '6A', '6B', '6C', '6D', '6E', '6F1', '6F2', '6F3', '6F4', '6F5', '6I', '6J', '6N', '6P', '6Q', '7A', '7B', '7C', '7D', '7E', '7F', '8', '9A', '9B', 'U1A', 'U1B', 'U2'], 'type': 'string', 'default': '6F2', 'description': 'Full SHW Series 600 Table 6/1 acceptable material class set, plus the\nTable 6/2 unacceptable classes.\n\nThe enum value is the SHW designator. Use `family` and `default_use`\nproperties for routing in the assembly and renderer code.'}, 'sub_base_class': {'enum': ['1A', '1B', '1C', '2A', '2B', '2C', '2D', '2E', '3', '4', '5A', '5B', '6A', '6B', '6C', '6D', '6E', '6F1', '6F2', '6F3', '6F4', '6F5', '6I', '6J', '6N', '6P', '6Q', '7A', '7B', '7C', '7D', '7E', '7F', '8', '9A', '9B', 'U1A', 'U1B', 'U2'], 'type': 'string', 'default': '1A', 'description': 'Full SHW Series 600 Table 6/1 acceptable material class set, plus the\nTable 6/2 unacceptable classes.\n\nThe enum value is the SHW designator. Use `family` and `default_use`\nproperties for routing in the assembly and renderer code.'}, 'tack_coat_type': {'type': 'string', 'default': 'cationic bitumen emulsion C40B4'}, 'binder_material': {'anyOf': [{'enum': ['HRA_30/14F', 'SMA_10_surf', 'SMA_14_surf', 'AC_10_close_surf', 'AC_6_dense_surf', 'TSCS', 'surf_dress', 'AC_20_dense_bin', 'AC_32_dense_bin', 'HRA_60/20', 'AC_32_dense_base', 'AC_20_dense_base', 'HRA_60/32', 'CBGM_A_C8/10', 'CBGM_B_C12/15', 'PBP_concrete_block', 'PA_open_graded', 'PC_no_fines'], 'type': 'string', 'description': 'Canonical UK flexible pavement materials. The enum value is the\nBS EN 13108 designation; legacy SHW Cl. names are carried as the\n`legacy_designation` field in PavementInfo.'}, {'type': 'null'}], 'default': None}, 'include_capping': {'type': 'boolean', 'default': False}, 'surface_material': {'anyOf': [{'enum': ['HRA_30/14F', 'SMA_10_surf', 'SMA_14_surf', 'AC_10_close_surf', 'AC_6_dense_surf', 'TSCS', 'surf_dress', 'AC_20_dense_bin', 'AC_32_dense_bin', 'HRA_60/20', 'AC_32_dense_base', 'AC_20_dense_base', 'HRA_60/32', 'CBGM_A_C8/10', 'CBGM_B_C12/15', 'PBP_concrete_block', 'PA_open_graded', 'PC_no_fines'], 'type': 'string', 'description': 'Canonical UK flexible pavement materials. The enum value is the\nBS EN 13108 designation; legacy SHW Cl. names are carried as the\n`legacy_designation` field in PavementInfo.'}, {'type': 'null'}], 'default': None}, 'traffic_category': {'enum': ['domestic', 'light', 'medium', 'heavy'], 'type': 'string', 'default': 'medium', 'description': 'Coarse traffic category for QS-level pavement build-up defaults.\n\nMaps to typical DMRB CD 226 design traffic ranges:\n DOMESTIC â\x89\x88 < 0.3 msa (driveways, courtyards)\n LIGHT â\x89\x88 0.3â\x80\x932.5 msa (estate roads, footways w/ vehicle access)\n MEDIUM â\x89\x88 2.5â\x80\x9310 msa (urban access, minor distributors)\n HEAVY â\x89\x88 10â\x80\x9330 msa (urban distributors, light industrial)\n\nFor design traffic > 30 msa or > category 4 subgrade, a full pavement\ndesign per DMRB CD 226 is required and the parametric defaults here\nare not sufficient â\x80\x94 the user must specify thicknesses and materials\nexplicitly.'}, 'base_thickness_mm': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None}, 'include_tack_coat': {'type': 'boolean', 'default': True}, 'binder_thickness_mm': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None}, 'capping_thickness_mm': {'type': 'integer', 'default': 350}, 'surface_thickness_mm': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None}, 'tack_coat_rate_kg_m2': {'type': 'number', 'default': 0.35}, 'sub_base_thickness_mm': {'type': 'integer', 'default': 150}, 'include_formation_prep': {'type': 'boolean', 'default': True}, 'excavation_extra_each_side_mm': {'type': 'integer', 'default': 0}}, 'description': 'Input parameters for a flexible pavement assembly.\n\nGeometric defaults match a 100m Ã\x97 6m urban access road (medium\ntraffic) per DMRB CD 226 starting build-up: 150mm Type 1 sub-base,\n150mm AC 32 base, 60mm AC 20 binder, 40mm SMA 10 surface.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'pipe_type': {'enum': ['hdpe_twin_wall', 'clay_perforated', 'upvc_slotted'], 'type': 'string', 'default': 'hdpe_twin_wall', 'description': 'Perforated carrier pipe type.'}, 'drain_length': {'type': 'number', 'default': 50.0}, 'has_top_seal': {'type': 'boolean', 'default': False}, 'invert_depth': {'type': 'number', 'default': 1.0}, 'bedding_context': {'enum': ['highway', 'building'], 'type': 'string', 'default': 'highway', 'description': 'Specification context for pipe bedding measurement.\n\nHIGHWAY â\x80\x94 MMHW Series 500 / HA 40/01. Bedding clause references\n SHW Cl. 503. Class N/F/B/A common; Class S less so.\nBUILDING â\x80\x94 NRM2 §33 / BS EN 1610. Class S is the typical default;\n Class A and Z used for deep or structural locations.'}, 'has_filter_wrap': {'type': 'boolean', 'default': True}, 'filter_aggregate': {'type': 'string', 'default': 'Type B filter (20-40mm)'}, 'cover_above_crown': {'type': 'number', 'default': 0.45}, 'excavation_batter': {'type': 'number', 'default': 1.0}, 'top_seal_thickness': {'type': 'number', 'default': 0.15}, 'trench_width_extra': {'type': 'number', 'default': 0.3}, 'filter_aggregate_class': {'type': 'string', 'default': 'Class 6N'}, 'pipe_wall_thickness_mm': {'type': 'integer', 'default': 25}, 'filter_geotextile_grade': {'type': 'string', 'default': '150 g/m² non-woven'}, 'working_space_each_side': {'type': 'number', 'default': 0.15}, 'pipe_internal_diameter_mm': {'type': 'integer', 'default': 150}, 'excavation_support_required': {'type': 'boolean', 'default': False}, 'bedding_thickness_below_pipe': {'type': 'number', 'default': 0.15}}}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'quantity': {'type': 'integer', 'default': 1}, 'mesh_grade': {'enum': ['galvanised_hexagonal', 'pvc_coated_galfan', 'galvanised_welded'], 'type': 'string', 'default': 'galvanised_hexagonal', 'description': 'Wire mesh grade per BS EN 10223-3 (woven) or BS EN 10218-2\n(welded).\n\nGALVANISED_HEXAGONAL â\x80\x94 Heavily galvanised double-twisted hexagonal\n woven wire mesh. Standard for non-aggressive\n environments. Wire diameter 2.7mm typical.\n Lifespan 30-60 years depending on environment.\nPVC_COATED_GALFAN â\x80\x94 Galfan (Zn-Al alloy) coated wire with\n polymer (PVC or PA6) outer coating. For\n aggressive environments (saline coastal,\n contaminated land, brackish water). Lifespan\n 60-120 years. Standard for permanent\n highway works on coastal alignments.\nGALVANISED_WELDED â\x80\x94 Welded rectangular wire mesh; stiffer\n baskets, sharper edges, less flexible.\n Sometimes preferred for architectural\n contexts where straight edges matter.'}, 'gabion_form': {'enum': ['stacked_rectangular', 'stacked_stepped', 'battered', 'facing_mattress'], 'type': 'string', 'default': 'stacked_rectangular', 'description': 'Structural form of the gabion retaining wall.\n\nSTACKED_RECTANGULAR â\x80\x94 Straight-faced stacked baskets; the most\n common practical form. Both front and back\n faces vertical. Each course is the same\n horizontal dimension. Typical for highway\n boundary walls 2-3m tall, garden/landscape\n walls, and small revetment walls.\n\nSTACKED_STEPPED â\x80\x94 Front-face stepped. Each successive course\n (from bottom up) is offset back from the\n one below. Used for architectural / heritage\n contexts where the visible face needs visual\n interest, and for taller walls where stability\n is improved by stepping the cg backwards.\n Step offset typically 0.25-0.50m per course.\n\nBATTERED â\x80\x94 Back-battered profile (front face vertical,\n back face battered inwards). Used for taller\n walls (4-6m+) where the increased base width\n per unit height improves overturning\n stability. Batter angle typically 6-15° from\n vertical (1:10 to 1:4 H:V).\n\nFACING_MATTRESS â\x80\x94 Thin (typically 150-300mm) face-mounted gabion\n mattresses (Reno-type) applied to a backing\n fill or natural slope. Used for slope facing,\n river-bank revetment, scour protection\n aprons. Routes the primary measurement line\n to GABION_FACING_MATTRESS (m²) rather than\n GABION_BASKET (m³). Includes both inclined\n slope-face mattresses and horizontal scour\n aprons.'}, 'wall_height': {'type': 'number', 'default': 3.0}, 'wall_length': {'type': 'number', 'default': 25.0}, 'course_count': {'type': 'integer', 'default': 3}, 'backfill_class': {'type': 'string', 'default': 'Class 6N'}, 'basket_width_m': {'type': 'number', 'default': 1.0}, 'blinding_grade': {'type': 'string', 'default': 'C8/10'}, 'basket_height_m': {'type': 'number', 'default': 1.0}, 'basket_length_m': {'type': 'number', 'default': 2.0}, 'retained_height': {'type': 'number', 'default': 2.7}, 'backfill_width_m': {'type': 'number', 'default': 0.5}, 'batter_angle_deg': {'type': 'number', 'default': 8.0}, 'geotextile_grade': {'type': 'string', 'default': '200 g/m²'}, 'include_blinding': {'type': 'boolean', 'default': True}, 'stone_fill_grade': {'enum': ['hard_angular_60_150', 'hard_angular_100_200', 'hard_angular_150_300', 'dressed_sandstone'], 'type': 'string', 'default': 'hard_angular_100_200', 'description': 'Stone fill specification per SHW Cl. 622 (gabions) or Cl. 623\n(rockfill).\n\nHARD_ANGULAR_60_150 â\x80\x94 60-150mm grade. Used for mattresses (thinner\n sections need smaller stone to fill properly)\n and small landscape walls.\nHARD_ANGULAR_100_200 â\x80\x94 100-200mm grade. The most common UK highway\n specification for standard 1m-cube gabion\n baskets.\nHARD_ANGULAR_150_300 â\x80\x94 150-300mm grade. Used for larger baskets\n (1.5m or 2m courses) and where larger stone\n is locally available economically.\nDRESSED_SANDSTONE â\x80\x94 Hand-dressed natural stone (typically\n sandstone or local stone matching heritage\n context). Architectural premium product.'}, 'excavation_batter': {'type': 'number', 'default': 1.0}, 'excavation_support': {'enum': ['open_batter', 'vertical'], 'type': 'string', 'default': 'open_batter', 'description': 'Excavation support strategy for below-ground assemblies.\n\nConsumed by retaining walls (cantilever, gravity, counterfort,\nanchored, bored pile), foundation assemblies, and drainage chambers\nthat involve a battered or vertical-supported pit. The enum value is\nsurfaced in the description text of the relevant excavation BoQ line\nand in some standards (CESMM4 E.4.4 et seq.) drives a separate code.'}, 'foundation_profile': {'enum': ['level', 'stepped'], 'type': 'string', 'default': 'level', 'description': 'Foundation formation profile â\x80\x94 level or stepped.\n\nConsumed by retaining walls and foundation assemblies built on\nsloping ground. STEPPED foundation reuses the v10 cross-cutting\nEXCAVATION_FOUNDATION stepping discrimination upgrade (originally\nadded for strip_foundation S8). The stepping branch in the standards\nhandlers detects ``is_stepped=True`` on EXCAVATION_FOUNDATION items\nand routes to the stepped-foundation codes.'}, 'include_geotextile': {'type': 'boolean', 'default': True}, 'blinding_thickness_m': {'type': 'number', 'default': 0.1}, 'mattress_thickness_mm': {'type': 'integer', 'default': 300}, 'mattress_apron_width_m': {'type': 'number', 'default': 4.0}, 'excavation_working_space': {'type': 'number', 'default': 0.3}, 'mattress_slope_angle_deg': {'type': 'number', 'default': 33.7}, 'step_offset_per_course_m': {'type': 'number', 'default': 0.3}}, 'description': 'Parameter form for a gabion retaining wall.\n\nA single dataclass that â\x80\x94 through combinations of its fields and\nthe ``gabion_form`` discriminator â\x80\x94 produces all eight\nVARIANT_PRESETS plus arbitrary user-specified geometries across\nall four GabionForm options. Sensible defaults yield a 3m\nhighway-boundary STACKED_RECTANGULAR wall with 1m Ã\x97 1m Ã\x97 2m\ngalvanised hexagonal baskets filled with 100-200mm graded stone.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'quantity': {'type': 'integer', 'default': 1}, 'toe_length': {'type': 'number', 'default': 0.0}, 'heel_length': {'type': 'number', 'default': 0.0}, 'stem_height': {'type': 'number', 'default': 3.0}, 'wall_length': {'type': 'number', 'default': 25.0}, 'back_profile': {'enum': ['vertical', 'battered'], 'type': 'string', 'default': 'battered', 'description': 'Back (retained) face profile.'}, 'front_profile': {'enum': ['vertical', 'battered', 'stepped'], 'type': 'string', 'default': 'vertical', 'description': 'Front (exposed) face profile.'}, 'backfill_class': {'type': 'string', 'default': 'Class 6N'}, 'base_thickness': {'type': 'number', 'default': 0.45}, 'blinding_grade': {'type': 'string', 'default': 'C8/10'}, 'concrete_grade': {'type': 'string', 'default': 'C25/30'}, 'drain_diameter': {'type': 'number', 'default': 0.15}, 'front_step_count': {'type': 'integer', 'default': 0}, 'excavation_batter': {'type': 'number', 'default': 1.0}, 'shear_key_depth_m': {'type': 'number', 'default': 0.0}, 'shear_key_width_m': {'type': 'number', 'default': 0.0}, 'excavation_support': {'enum': ['open_batter', 'vertical'], 'type': 'string', 'default': 'open_batter', 'description': 'Excavation support strategy for below-ground assemblies.\n\nConsumed by retaining walls (cantilever, gravity, counterfort,\nanchored, bored pile), foundation assemblies, and drainage chambers\nthat involve a battered or vertical-supported pit. The enum value is\nsurfaced in the description text of the relevant excavation BoQ line\nand in some standards (CESMM4 E.4.4 et seq.) drives a separate code.'}, 'foundation_profile': {'enum': ['level', 'stepped'], 'type': 'string', 'default': 'level', 'description': 'Foundation formation profile â\x80\x94 level or stepped.\n\nConsumed by retaining walls and foundation assemblies built on\nsloping ground. STEPPED foundation reuses the v10 cross-cutting\nEXCAVATION_FOUNDATION stepping discrimination upgrade (originally\nadded for strip_foundation S8). The stepping branch in the standards\nhandlers detects ``is_stepped=True`` on EXCAVATION_FOUNDATION items\nand routes to the stepped-foundation codes.'}, 'include_geotextile': {'type': 'boolean', 'default': True}, 'stem_thickness_top': {'type': 'number', 'default': 0.4}, 'drain_surround_width': {'type': 'number', 'default': 0.4}, 'formation_below_base': {'type': 'number', 'default': 0.15}, 'drain_surround_height': {'type': 'number', 'default': 0.4}, 'foundation_step_count': {'type': 'integer', 'default': 0}, 'stem_thickness_bottom': {'type': 'number', 'default': 1.3}, 'excavation_working_space': {'type': 'number', 'default': 0.6}, 'foundation_step_height_m': {'type': 'number', 'default': 0.0}, 'backfill_height_above_base': {'type': 'number', 'default': 2.8}, 'nominal_face_reinforcement_kg_per_m3': {'type': 'number', 'default': 0.0}}, 'description': 'Parameter form for a mass concrete gravity retaining wall.\n\nA single dataclass that â\x80\x94 through combinations of its fields â\x80\x94\nproduces all eight VARIANT_PRESETS plus arbitrary user-specified\ngeometries. Sensible defaults yield a 3 m high standard highway\nboundary wall.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'quantity': {'type': 'integer', 'default': 1}, 'gully_type': {'enum': ['trapped_road_gully', 'untrapped_road_gully', 'yard_gully', 'kerb_inlet_gully'], 'type': 'string', 'default': 'trapped_road_gully', 'description': 'Style of gully.'}, 'pot_depth_m': {'type': 'number', 'default': 0.9}, 'grating_type': {'type': 'string', 'default': 'hinged ductile iron'}, 'bedding_grade': {'type': 'string', 'default': 'C20/25'}, 'grating_loading': {'enum': ['A15', 'B125', 'C250', 'D400', 'E600'], 'type': 'string', 'default': 'D400', 'description': 'BS EN 124 loading class.'}, 'has_kerb_outlet': {'type': 'boolean', 'default': False}, 'haunching_grade': {'type': 'string', 'default': 'C20/25'}, 'connection_length_m': {'type': 'number', 'default': 2.5}, 'connection_material': {'type': 'string', 'default': 'vitrified clay'}, 'formation_below_pot': {'type': 'number', 'default': 0.15}, 'pot_wall_thickness_mm': {'type': 'integer', 'default': 60}, 'connection_diameter_mm': {'type': 'integer', 'default': 150}, 'working_space_each_side': {'type': 'number', 'default': 0.3}, 'connection_bedding_class': {'enum': ['N', 'F', 'B', 'S', 'A', 'Z'], 'type': 'string', 'default': 'B', 'description': 'Geometric bedding class per HA 40/01 / BS EN 1610.\n\nListed in ascending order of structural support.'}, 'grating_clear_opening_mm': {'type': 'integer', 'default': 425}, 'pot_internal_diameter_mm': {'type': 'integer', 'default': 450}, 'connection_bedding_context': {'enum': ['highway', 'building'], 'type': 'string', 'default': 'highway', 'description': 'Specification context for pipe bedding measurement.\n\nHIGHWAY â\x80\x94 MMHW Series 500 / HA 40/01. Bedding clause references\n SHW Cl. 503. Class N/F/B/A common; Class S less so.\nBUILDING â\x80\x94 NRM2 §33 / BS EN 1610. Class S is the typical default;\n Class A and Z used for deep or structural locations.'}, 'connection_invert_at_gully_m': {'type': 'number', 'default': 0.85}, 'connection_wall_thickness_mm': {'type': 'integer', 'default': 25}, 'connection_invert_at_carrier_m': {'type': 'number', 'default': 1.25}}}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'length_m': {'type': 'number', 'default': 10.0}, 'max_depth_m': {'type': 'number', 'default': 1.5}, 'trench_width_m': {'type': 'number', 'default': 0.7}, 'pipe_diameter_mm': {'type': 'integer', 'default': 225}, 'existing_asset_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'hard_material_type': {'enum': ['natural_rock', 'artificial_hard_material'], 'type': 'string', 'default': 'natural_rock', 'description': 'The type of hard material encountered.\n\nThe discriminator that routes through the four standards\' hard-\nmaterial codes:\n natural_rock -> CESMM4 E.6, NRM2 5.6.1, MMHW 500.6.1, SMM7 R12.6.1\n artificial -> CESMM4 E.7, NRM2 5.6.2, MMHW 500.6.2, SMM7 R12.6.2\n\nNatural rock = igneous/metamorphic/strongly cemented sedimentary\nrequiring blasting or heavy mechanical breaking; the UK industry\nthreshold is broadly "material with a UCS > 20 MPa or visibly\nintact rock requiring more than ripper-mounted tracked plant".\n\nArtificial hard material = man-made obstructions encountered\nduring excavation â\x80\x94 mass concrete, reinforced concrete bases,\nmasonry walls, buried foundations, kerbs and gully bases below\nfinished surface, redundant utility chambers.\n\nThese are the two materially-different operations that the four\nUK standards uniformly distinguish.'}, 'height_of_hard_material_m': {'type': 'number', 'default': 0.5}}, 'description': "Parameters for a single hard-material extra-over scenario.\n\nGeometry interpretation:\n - `length_m` is the chainage extent of the hard-material zone\n (i.e. how many metres of pipe-run encounter hard material).\n This is the MMHW/SMM7 quantity directly.\n - `trench_width_m` is the trench plan width at the level of the\n hard material â\x80\x94 used (with height_of_hard_material_m and\n length_m) to compute the volumetric quantity used by\n CESMM4/NRM2.\n - `height_of_hard_material_m` is the vertical extent of hard\n material within the trench section â\x80\x94 the bottom of the\n trench wraps the pipe envelope, so the hard-material height\n is typically less than the full trench depth. This is the\n QS's judgment, informed by site investigation.\n - `max_depth_m` is the depth (from finished ground level) to\n the bottom of the hard-material zone â\x80\x94 drives the depth\n banding in all four handlers.\n - `pipe_diameter_mm` is descriptive only â\x80\x94 propagated to the\n WorkItem for cross-referencing the carrier pipe.\n\nVolume = length_m Ã\x97 trench_width_m Ã\x97 height_of_hard_material_m."}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'cover_mm': {'type': 'integer', 'default': 50}, 'quantity': {'type': 'integer', 'default': 1}, 'apron_length': {'type': 'number', 'default': 2.0}, 'headwall_type': {'enum': ['in_situ', 'precast'], 'type': 'string', 'default': 'in_situ', 'description': 'Construction method for the headwall.'}, 'apron_overhang': {'type': 'number', 'default': 0.3}, 'blinding_grade': {'type': 'string', 'default': 'C8/10'}, 'concrete_grade': {'type': 'string', 'default': 'C32/40'}, 'apron_thickness': {'type': 'number', 'default': 0.25}, 'back_wall_height': {'type': 'number', 'default': 1.5}, 'back_wall_length': {'type': 'number', 'default': 2.5}, 'wing_wall_height': {'type': 'number', 'default': 1.5}, 'wing_wall_length': {'type': 'number', 'default': 1.5}, 'scour_apron_width': {'type': 'number', 'default': 4.0}, 'scour_apron_length': {'type': 'number', 'default': 2.0}, 'back_wall_thickness': {'type': 'number', 'default': 0.3}, 'scour_stone_size_mm': {'type': 'integer', 'default': 200}, 'wing_wall_splay_deg': {'type': 'number', 'default': 30.0}, 'wing_wall_thickness': {'type': 'number', 'default': 0.25}, 'has_scour_protection': {'type': 'boolean', 'default': True}, 'invert_below_apron_m': {'type': 'number', 'default': 0.0}, 'wing_wall_tip_height': {'type': 'number', 'default': 0.3}, 'apron_main_bar_dia_mm': {'type': 'integer', 'default': 12}, 'formation_below_apron': {'type': 'number', 'default': 0.075}, 'pipe_wall_thickness_mm': {'type': 'integer', 'default': 50}, 'apron_main_bar_pitch_mm': {'type': 'integer', 'default': 200}, 'scour_blanket_thickness': {'type': 'number', 'default': 0.3}, 'working_space_each_side': {'type': 'number', 'default': 0.45}, 'back_wall_main_bar_dia_mm': {'type': 'integer', 'default': 16}, 'pipe_internal_diameter_mm': {'type': 'integer', 'default': 300}, 'wing_wall_main_bar_dia_mm': {'type': 'integer', 'default': 12}, 'back_wall_main_bar_pitch_mm': {'type': 'integer', 'default': 200}, 'wing_wall_main_bar_pitch_mm': {'type': 'integer', 'default': 200}, 'apron_distribution_bar_dia_mm': {'type': 'integer', 'default': 12}, 'apron_distribution_bar_pitch_mm': {'type': 'integer', 'default': 200}, 'back_wall_distribution_bar_dia_mm': {'type': 'integer', 'default': 12}, 'back_wall_distribution_bar_pitch_mm': {'type': 'integer', 'default': 200}}}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'size': {'enum': ['PHW_300', 'PHW_375', 'PHW_450', 'PHW_600', 'PHW_750', 'PHW_900', 'PHW_1050', 'PHW_1200', 'PHW_1500'], 'type': 'string', 'default': 'PHW_600', 'description': 'Standard UK precast headwall sizes, by outfall pipe internal diameter.\n\nThese bracket the offerings from Marshalls CPM, FP McCann, and\nStanton Bonna. The unit size determines the CESMM4 Class H sub-code\n(H.7.1 â\x89¤ 1200mm, H.7.2 > 1200mm), the typical mass for handling\nplant requirements, and the bedding footprint.'}, 'quantity': {'type': 'integer', 'default': 1}, 'project_ref': {'type': 'string', 'default': 'Attenuation Outlet'}, 'bedding_type': {'enum': ['concrete_bed', 'granular_bed'], 'type': 'string', 'default': 'concrete_bed', 'description': 'Bedding type beneath a precast headwall.\n\nCONCRETE_BED uses mass concrete blinding (typically C8/10 or C16/20)\nunder the unit, providing a level rigid surface and tying the unit\nto the formation. Common for soft cohesive ground and where flow\nerosion under the unit is a risk.\n\nGRANULAR_BED uses imported Class 6N or 6P granular material per\nSHW Cl. 803, compacted and levelled. Common for non-erodible\ngranular soils where a concrete bed is unnecessary.'}, 'has_penstock': {'type': 'boolean', 'default': False}, 'supply_route': {'anyOf': [{'enum': ['contractor_full', 'contractor_install_pc_supply', 'provisional_sum', 'utility_provider_supply', 'employer_direct'], 'type': 'string'}, {'type': 'null'}], 'default': None}, 'chainage_label': {'type': 'string', 'default': ''}, 'has_flap_valve': {'type': 'boolean', 'default': False}, 'penstock_size_mm': {'type': 'integer', 'default': 0}, 'gabion_mesh_grade': {'type': 'string', 'default': 'Type A galfan PVC-coated mesh to BS EN 10223-3'}, 'has_weir_overflow': {'type': 'boolean', 'default': False}, 'flap_valve_size_mm': {'type': 'integer', 'default': 0}, 'orifice_diameter_mm': {'type': 'integer', 'default': 150}, 'scour_apron_width_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'scour_stone_size_mm': {'type': 'integer', 'default': 200}, 'concrete_apron_grade': {'type': 'string', 'default': 'C32/40'}, 'orifice_manufacturer': {'type': 'string', 'default': 'generic'}, 'scour_apron_length_m': {'type': 'number', 'default': 2.0}, 'scour_protection_type': {'enum': ['rock_armour', 'gabion_mattress', 'concrete_apron', 'none'], 'type': 'string', 'default': 'rock_armour', 'description': 'Scour protection variant downstream of the headwall outfall.\n\nROCK_ARMOUR is the existing headwall_precast variant (granular fill,\nrock armour blanket). GABION_MATTRESS and CONCRETE_APRON are the\nnew S21 extensions for higher-energy or longer-lasting requirements.\nNONE skips scour protection entirely (rare; only suitable for\ndischarge into a robust receiving channel like a piled concrete\nweir basin).'}, 'concrete_bedding_grade': {'type': 'string', 'default': 'C8/10'}, 'scour_blanket_thickness_m': {'type': 'number', 'default': 0.3}, 'orifice_target_discharge_ls': {'type': 'number', 'default': 5.0}, 'weir_overflow_crest_height_m': {'type': 'number', 'default': 0.5}, 'weir_overflow_crest_length_m': {'type': 'number', 'default': 1.0}}, 'description': 'Parameter form for an attenuation outlet headwall.\n\nComposes a precast headwall (size, bedding) with one always-present\norifice plate and up to three optional outlet-control ironmongery\nitems (flap valve, weir overflow, penstock), plus a scour\nprotection variant.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'size': {'enum': ['PHW_300', 'PHW_375', 'PHW_450', 'PHW_600', 'PHW_750', 'PHW_900', 'PHW_1050', 'PHW_1200', 'PHW_1500'], 'type': 'string', 'default': 'PHW_600', 'description': 'Standard UK precast headwall sizes, by outfall pipe internal diameter.\n\nThese bracket the offerings from Marshalls CPM, FP McCann, and\nStanton Bonna. The unit size determines the CESMM4 Class H sub-code\n(H.7.1 â\x89¤ 1200mm, H.7.2 > 1200mm), the typical mass for handling\nplant requirements, and the bedding footprint.'}, 'quantity': {'type': 'integer', 'default': 1}, 'unit_mass_t': {'type': 'number', 'default': None}, 'bedding_type': {'enum': ['concrete_bed', 'granular_bed'], 'type': 'string', 'default': 'concrete_bed', 'description': 'Bedding type beneath a precast headwall.\n\nCONCRETE_BED uses mass concrete blinding (typically C8/10 or C16/20)\nunder the unit, providing a level rigid surface and tying the unit\nto the formation. Common for soft cohesive ground and where flow\nerosion under the unit is a risk.\n\nGRANULAR_BED uses imported Class 6N or 6P granular material per\nSHW Cl. 803, compacted and levelled. Common for non-erodible\ngranular soils where a concrete bed is unnecessary.'}, 'unit_depth_m': {'type': 'number', 'default': None}, 'unit_width_m': {'type': 'number', 'default': None}, 'apron_width_m': {'type': 'number', 'default': None}, 'unit_height_m': {'type': 'number', 'default': None}, 'apron_length_m': {'type': 'number', 'default': None}, 'bedding_overhang_m': {'type': 'number', 'default': 0.15}, 'scour_apron_width_m': {'type': 'number', 'default': None}, 'scour_stone_size_mm': {'type': 'integer', 'default': 200}, 'bedding_thickness_mm': {'type': 'integer', 'default': 150}, 'has_scour_protection': {'type': 'boolean', 'default': True}, 'scour_apron_length_m': {'type': 'number', 'default': 2.0}, 'concrete_bedding_grade': {'type': 'string', 'default': 'C8/10'}, 'granular_bedding_class': {'type': 'string', 'default': '6N'}, 'formation_below_bedding_m': {'type': 'number', 'default': 0.075}, 'pipe_internal_diameter_mm': {'type': 'integer', 'default': None}, 'scour_blanket_thickness_m': {'type': 'number', 'default': 0.3}, 'working_space_each_side_m': {'type': 'number', 'default': 0.45}}, 'description': "Parameter form for a precast headwall.\n\nCatalogue-driven: pick a `size` and the unit's nominal physical\ndimensions are read from `_CATALOGUE`. Override individual physical\nfields if a specific manufacturer differs."}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'depth_class': {'enum': ['shallow', 'medium', 'deep', 'extra_deep'], 'type': 'string', 'default': 'shallow', 'description': 'Channel depth classification per typical UK pricing tiers.\n\nDepth drives unit weight, bedding volume, trench-support\nrequirement, and ground-water-handling cost independently of the\nchannel type. UK practice prices channel depth in four\ncommercial bands:\n\nSHALLOW â\x80\x94 â\x89¤150mm. Footway / pedestrian area / car park.\nMEDIUM â\x80\x94 151-300mm. Standard carriageway edge.\nDEEP â\x80\x94 301-500mm. High-flow carriageway / motorway edge.\nEXTRA_DEEP â\x80\x94 >500mm. Junction sump / heavy-flow location.'}, 'channel_type': {'enum': ['linear_polymer_concrete', 'linear_concrete', 'slot_drain', 'combined_kerb_drainage', 'steel_grated_channel'], 'type': 'string', 'default': 'linear_polymer_concrete', 'description': 'Channel product classification per BS EN 1433 + UK industry practice.\n\nLINEAR_POLYMER_CONCRETE â\x80\x94 Monolithic moulded fibre-reinforced polymer-\n concrete unit (ACO-pattern, the dominant UK case). Tight-tolerance\n manufactured joint, ductile-iron grating per BS EN 124.\nLINEAR_CONCRETE â\x80\x94 Precast reinforced concrete unit (Charcon-\n pattern). Rebated joint, ductile-iron grating per BS EN 124.\nSLOT_DRAIN â\x80\x94 Recessed narrow-slot channel section\n (stainless-steel or polymer-concrete). Used where visual\n impact must be minimised (conservation areas, pedestrianised\n zones, courtyard schemes).\nCOMBINED_KERB_DRAINAGE â\x80\x94 Integrated kerb+drain monolithic unit per\n SHW Cl. 514 (Beany / Safeticurb-pattern). The kerb face and\n the channel are a single precast item. Used where kerb-line\n installation and surface drainage are integrated.\nSTEEL_GRATED_CHANNEL â\x80\x94 Heavy-duty stainless-steel or galvanised-\n steel grated channel for industrial-loading service\n (Class E600/F900 BS EN 124). Used at airports, port hardstandings,\n and industrial yards.'}, 'outfall_type': {'anyOf': [{'enum': ['end_outfall', 'branch_outfall', 'side_outfall'], 'type': 'string', 'description': 'Outfall fitting classification per UK industry practice.\n\nEND_OUTFALL â\x80\x94 Termination of channel run with downstream\n connection to chamber or carrier pipe.\nBRANCH_OUTFALL â\x80\x94 Mid-run discharge connection (T-fitting to\n the channel base).\nSIDE_OUTFALL â\x80\x94 Lateral discharge to an adjacent chamber\n (S-fitting through the channel side wall).'}, {'type': 'null'}], 'default': 'end_outfall'}, 'outfall_count': {'type': 'integer', 'default': 1}, 'silt_box_type': {'anyOf': [{'enum': ['standard', 'heavy_duty', 'deep_sump'], 'type': 'string', 'description': 'Silt box classification per BS EN 124 load class + service.\n\nSTANDARD â\x80\x94 Class C250 BS EN 124. Footway / car park service.\nHEAVY_DUTY â\x80\x94 Class D400 BS EN 124. Standard carriageway service.\nDEEP_SUMP â\x80\x94 Extended sediment trap depth. For high-silt-load\n locations (forest edge, construction-site adjacent, etc.).'}, {'type': 'null'}], 'default': None}, 'silt_box_count': {'type': 'integer', 'default': 0}, 'channel_depth_mm': {'type': 'integer', 'default': 100}, 'channel_length_m': {'type': 'number', 'default': 50.0}, 'branch_outfall_count': {'type': 'integer', 'default': 0}}, 'description': 'Inputs for the highway_drainage_channel assembly.\n\nRequired:\n channel_type â\x80\x94 ChannelType enum (or string equivalent)\n depth_class â\x80\x94 DepthClass enum (or string)\n channel_depth_mm â\x80\x94 actual channel depth in mm\n channel_length_m â\x80\x94 channel run length in metres\n\nOptional:\n outfall_type â\x80\x94 OutfallType enum (or string); defaults to\n END_OUTFALL when outfall_count > 0\n outfall_count â\x80\x94 number of primary outfalls (default 1)\n branch_outfall_count â\x80\x94 number of additional branch outfalls\n (default 0)\n silt_box_type â\x80\x94 SiltBoxType enum (or string); required\n when silt_box_count > 0\n silt_box_count â\x80\x94 number of silt boxes (default 0)'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'kerb_type': {'enum': ['HB2', 'HB1', 'SP', 'BN', 'EF', 'ER'], 'type': 'string', 'default': 'HB2', 'description': 'Precast concrete kerb profiles per BS EN 1340 (and the SHW Cl. 1101\ntype designators used in UK highway practice).\n\nDimensions are width Ã\x97 height in mm (cross-section). Upstand is the\nportion above road level (typically half the height for HB types).'}, 'kerb_length': {'type': 'number', 'default': 25.0}, 'channel_type': {'enum': ['none', 'CS1', 'CS2', 'dish'], 'type': 'string', 'default': 'none', 'description': 'Optional channel block on the carriageway side of the kerb.'}, 'sub_base_class': {'enum': ['1A', '1B', '1C', '2A', '2B', '2C', '2D', '2E', '3', '4', '5A', '5B', '6A', '6B', '6C', '6D', '6E', '6F1', '6F2', '6F3', '6F4', '6F5', '6I', '6J', '6N', '6P', '6Q', '7A', '7B', '7C', '7D', '7E', '7F', '8', '9A', '9B', 'U1A', 'U1B', 'U2'], 'type': 'string', 'default': '1A', 'description': 'Full SHW Series 600 Table 6/1 acceptable material class set, plus the\nTable 6/2 unacceptable classes.\n\nThe enum value is the SHW designator. Use `family` and `default_use`\nproperties for routing in the assembly and renderer code.'}, 'bed_thickness_mm': {'type': 'integer', 'default': 150}, 'bed_concrete_grade': {'type': 'string', 'default': 'C20/25'}, 'haunch_height_ratio': {'type': 'number', 'default': 0.5}, 'haunch_concrete_grade': {'type': 'string', 'default': 'C20/25'}, 'sub_base_thickness_mm': {'type': 'integer', 'default': 150}, 'bed_extra_each_side_mm': {'type': 'integer', 'default': 100}, 'haunch_width_at_base_mm': {'type': 'integer', 'default': 150}, 'excavation_extra_each_side_mm': {'type': 'integer', 'default': 50}}, 'description': 'Input parameters for a kerb run assembly.\n\nGeometric defaults match a standard UK HB2 road kerb on 150mm\nconcrete bed over 150mm Type 1 sub-base, with triangular haunch\nrising to half the kerb height on the back face.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'quantity': {'type': 'integer', 'default': 1}, 'column_type': {'enum': ['steel_galvanised', 'aluminium', 'composite_grp', 'decorative_cast_iron'], 'type': 'string', 'default': 'steel_galvanised', 'description': 'Column material classification per BS EN 40-5/6/7.\n\nSTEEL_GALVANISED â\x80\x94 Carbon-steel column shaft, hot-dip galvanised\n after fabrication. The dominant UK case (~85% of new street\n lighting installations). BS EN 40-5.\nALUMINIUM â\x80\x94 Extruded aluminium column. Used for ped-cycle\n track lighting (lighter handling) and seafront/marine zones\n (corrosion resistance). BS EN 40-6.\nCOMPOSITE_GRP â\x80\x94 Glass-reinforced polymer column. Used in zones\n with high crash energy (frangible) or where electrical\n isolation is required. BS EN 40-7.\nDECORATIVE_CAST_IRON â\x80\x94 Cast-iron decorative column for conservation\n areas and heritage zones. Bespoke finish; BS EN 40-5 with\n traditional Victorian/Edwardian design.'}, 'bracket_type': {'anyOf': [{'enum': ['single_side_entry', 'double_side_entry', 'post_top_adaptor', 'decorative_swan_neck'], 'type': 'string', 'description': 'Column bracket classification per BS EN 40-2.\n\nSINGLE_SIDE_ENTRY â\x80\x94 Single side-entry outreach bracket. The\n dominant case for carriageway lighting where the luminaire\n is offset over the kerb.\nDOUBLE_SIDE_ENTRY â\x80\x94 Double side-entry bracket carrying two\n luminaires (one each side). Used at junctions / where dual\n carriageways meet at a single column.\nPOST_TOP_ADAPTOR â\x80\x94 Post-top adaptor (luminaire mounted on\n column tip, no outreach). Used for residential and ped-cycle\n lighting where the luminaire is directly above the column.\nDECORATIVE_SWAN_NECK â\x80\x94 Decorative swan-neck bracket for heritage\n / conservation zones.'}, {'type': 'null'}], 'default': None}, 'bracket_count': {'type': 'integer', 'default': 0}, 'luminaire_type': {'enum': ['led_M_class', 'led_decorative', 'son_legacy', 'sox_legacy', 'floodlight'], 'type': 'string', 'default': 'led_M_class', 'description': 'Luminaire classification per BS EN 13201 / ILP TR23.\n\nLED_M_CLASS â\x80\x94 LED luminaire suitable for M-class carriageway\n lighting per BS EN 13201. The dominant new-install case\n post-2015.\nLED_DECORATIVE â\x80\x94 LED decorative lantern for conservation-area /\n heritage zones (Victorian/Edwardian styling).\nSON_LEGACY â\x80\x94 High-pressure sodium SON lamp luminaire. Legacy\n only â\x80\x94 included for like-for-like replacement schemes.\nSOX_LEGACY â\x80\x94 Low-pressure sodium SOX lamp luminaire. Legacy\n only â\x80\x94 banned for new installs since the 2010s; included for\n rare replacement.\nFLOODLIGHT â\x80\x94 Asymmetric-beam floodlight luminaire (junction\n floodlighting, pedestrian-area floodlighting).'}, 'foundation_type': {'enum': ['precast_socket', 'insitu_reinforced', 'root_planted'], 'type': 'string', 'default': 'precast_socket', 'description': "Column foundation classification per SHW Cl. 1304 / TR 22.\n\nPRECAST_SOCKET â\x80\x94 Precast concrete plant base socket. Typical\n for columns â\x89¤8m on residential/urban streets. Quick install\n (drop-in), reusable across the contractor's stock.\nINSITU_REINFORCED â\x80\x94 In-situ reinforced concrete foundation with\n holding-down bolts. Typical for columns â\x89¥10m where wind/dynamic\n loads exceed the precast socket's anchorage capacity.\nROOT_PLANTED â\x80\x94 Direct-buried planted column (no separate\n foundation block); the steel column extends below ground to\n TR 22 minimum embedment depth."}, 'bracket_reach_mm': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None}, 'mounting_height_m': {'type': 'number', 'default': 6.0}, 'column_height_class': {'enum': ['h_5m', 'h_6m', 'h_8m', 'h_10m', 'h_12m', 'h_15m'], 'type': 'string', 'default': 'h_6m', 'description': 'Column mounting height class per TR 22 standard heights.\n\nThe six values correspond to UK standard heights for street\nlighting. Each height class drives steel section thickness, base\nplate size, and foundation depth per BS EN 40-2.\n\nH_5M â\x80\x94 5m (residential / footway side)\nH_6M â\x80\x94 6m (urban residential / pedestrian areas)\nH_8M â\x80\x94 8m (urban distributor / town centre)\nH_10M â\x80\x94 10m (urban traffic route / arterial)\nH_12M â\x80\x94 12m (motorway slip road / interchange approaches)\nH_15M â\x80\x94 15m (motorway main line / high-mast areas)'}, 'luminaire_wattage_W': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': 60}, 'column_loading_class': {'enum': ['A', 'B', 'C', 'D'], 'type': 'string', 'default': 'B', 'description': "Column wind-loading class per BS EN 40-3.\n\nThe class defines the permitted luminaire+bracket projected wind\narea for a given column section. Class jumps drive the column's\nsteel weight independently of mounting height.\n\nA â\x80\x94 small luminaire, projected area <0.025 m²\nB â\x80\x94 medium luminaire, 0.025-0.045 m²\nC â\x80\x94 large luminaire / single bracket, 0.045-0.075 m²\nD â\x80\x94 high-mast / multi-luminaire, >0.075 m²"}}, 'description': 'Inputs for the lighting_column assembly.\n\nDefaults anchored to URBAN_6M_LED â\x80\x94 UK urban distributor: 6 m steel\ngalvanised column on precast socket, BS EN 40-3 Class B, LED M-class\nluminaire (~60 W typical). Required-field defaults added per G.6.7.24\nprecedent â\x80\x94 non-breaking API enrichment opens the slug to schema-\ndriven workspace defaults.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'quantity': {'type': 'integer', 'default': 1}, 'base_grade': {'type': 'string', 'default': 'C32/40'}, 'access_type': {'enum': ['step_irons', 'ladder', 'none'], 'type': 'string', 'default': 'step_irons'}, 'invert_depth': {'type': 'number', 'default': 3.5}, 'cover_loading': {'enum': ['A15', 'B125', 'C250', 'D400', 'E600', 'F900'], 'type': 'string', 'default': 'D400'}, 'base_thickness': {'type': 'number', 'default': 0.2}, 'benching_grade': {'type': 'string', 'default': 'C32/40'}, 'blinding_grade': {'type': 'string', 'default': 'C8/10'}, 'wall_thickness': {'type': 'number', 'default': 0.15}, 'base_projection': {'type': 'number', 'default': 0.15}, 'cover_slab_grade': {'type': 'string', 'default': 'C32/40'}, 'excavation_batter': {'type': 'number', 'default': 0.5}, 'has_reducing_slab': {'type': 'boolean', 'default': True}, 'internal_diameter': {'type': 'number', 'default': 1.5}, 'step_iron_spacing': {'type': 'number', 'default': 0.3}, 'surround_material': {'type': 'string', 'default': '20mm single-size aggregate'}, 'blinding_thickness': {'type': 'number', 'default': 0.075}, 'excavation_support': {'enum': ['open_batter', 'vertical'], 'type': 'string', 'default': 'open_batter'}, 'surround_thickness': {'type': 'number', 'default': 0.15}, 'cover_clear_opening': {'type': 'number', 'default': 0.6}, 'cover_slab_thickness': {'type': 'number', 'default': 0.2}, 'cover_to_top_of_slab': {'type': 'number', 'default': 0.075}, 'geotextile_full_wrap': {'type': 'boolean', 'default': True}, 'seating_rings_height': {'type': 'number', 'default': 0.15}, 'main_channel_diameter': {'type': 'number', 'default': 0.3}, 'reducing_slab_at_depth': {'type': 'number', 'default': 1.2}, 'reducing_slab_thickness': {'type': 'number', 'default': 0.225}, 'shaft_internal_diameter': {'type': 'number', 'default': 0.675}, 'working_space_each_side': {'type': 'number', 'default': 0.5}, 'benching_rebar_kg_per_m3': {'type': 'number', 'default': 60.0}, 'base_slab_rebar_kg_per_m3': {'type': 'number', 'default': 110.0}, 'cover_slab_rebar_kg_per_m3': {'type': 'number', 'default': 130.0}, 'sheet_pile_depth_below_formation': {'type': 'number', 'default': 1.0}}}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'size': {'enum': ['PMC_1200', 'PMC_1500', 'PMC_1800', 'PMC_2100', 'PMC_2400'], 'type': 'string', 'default': 'PMC_1500', 'description': 'Standard UK precast monolithic-base manhole chamber internal\ndiameters. Catalogued by Marshalls CPM, FP McCann, Stanton Bonna,\nand CPM Group. PMC1200 is the smallest commonly stocked monolithic\nbase; PMC2400 is the largest practical without bespoke order.'}, 'quantity': {'type': 'integer', 'default': 1}, 'access_type': {'enum': ['step_irons', 'ladder', 'none'], 'type': 'string', 'default': 'step_irons'}, 'ring_mass_t': {'type': 'number', 'default': None}, 'bedding_type': {'enum': ['granular', 'concrete'], 'type': 'string', 'default': 'granular', 'description': 'Bedding layer beneath a precast monolithic base.'}, 'invert_depth': {'type': 'number', 'default': 3.5}, 'cover_loading': {'enum': ['A15', 'B125', 'C250', 'D400', 'E600', 'F900'], 'type': 'string', 'default': 'D400', 'description': 'BS EN 124 cover-and-frame loading classes.'}, 'ring_height_m': {'type': 'number', 'default': None}, 'wall_thickness': {'type': 'number', 'default': None}, 'base_unit_mass_t': {'type': 'number', 'default': None}, 'cover_slab_grade': {'type': 'string', 'default': 'C40/50'}, 'excavation_batter': {'type': 'number', 'default': 0.5}, 'has_reducing_slab': {'type': 'boolean', 'default': True}, 'internal_diameter': {'type': 'number', 'default': None}, 'step_iron_spacing': {'type': 'number', 'default': 0.3}, 'surround_material': {'type': 'string', 'default': '20mm single-size aggregate'}, 'base_unit_height_m': {'type': 'number', 'default': None}, 'bedding_overhang_m': {'type': 'number', 'default': 0.15}, 'excavation_support': {'enum': ['open_batter', 'vertical'], 'type': 'string', 'default': 'open_batter'}, 'surround_thickness': {'type': 'number', 'default': 0.15}, 'cover_clear_opening': {'type': 'number', 'default': 0.6}, 'bedding_thickness_mm': {'type': 'integer', 'default': 150}, 'cover_slab_thickness': {'type': 'number', 'default': 0.2}, 'cover_to_top_of_slab': {'type': 'number', 'default': 0.075}, 'geotextile_full_wrap': {'type': 'boolean', 'default': True}, 'seating_rings_height': {'type': 'number', 'default': 0.15}, 'bedding_concrete_grade': {'type': 'string', 'default': 'C8/10'}, 'bedding_granular_class': {'type': 'string', 'default': '6N'}, 'reducing_slab_at_depth': {'type': 'number', 'default': 1.2}, 'reducing_slab_thickness': {'type': 'number', 'default': 0.225}, 'shaft_internal_diameter': {'type': 'number', 'default': 0.675}, 'working_space_each_side': {'type': 'number', 'default': 0.5}, 'sheet_pile_depth_below_formation': {'type': 'number', 'default': 1.0}}, 'description': "Parameter form for a fully monolithic precast concrete manhole.\n\nCatalogue-driven: pick a ``size`` and the chamber's nominal\ndimensions, masses, and ring heights are read from ``_CATALOGUE``.\nOverride individual fields if a specific manufacturer differs."}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['assembly_slug', 'sections'], 'properties': {'sections': {'type': 'array', 'items': {'type': 'object', 'additionalProperties': True}}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}, 'aggregate_boq': {'type': 'boolean', 'default': True}, 'assembly_slug': {'type': 'string'}, 'shared_params': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'include_backup': {'type': 'boolean', 'default': False}, 'include_section_boq': {'type': 'boolean', 'default': False}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'section_count', 'section_summary', 'aggregated_boq_rows'], 'properties': {'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['section_label', 'warning'], 'properties': {'warning': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}, 'section_label': {'type': 'string', 'minLength': 1}}, 'description': 'A section-labelled geometry/advisory warning.', 'additionalProperties': False}}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'section_count': {'type': 'integer', 'minimum': 1}, 'parameters_used': {'type': 'object', 'additionalProperties': True}, 'section_results': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'section_summary': {'type': 'array', 'items': {'type': 'object', 'required': ['label', 'totals_summary'], 'properties': {'label': {'type': 'string', 'minLength': 1}, 'run_length': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}}, 'description': 'Cheap always-on per-section line: label + run length + totals.', 'additionalProperties': False}}, 'aggregated_boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}}, 'description': 'Aggregated + per-section result for a sectioned assembly run.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'width': {'type': 'number', 'default': 2.0}, 'length': {'type': 'number', 'default': 2.0}, 'top_mat': {'type': 'boolean', 'default': True}, 'cover_mm': {'type': 'integer', 'default': 50}, 'thickness': {'type': 'number', 'default': 0.45}, 'has_pedestal': {'type': 'boolean', 'default': False}, 'working_space': {'type': 'number', 'default': 0.3}, 'blinding_grade': {'type': 'string', 'default': 'C8/10'}, 'concrete_grade': {'type': 'string', 'default': 'C32/40'}, 'pedestal_width': {'type': 'number', 'default': 0.4}, 'side_bar_count': {'type': 'integer', 'default': 2}, 'pedestal_height': {'type': 'number', 'default': 0.5}, 'pedestal_length': {'type': 'number', 'default': 0.4}, 'top_bar_pitch_mm': {'type': 'integer', 'default': 200}, 'main_bar_pitch_mm': {'type': 'integer', 'default': 150}, 'blinding_thickness': {'type': 'number', 'default': 0.075}, 'top_bar_diameter_mm': {'type': 'integer', 'default': 12}, 'main_bar_diameter_mm': {'type': 'integer', 'default': 16}, 'side_bar_diameter_mm': {'type': 'integer', 'default': 10}}}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'post_count': {'type': 'integer', 'default': 0}, 'parapet_type': {'enum': ['pedestrian_only', 'vehicle_p1_p2', 'vehicle_h1_h2_h3', 'combined_pedestrian_vehicle'], 'type': 'string', 'default': 'vehicle_p1_p2', 'description': 'Parapet system classification per UK design practice.\n\nPEDESTRIAN_ONLY â\x80\x94 BS 7818 handrail-and-infill for\n footway / pedestrian-only bridges. Live load to BS EN 1991-2\n but NO vehicle containment requirement.\nVEHICLE_P1_P2 â\x80\x94 BS EN 1317-2 containment class P1\n or P2. Low-containment vehicle parapet for low-speed roads\n (â\x89¤50mph). NOTE: in BS EN 1317-2 itself, P1/P2 are pedestrian\n classes; UK vehicle-parapet practice extends the P-prefix to\n cover low-containment vehicle situations.\nVEHICLE_H1_H2_H3 â\x80\x94 BS EN 1317-2 containment class H1,\n H2 or H3. Higher-containment vehicle parapet for motorways\n and high-speed roads.\nCOMBINED_PEDESTRIAN_VEHICLE â\x80\x94 Composite design with vehicle-rated\n lower section per BS EN 1317-2 and pedestrian-rated upper rail\n per BS 7818. Used on shared footway/carriageway bridges.'}, 'transition_type': {'anyOf': [{'enum': ['to_vrs', 'to_abutment', 'expansion_joint'], 'type': 'string', 'description': 'Parapet transition classification.\n\nTO_VRS â\x80\x94 Most common. Parapet-to-ground-level VRS\n transition at the bridge approach end (deck-end to embankment).\n Subject to BS EN 1317-4 transition compatibility requirements.\nTO_ABUTMENT â\x80\x94 Parapet anchorage transition into masonry or\n concrete bridge abutment wall (no VRS continuation â\x80\x94\n terminates at the abutment).\nEXPANSION_JOINT â\x80\x94 Continuity break in the parapet at a deck\n expansion joint on long bridges, accommodating structural\n movement.'}, {'type': 'null'}], 'default': None}, 'parapet_length_m': {'type': 'number', 'default': 25.0}, 'transition_count': {'type': 'integer', 'default': 0}, 'containment_level': {'enum': ['P1', 'P2', 'N1', 'N2', 'H1', 'H2', 'H3', 'H4a', 'H4b'], 'type': 'string', 'default': 'N2', 'description': 'BS EN 1317-2 / BS EN 1317-6 containment classification.\n\nPedestrian classes:\n P1 â\x80\x94 Light pedestrian containment.\n P2 â\x80\x94 Heavier pedestrian containment (e.g. cyclist permitted).\n\nVehicle classes (ascending containment energy):\n N1 â\x80\x94 Low containment, normal traffic.\n N2 â\x80\x94 Higher of the normal range.\n H1 â\x80\x94 Higher containment, high-speed road.\n H2 â\x80\x94 Higher containment, dual carriageway.\n H3 â\x80\x94 Very high containment, motorway.\n H4a â\x80\x94 Highest containment, motorway HGV restraint.\n H4b â\x80\x94 Highest containment, motorway HGV+bus restraint.'}, 'parapet_height_mm': {'type': 'integer', 'default': 1100}}, 'description': 'Inputs for the parapet assembly.\n\nRequired:\n parapet_type â\x80\x94 ParapetType enum (or string equivalent)\n containment_level â\x80\x94 ContainmentLevel enum (or string)\n parapet_height_mm â\x80\x94 nominal parapet height above deck in mm\n parapet_length_m â\x80\x94 parapet run length in metres\n\nOptional:\n post_count â\x80\x94 number of enumerated posts (default 0 â\x80\x94\n posts deemed-included in parapet m-rate).\n Set > 0 only for contracts requiring\n specialist per-post pricing.\n transition_type â\x80\x94 TransitionType enum (or string). Required\n if transition_count > 0.\n transition_count â\x80\x94 number of transition pieces (default 0).'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'width': {'type': 'number', 'default': 5.0}, 'length': {'type': 'number', 'default': 12.0}, 'surface_type': {'enum': ['PBP', 'PA', 'PC'], 'type': 'string', 'default': 'PBP', 'description': 'Three principal UK permeable surface types per CIRIA C753.\nMapped 1:1 onto the new PavementFamily enum extensions (PBP/PA/PC).\nCarried as a dedicated enum on Parameters so the assembly\nparametrisation expresses intent in CIRIA-Manual vocabulary.'}, 'geotextile_grade': {'type': 'string', 'default': '200 g/m² non-woven'}, 'tanking_material': {'type': 'string', 'default': 'HDPE'}, 'include_outlet_pipe': {'type': 'boolean', 'default': False}, 'infiltration_system': {'enum': ['A', 'B', 'C'], 'type': 'string', 'default': 'A', 'description': 'Three CIRIA C753 (SuDS Manual Ch.20) permeable-pavement infiltration\nregimes. Drives the membrane / outlet pipe inclusion.'}, 'reservoir_shw_class': {'enum': ['1A', '1B', '1C', '2A', '2B', '2C', '2D', '2E', '3', '4', '5A', '5B', '6A', '6B', '6C', '6D', '6E', '6F1', '6F2', '6F3', '6F4', '6F5', '6I', '6J', '6N', '6P', '6Q', '7A', '7B', '7C', '7D', '7E', '7F', '8', '9A', '9B', 'U1A', 'U1B', 'U2'], 'type': 'string', 'default': '3', 'description': 'Full SHW Series 600 Table 6/1 acceptable material class set, plus the\nTable 6/2 unacceptable classes.\n\nThe enum value is the SHW designator. Use `family` and `default_use`\nproperties for routing in the assembly and renderer code.'}, 'reservoir_voids_pct': {'type': 'integer', 'default': 30}, 'outlet_pipe_length_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'surface_thickness_mm': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None}, 'include_formation_prep': {'type': 'boolean', 'default': True}, 'reservoir_thickness_mm': {'type': 'integer', 'default': 350}, 'laying_course_shw_class': {'enum': ['1A', '1B', '1C', '2A', '2B', '2C', '2D', '2E', '3', '4', '5A', '5B', '6A', '6B', '6C', '6D', '6E', '6F1', '6F2', '6F3', '6F4', '6F5', '6I', '6J', '6N', '6P', '6Q', '7A', '7B', '7C', '7D', '7E', '7F', '8', '9A', '9B', 'U1A', 'U1B', 'U2'], 'type': 'string', 'default': '6N', 'description': 'Full SHW Series 600 Table 6/1 acceptable material class set, plus the\nTable 6/2 unacceptable classes.\n\nThe enum value is the SHW designator. Use `family` and `default_use`\nproperties for routing in the assembly and renderer code.'}, 'outlet_pipe_diameter_mm': {'type': 'integer', 'default': 150}, 'tanking_thickness_micron': {'type': 'integer', 'default': 2000}, 'include_laying_course_line': {'type': 'boolean', 'default': False}, 'laying_course_thickness_mm': {'type': 'integer', 'default': 30}, 'include_geotextile_separator': {'type': 'boolean', 'default': True}, 'excavation_extra_each_side_mm': {'type': 'integer', 'default': 0}}, 'description': 'Input parameters for a permeable pavement assembly.\n\nGeometric defaults match a 12m Ã\x97 5m residential drive with PBP\nsurface and System A (full infiltration) â\x80\x94 the dominant UK\nsmall-civils SuDS use case.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'size': {'enum': ['NS3', 'NS6', 'NS10', 'NS15', 'NS30', 'NS65', 'NS100'], 'type': 'string', 'default': 'NS10', 'description': 'Nominal size NS designation per BS EN 858-2. The number is the\nnominal flow rating in l/s; the catalogue dimensions are sized to\nsuit the full-retention storage volume V_oil = NS Ã\x97 10 litres\n(cl. 4.3.6). Bypass units of the same NS rating share dimensions\nin most UK manufacturer ranges (the bypass weir is internal).\n\nSeven catalogue entries spanning the practical UK range:\n NS3 â\x80\x94 small private yard, ~600m² impermeable catchment\n NS6 â\x80\x94 modest commercial / garage forecourt, ~1,200m²\n NS10 â\x80\x94 typical commercial yard / small forecourt, ~2,000m²\n NS15 â\x80\x94 larger commercial site, ~3,000m²\n NS30 â\x80\x94 large car park / petrol forecourt, ~6,000m²\n NS65 â\x80\x94 major forecourt / small depot, ~13,000m²\n NS100 â\x80\x94 industrial / lorry park / motorway service area, ~20,000m²\n\n(NS rating â\x86\x94 catchment area mapping is approximate; BS EN 858-2\ncl. 4.3.4 gives the formula NS = A Ã\x97 i Ã\x97 f, where i is the design\nrainfall intensity and f is the fluid-density factor.)'}, 'width_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'height_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'length_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'integer', 'default': 1}, 'project_ref': {'type': 'string', 'default': ''}, 'unit_mass_t': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'ns_rating_ls': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'supply_route': {'enum': ['contractor_full', 'contractor_install_pc_supply', 'provisional_sum', 'utility_provider_supply', 'employer_direct'], 'type': 'string', 'default': 'contractor_install_pc_supply'}, 'oil_storage_l': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'chainage_label': {'type': 'string', 'default': ''}, 'surround_class': {'type': 'string', 'default': '6N'}, 'invert_to_top_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'silt_capacity_l': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'interceptor_type': {'enum': ['full_retention', 'bypass'], 'type': 'string', 'default': 'full_retention', 'description': 'Separator type per BS EN 858-2 cl. 4.3:\n\n FULL_RETENTION (NS / NSF designation): treats the full design flow\n from the contributing impermeable catchment. Sized to retain the\n full contents of one compartment of a road tanker (â\x89¥ 7,600 litres\n per cl. 4.3.6 for forecourt applications). Used at petrol filling\n stations, fuel depots, and any high-spill-risk site.\n\n BYPASS (NSB designation): treats only the first-flush of run-off\n (typically up to 6.5 mm/h equivalent rainfall, ~10% of design\n peak). Above that rate, excess flow bypasses the separator via\n an internal weir. Used at large car parks where the spill risk\n is low and bypass of large storm flows is acceptable. Oil\n storage volume V = NSB Ã\x97 15 (cl. 4.3.6) â\x80\x94 50% more storage per\n nominal-size unit than full-retention.'}, 'cover_to_invert_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'excavation_batter': {'type': 'number', 'default': 0.5}, 'performance_class': {'enum': ['class_1', 'class_2'], 'type': 'string', 'default': 'class_1', 'description': 'Performance class per BS EN 858-1 cl. 5.4 / 5.5. Tested oil-in-water\nconcentration at outflow under standard test conditions:\n\n CLASS_1: â\x89¤ 5 mg/l. Includes a coalescing filter and an automatic\n closure device (auto-shut valve triggered when oil layer\n reaches design depth). Required for discharge to:\n - surface water sewer\n - watercourse (river / stream)\n - soakaway (with engineer agreement)\n - any controlled water body\n CLASS_2: â\x89¤ 100 mg/l. Gravity separation only (no coalescer). Used\n for discharge to a foul sewer or to upstream of a Class 1\n unit (rare two-stage configuration).'}, 'bedding_overhang_m': {'type': 'number', 'default': 0.3}, 'excavation_support': {'enum': ['open_batter', 'vertical_supported'], 'type': 'string', 'default': 'open_batter', 'description': 'Excavation support method. OPEN_BATTER assumes stable ground and\nenough working area for battered sides (typically 1V:1H or steeper);\nVERTICAL_SUPPORTED requires sheet piling, trench boxes, or shoring\nand emits an EXCAVATION_SUPPORT (m²) line.'}, 'catalogue_size_label': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'bedding_blinding_grade': {'type': 'string', 'default': 'C8/10'}, 'cover_to_top_of_unit_m': {'type': 'number', 'default': 0.3}, 'has_separate_silt_chamber': {'type': 'boolean', 'default': False}, 'working_space_each_side_m': {'type': 'number', 'default': 0.5}, 'geotextile_separator_grade': {'type': 'string', 'default': '200 g/m²'}, 'bedding_blinding_thickness_mm': {'type': 'integer', 'default': 150}, 'surround_thickness_each_side_m': {'type': 'number', 'default': 0.3}, 'sheet_pile_depth_below_invert_m': {'type': 'number', 'default': 1.0}}, 'description': 'Parameter form for a petrol/oil interceptor installation.\n\nCatalogue-driven on three axes: size (NS rating, catalogue lookup\nfor dimensions/mass/silt), class (performance â\x80\x94 CLASS_1/CLASS_2),\nand type (full retention vs bypass).'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'pipe_length': {'type': 'number', 'default': 25.0}, 'invert_depth': {'type': 'number', 'default': 1.5}, 'bedding_class': {'enum': ['N', 'F', 'B', 'S', 'A', 'Z'], 'type': 'string', 'default': 'B', 'description': 'Geometric bedding class per HA 40/01 / BS EN 1610.\n\nListed in ascending order of structural support.'}, 'pipe_material': {'enum': ['vitrified_clay', 'hdpe', 'upvc', 'concrete', 'ductile_iron'], 'type': 'string', 'default': 'vitrified_clay', 'description': 'Carrier pipe material.'}, 'backfill_class': {'type': 'string', 'default': 'Class 2A general fill'}, 'bedding_context': {'enum': ['highway', 'building'], 'type': 'string', 'default': 'highway', 'description': 'Specification context for pipe bedding measurement.\n\nHIGHWAY â\x80\x94 MMHW Series 500 / HA 40/01. Bedding clause references\n SHW Cl. 503. Class N/F/B/A common; Class S less so.\nBUILDING â\x80\x94 NRM2 §33 / BS EN 1610. Class S is the typical default;\n Class A and Z used for deep or structural locations.'}, 'cover_above_crown': {'type': 'number', 'default': 0.15}, 'excavation_batter': {'type': 'number', 'default': 1.0}, 'trench_width_extra': {'type': 'number', 'default': 0.3}, 'pipe_wall_thickness_mm': {'type': 'integer', 'default': 50}, 'working_space_each_side': {'type': 'number', 'default': 0.15}, 'pipe_internal_diameter_mm': {'type': 'integer', 'default': 300}, 'excavation_support_required': {'type': 'boolean', 'default': False}, 'bedding_thickness_below_pipe': {'type': 'number', 'default': 0.15}}}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'diameter_mm': {'type': 'integer', 'default': 225}, 'test_method': {'enum': ['cctv', 'air_pressure', 'water_pressure', 'mandrel_pull'], 'type': 'string', 'default': 'cctv', 'description': "Method of testing applied to the installed pipework.\n\nThe discriminator that routes through to the four standards'\nsub-codes:\n cctv -> CESMM4 I.8.1 / NRM2 33.18.1\n / MMHW 500.7.1 / SMM7 R12.7.1\n air_pressure -> CESMM4 I.8.2 / NRM2 33.18.2\n / MMHW 500.7.2 / SMM7 R12.7.2\n water_pressure -> CESMM4 I.8.3 / NRM2 33.18.3\n / MMHW 500.7.3 / SMM7 R12.7.3\n mandrel_pull -> CESMM4 I.8.4 / NRM2 33.18.4\n / MMHW 500.7.4 / SMM7 R12.7.4"}, 'pipe_material': {'type': 'string', 'default': 'vitrified clay'}, 'length_tested_m': {'type': 'number', 'default': 100.0}}, 'description': 'Parameters for a single pipework testing measurement.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'quantity': {'type': 'integer', 'default': 1}, 'fill_class': {'type': 'string', 'default': 'Class 6I'}, 'rsw_facing': {'enum': ['precast_panel', 'modular_block', 'wraparound', 'steel_mesh_face'], 'type': 'string', 'default': 'precast_panel', 'description': 'Facing system of the reinforced soil wall.\n\nPRECAST_PANEL â\x80\x94 Reinforced Earthâ\x84¢ / Freyssinet / VSL Retained Earth\n style precast concrete facing panels (T-shape or\n cruciform). Primary measurement: face area m²\n routes to RSW_FACING_PANEL. Steel tie strips\n route separately to RSW_TIE_STRIP. Geogrid\n reinforcement (where used in addition to or in\n place of tie strips) routes to GEOGRID. Typical\n highway use: motorway widening, bridge approach\n embankments, mainline-network junction\n improvements.\n\nMODULAR_BLOCK â\x80\x94 Segmental concrete block facing (Allan Block /\n Keystone / Anchor / Versa-Lok). Primary\n measurement: face area m² routes to\n RSW_MODULAR_BLOCK. Geogrid layers clamped between\n courses route to GEOGRID. Typical use: retail\n park boundary walls, golf-course retaining walls,\n cycle bridge approaches, residential development\n grading.\n\nWRAPAROUND â\x80\x94 Soft-faced wraparound system: geogrid wraps the\n face of each lift and folds back into the\n reinforced fill. Primary measurement: face area\n m² routes to RSW_WRAPAROUND_FACE (the extra\n wraparound geogrid is built into the rate);\n horizontal reinforcement layers route to\n GEOGRID. Typical use: embankment toe\n stabilisation, slope-repair works, vegetated\n landscape retaining structures, temporary\n haul-road retaining walls.\n\nSTEEL_MESH_FACE â\x80\x94 Welded steel mesh "gabion-style" face with\n geogrid extending into the reinforced fill\n behind (Maccaferri Terramesh / Tensar Terramesh\n system). The face is structurally a gabion at\n the face line but the bulk of the structure is\n reinforced soil. Primary measurement: face is\n a thin gabion-style basket and routes to\n GABION_BASKET (re-using the S29 vocabulary â\x80\x94\n every RSW STEEL_MESH_FACE variant has zero new\n face WorkCategory introduction). Geogrid\n reinforcement layers extending into the fill\n route to GEOGRID. Typical use: highway boundary\n walls where the gabion aesthetic is wanted but\n the wall is too tall for a gravity gabion\n structure.'}, 'layer_count': {'type': 'integer', 'default': 8}, 'wall_height': {'type': 'number', 'default': 6.0}, 'wall_length': {'type': 'number', 'default': 40.0}, 'block_pattern': {'enum': ['allan_block', 'keystone', 'anchor_vertica', 'versa_lok'], 'type': 'string', 'default': 'allan_block', 'description': 'Block pattern for MODULAR_BLOCK variant.'}, 'geogrid_grade': {'enum': ['biaxial_pp', 'uniaxial_hdpe', 'uniaxial_polyester', 'galfan_steel_strip'], 'type': 'string', 'default': 'uniaxial_polyester', 'description': 'Geogrid product grade per BS EN 13251 / BS 8006-1:2010.\n\nThe grade governs the long-term design strength T_d (kN/m), which\ndrives the layer length and the layer count required for stability.'}, 'blinding_grade': {'type': 'string', 'default': 'C8/10'}, 'face_treatment': {'enum': ['vegetated', 'biodegradable_erosion_mat', 'sprayed_hydroseed'], 'type': 'string', 'default': 'vegetated', 'description': 'Surface treatment for WRAPAROUND variant.'}, 'lift_height_mm': {'type': 'integer', 'default': 600}, 'block_height_mm': {'type': 'integer', 'default': 200}, 'face_panel_type': {'enum': ['t_shape_cruciform', 'hexagonal', 'rectangular_flat'], 'type': 'string', 'default': 't_shape_cruciform', 'description': 'Facing panel pattern for PRECAST_PANEL variant.'}, 'layer_spacing_m': {'type': 'number', 'default': 0.75}, 'geotextile_grade': {'type': 'string', 'default': '200 g/m²'}, 'include_blinding': {'type': 'boolean', 'default': True}, 'depth_into_fill_m': {'type': 'number', 'default': 4.5}, 'excavation_batter': {'type': 'number', 'default': 1.0}, 'excavation_support': {'enum': ['open_batter', 'vertical'], 'type': 'string', 'default': 'open_batter', 'description': 'Excavation support strategy for below-ground assemblies.\n\nConsumed by retaining walls (cantilever, gravity, counterfort,\nanchored, bored pile), foundation assemblies, and drainage chambers\nthat involve a battered or vertical-supported pit. The enum value is\nsurfaced in the description text of the relevant excavation BoQ line\nand in some standards (CESMM4 E.4.4 et seq.) drives a separate code.'}, 'foundation_profile': {'enum': ['level', 'stepped'], 'type': 'string', 'default': 'level', 'description': 'Foundation formation profile â\x80\x94 level or stepped.\n\nConsumed by retaining walls and foundation assemblies built on\nsloping ground. STEPPED foundation reuses the v10 cross-cutting\nEXCAVATION_FOUNDATION stepping discrimination upgrade (originally\nadded for strip_foundation S8). The stepping branch in the standards\nhandlers detects ``is_stepped=True`` on EXCAVATION_FOUNDATION items\nand routes to the stepped-foundation codes.'}, 'include_geotextile': {'type': 'boolean', 'default': True}, 'include_tie_strips': {'type': 'boolean', 'default': True}, 'panel_thickness_mm': {'type': 'integer', 'default': 180}, 'tie_strip_length_m': {'type': 'number', 'default': 4.5}, 'tie_strip_width_mm': {'type': 'integer', 'default': 50}, 'blinding_thickness_m': {'type': 'number', 'default': 0.1}, 'panel_concrete_grade': {'type': 'string', 'default': 'C40/50'}, 'terramesh_mesh_grade': {'type': 'string', 'default': 'galvanised hexagonal (BS EN 10223-3)'}, 'terramesh_stone_size': {'type': 'string', 'default': '100-200'}, 'tie_strip_thickness_mm': {'type': 'integer', 'default': 4}, 'excavation_working_space': {'type': 'number', 'default': 0.3}, 'terramesh_basket_width_m': {'type': 'number', 'default': 0.7}, 'tie_strip_density_per_m2': {'type': 'number', 'default': 2.0}, 'terramesh_basket_height_m': {'type': 'number', 'default': 1.0}, 'terramesh_basket_length_m': {'type': 'number', 'default': 2.0}, 'block_setback_per_course_mm': {'type': 'integer', 'default': 15}, 'geogrid_long_term_strength_kN': {'type': 'number', 'default': 80.0}}, 'description': 'Parameter form for a reinforced soil wall.\n\nA single dataclass that â\x80\x94 through combinations of its fields and\nthe ``rsw_facing`` discriminator â\x80\x94 produces all eight\nVARIANT_PRESETS plus arbitrary user-specified geometries across\nall four RSWFacing options. Sensible defaults yield a 6m\nhighway-approach PRECAST_PANEL wall.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'width': {'type': 'number', 'default': 7.0}, 'length': {'type': 'number', 'default': 50.0}, 'mesh_type': {'enum': ['A142', 'A193', 'A252', 'A393', 'A483'], 'type': 'string', 'default': 'A393', 'description': 'BS 4483 fabric mesh designations relevant to JRC pavement.'}, 'lane_width_m': {'type': 'number', 'default': 3.5}, 'capping_class': {'enum': ['1A', '1B', '1C', '2A', '2B', '2C', '2D', '2E', '3', '4', '5A', '5B', '6A', '6B', '6C', '6D', '6E', '6F1', '6F2', '6F3', '6F4', '6F5', '6I', '6J', '6N', '6P', '6Q', '7A', '7B', '7C', '7D', '7E', '7F', '8', '9A', '9B', 'U1A', 'U1B', 'U2'], 'type': 'string', 'default': '6F2', 'description': 'Full SHW Series 600 Table 6/1 acceptable material class set, plus the\nTable 6/2 unacceptable classes.\n\nThe enum value is the SHW designator. Use `family` and `default_use`\nproperties for routing in the assembly and renderer code.'}, 'pavement_type': {'enum': ['URC', 'JRC', 'CRCP'], 'type': 'string', 'default': 'JRC', 'description': 'Named UK rigid pavement variants per DMRB CD 226 / HD 26.\n\nURC : Unreinforced Concrete (jointed, no mesh, dowels + tie bars only)\nJRC : Jointed Reinforced Concrete (mesh mid-depth, dowels + tie bars)\nCRCP : Continuously Reinforced Concrete Pavement (continuous longitudinal\n steel, no transverse joints)'}, 'concrete_grade': {'anyOf': [{'enum': ['C32/40', 'C40/50', 'C50/60'], 'type': 'string', 'description': 'Concrete grades typical for UK PQC per SHW Cl. 1001.\nPQ grades are project-specified but these three cover the bulk of\nUK practice for the small-civils market this product targets.'}, {'type': 'null'}], 'default': None}, 'sub_base_class': {'enum': ['1A', '1B', '1C', '2A', '2B', '2C', '2D', '2E', '3', '4', '5A', '5B', '6A', '6B', '6C', '6D', '6E', '6F1', '6F2', '6F3', '6F4', '6F5', '6I', '6J', '6N', '6P', '6Q', '7A', '7B', '7C', '7D', '7E', '7F', '8', '9A', '9B', 'U1A', 'U1B', 'U2'], 'type': 'string', 'default': '1A', 'description': 'Full SHW Series 600 Table 6/1 acceptable material class set, plus the\nTable 6/2 unacceptable classes.\n\nThe enum value is the SHW designator. Use `family` and `default_use`\nproperties for routing in the assembly and renderer code.'}, 'include_capping': {'type': 'boolean', 'default': False}, 'slab_thickness_mm': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None}, 'capping_thickness_mm': {'type': 'integer', 'default': 350}, 'expansion_joint_count': {'type': 'integer', 'default': 0}, 'sub_base_thickness_mm': {'type': 'integer', 'default': 150}, 'crcp_long_bar_pitch_mm': {'type': 'integer', 'default': 150}, 'include_formation_prep': {'type': 'boolean', 'default': True}, 'crcp_long_bar_diameter_mm': {'type': 'integer', 'default': 16}, 'membrane_thickness_micron': {'type': 'integer', 'default': 125}, 'transverse_joint_spacing_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'include_separation_membrane': {'type': 'boolean', 'default': True}, 'excavation_extra_each_side_mm': {'type': 'integer', 'default': 0}}, 'description': 'Input parameters for a rigid pavement assembly.\n\nDefaults: 50m Ã\x97 7m urban distributor â\x80\x94 JRC with 25m bay length, 230mm\nslab on 150mm Type 1 sub-base, A393 mesh mid-depth. Tie bars at\n3.5m lane boundary. No capping by default.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'area_m2': {'type': 'number', 'default': 0.0}, 'quantity': {'type': 'integer', 'default': 1}, 'stud_type': {'anyOf': [{'enum': ['non_depressible', 'depressible', 'bidirectional'], 'type': 'string', 'description': 'Reflective road stud type per BS EN 1463-1.\n\nNON_DEPRESSIBLE â\x80\x94 Older specification adhered or mechanically fixed,\n still common on minor roads and lower-volume routes. Not\n snowplough-resistant.\nDEPRESSIBLE â\x80\x94 Motorway / dual-carriageway specification per\n BS EN 1463-1 Class TRP-D. Stud body retracts into the running\n surface under snowplough blade pressure.\nBIDIRECTIONAL â\x80\x94 Two-way visibility stud for junction approaches\n and central reserves.'}, {'type': 'null'}], 'default': None}, 'stud_count': {'type': 'integer', 'default': 0}, 'symbol_type': {'anyOf': [{'enum': ['arrow', 'word', 'give_way_triangle', 'transverse_bar', 'mini_roundabout', 'cycle_symbol'], 'type': 'string', 'description': 'Painted symbol/legend type. UK practice enumerates per occurrence\nregardless of physical size (a STOP word is 1nr whether the\ncharacters are 1.6m or 2.8m).\n\nARROW â\x80\x94 Directional arrow per TSRGD 2016 Schedule 7.\nWORD â\x80\x94 Word/legend (BUS, KEEP CLEAR, SLOW, SCHOOL,\n STOP, GIVE WAY) per TSRGD Schedule 8.\nGIVE_WAY_TRIANGLE â\x80\x94 Give-way triangle marking per TSRGD diagram 1023.\nTRANSVERSE_BAR â\x80\x94 Transverse bar pair per TSRGD Schedule 6 (the\n transverse element of give-way / stop lines).\nMINI_ROUNDABOUT â\x80\x94 Mini-roundabout central symbol per TSRGD\n diagram 1003.4.\nCYCLE_SYMBOL â\x80\x94 Cycle symbol per TSRGD diagram 1057 (painted\n cycle icon on cycle lane or shared surface).'}, {'type': 'null'}], 'default': None}, 'symbol_count': {'type': 'integer', 'default': 0}, 'line_length_m': {'type': 'number', 'default': 200.0}, 'line_width_class': {'enum': ['standard_100mm', 'wide_200mm', 'extra_wide_300mm', 'hatched_400mm_plus'], 'type': 'string', 'default': 'standard_100mm', 'description': 'Line width band per UK QS pricing practice. Line width is the\ndominant cost driver per linear metre of marking â\x80\x94 paint coverage\nscales linearly with width, and the marking-application contractor\nprices per width band.\n\nSTANDARD_100MM â\x80\x94 â\x89¤150mm (standard centre/edge line; 100mm is\n the dominant case)\nWIDE_200MM â\x80\x94 >150-200mm (motorway edge line, distributor-\n road edge line)\nEXTRA_WIDE_300MM â\x80\x94 >200-300mm (stop line at signalised junction,\n heavy-use edge line)\nHATCHED_400MM_PLUS â\x80\x94 >300mm (hatched edge stripe, ghost-island\n boundary marking)'}, 'marking_material': {'enum': ['thermoplastic', 'cold_paint', 'preformed_tape', 'mma'], 'type': 'string', 'default': 'thermoplastic', 'description': 'Road marking material per SHW Cl. 1208.\n\nTHERMOPLASTIC â\x80\x94 Hot-applied thermoplastic (dominant UK material;\n 4-7 year life on highway routes).\nCOLD_PAINT â\x80\x94 Cold-applied paint per BS EN 1871 (lower-cost,\n 1-2 year life, common for car parks and minor\n installations).\nPREFORMED_TAPE â\x80\x94 Preformed retroreflective tape; specialist\n applications (temporary diversions, premium-\n retroreflective requirements).\nMMA â\x80\x94 Methyl methacrylate cold-applied two-pack resin;\n high-friction, high-durability, premium cost.\n\nMaterial is carried on the description text only per UK QS practice\n(NOT a structural discriminator and NOT a banding axis). Material\ndifferences are priced as part of the per-line-width rate rather\nthan as separate bill lines.'}, 'area_marking_type': {'anyOf': [{'enum': ['hatched_chevron', 'ghost_island', 'box_junction', 'cycle_box', 'bus_stop_box', 'keep_clear'], 'type': 'string', 'description': 'Painted-area marking type per TSRGD 2016 Schedule 9 and various\ndiagram-numbered references. The area cost driver is paint/\nthermoplastic coverage (m² of painted surface).\n\nHATCHED_CHEVRON â\x80\x94 Hatched chevron area between carriageways,\n typically at 45° hatching with bordered edges. TSRGD Schedule 9.\nGHOST_ISLAND â\x80\x94 Painted refuge area within carriageway, hatched\n border. Common at minor-road junctions and right-turn lanes.\nBOX_JUNCTION â\x80\x94 Yellow box junction (cross-hatched, anti-grid-\n locking). TSRGD diagram 1043.\nCYCLE_BOX â\x80\x94 Cycle-box / advanced stop line area, typically\n green-coloured surface plus cycle symbol. TSRGD diagram 1001.2.\nBUS_STOP_BOX â\x80\x94 Bus stop cage marking (painted bus-stop bay\n outline + BUS legend). TSRGD diagram 1025.\nKEEP_CLEAR â\x80\x94 KEEP CLEAR rectangular zone prohibiting waiting\n and parking. TSRGD diagram 1026.'}, {'type': 'null'}], 'default': None}, 'existing_asset_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'marking_line_type': {'anyOf': [{'enum': ['continuous', 'broken_short', 'broken_long', 'double_continuous', 'lane_line'], 'type': 'string', 'description': 'Longitudinal road marking line type per TSRGD 2016 Schedule 6.\n\nCONTINUOUS â\x80\x94 Continuous longitudinal line. Used for edge lines, lane\n edge lines on motorways, and prohibitive centre lines where\n overtaking is forbidden. The dominant single-line case.\n\nBROKEN_SHORT â\x80\x94 Broken short-pattern line (short mark, long gap).\n Used for permissive centre lines on rural roads and lane lines\n on dual carriageways. Standard pattern per TSRGD diagram 1004.\n\nBROKEN_LONG â\x80\x94 Broken long-pattern hazard warning line (long mark,\n short gap). Used for cautionary centre lines warning of hazard\n ahead â\x80\x94 junction approach, bend ahead, restricted visibility.\n TSRGD diagram 1005.\n\nDOUBLE_CONTINUOUS â\x80\x94 Double continuous longitudinal line, used where\n overtaking is prohibited in both directions. TSRGD diagram\n 1013.1.\n\nLANE_LINE â\x80\x94 Lane-dividing line on motorway or dual-carriageway\n (broken pattern, typically 100mm with reflective studs).\n TSRGD diagram 1004.\n\nThe five line types span the genuinely-different UK commercial\ndecisions a QS would face when pricing a road-marking tender.'}, {'type': 'null'}], 'default': 'continuous'}, 'reflective_colour': {'anyOf': [{'enum': ['white', 'red', 'amber', 'green', 'blue'], 'type': 'string', 'description': 'Reflective road stud colour per TSRGD 2016.\n\nWHITE â\x80\x94 Lane lines (lane-dividing studs on motorway lane separators).\nRED â\x80\x94 Left edge of carriageway (UK left-hand drive convention).\nAMBER â\x80\x94 Right edge / central reserve / motorway hard shoulder line.\nGREEN â\x80\x94 Lay-by / slip-road indication.\nBLUE â\x80\x94 Emergency / fire-hydrant marking.'}, {'type': 'null'}], 'default': None}, 'secondary_line_type': {'anyOf': [{'enum': ['continuous', 'broken_short', 'broken_long', 'double_continuous', 'lane_line'], 'type': 'string', 'description': 'Longitudinal road marking line type per TSRGD 2016 Schedule 6.\n\nCONTINUOUS â\x80\x94 Continuous longitudinal line. Used for edge lines, lane\n edge lines on motorways, and prohibitive centre lines where\n overtaking is forbidden. The dominant single-line case.\n\nBROKEN_SHORT â\x80\x94 Broken short-pattern line (short mark, long gap).\n Used for permissive centre lines on rural roads and lane lines\n on dual carriageways. Standard pattern per TSRGD diagram 1004.\n\nBROKEN_LONG â\x80\x94 Broken long-pattern hazard warning line (long mark,\n short gap). Used for cautionary centre lines warning of hazard\n ahead â\x80\x94 junction approach, bend ahead, restricted visibility.\n TSRGD diagram 1005.\n\nDOUBLE_CONTINUOUS â\x80\x94 Double continuous longitudinal line, used where\n overtaking is prohibited in both directions. TSRGD diagram\n 1013.1.\n\nLANE_LINE â\x80\x94 Lane-dividing line on motorway or dual-carriageway\n (broken pattern, typically 100mm with reflective studs).\n TSRGD diagram 1004.\n\nThe five line types span the genuinely-different UK commercial\ndecisions a QS would face when pricing a road-marking tender.'}, {'type': 'null'}], 'default': None}, 'actual_line_width_mm': {'type': 'integer', 'default': 100}, 'secondary_line_length_m': {'type': 'number', 'default': 0.0}}, 'description': 'Parameters for a single road marking installation.\n\nDefaults anchored to URBAN_CONTINUOUS_WHITE_LINE â\x80\x94 200 m of\ncontinuous 100 mm thermoplastic edge/centre line. Required-field\ndefaults added per G.6.7.24 precedent â\x80\x94 non-breaking API enrichment\nopens the slug to schema-driven workspace defaults and defaults-\nbased parity-fixture regen.\n\nGeometry interpretation:\n - ``line_length_m`` is the linear length of the primary marking\n line (continuous edge/centre line, broken pattern, etc.). UK\n practice measures along the line centreline. Set to 0 if no\n primary line is part of the installation.\n - ``secondary_line_length_m`` is for installations with two distinct\n line types (e.g. broken_short main centreline + broken_long\n hazard section). Set to 0 to omit. The secondary line shares\n the same width_class and material as the primary line.\n - ``area_m2`` is the m² of painted area marking (hatched chevron,\n ghost island, box junction, etc.). Set to 0 if no area is\n present.\n - ``symbol_count`` is the number of distinct painted symbol\n occurrences (arrows, words, give-way triangles). Set to 0 if\n no symbols are present.\n - ``stud_count`` is the number of reflective road studs. Set to\n 0 if no studs are present.\n\nDiscrimination & banding:\n - ``marking_line_type`` discriminates the description text for the\n ROAD_MARKING_LINE WorkItem(s). Required if line_length_m > 0.\n - ``line_width_class`` discriminates the BANDED CODE in MMHW\n (1D-banding axis) and the description text in other standards.\n - ``area_marking_type`` discriminates description for the\n ROAD_MARKING_AREA WorkItem. Required if area_m2 > 0.\n - ``symbol_type`` discriminates description for the\n ROAD_MARKING_SYMBOL WorkItem. Required if symbol_count > 0.\n - ``stud_type`` and ``reflective_colour`` discriminate description\n for the ROAD_STUD WorkItem. Required if stud_count > 0.\n - ``marking_material`` is carried on every description but is\n NOT a discriminator or banding axis (UK QS convention).'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'cover_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'material': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pipe_od_mm': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None}, 'njug_colour': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'project_ref': {'type': 'string', 'default': 'Single Service Run'}, 'service_type': {'enum': ['water', 'gas_lp', 'gas_mp', 'electricity_lv', 'electricity_hv', 'telecoms', 'fibre', 'street_lighting'], 'type': 'string', 'default': 'water', 'description': 'Utility service categories per NJUG Volume 1.'}, 'support_type': {'enum': ['none', 'trench_box', 'sheet_pile', 'timber_board'], 'type': 'string', 'default': 'none', 'description': 'How the trench sides are supported during installation.'}, 'warning_tape': {'type': 'boolean', 'default': True}, 'bedding_class': {'enum': ['N', 'F', 'B', 'S', 'A', 'Z'], 'type': 'string', 'default': 'S', 'description': 'Geometric bedding class per HA 40/01 / BS EN 1610.\n\nListed in ascending order of structural support.'}, 'chainage_label': {'type': 'string', 'default': ''}, 'trench_width_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'bedding_context': {'enum': ['highway', 'building'], 'type': 'string', 'default': 'highway', 'description': 'Specification context for pipe bedding measurement.\n\nHIGHWAY â\x80\x94 MMHW Series 500 / HA 40/01. Bedding clause references\n SHW Cl. 503. Class N/F/B/A common; Class S less so.\nBUILDING â\x80\x94 NRM2 §33 / BS EN 1610. Class S is the typical default;\n Class A and Z used for deep or structural locations.'}, 'trench_length_m': {'type': 'number', 'default': 50.0}, 'bedding_thickness_m': {'type': 'number', 'default': 0.1}, 'surround_above_crown_m': {'type': 'number', 'default': 0.15}, 'tape_height_above_crown_m': {'type': 'number', 'default': 0.3}, 'working_space_below_bed_mm': {'type': 'integer', 'default': 100}, 'surface_reinstatement_thickness_m': {'type': 'number', 'default': 0.0}}, 'description': "Parameters for a single-service utility run.\n\nMaps neatly to a one-column UI form: the user picks a service type\nfrom a dropdown, optionally tweaks cover/OD/material, sets length\nand trench width, and that's it. The wrapper builds the equivalent\n``ServiceBand`` + single-band ``CombinedServicesTrenchParameters``\ninternally.\n\nAll defaults align with NJUG 7 minimum-cover guidance for the\nselected service type (resolved at compute-time via the same\n``_NJUG_DEFAULTS`` table that CST consumes)."}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'hot_spot': {'enum': ['low', 'medium', 'high', 'very_high'], 'type': 'string', 'default': 'low', 'description': 'CIRIA C753 §25.5 / Table 25.5 hot-spot land-use categories.\n\nA "hot spot" is a catchment area whose runoff carries elevated\npollution risk â\x80\x94 primarily hydrocarbons (fuel, oil), heavy metals\n(from brake wear, tyre wear), or de-icing chemicals. C753 requires\nenhanced treatment OR a discount on the infiltration rate (more\ntreatment time in the soil) for hot-spot catchments.\n\nThe values below match C753 Table 25.5 categorisation:\n\n LOW â\x80\x94 residential, footways, amenity (no discount)\n MEDIUM â\x80\x94 car parks, minor roads, supermarket forecourts\n HIGH â\x80\x94 A-roads, large car parks, HGV access, industrial yards\n VERY_HIGH â\x80\x94 fuel forecourts, lorry parks, vehicle workshops, depots\n (NB: C753 may direct that infiltration is NOT\n permitted at all without pre-treatment)'}, 'quantity': {'type': 'integer', 'default': 1}, 'soil_type': {'type': 'string', 'default': 'silty sand'}, 'tank_type': {'enum': ['crate', 'pipes'], 'type': 'string', 'default': 'crate'}, 'confidence': {'enum': ['low', 'medium', 'high'], 'type': 'string', 'default': 'medium', 'description': 'CIRIA C753 Table 25.4 confidence categories for the\nfactor-of-safety on the as-measured infiltration rate.\n\nThe factor compensates for spatial heterogeneity in soil\npermeability, seasonal water-table variation, and long-term\nclogging by fines.\n\n LOW â\x80\x94 single soakage test, FoS = 10\n MEDIUM â\x80\x94 2-3 tests, FoS = 4\n HIGH â\x80\x94 â\x89¥3 tests with consistent results + groundwater\n monitoring, FoS = 2'}, 'void_ratio': {'type': 'number', 'default': 0.3}, 'project_ref': {'type': 'string', 'default': 'Soakaway'}, 'plan_width_m': {'type': 'number', 'default': 5.0}, 'plan_length_m': {'type': 'number', 'default': 10.0}, 'chainage_label': {'type': 'string', 'default': ''}, 'storage_depth_m': {'type': 'number', 'default': 2.0}, 'crate_void_ratio': {'type': 'number', 'default': 0.95}, 'catchment_area_m2': {'type': 'number', 'default': 500.0}, 'cover_to_tank_top': {'type': 'number', 'default': 0.5}, 'excavation_batter': {'type': 'number', 'default': 0.5}, 'rainfall_depth_mm': {'type': 'number', 'default': 60.0}, 'excavation_support': {'enum': ['open_batter', 'vertical'], 'type': 'string', 'default': 'open_batter'}, 'runoff_surface_type': {'enum': ['hard_impermeable', 'hard_permeable', 'gravel', 'grass', 'pervious_paving'], 'type': 'string', 'default': 'hard_impermeable', 'description': 'Runoff coefficient categories per BRE 365 / C753 Table 24.1.\nUsed when ``design_storm_volume_m3`` is computed from catchment\narea rather than supplied directly.\n\nValues map to typical Cv (volumetric runoff coefficient) for the\nUK climate and design storm range; the engine uses these as\ndefaults but a user can override.'}, 'has_distribution_pipe': {'type': 'boolean', 'default': True}, 'design_storm_volume_m3': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'working_space_each_side': {'type': 'number', 'default': 0.6}, 'distribution_pipe_length_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'distribution_pipe_material': {'type': 'string', 'default': 'perforated HDPE'}, 'runoff_coefficient_override': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'distribution_pipe_diameter_mm': {'type': 'integer', 'default': 150}, 'measured_infiltration_rate_m_per_s': {'type': 'number', 'default': 0.0001}}, 'description': "Parameters for a CIRIA C753 infiltration soakaway.\n\nTwo ways to specify the design storm:\n\n (a) ``design_storm_volume_m3`` directly (from an upstream\n MicroDrainage / InfoWorks ICM model) â\x80\x94 preferred for any\n catchment > 1 ha or where the upstream model is the\n design-of-record.\n\n (b) ``catchment_area_m2`` + ``rainfall_depth_mm`` +\n ``runoff_surface_type`` (or ``runoff_coefficient_override``)\n â\x80\x94 the rational-method shortcut, appropriate for small-catchment\n soakaways (housing estate, supermarket forecourt, small\n commercial yard) where a senior QS / drainage engineer\n would sketch the design from these three numbers.\n\nIf both are specified, ``design_storm_volume_m3`` wins.\n\nSoil characterisation:\n - ``measured_infiltration_rate_m_per_s``: from a BRE 365\n falling-head soakage test on site\n - ``confidence``: per C753 Table 25.4 â\x80\x94 LOW (single test, FoS=10),\n MEDIUM (2-3 tests, FoS=4), HIGH (â\x89¥3 tests + groundwater\n monitoring, FoS=2)\n - ``hot_spot``: per C753 §25.5 â\x80\x94 LOW (residential / amenity),\n MEDIUM (car parks, minor roads), HIGH (A-roads, large car\n parks), VERY_HIGH (forecourts, lorry parks â\x80\x94 not permitted\n without pre-treatment)\n\nGeometry:\n Rectangular plan, prismatic depth. The depth here is the\n effective storage depth (water level at design fill); the\n attenuation_tank's ``cover_to_tank_top`` covers the soil cover\n above the granular surround.\n\nThe granular fill type is governed by the underlying\nattenuation_tank delegate â\x80\x94 pick ``tank_type=CRATE`` for modular\ngeocellular soakaways (typical for high storage / low footprint)\nor ``tank_type=PIPES`` for large-bore concrete pipe soakaways\n(typical for highway and industrial). The ``void_ratio`` here\napplies to the granular-fill case (TankType.CRATE with\n``crate_void_ratio`` becomes a free user choice; for the pipe\ncase the pipes themselves provide the storage volume)."}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'quantity': {'type': 'integer', 'default': 1}, 'nail_rows': {'type': 'integer', 'default': 4}, 'face_system': {'enum': ['shotcrete_mesh', 'hard_facing_panel', 'flexible_mesh', 'vegetated_geogrid'], 'type': 'string', 'default': 'shotcrete_mesh', 'description': "Face system for the soil-nailed slope.\n\nSHOTCRETE_MESH â\x80\x94 Wet-mix sprayed concrete (typically C25/30 to\n C32/40) over a single layer of welded steel\n fabric mesh (BS 4483 A193 to A393), with\n horizontal reinforcing waling bars at each\n nail row. The dominant UK choice for permanent\n highway-cutting stabilisation per SHW Cl. 644.\n Routes: SHOTCRETE_FACE (m²) + FACE_MESH_\n REINFORCEMENT (m²) + SOIL_NAIL (Nr) +\n GEOTEXTILE_FILTER (m², drainage strips).\n\nHARD_FACING_PANEL â\x80\x94 Precast concrete face panels (typically 1.5m\n Ã\x97 1.5m Ã\x97 0.15m thick, RC) bolted to the slope\n via the nail head plates. The premium face\n system for permanent works adjacent to\n sensitive receptors (carriageways, railways,\n bridges) where the maintained appearance of a\n hard concrete face is required and the\n durability requirement exceeds shotcrete's\n design life. Routes: CONCRETE_REINFORCED\n (m³, panels) + SOIL_NAIL (Nr) +\n GEOTEXTILE_FILTER (m²). NB: shotcrete and\n face mesh are NOT emitted â\x80\x94 the precast\n panel IS the face.\n\nFLEXIBLE_MESH â\x80\x94 Heavy-duty galvanised steel mesh drape (BS 4483\n A252 or similar, but typically a proprietary\n rockfall/erosion-protection drape mesh such as\n Geobrugg TECCO, Maccaferri Steelgrid HR) over\n the slope face, pinned by the nail head plates\n but NOT covered by shotcrete. The light-touch\n face system for weathered-rock cut faces where\n the dominant failure mode is surface ravelling\n rather than mass instability. Routes:\n FACE_MESH_REINFORCEMENT (m²) + SOIL_NAIL (Nr).\n No shotcrete, no drainage strips required.\n\nVEGETATED_GEOGRID â\x80\x94 Geogrid (PP or HDPE biaxial, e.g. Tensar SS35\n or Maccaferri PSG type) wrapped over the\n slope face with topsoil and seed/turf\n established on the surface. The soft-face,\n environmentally-sensitive option â\x80\x94 used for\n landslide stabilisation in rural / parkland\n settings, river-bank stabilisation, and\n landscape-led highway schemes. Routes:\n GEOGRID (m²) + SOIL_NAIL (Nr) + GEOTEXTILE_\n FILTER (m², drainage strips) + TOPSOIL_PLACE\n (m², face soil layer).\n\nThe four face systems span UK practice from light protection\n(FLEXIBLE_MESH) through standard (SHOTCRETE_MESH) and premium\n(HARD_FACING_PANEL) to environmentally-sensitive (VEGETATED_\nGEOGRID). These are the genuinely different commercial\ndecision points a QS would face when pricing a soil-nailed\nslope tender."}, 'steel_grade': {'type': 'string', 'default': 'B500B'}, 'geogrid_grade': {'type': 'string', 'default': 'PP_biaxial_35kN'}, 'nail_length_m': {'type': 'number', 'default': 6.0}, 'slope_height_m': {'type': 'number', 'default': 8.0}, 'slope_length_m': {'type': 'number', 'default': 30.0}, 'bar_diameter_mm': {'type': 'integer', 'default': 25}, 'nail_permanence': {'enum': ['permanent', 'temporary'], 'type': 'string', 'default': 'permanent', 'description': 'Permanent or temporary soil nail per BS EN 14490 Table 1.\n\nPERMANENT â\x80\x94 Design life â\x89¥ 2 years. Bar requires double corrosion\n protection (DCP): epoxy-coated bar OR galvanised bar\n + grouted cementitious annulus + corrugated plastic\n sheath. Conventional UK choice for highway-cutting\n stabilisation under SHW Cl. 644.\nTEMPORARY â\x80\x94 Design life < 2 years. Single corrosion protection\n (SCP) acceptable â\x80\x94 bare bar in cementitious grout\n annulus is sufficient. Used for temporary basement\n support and short-term construction-phase\n stabilisation.'}, 'shotcrete_grade': {'type': 'string', 'default': 'C25/30'}, 'slope_angle_deg': {'type': 'number', 'default': 65.0}, 'drill_diameter_mm': {'type': 'integer', 'default': 100}, 'existing_asset_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'grout_strength_mpa': {'type': 'integer', 'default': 25}, 'panel_thickness_mm': {'type': 'integer', 'default': 150}, 'nail_inclination_deg': {'type': 'number', 'default': 15.0}, 'panel_concrete_grade': {'type': 'string', 'default': 'C32/40'}, 'topsoil_thickness_mm': {'type': 'integer', 'default': 150}, 'face_mesh_designation': {'type': 'string', 'default': 'A193'}, 'shotcrete_thickness_mm': {'type': 'integer', 'default': 100}, 'drainage_strip_width_mm': {'type': 'integer', 'default': 300}, 'nail_vertical_spacing_m': {'type': 'number', 'default': 1.5}, 'drainage_strip_spacing_m': {'type': 'number', 'default': 3.0}, 'nail_horizontal_spacing_m': {'type': 'number', 'default': 1.5}}, 'description': 'Parameters for a single soil-nailed slope.\n\nGeometry interpretation:\n - ``slope_height_m`` is the vertical extent of the cut slope\n (top of crest to toe of slope).\n - ``slope_angle_deg`` is the slope angle from horizontal\n (typically 50-80° for soil-nailed cuts).\n - ``slope_length_m`` is the horizontal length along the slope\n crest â\x80\x94 the spatial extent of the assembly along the highway\n alignment.\n - ``nail_rows`` is the number of horizontal rows of nails;\n ``nail_horizontal_spacing_m`` and ``nail_vertical_spacing_m``\n give the in-row and between-row centres (m).\n - ``nail_length_m`` is the design nail length (excavation +\n bond length; same for all nails in this assembly â\x80\x94 for\n variable-length schemes, instantiate multiple assemblies).\n - ``nail_inclination_deg`` is the angle below horizontal of\n the nail axis (typically 10-20°).\n\nFace-system attributes (used only if relevant to ``face_system``):\n - ``shotcrete_thickness_mm`` / ``shotcrete_grade`` / \n ``face_mesh_designation`` â\x80\x94 SHOTCRETE_MESH only.\n - ``panel_thickness_mm`` / ``panel_concrete_grade`` â\x80\x94\n HARD_FACING_PANEL only.\n - ``geogrid_grade`` / ``topsoil_thickness_mm`` â\x80\x94\n VEGETATED_GEOGRID only.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'width': {'type': 'number', 'default': 0.75}, 'length': {'type': 'number', 'default': 10.0}, 'cover_mm': {'type': 'integer', 'default': 50}, 'thickness': {'type': 'number', 'default': 0.35}, 'is_stepped': {'type': 'boolean', 'default': False}, 'step_count': {'type': 'integer', 'default': 0}, 'step_height': {'type': 'number', 'default': 0.3}, 'working_space': {'type': 'number', 'default': 0.3}, 'blinding_grade': {'type': 'string', 'default': 'C8/10'}, 'concrete_grade': {'type': 'string', 'default': 'C32/40'}, 'founding_depth': {'type': 'number', 'default': 1.0}, 'blinding_thickness': {'type': 'number', 'default': 0.075}, 'top_long_bar_count': {'type': 'integer', 'default': 2}, 'bottom_long_bar_count': {'type': 'integer', 'default': 2}, 'transverse_bar_pitch_mm': {'type': 'integer', 'default': 250}, 'top_long_bar_diameter_mm': {'type': 'integer', 'default': 12}, 'transverse_bar_diameter_mm': {'type': 'integer', 'default': 8}, 'bottom_long_bar_diameter_mm': {'type': 'integer', 'default': 16}}, 'description': 'Parameters for the strip foundation assembly.\n\nDefaults are tuned to a typical UK domestic / light commercial strip:\n750mm wide, 350mm deep, 10m long, founded ~700mm below GL on 75mm\nblinding. Reinforcement is 2T16 bottom + 2T12 top with T8 transverse\ndistribution at 250 centres â\x80\x94 a conservative starting point\nrefineable per loading.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'lining': {'enum': ['vegetated', 'geotextile_reinforced', 'rip_rap'], 'type': 'string', 'default': 'vegetated', 'description': 'Swale lining type â\x80\x94 drives which WorkItems are emitted.'}, 'bed_width': {'type': 'number', 'default': 0.5}, 'trm_grade': {'type': 'string', 'default': '300 g/m² turf reinforcement mat (SHW Cl. 624)'}, 'swale_depth': {'type': 'number', 'default': 0.4}, 'rip_rap_spec': {'type': 'string', 'default': '200-300mm rip-rap rock fill (SHW Cl. 622, Class 6F2)'}, 'swale_length': {'type': 'number', 'default': 50.0}, 'check_dam_count': {'type': 'integer', 'default': 0}, 'grass_seed_spec': {'type': 'string', 'default': 'amenity grass seed mix, BS 7370-3'}, 'rip_rap_thickness': {'type': 'number', 'default': 0.25}, 'check_dam_material': {'enum': ['stone', 'concrete'], 'type': 'string', 'default': 'stone', 'description': 'Material for optional check-dams.'}, 'check_dam_thickness': {'type': 'number', 'default': 0.3}, 'topsoil_place_depth': {'type': 'number', 'default': 0.15}, 'topsoil_strip_depth': {'type': 'number', 'default': 0.25}, 'longitudinal_gradient': {'type': 'number', 'default': 0.02}, 'formation_prep_required': {'type': 'boolean', 'default': True}, 'left_side_slope_h_per_v': {'type': 'number', 'default': 3.0}, 'right_side_slope_h_per_v': {'type': 'number', 'default': 3.0}, 'rip_rap_geotextile_grade': {'type': 'string', 'default': '200 g/m² non-woven filter (SHW Cl. 624)'}, 'topsoil_strip_envelope_offset': {'type': 'number', 'default': 0.5}}}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'faces': {'type': 'integer', 'default': 1}, 'quantity': {'type': 'integer', 'default': 1}, 'sign_type': {'enum': ['warning_triangular', 'regulatory_circular', 'regulatory_rectangular', 'directional_rectangular', 'information_rectangular'], 'type': 'string', 'default': 'warning_triangular', 'description': 'Traffic sign type per TSRGD 2016 classification.\n\nWARNING_TRIANGULAR â\x80\x94 Warning sign per TSRGD 2016 Schedule 2.\n Equilateral triangular face (typically 750mm/900mm/1200mm\n per side per TSM Ch. 4). Red border on white background;\n warning of hazards ahead. The dominant low-cost UK case.\n\nREGULATORY_CIRCULAR â\x80\x94 Regulatory sign per TSRGD 2016 Schedule 3.\n Circular face (typically 600mm/750mm/900mm diameter).\n Red border (prohibition) or blue (mandatory). The\n dominant UK enumerated-regulatory case.\n\nREGULATORY_RECTANGULAR â\x80\x94 Regulatory sign per TSRGD 2016\n Schedules 3 and 4. Rectangular face â\x80\x94 used for parking\n restrictions, speed limits with supplementary plates,\n loading bays. White background with text/symbols.\n\nDIRECTIONAL_RECTANGULAR â\x80\x94 Directional sign per TSRGD 2016\n Schedule 11. Rectangular face â\x80\x94 large area for route\n legends. Green (primary routes), blue (motorways), white\n (local). Internally illuminated where specified per\n TSM Ch. 7.\n\nINFORMATION_RECTANGULAR â\x80\x94 Information sign per TSRGD 2016\n Schedule 12. Rectangular face â\x80\x94 tourist destinations,\n facilities, services, place names.\n\nThe five sign types span the genuinely-different UK commercial\ndecisions a QS would face when pricing a traffic-sign tender.'}, 'post_count': {'type': 'integer', 'default': 1}, 'post_length_m': {'type': 'number', 'default': 3.0}, 'post_material': {'enum': ['steel', 'aluminium', 'timber'], 'type': 'string', 'default': 'steel', 'description': 'Sign post material per SHW Cl. 1201. UK convention specifies\nhot-dip galvanised steel as the default; aluminium is used for\nlightweight applications; timber is exceptional (heritage\nlocations only).'}, 'concrete_grade': {'type': 'string', 'default': 'C25/30'}, 'face_area_class': {'enum': ['small', 'medium', 'large', 'very_large'], 'type': 'string', 'default': 'small', 'description': 'Sign face area band per UK QS pricing practice. The face area\ndrives material cost (retroreflective sheeting per m²),\nfabrication cost, and (above the small threshold) typically\ndrives the number of posts required. Bands chosen to match\ntypical UK signage practice per TSM Ch. 4:\n\nSMALL â\x80\x94 â\x89¤0.5m² (typical warning triangle 900mm side)\nMEDIUM â\x80\x94 0.5-2.0m² (typical regulatory 750-900mm dia,\n small directional plate)\nLARGE â\x80\x94 2.0-10.0m² (typical single-route directional\n on twin posts)\nVERY_LARGE â\x80\x94 >10m² (gantry-mounted ADS panel covering\n multiple lanes; sometimes called "gantry"\n face area class)'}, 'foundation_type': {'enum': ['post_mounted_small', 'post_mounted_large', 'twin_post_pad', 'gantry_pad'], 'type': 'string', 'default': 'post_mounted_small', 'description': 'Sign foundation type per SHW Cl. 1204. Drives the SIGN_FOUNDATION\ndescription and the implicit unit rate the QS will apply.\n\nPOST_MOUNTED_SMALL â\x80\x94 Small mass-concrete block (~0.3m³) for a\n single warning or regulatory sign on a single post. The\n dominant UK case by count.\nPOST_MOUNTED_LARGE â\x80\x94 Larger mass-concrete block (~0.6m³) for\n a heavier sign or longer post (>3m post height).\nTWIN_POST_PAD â\x80\x94 Pair of small mass-concrete blocks linked\n by a ground beam for a twin-post directional sign.\nGANTRY_PAD â\x80\x94 Full reinforced pad (~2m³+) for gantry\n legs. Concrete is still deemed-included in the unit rate\n per SHW Cl. 1205 â\x80\x94 the gantry pad is bundled with gantry\n leg supply.'}, 'existing_asset_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'actual_face_area_m2': {'type': 'number', 'default': 0.35}, 'mounting_height_class': {'enum': ['post_mounted', 'elevated', 'gantry'], 'type': 'string', 'default': 'post_mounted', 'description': 'Sign mounting height band per UK QS pricing practice. The\nmounting height drives access cost (small post = step-ladder;\nelevated = MEWP / cherry picker; gantry = full lane closure +\nspecialist lifting). Bands chosen to match typical UK access\npractice:\n\nPOST_MOUNTED â\x80\x94 <3m AGL (above ground level) â\x80\x94 typical for\n warning and regulatory signs on single posts.\n Hand-tool access from the verge.\nELEVATED â\x80\x94 3-5m AGL â\x80\x94 typical for large directional signs\n on twin posts. MEWP / cherry-picker access.\nGANTRY â\x80\x94 >5m AGL â\x80\x94 overhead gantry signs spanning\n carriageway. Lane-closure + specialist lifting\n required.'}, 'approximate_foundation_volume_m3': {'type': 'number', 'default': 0.3}}, 'description': 'Parameters for a single traffic sign installation.\n\nGeometry interpretation:\n - ``post_length_m`` is the length of the supporting post above\n ground (UK convention measures the *above-ground* length, not\n the often-greater driven/embedded length). For gantry signs,\n this is the height of each gantry leg.\n - ``post_count`` is the number of supporting posts. Typical\n values: 1 (small warning/regulatory), 2 (twin-post directional,\n gantry legs).\n - ``faces`` is the number of distinct sign faces on the\n assembly. A single gantry can carry 1-3 distinct sign faces\n (one per lane); a twin-post directional can carry advance\n and confirmation faces.\n\nFace geometry:\n - ``actual_face_area_m2`` is the m² of a single face (used for\n face-area descriptions; the WorkItem quantity is enumerated\n per face).\n\nFoundation:\n - ``foundation_type`` carries the SHW Cl. 1204 classification.\n - ``concrete_grade`` is for description text â\x80\x94 concrete is\n deemed-included in the foundation unit rate (no separate\n CONCRETE line emitted).\n - ``approximate_foundation_volume_m3`` is for description text\n only â\x80\x94 UK QS convention does not measure sign-foundation\n concrete separately (see SHW Cl. 1204).'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'quantity': {'type': 'integer', 'default': 1}, 'project_ref': {'type': 'string', 'default': 'Utility Chamber'}, 'unit_mass_t': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'chamber_type': {'enum': ['JC1', 'JC2', 'JC3', 'JC4', 'FW6', 'RW9', 'valve_chamber', 'ecv_pit', 'link_box', 'draw_pit'], 'type': 'string', 'default': 'JC2', 'description': 'Ten catalogue chamber types covering the UK utility-estimating palette.'}, 'plan_width_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'supply_route': {'anyOf': [{'enum': ['contractor_full', 'contractor_install_pc_supply', 'provisional_sum', 'utility_provider_supply', 'employer_direct'], 'type': 'string'}, {'type': 'null'}], 'default': None}, 'bedding_class': {'type': 'string', 'default': '6N'}, 'cover_loading': {'anyOf': [{'enum': ['A15', 'B125', 'C250', 'D400', 'E600', 'F900'], 'type': 'string', 'description': 'BS EN 124 cover-and-frame loading classes.'}, {'type': 'null'}], 'default': None}, 'plan_length_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'chainage_label': {'type': 'string', 'default': ''}, 'internal_depth_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'wall_thickness_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'excavation_batter': {'type': 'number', 'default': 0.5}, 'surround_material': {'type': 'string', 'default': '20mm single-size aggregate'}, 'bedding_overhang_m': {'type': 'number', 'default': 0.1}, 'excavation_support': {'enum': ['open_batter', 'vertical'], 'type': 'string', 'default': 'open_batter'}, 'bedding_thickness_mm': {'type': 'integer', 'default': 150}, 'geotextile_full_wrap': {'type': 'boolean', 'default': False}, 'surround_thickness_m': {'type': 'number', 'default': 0.15}, 'cover_clear_opening_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'cover_to_top_of_unit_m': {'type': 'number', 'default': 0.075}, 'working_space_each_side_m': {'type': 'number', 'default': 0.3}, 'sheet_pile_depth_below_formation_m': {'type': 'number', 'default': 0.5}}, 'description': "Parameter form for a utility access chamber.\n\nCatalogue-driven: pick a ``chamber_type`` and the chamber's nominal\nplan dimensions, depth, wall thickness, cover loading and supply\nroute default are read from ``_CATALOGUE``. Any field left as\n``None`` resolves to the catalogue default at ``__post_init__``\ntime; an explicit value wins.\n\nThe ``supply_route`` parameter follows the same rule: ``None`` â\x86\x92\ncatalogue default (UTILITY_PROVIDER_SUPPLY for JC1â\x80\x93JC4,\nCONTRACTOR_FULL for the other six). Setting an explicit value\noverrides â\x80\x94 e.g. setting ``SupplyRoute.CONTRACTOR_FULL`` on a JC2\ncaptures the private-estate case where the chamber is contractor-\nsupplied rather than Openreach-supplied."}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'top_mat': {'type': 'boolean', 'default': False}, 'cover_mm': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'integer', 'default': 1}, 'kiosk_type': {'enum': ['lv_pillar', 'fttc_cabinet', 'ev_charger', 'dno_substation', 'generic_pad'], 'type': 'string', 'default': 'lv_pillar', 'description': 'The five kiosk types in the launch catalogue.'}, 'project_ref': {'type': 'string', 'default': 'Utility Kiosk Base'}, 'thickness_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'plan_width_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'supply_route': {'anyOf': [{'enum': ['contractor_full', 'contractor_install_pc_supply', 'provisional_sum', 'utility_provider_supply', 'employer_direct'], 'type': 'string'}, {'type': 'null'}], 'default': None}, 'plan_length_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'blinding_grade': {'type': 'string', 'default': 'C8/10'}, 'chainage_label': {'type': 'string', 'default': ''}, 'concrete_grade': {'type': 'string', 'default': 'C32/40'}, 'rebar_pitch_mm': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None}, 'side_bar_count': {'type': 'integer', 'default': 2}, 'working_space_m': {'type': 'number', 'default': 0.3}, 'top_bar_pitch_mm': {'type': 'integer', 'default': 250}, 'pedestal_height_m': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'rebar_diameter_mm': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None}, 'top_bar_diameter_mm': {'type': 'integer', 'default': 10}, 'blinding_thickness_m': {'type': 'number', 'default': 0.075}}, 'description': 'Parameters for a utility kiosk base.\n\nFields marked "(None â\x86\x92 catalogue)" resolve from the catalogue entry\nat ``__post_init__`` time; an explicit non-None value always wins.'}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['params'], 'properties': {'params': {'type': 'object', 'properties': {'length_m': {'type': 'number', 'default': 100.0}, 'quantity': {'type': 'integer', 'default': 1}, 'to_system': {'type': 'string', 'default': 'bridge_parapet'}, 'from_system': {'type': 'string', 'default': 'tensioned_corrugated_beam'}, 'transitions': {'type': 'integer', 'default': 0}, 'wire_strands': {'type': 'integer', 'default': 4}, 'concrete_grade': {'type': 'string', 'default': 'C32/40'}, 'post_spacing_m': {'type': 'number', 'default': 2.0}, 'terminal_class': {'enum': ['P1', 'P2', 'P3', 'P4'], 'type': 'string', 'default': 'P2', 'description': 'BS EN 1317-4 terminal performance class. P1-P4 reflects energy\nabsorption and lateral redirection performance under impact.\nHigher number = more demanding test.'}, 'foundation_type': {'enum': ['driven', 'socketed', 'insitu_foundation', 'precast_slab'], 'type': 'string', 'default': 'driven', 'description': 'Post/barrier foundation type. Drives whether excavation and\nconcrete foundation lines are emitted.\n\nDRIVEN â\x80\x94 Steel post driven directly into the verge.\n No excavation or concrete foundation emitted.\n Conventional for TENSIONED_CORRUGATED_BEAM and\n UNTENSIONED_CORRUGATED_BEAM on standard verges.\n\nSOCKETED â\x80\x94 Steel post set into a precast concrete socket;\n socket embedded in lean-mix concrete foundation.\n Emits a concrete foundation line (m³). Used where\n driven installation is not feasible (rock close to\n surface, contaminated ground, sensitive utilities).\n\nINSITU_FOUND â\x80\x94 Continuous reinforced concrete strip foundation\n cast beneath in-situ concrete VRS. Emits\n CONCRETE_REINFORCED + REINFORCEMENT + FORMWORK\n lines for the foundation itself. Always paired\n with CONCRETE_STEP_INSITU.\n\nPRECAST_SLAB â\x80\x94 Precast concrete VRS units sit on a pre-cast\n levelled slab foundation; foundation deemed\n included in the precast supply rate.'}, 'vrs_system_type': {'enum': ['tensioned_corrugated_beam', 'untensioned_corrugated_beam', 'wire_rope', 'concrete_step_insitu', 'concrete_single_slope_precast', 'combined_heavy_duty'], 'type': 'string', 'default': 'tensioned_corrugated_beam', 'description': 'Vehicle restraint system structural type per BS EN 1317-2 / SHW\nCl. 402-404.\n\nTENSIONED_CORRUGATED_BEAM â\x80\x94 Hot-dip galvanised steel "W-beam"\n section, tensioned end-to-end via anchor terminals. Steel posts\n at 2.0m or 4.0m centres (driven or socketed). The dominant UK\n motorway-verge system per SHW Cl. 402 Working Width 4 (W4)\n Containment N2. Single-sided.\n\nUNTENSIONED_CORRUGATED_BEAM â\x80\x94 Same W-beam profile but without\n end-anchored tensioning â\x80\x94 relies on post stiffness rather than\n cable tension. Lower containment, higher working width. SHW\n Cl. 402 Working Width 2 (W2) Containment N2. Used on urban\n dual-carriageways and where containment requirement is\n moderate.\n\nWIRE_ROPE â\x80\x94 3- or 4-strand pre-tensioned steel\n wire rope between sparse posts (3.2m centres typical). Highest\n working width for given containment (W6 or higher), narrowest\n physical footprint. The dominant UK motorway-central-reserve\n system per SHW Cl. 403. NOT permitted in narrow central\n reserves where W6 cannot be accommodated.\n\nCONCRETE_STEP_INSITU â\x80\x94 In-situ reinforced concrete VRS,\n F-shape or step-shape cross-section per SHW Cl. 404. Highest\n containment per UK practice (H2 standard, H4a for vulnerable-\n receptor verges). Working width W1-W2. The dominant UK choice\n for bridge approaches, viaduct edges, and verges adjacent to\n watercourses/structures. Carries BS 8666 reinforcement.\n\nCONCRETE_SINGLE_SLOPE_PRECAST â\x80\x94 Precast concrete F-shape units\n (typically 6m units, bolted to slab foundation or sit-on-grade).\n Same containment family as CONCRETE_STEP_INSITU but priced as\n precast supply-and-install. Reinforcement deemed-included in\n the precast unit price. Used where rapid installation is\n commercially decisive (rolling roadworks, off-peak working).\n\nCOMBINED_HEAVY_DUTY â\x80\x94 Tensioned corrugated beam over a\n concrete kerb upstand or with double-rail layout for H4a\n containment. SHW Cl. 402 + Cl. 404 hybrid. Used at the\n outboard side of motorway verges adjacent to schools,\n residential properties, or sensitive natural features where\n H4a containment is the design requirement.\n\nThe six system types span the genuinely-different UK commercial\ndecisions a QS would face when pricing a VRS tender.'}, 'wire_tension_kn': {'type': 'integer', 'default': 25}, 'beam_thickness_mm': {'type': 'number', 'default': 4.0}, 'containment_level': {'enum': ['N2', 'H1', 'H2', 'H4a'], 'type': 'string', 'default': 'N2', 'description': 'BS EN 1317-2 containment level. The vehicle mass + speed test\nclass the barrier has been demonstrated to contain. UK practice\ntypically specifies one of:\n\nN2 â\x80\x94 Normal containment (passenger car, 1500kg @ 110km/h)\nH1 â\x80\x94 Higher containment 1 (rigid heavy vehicle, 10000kg @ 70km/h)\nH2 â\x80\x94 Higher containment 2 (single-deck bus, 13000kg @ 70km/h)\nH4a â\x80\x94 Highest containment (rigid lorry, 30000kg @ 65km/h)'}, 'existing_asset_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'terminals_per_run': {'type': 'integer', 'default': 2}, 'foundation_depth_m': {'type': 'number', 'default': 0.6}, 'foundation_width_m': {'type': 'number', 'default': 0.9}, 'working_width_class': {'enum': ['W1', 'W2', 'W4', 'W6'], 'type': 'string', 'default': 'W4', 'description': 'BS EN 1317-2 working width class. The maximum lateral\ndisplacement of the barrier under design impact, measured in metres.\nUK practice typically specifies one of these four classes:\n\nW1 â\x80\x94 â\x89¤ 0.6m (minimum footprint, concrete VRS only)\nW2 â\x80\x94 â\x89¤ 0.8m (concrete VRS, untensioned corrugated, narrow median)\nW4 â\x80\x94 â\x89¤ 1.3m (tensioned corrugated beam typical)\nW6 â\x80\x94 â\x89¤ 2.1m (wire rope typical)'}, 'precast_unit_length_m': {'type': 'number', 'default': 6.0}, 'reinforcement_kg_per_m': {'type': 'number', 'default': 85.0}, 'concrete_cross_section_m2': {'type': 'number', 'default': 0.45}}, 'description': "Parameters for a single vehicle restraint system run.\n\nGeometry interpretation:\n - ``length_m`` is the run length along the highway alignment.\n - ``post_spacing_m`` is the centre-to-centre spacing of supporting\n steel posts (irrelevant for INSITU and PRECAST_SLAB foundation\n types). Typical UK values: 2.0m (TCB), 4.0m (TCB W6 variant),\n 3.2m (wire rope), 1.5m (high-containment hybrid).\n - ``terminals_per_run`` is typically 2 (one at each end of a\n continuous run); can be 1 for a barrier that returns into a\n structure at one end.\n - ``transitions`` is the number of system-type transitions\n within the run (e.g. to a parapet or to a different VRS type).\n Zero is normal for a single-system run.\n\nSystem-type-specific attributes (set only those relevant to the\nvariant's ``vrs_system_type``):\n - ``beam_thickness_mm`` â\x80\x94 corrugated-beam variants only.\n - ``wire_strands`` / ``wire_tension_kn`` â\x80\x94 wire rope only.\n - ``concrete_grade`` / ``concrete_cross_section_m2`` /\n ``reinforcement_kg_per_m`` â\x80\x94 concrete variants only.\n - ``foundation_width_m`` / ``foundation_depth_m`` â\x80\x94 INSITU_FOUND\n foundation only.\n - ``precast_unit_length_m`` â\x80\x94 precast variants only."}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'MMHW'}, 'output_mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup', 'full_json'], 'type': 'string', 'default': 'full_json'}, 'deliverables': {'anyOf': [{'type': 'array', 'items': {'enum': ['xlsx', 'dxf', 'pdf'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'properties': {'component': {'enum': ['all', 'chunking', 'discipline', 'render'], 'type': 'string', 'default': 'all', 'description': 'Which part to fetch; omit for the whole kit.'}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'type': 'string'}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['project_id'], 'properties': {'project_id': {'type': 'string'}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['project_id', 'name', 'client', 'project_number', 'location', 'description', 'status', 'default_standard', 'currency', 'assemblies'], 'properties': {'name': {'type': 'string'}, 'client': {'type': 'string'}, 'status': {'type': 'string'}, 'currency': {'type': 'string'}, 'location': {'type': 'string'}, 'assemblies': {'type': 'array', 'items': {'type': 'object', 'required': ['id', 'slug', 'label', 'position', 'parameters', 'notes', 'enabled'], 'properties': {'id': {'type': 'string'}, 'slug': {'type': 'string'}, 'label': {'type': 'string'}, 'notes': {'type': 'string'}, 'enabled': {'type': 'boolean'}, 'position': {'type': 'integer'}, 'parameters': {'type': 'object', 'additionalProperties': True}}, 'description': 'Single assembly row inside a fetched project payload.', 'additionalProperties': False}}, 'project_id': {'type': 'string'}, 'description': {'type': 'string'}, 'project_number': {'type': 'string'}, 'default_standard': {'type': 'string'}}, 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['skill'], 'properties': {'skill': {'type': 'string', 'maxLength': 64, 'description': 'Skill slug from list_skills.'}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'type': 'string'}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'properties': {}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['projects'], 'properties': {'projects': {'type': 'array', 'items': {'type': 'object', 'required': ['project_id', 'name', 'client', 'project_number', 'status', 'default_standard', 'currency', 'assembly_count', 'created_at', 'updated_at'], 'properties': {'name': {'type': 'string'}, 'client': {'type': 'string'}, 'status': {'type': 'string'}, 'currency': {'type': 'string'}, 'created_at': {'type': 'string'}, 'project_id': {'type': 'string'}, 'updated_at': {'type': 'string'}, 'assembly_count': {'type': 'integer'}, 'project_number': {'type': 'string'}, 'default_standard': {'type': 'string'}}, 'description': 'One row inside the ``GET /api/v1/mcp/projects`` list response. Narrowed\nshape â\x80\x94 no parameters, no assembly details â\x80\x94 keeps the list endpoint\ncheap to serialise even when an owner has many projects.', 'additionalProperties': False}}}, 'description': 'Response payload for ``GET /api/v1/mcp/projects``.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'properties': {}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'type': 'array', 'items': {'type': 'object', 'required': ['slug', 'title', 'summary'], 'properties': {'slug': {'type': 'string', 'minLength': 1, 'description': 'Pass this to get_skill.'}, 'tier': {'type': 'string', 'const': 'paid', 'default': 'paid'}, 'title': {'type': 'string', 'minLength': 1}, 'summary': {'type': 'string', 'minLength': 1}}, 'description': 'One row of the skill catalogue surfaced by ``list_skills``.', 'additionalProperties': False}}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['project_id'], 'properties': {'request': {'anyOf': [{'type': 'object', 'properties': {'standard_codes': {'anyOf': [{'type': 'array', 'items': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Body for ``POST /api/v1/mcp/project/{id}/recompute``. Empty body is allowed â\x80\x94\nomits the standards filter and renders against all four.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'project_id': {'type': 'string'}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['project_id', 'standards_rendered', 'assembly_count', 'work_item_count', 'boqs_by_standard', 'procurement_summary', 'assembly_drawings'], 'properties': {'project_id': {'type': 'string'}, 'assembly_count': {'type': 'integer'}, 'work_item_count': {'type': 'integer'}, 'boqs_by_standard': {'type': 'object', 'additionalProperties': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'description', 'unit', 'quantity'], 'properties': {'code': {'type': 'string'}, 'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string'}, 'group': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'sub_group': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'description': {'type': 'string'}, 'nrm1_element': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'nrm1_sub_element': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'nrm1_group_element': {'anyOf': [{'type': 'integer'}, {'type': 'null'}], 'default': None}}, 'description': "Slim BoQ row for the recompute response. Matches the engine's own\n``BoQItem`` columns; rate / amount stay null per the freemium-MCP\npricing-is-yours discipline (schema § 1.3).", 'additionalProperties': False}}}, 'assembly_drawings': {'type': 'array', 'items': {'type': 'object', 'required': ['assembly_id', 'slug', 'label', 'position'], 'properties': {'slug': {'type': 'string'}, 'label': {'type': 'string'}, 'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1, 'description': 'Base64-encoded SVG document'}, 'viewbox_x': {'type': 'number', 'description': 'SVG viewBox x in engine units (m)'}, 'viewbox_y': {'type': 'number', 'description': 'SVG viewBox y in engine units (m)'}, 'entity_count': {'type': 'integer', 'minimum': 0, 'description': 'Number of DrawEntities rendered'}, 'viewbox_width': {'type': 'number', 'description': 'SVG viewBox width in engine units (m)', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'description': 'SVG viewBox height in engine units (m)', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm', 'description': 'Engine geometry is in metres. Surfaced here so the client never has to guess; if a future engine switches to mm this becomes the discriminator.'}}, 'description': 'Server-rendered SVG preview of the assembly geometry.\n\nPer G.6.3 / STATUS.md decision 6 (2026-05-19): one source of\ngeometry (`DrawEntity` list emitted by `Assembly.compute`), two\noutput paths (this SVG for inline preview, the `GET .../dxf`\nendpoint for the real CAD download). The browser displays\n`svg_b64` decoded inline; `viewbox` drives client zoom/pan\ncontrols without re-parsing the SVG.\n\n`svg_b64` is base64 of a UTF-8 SVG document with one `<g\nclass="cq-layer cq-layer-<name>">` per layer. Styling defaults are\ninlined so the preview renders without an external stylesheet;\nfront-end CSS may override via the class names.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'position': {'type': 'integer'}, 'assembly_id': {'type': 'string'}}, 'description': "One enabled assembly's drawing payload for the project recompute\nresponse (G.4.4b Step 2).\n\nMirrors the per-assembly drawing surface from\n``POST /api/assemblies/{slug}/compute`` (same ``DrawingRef`` shape,\nsame SVG renderer via ``build_drawing_ref``) so the project view's\ncontact-sheet centre pane renders identically to the single-assembly\ncalculator preview. ``drawing`` is nullable to stay backward-\ncompatible with assemblies that don't emit ``draw_entities`` (older\nshape); the few assemblies emitting an empty list still get a tiny\nplaceholder SVG so the UI never has to special-case absence.", 'additionalProperties': False}}, 'standards_rendered': {'type': 'array', 'items': {'type': 'string'}}, 'procurement_summary': {'type': 'array', 'items': {'type': 'object', 'required': ['category', 'spec', 'quantity', 'unit', 'source_assemblies'], 'properties': {'spec': {'type': 'string'}, 'unit': {'type': 'string'}, 'category': {'type': 'string'}, 'quantity': {'type': 'number', 'minimum': 0}, 'source_assemblies': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "One row of the project's procurement summary (G.4.4b Step 1).\n\nThe procurement summary is the standard-agnostic material rollup keyed\non ``(category, spec, unit)`` â\x80\x94 distinct from ``boqs_by_standard`` (a\nmeasurement-standard projection) and identical across all four\nstandards by construction. Drives the right pane of\n``/workspace/[project_id]`` and the ``Procurement`` sheet of the\nproject XLSX (per launch spec § 3.4.2).", 'additionalProperties': False}}}, 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['request'], 'properties': {'request': {'type': 'object', 'required': ['skill', 'compute_results'], 'properties': {'skill': {'type': 'string', 'description': "One of ['civilquants/qs_boq_export', 'civilquants/qs_boq_word_report']. Word skill ('civilquants/qs_boq_word_report') is paid-only; Excel skill is open to free callers with sheet protection + watermark."}, 'options': {'type': 'object', 'properties': {'standards': {'anyOf': [{'type': 'array', 'items': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}}, {'type': 'null'}], 'default': None, 'description': 'Subset of {CESMM4, NRM2, SMM7, MMHW} to render BoQ tabs for. Omit for every standard present in the compute_results.'}, 'include_backup_tabs': {'type': 'boolean', 'default': True, 'description': 'Per launch spec § 3.4.1b â\x80\x94 emit one Backup_<STD>_<NNN> sheet per BoQ row. Excel skill only.'}, 'include_procurement_summary': {'type': 'boolean', 'default': False, 'description': 'Per launch spec § 3.4.1c â\x80\x94 emit an aggregated Procurement_Summary sheet alongside the BoQ tabs. Excel skill only.'}}, 'description': 'Caller-tunable render options per launch spec § 3.4.1 a/b/c.', 'additionalProperties': False}, 'compute_results': {'type': 'array', 'items': {'type': 'object', 'required': ['assembly_slug', 'standard', 'parameters_used', 'boq_rows', 'totals_summary', 'text_summary'], 'properties': {'drawing': {'anyOf': [{'type': 'object', 'required': ['svg_b64', 'viewbox_x', 'viewbox_y', 'viewbox_width', 'viewbox_height', 'entity_count'], 'properties': {'svg_b64': {'type': 'string', 'minLength': 1}, 'viewbox_x': {'type': 'number'}, 'viewbox_y': {'type': 'number'}, 'entity_count': {'type': 'integer', 'minimum': 0}, 'viewbox_width': {'type': 'number', 'exclusiveMinimum': 0}, 'viewbox_height': {'type': 'number', 'exclusiveMinimum': 0}, 'unit_of_drawing': {'type': 'string', 'const': 'm', 'default': 'm'}}, 'description': "Schema § 1.6a â\x80\x94 inline server-rendered SVG preview of the geometry.\n\nThe MCP mirror of the web ``/compute`` response's ``drawing`` field\n(``api.schemas.compute.DrawingRef``): the same on-screen dimensioned\ndrawing both tiers see in the workspace, surfaced on the MCP compute\nresponse so a chat client can render it inline (60th-fire item C). This\nis the on-screen preview â\x80\x94 present on BOTH tiers per the free/paid\nboundary; the downloadable CAD artefacts (DXF / dimensioned PDF) remain\nthe paid differentiator via the export tools.\n\nDefined here rather than importing ``DrawingRef`` because the web\n``schemas`` package imports back into this module (``schemas.render``),\nso reusing it would create an import cycle â\x80\x94 the MCP wire contract keeps\nits own copy, the same pattern as ``BoQRow`` / ``DrawingReference``.", 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'boq_rows': {'type': 'array', 'items': {'type': 'object', 'required': ['work_section', 'description', 'quantity', 'unit', 'attribution'], 'properties': {'rate': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'unit': {'type': 'string', 'minLength': 1}, 'amount': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'audit_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'quantity': {'type': 'number', 'minimum': 0}, 'attribution': {'type': 'string', 'minLength': 1}, 'description': {'type': 'string', 'minLength': 1}, 'work_section': {'type': 'string', 'minLength': 1}}, 'description': "Schema § 1.3 â\x80\x94 a single bill row in the requested standard's format.\n\n`description` is the non-verbatim functional description per spec § 13.9 /\n§ 15 invariant â\x80\x94 NEVER reproduces a standard's verbatim clause text.\n`rate` / `amount` ship null because rates are commodity data the customer\nowns; the engine's job is the measurement, not the pricing.", 'additionalProperties': False}}, 'drawings': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['drawing_type', 'format', 'url', 'sheet_size', 'scale'], 'properties': {'url': {'type': 'string', 'minLength': 1}, 'scale': {'type': 'string', 'minLength': 1}, 'format': {'enum': ['DXF', 'PDF', 'SVG'], 'type': 'string'}, 'layers': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}, 'sheet_size': {'enum': ['A1', 'A2', 'A3', 'A4'], 'type': 'string'}, 'drawing_type': {'enum': ['section', 'plan', 'elevation', 'isometric', 'detail'], 'type': 'string'}}, 'description': 'Schema § 1.6 â\x80\x94 paid-tier drawing artefact pointer.\n\n`url` is an R2-signed URL; expiry is carried in `_meta.deliverables.expires_at`\non the envelope (not duplicated here). `layers` is DXF-only; PDF/SVG\ncallers omit it.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, 'warnings': {'type': 'array', 'items': {'type': 'object', 'required': ['code', 'severity', 'message'], 'properties': {'code': {'type': 'string', 'minLength': 1}, 'detail': {'type': 'object', 'additionalProperties': {'type': 'number'}}, 'message': {'type': 'string', 'minLength': 1}, 'severity': {'enum': ['info', 'advisory', 'caution'], 'type': 'string'}, 'affected_params': {'type': 'array', 'items': {'type': 'string'}}}, 'description': "Schema § 1.8 â\x80\x94 a non-fatal geometry advisory (56th-fire T2).\n\nThe wire projection of the engine's `core.GeometryWarning`. Advisory only:\na warning NEVER changes a measured quantity â\x80\x94 it flags geometry that is\nvalid but likely a mistake (e.g. a stale dependent-height default). Present\non BOTH tiers â\x80\x94 a correctness/safety signal, not a paid feature.", 'additionalProperties': False}}, 'audit_trail': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['id', 'boq_row_index', 'derivation'], 'properties': {'id': {'type': 'string', 'minLength': 1}, 'formula': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'derivation': {'type': 'string', 'minLength': 1}, 'boq_row_index': {'type': 'integer', 'minimum': 0}, 'parameters_referenced': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'Schema § 1.7 â\x80\x94 paid-tier audit-trail entry.\n\nOne entry per BoQ row; `boq_row_index` ties to the row position in\n`ComputeResult.boq_rows`. `derivation` is the human-readable formula\nwalk-through; `formula` is the optional formal expression.', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'text_summary': {'type': 'string', 'maxLength': 2000, 'minLength': 1}, 'assembly_slug': {'type': 'string', 'minLength': 1}, 'totals_summary': {'type': 'object', 'properties': {'entries': {'type': 'object', 'additionalProperties': {'type': 'object', 'required': ['quantity', 'unit'], 'properties': {'unit': {'type': 'string', 'minLength': 1}, 'quantity': {'type': 'number', 'minimum': 0}}, 'description': 'Schema § 1.4 â\x80\x94 single material/work-class total entry.', 'additionalProperties': False}}}, 'description': 'Schema § 1.4 â\x80\x94 totals_summary as a typed wrapper around the free-form dict.\n\nWire shape is a flat object (`{"concrete_m3": {...}, "rebar_t": {...}}`).\nWe model it as `RootModel`-equivalent via `model_config(extra="allow")`\n+ a single `__root__`-style `entries` dict. Pydantic v2 recommends\n`RootModel` for free-form roots; using a wrapper class keeps the import\nsurface uniform with the rest of this module.', 'additionalProperties': False}, 'parameters_used': {'type': 'object', 'properties': {'assumptions': {'type': 'array', 'items': {'type': 'string'}}, 'user_supplied': {'type': 'object', 'additionalProperties': True}, 'engine_defaults': {'type': 'object', 'additionalProperties': True}}, 'description': 'Schema § 1.2 â\x80\x94 the parameter snapshot the engine actually used.\n\nSplits user-supplied values from engine defaults so customers can see\nwhich numbers came from them and which the engine filled in. Every\ndefaulted parameter SHOULD have a corresponding entry in `assumptions`\nâ\x80\x94 the bridge layer enforces this when wrapping engine output.', 'additionalProperties': False}}, 'description': 'Schema § 1.1 â\x80\x94 the typed payload returned inside `MCPResponse[ComputeResult]`.\n\nFree-tier responses omit `drawings` (the downloadable CAD artefact\npointers â\x80\x94 the paid differentiator); the bridge enforces this. The\n`audit_trail` and the inline `drawing` preview are present on BOTH tiers\n(V1 ALIGN / 60th-fire D + C). `text_summary` is bounded to 2000 chars â\x80\x94\nkeeps the LLM-facing summary token-cheap and forces longer narrative into\nBoQ row descriptions where it belongs. `warnings` is the non-fatal\ngeometry advisory list (both tiers).', 'additionalProperties': False}, 'maxItems': 100, 'minItems': 1, 'description': 'Up to 100 ComputeResult entries per call â\x80\x94 comfortably above the 46-assembly v1 catalogue. Caps in-memory render at a sane ceiling to defend against denial-of-wallet from a compromised paid token.'}, 'personalisation': {'type': 'object', 'properties': {'client': {'anyOf': [{'type': 'string', 'maxLength': 200}, {'type': 'null'}], 'default': None}, 'co_brand': {'anyOf': [{'type': 'object', 'required': ['firm_name'], 'properties': {'logo_url': {'anyOf': [{'type': 'string', 'format': 'uri', 'minLength': 1}, {'type': 'null'}], 'default': None, 'description': 'Accepted for the v1 wire contract; logo embedding is deferred. Validated as an http(s) URL today so a future fetch never sees file:// / ftp:// / SSRF payloads.'}, 'firm_name': {'type': 'string', 'maxLength': 200, 'minLength': 1}, 'brand_color_hex': {'anyOf': [{'type': 'string', 'pattern': '^#?[0-9A-Fa-f]{6}$'}, {'type': 'null'}], 'default': None, 'description': 'Accepted for the v1 wire contract; theme swap is deferred to a follow-up.'}}, 'description': 'Optional customer dual-branding payload per launch spec § 3.4.0.', 'additionalProperties': False}, {'type': 'null'}], 'default': None, 'description': 'Customer dual-branding payload per launch spec § 3.4.0. Required when `branding_mode` is `customer` or `dual`; must be null when `branding_mode` is `unbranded`.'}, 'prepared_by': {'anyOf': [{'type': 'string', 'maxLength': 200}, {'type': 'null'}], 'default': None}, 'project_name': {'anyOf': [{'type': 'string', 'maxLength': 200}, {'type': 'null'}], 'default': None}, 'branding_mode': {'enum': ['unbranded', 'customer', 'dual'], 'type': 'string', 'default': 'unbranded', 'description': 'Paid-tier branding mode per launch spec § 3.4.0. `unbranded` (default) = clean white. `customer` = customer firm only, CQ stripped. `dual` = customer + CQ side-by-side. Free-tier callers have this field ignored; their output is always CQ-branded + locked + watermarked.'}}, 'description': 'Personalisation injected on the cover sheet per schema § 4.3.', 'additionalProperties': False}}, 'description': 'Wire shape for POST /api/v1/mcp/render.', 'additionalProperties': False}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['watermark_state', 'byte_size', 'skill'], 'properties': {'skill': {'type': 'string', 'description': 'Echoes the resolved skill slug.'}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Reserved for a future PDF skill backend.'}, 'docx_b64': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Base64-encoded .docx document bytes (Word skill, local store mode only).'}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Pre-signed R2 GET URL for .docx (Word skill, R2 store mode).'}, 'xlsx_b64': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Base64-encoded .xlsx workbook bytes (Excel skill, local store mode only).'}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None, 'description': 'Pre-signed R2 GET URL for .xlsx (Excel skill, R2 store mode).'}, 'byte_size': {'type': 'integer', 'minimum': 0, 'description': 'Decoded size of whichever deliverable was rendered.'}, 'watermark_state': {'enum': ['free', 'none'], 'type': 'string', 'description': '`free` when the free-tier sheet protection + watermark is applied; `none` for paid output.'}}, 'description': 'Wire response shape â\x80\x94 schema § 4 RenderResult.\n\nPer Phase 3.4 A.3: each skill has TWO possible delivery modes that\nmap to ``CIVILQUANTS_ARTEFACT_STORE``:\n * ``local`` (dev default) â\x80\x94 base64-inline in ``xlsx_b64`` / ``docx_b64``\n * ``r2`` (production) â\x80\x94 pre-signed URL in ``xlsx_url`` / ``docx_url``\nThe validator enforces "exactly one delivery channel per skill" â\x80\x94 a\nsingle render call returns exactly one of {b64, url} for its target\nformat, never both. The other skill\'s fields stay null.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['description'], 'properties': {'description': {'type': 'string'}, 'preferred_standard': {'anyOf': [{'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, {'type': 'null'}], 'default': None}, 'return_resolution_log': {'type': 'boolean', 'default': False}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['query', 'confidence'], 'properties': {'query': {'type': 'string'}, 'questions': {'type': 'array', 'items': {'type': 'string'}}, 'candidates': {'type': 'array', 'items': {'type': 'object', 'required': ['slug', 'display_name', 'tier', 'category_l1', 'category_l2', 'compute_tool'], 'properties': {'slug': {'type': 'string', 'minLength': 1}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'fields': {'type': 'array', 'items': {'type': 'object', 'required': ['name', 'label', 'default', 'group'], 'properties': {'max': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'min': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'default': None}, 'name': {'type': 'string', 'minLength': 1}, 'unit': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'group': {'type': 'string', 'minLength': 1}, 'label': {'type': 'string', 'minLength': 1}, 'default': {'anyOf': [{'type': 'number'}, {'type': 'integer'}, {'type': 'string'}, {'type': 'boolean'}, {'type': 'null'}]}, 'help_text': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'load_bearing': {'type': 'boolean', 'default': False}, 'is_run_length': {'type': 'boolean', 'default': False}}, 'description': 'One Parameters field, with the metadata a caller fills a value from.', 'additionalProperties': False}}, 'category_l1': {'type': 'string'}, 'category_l2': {'type': 'string'}, 'compute_tool': {'type': 'string', 'minLength': 1}, 'display_name': {'type': 'string', 'minLength': 1}, 'standard_note': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'free_alternative': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'suggested_params': {'type': 'array', 'items': {'type': 'object', 'required': ['name', 'value', 'source'], 'properties': {'name': {'type': 'string', 'minLength': 1}, 'unit': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'value': {'type': 'number'}, 'source': {'type': 'string', 'minLength': 1}}, 'description': 'A value the description stated with a clear anchor â\x80\x94 a caller-confirmed\nsuggestion, NOT an authoritative value and never auto-fed to compute.', 'additionalProperties': False}}, 'multi_section_tool': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'supports_multi_section': {'type': 'boolean', 'default': False}}, 'description': 'A candidate assembly the description routed to.', 'additionalProperties': False}}, 'confidence': {'enum': ['high', 'medium', 'low'], 'type': 'string'}, 'resolution_log': {'anyOf': [{'type': 'array', 'items': {'type': 'object', 'required': ['slug', 'score'], 'properties': {'slug': {'type': 'string'}, 'score': {'type': 'number'}, 'matched_terms': {'type': 'array', 'items': {'type': 'string'}}}, 'description': 'One row of the optional resolution log (return_resolution_log).', 'additionalProperties': False}}, {'type': 'null'}], 'default': None}, 'preferred_standard': {'anyOf': [{'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string'}, {'type': 'null'}], 'default': None}}, 'description': 'The typed payload wrapped in MCPResponse[ResolveResult].', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
입력 스키마
{'type': 'object', 'required': ['request'], 'properties': {'request': {'type': 'object', 'required': ['name'], 'properties': {'name': {'type': 'string', 'maxLength': 200, 'minLength': 1}, 'client': {'type': 'string', 'default': '', 'maxLength': 200}, 'currency': {'type': 'string', 'default': 'GBP', 'maxLength': 3, 'minLength': 3}, 'location': {'type': 'string', 'default': '', 'maxLength': 300}, 'assemblies': {'type': 'array', 'items': {'type': 'object', 'required': ['slug'], 'properties': {'slug': {'type': 'string', 'minLength': 1}, 'label': {'type': 'string', 'default': ''}, 'notes': {'type': 'string', 'default': ''}, 'parameters': {'type': 'object', 'additionalProperties': True}}, 'description': 'One assembly entry inside a project save request.', 'additionalProperties': False}}, 'description': {'type': 'string', 'default': ''}, 'project_number': {'type': 'string', 'default': '', 'maxLength': 60}, 'default_standard': {'enum': ['CESMM4', 'NRM2', 'SMM7', 'MMHW'], 'type': 'string', 'default': 'CESMM4'}}, 'description': 'Body for ``POST /api/v1/mcp/project/save``.', 'additionalProperties': False}}, 'additionalProperties': False}
출력 스키마
{'type': 'object', 'required': ['result'], 'properties': {'result': {'anyOf': [{'type': 'object', 'required': ['_meta'], 'properties': {'data': {'anyOf': [{'type': 'object', 'required': ['project_id', 'assembly_ids'], 'properties': {'project_id': {'type': 'string'}, 'assembly_ids': {'type': 'array', 'items': {'type': 'string'}}}, 'additionalProperties': False}, {'type': 'null'}], 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}, {'type': 'object', 'required': ['_meta'], 'properties': {'data': {'title': 'Data', 'default': None}, '_meta': {'type': 'object', 'required': ['request_id', 'issued_at', 'tier'], 'properties': {'hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'tier': {'enum': ['free', 'paid'], 'type': 'string'}, 'tos_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'issued_at': {'type': 'string', 'minLength': 1}, 'request_id': {'type': 'string', 'minLength': 1}, 'document_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'output_mode': {'anyOf': [{'type': 'object', 'required': ['mode', 'omitted_fields', 'retrieve_with'], 'properties': {'mode': {'enum': ['summary', 'material_schedule', 'boq', 'boq_with_backup'], 'type': 'string'}, 'retrieve_with': {'type': 'string', 'minLength': 1}, 'omitted_fields': {'type': 'array', 'items': {'type': 'string'}, 'minItems': 1}}, 'description': 'Surfaces what a trimmed ``output_mode`` withheld from ``data``.\n\nA trimmed mode (``summary`` / ``material_schedule`` / ``boq`` /\n``boq_with_backup``) withholds\nalready-computed fields to keep the chat payload small. The withheld value\nreads to a client agent as "capability missing" (the box-culvert "geometry\nbuilder isn\'t firing" scare) rather than "pared for size": ``drawing`` and\n``audit_trail`` appear as ``null``, ``boq_rows`` as an empty list ``[]``\n(its type forbids ``null``) â\x80\x94 both indistinguishable from a genuine absent\nresult. This names the withheld fields and the exact mode that brings each\nback, so the value is unambiguous. Absent on the default ``full_json`` mode\nâ\x80\x94 nothing is withheld, nothing to point at.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'deliverables': {'anyOf': [{'type': 'object', 'required': ['expires_at'], 'properties': {'dxf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'pdf_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'docx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'xlsx_url': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'expires_at': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.3 â\x80\x94 R2 signed URLs (24h TTL).', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'tier_upgrade': {'anyOf': [{'type': 'object', 'required': ['available_tiers'], 'properties': {'pass_credit': {'anyOf': [{'type': 'object', 'required': ['amount_local', 'currency', 'redeemable_until'], 'properties': {'currency': {'type': 'string'}, 'applies_to': {'type': 'string', 'const': 'solo_first_month', 'default': 'solo_first_month'}, 'amount_local': {'type': 'number'}, 'redeemable_until': {'type': 'string'}}, 'description': 'Canonical schema § 0.7 â\x80\x94 pass-credit upgrade hook.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'pricing_url': {'type': 'string', 'default': 'https://civilquants.com/pricing'}, 'current_tier': {'type': 'string', 'const': 'free', 'default': 'free'}, 'available_tiers': {'type': 'array', 'items': {'type': 'object', 'required': ['tier_slug', 'display_name', 'price_local', 'currency', 'billing', 'unlock_summary'], 'properties': {'billing': {'enum': ['one_off', 'monthly', 'annual'], 'type': 'string'}, 'currency': {'enum': ['GBP', 'SGD', 'EUR', 'USD', 'CAD', 'AUD', 'NZD', 'MYR'], 'type': 'string'}, 'tier_slug': {'enum': ['7_day_pass', 'solo', 'studio', 'practice'], 'type': 'string'}, 'price_local': {'type': 'number'}, 'display_name': {'type': 'string'}, 'unlock_summary': {'type': 'string', 'minLength': 1}}, 'description': 'Canonical schema § 0.7 â\x80\x94 single tier in the upgrade carousel.', 'additionalProperties': False}}}, 'description': 'Canonical schema § 0.7 â\x80\x94 present on free-tier responses only.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'upgrade_hint': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'schema_version': {'type': 'string', 'const': '1.0.0', 'default': '1.0.0'}, 'scope_boundary': {'anyOf': [{'type': 'object', 'required': ['produced', 'not_in_scope'], 'properties': {'produced': {'type': 'array', 'items': {'type': 'string'}}, 'not_in_scope': {'type': 'array', 'items': {'type': 'string'}}, 'recommended_companions': {'anyOf': [{'type': 'array', 'items': {'type': 'string'}}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.6 â\x80\x94 surfaces what this assembly produces vs not.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}, 'warranty_disclaimer': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'default': None}, 'rate_limit_remaining': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.2 â\x80\x94 present on every MCPResponse.\n\nRequired fields: `schema_version`, `request_id`, `issued_at`, `tier`.\nThe free-tier-only fields (`upgrade_hint`, `tos_url`, `warranty_disclaimer`,\n`tier_upgrade`, `rate_limit_remaining`) are populated by the middleware\nwhen `tier == "free"`; absent on paid-tier responses.', 'additionalProperties': False}, 'error': {'anyOf': [{'type': 'object', 'required': ['code', 'message', 'recoverable'], 'properties': {'code': {'enum': ['RATE_LIMIT_EXCEEDED', 'TIER_INSUFFICIENT', 'INVALID_INPUT', 'SCHEMA_VERSION_MISMATCH', 'SCHEMA_INVARIANT_VIOLATION', 'UPSTREAM_TIMEOUT', 'BACKEND_FAILURE', 'IP_BLOCKED', 'RESOURCE_NOT_FOUND', 'RENDER_FAILURE', 'OCR_LOW_CONFIDENCE', 'MANUAL_REVIEW_REQUIRED', 'ACCEPTANCE_REQUIRED', 'INVALID_TOKEN'], 'type': 'string', 'description': 'Canonical schema § 0.5 catalogue.\n\nEach member maps to a documented `recoverable` flag (see\n`IS_RECOVERABLE`) â\x80\x94 clients use the flag to decide retry vs surface.'}, 'details': {'anyOf': [{'type': 'object', 'additionalProperties': True}, {'type': 'null'}], 'default': None}, 'message': {'type': 'string', 'minLength': 1}, 'recoverable': {'type': 'boolean'}, 'retry_after_seconds': {'anyOf': [{'type': 'integer', 'minimum': 0}, {'type': 'null'}], 'default': None}}, 'description': 'Canonical schema § 0.4 â\x80\x94 error payload returned in `MCPResponse.error`.', 'additionalProperties': False}, {'type': 'null'}], 'default': None}}, 'additionalProperties': False}]}}, 'x-fastmcp-wrap-result': True}
최근 도구 변경
유사한 MCP 서버
Sbir
Provides SBIR/STTR public data, including agency-level award statistics and related federal innovation-program information.
Trustbase Lab · Global Chemical Recycling Intelligence
Provides recovered carbon black and chemical recycling data covering suppliers, grades, standards, policies, prices, trade flows,…
mfgcalcs
Provides manufacturing calculators, sourcing optimization, tariff and economic data, forecasts, benchmarks, citations, provenance…
steel-tools
Provides steel takeoff, weight, and gauge calculations along with RFQ, RFI, NCR, and Bluebeam markup document generation.
SpaceNexus space data
Provides read-only data on space launches, schedule changes, funding, companies, jobs, space weather, and Moon missions.
cpp-cpm-engine
Performs forensic Primavera P6 schedule analysis, delay attribution, critical-path validation, DCMA-14 checks, time-impact analys…
Faber Machine Market
Produces paid structured research and decision-support outputs covering evidence quality, information changes, infrastructure, re…
feode-mcp
Provides precision machining, testing, drill-pipe, subsea equipment, certifications, technical specifications, and structured mac…