Skip to content

MCP Server

ucon includes a Model Context Protocol (MCP) server that exposes unit conversion and dimensional analysis to AI agents like Claude.

Installation

pip install ucon-tools[mcp]

Python 3.10+

The MCP server requires Python 3.10 or higher.

Configuration

Claude Desktop

Add to your claude_desktop_config.json:

Via uvx (recommended):

{
  "mcpServers": {
    "ucon": {
      "command": "uvx",
      "args": ["--from", "ucon-tools[mcp]", "ucon-mcp"]
    }
  }
}

Local development:

{
  "mcpServers": {
    "ucon": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/ucon-tools", "--extra", "mcp", "ucon-mcp"]
    }
  }
}

Claude Code / Cursor

The same configuration works for other MCP-compatible AI tools.

Available Tools

convert

Convert a value from one unit to another.

convert(value=5, from_unit="km", to_unit="mi")
# → {"quantity": 3.107, "unit": "mi", "dimension": "length"}

Supports:

  • Base units: meter, m, second, s, gram, g
  • Scaled units: km, mL, kg, MHz
  • Composite units: m/s, kg*m/s^2, N*m
  • Exponents: m^2, s^-1 (ASCII) or , s⁻¹ (Unicode)

decompose

Build a factor chain for compute() by analyzing dimensional requirements.

Query mode — simple conversions:

decompose(query="500 mL to L")
# → {"initial_value": 500, "initial_unit": "mL", "target_unit": "L", "factors": [...]}

Structured mode — multi-step problems with known quantities:

decompose(
    initial_unit="mcg/(kg*min)",
    target_unit="mg/h",
    known_quantities=[{"value": 70, "unit": "kg"}]
)
# → {"factors": [{"value": 70, "numerator": "kg", ...}, ...]}
# Pass the result's factors directly to compute()

The tool performs dimensional gap analysis, places known quantities in the correct position (numerator or denominator), and adds conversion factors for remaining unit mismatches.

compute

Perform multi-step factor-label calculations with dimensional tracking.

compute(
    initial_value=154,
    initial_unit="lb",
    factors=[
        {"value": 1, "numerator": "kg", "denominator": "2.205 lb"},
        {"value": 15, "numerator": "mg", "denominator": "kg*day"},
        {"value": 1, "numerator": "day", "denominator": "3 ea"},
    ]
)
# → {"quantity": 349.2, "unit": "mg/ea", "dimension": "mass/count", "steps": [...]}

Each step in the response shows intermediate quantity, unit, and dimension.

list_units

Discover available units, optionally filtered by dimension.

list_units(dimension="length")
# → [{"name": "meter", "shorthand": "m", "dimension": "length", ...}, ...]

list_scales

List SI and binary prefixes.

list_scales()
# → [{"name": "kilo", "prefix": "k", "factor": 1000.0}, ...]

check_dimensions

Check if two units have compatible dimensions.

check_dimensions(unit_a="kg", unit_b="lb")
# → {"compatible": true, "dimension_a": "mass", "dimension_b": "mass"}

check_dimensions(unit_a="kg", unit_b="m")
# → {"compatible": false, "dimension_a": "mass", "dimension_b": "length"}

list_dimensions

List available physical dimensions.

list_dimensions()
# → ["acceleration", "area", "energy", "force", "length", "mass", ...]

define_unit

Register a custom unit for the session.

define_unit(name="slug", dimension="mass", aliases=["slug"])
# → {"success": true, "message": "Unit 'slug' registered..."}

define_conversion

Add a conversion edge between units.

define_conversion(src="slug", dst="kg", factor=14.5939)
# → {"success": true, "message": "Conversion edge 'slug' → 'kg' added..."}

list_constants

List available physical constants, optionally filtered by category.

list_constants()
# → [{"symbol": "c", "name": "speed of light in vacuum", "value": 299792458, ...}, ...]

list_constants(category="exact")
# → [7 SI defining constants]

list_constants(category="session")
# → [user-defined constants]

Categories: "exact" (7), "derived" (3), "measured" (7), "session" (user-defined).

define_constant

Register a custom constant for the session.

define_constant(
    symbol="vₛ",
    name="speed of sound in dry air at 20°C",
    value=343,
    unit="m/s"
)
# → {"success": true, "symbol": "vₛ", ...}

reset_session

Clear custom units, conversions, and constants.

reset_session()
# → {"success": true, "message": "Session reset..."}

define_quantity_kind

Register a quantity kind for semantic disambiguation.

define_quantity_kind(
    name="entropy_change",
    dimension="energy/temperature",
    description="Change in entropy for a thermodynamic process"
)
# → {"success": true, "name": "entropy_change", "vector_signature": "M·L²·T⁻²·Θ⁻¹", ...}

Quantity kinds identify physically distinct quantities that share the same dimensional signature (e.g., entropy change vs heat capacity).

declare_computation

Declare computational intent before performing a calculation.

declare_computation(
    quantity_kind="entropy_change",
    expected_unit="J/K"
)
# → {"declaration_id": "...", "status": "valid", "compatible_kinds": ["heat_capacity"], ...}

Establishes the expected quantity kind so validate_result() can verify the result.

validate_result

Validate that a computed result matches the declared quantity kind.

validate_result(
    value=91.5,
    unit="J/K",
    reasoning="Calculated ΔS = Q/T for isothermal heat transfer"
)
# → {"passed": true, "confidence": "high", "semantic_warnings": [], ...}

Checks dimensional consistency and analyzes reasoning text for semantic conflicts.

list_formulas

List registered domain formulas with dimensional constraints.

list_formulas()
# → [{"name": "bmi", "description": "Body Mass Index", "parameters": {"mass": "mass", "height": "length"}}]

call_formula

Invoke a registered formula with dimensionally-validated inputs.

call_formula(
    name="bmi",
    parameters={
        "mass": {"value": 70, "unit": "kg"},
        "height": {"value": 1.75, "unit": "m"}
    }
)
# → {"formula": "bmi", "quantity": 22.86, "unit": "kg/m²", ...}

See Registering Formulas for how to create formulas.

Error Recovery

When conversions fail, the MCP server returns structured errors with suggestions:

convert(value=1, from_unit="kilogram", to_unit="meter")
# → {
#     "error": "Dimension mismatch: mass ≠ length",
#     "error_type": "dimension_mismatch",
#     "likely_fix": "Use a mass unit like 'lb' or 'g'"
# }

For typos:

convert(value=1, from_unit="kilgoram", to_unit="kg")
# → {
#     "error": "Unknown unit: 'kilgoram'",
#     "error_type": "unknown_unit",
#     "likely_fix": "Did you mean 'kilogram'?"
# }

Custom Units (Inline)

For one-off conversions without session state:

convert(
    value=1,
    from_unit="slug",
    to_unit="kg",
    custom_units=[{"name": "slug", "dimension": "mass", "aliases": ["slug"]}],
    custom_edges=[{"src": "slug", "dst": "kg", "factor": 14.5939}]
)

Example Conversation

User: How many milligrams of ibuprofen should a 154 lb patient receive if the dose is 10 mg/kg?

Claude: (calls compute)

compute(
    initial_value=154,
    initial_unit="lb",
    factors=[
        {"value": 1, "numerator": "kg", "denominator": "2.205 lb"},
        {"value": 10, "numerator": "mg", "denominator": "kg"},
    ]
)

Result: 698.4 mg

The step trace shows dimensional consistency at each point, so Claude can verify the calculation is physically meaningful.

Guides

Background