Unit converter powered by the GNU units database — convert between 3000+ units of measurement, evaluate compound unit expressions, reduce quantities to SI base units, run dimensional analysis, and look up unit definitions. Offline and deterministic.
mcp-gnu-units demonstrates solid definition quality with well-structured tool definitions, comprehensive parameter descriptions, and documented output schemas. All four tools are explicitly registered with FastMCP and have detailed docstrings. Parameter schemas use Pydantic Field annotations with descriptions, min/max constraints, and type hints. Descriptions are informative (ranging 150 - 400 chars) and explain WHAT the tool does, WHEN to use it, and WHAT it returns. However, there are gaps in error handling guidance and some parameter descriptions could be more actionable. The server follows good naming conventions (verb_noun pattern: info, find_units, convert, convert_to_si) and maintains consistency across tools. Output schemas are documented in docstrings but not formally exposed in the MCP tool registration (FastMCP does not appear to serialize schema details in responses). Security is handled well, no credentials are exposed as parameters. Overall, the tools are production-ready with minor refinements needed for LLM error recovery and some edge-case parameter guidance.
Convert a value or unit expression from one unit to another (GNU units engine, TODO §16). The universal conversion core: one tool covers every category (length, mass, time, temperature, area, volume, energy, power, speed, data, …) plus compound expressions like `kW*h` or `acre*ft`. Linear conversions return the ratio of coefficients; a nonlinear target (e.g. `tempF`) applies that unit's inverse. Returns: `from` and `to` (echoed), `result` (the converted magnitude WITH the target unit, e.g. "1.609344 km" — the primary human-readable answer), `value` (the same magnitude as a bare float for programmatic use), and `exact` (true when the result is exact, false when it was rounded). Errors cleanly (isError) when a unit is unknown, an expression is malformed, or the two sides are not conformable. Example: convert("1 mile", "km") -> {"from":"1 mile","to":"km","result":"1.609344 km","value":1.609344,"exact":true}
Reduce a value or unit expression to SI base units. Reduces any linear unit to its SI base-unit (primitive) form: `km` → `1000 m`, `hour` → `3600 s`, `kW*hour` → `3.6e+06 kg m^2 / s^2`, etc. Use it to check whether a unit is valid, canonicalize quantities for comparison, or run dimensional analysis (the signature of the reduced form is the quantity's physical dimension). Nonlinear units (e.g. `tempF`, `dB`) have no linear SI form and error. Raise an `isError` result when a unit is unknown, an expression is malformed, or the unit is nonlinear. Example: convert_to_si("55 mile/hour") -> {"expr":"55 mile/hour","result":"24.5872 m / s","value":24.5872,"exact":false, "dimension":"m / s"}
Search the GNU units database for units whose name or definition contains a keyword. Basic substring search over the 3000+ unit GNU units database (TODO §14.1). A hit is any unit whose name OR definition text contains `query` (case-insensitive); prefixes are excluded. Results are returned in the database's native order and capped at `limit`. Use this to discover the exact spelling of a unit before calling a conversion tool. Returns: `query` (echoed), `count` (number of results returned), and `results`, a list of objects each carrying: - `name` : the unit's name. - `definition` : its definition text (the source line with the leading name token removed, so the name is not repeated). - `kind` : "unit" | "primitive" | "function" | "table". - `dimension` : the unit reduced to base-unit signature, e.g. "kg m^2 / s^3" for power — use it to check whether two units are conformable without a second call. Omitted for hits that do not reduce (functions, tables). - `base_value` : the unit reduced to base/primitive units, coefficient included, e.g. "745.699 kg m^2 / s^3". Omitted alongside `dimension` when the hit does not reduce. Enriching each hit lets you search AND triage in a single call instead of a follow-up lookup per unit. Example: find_units("horsepower") -> {"query":"horsepower","count":9,"results":[{"name":"horsepower", "definition":"550 foot pound force / sec","kind":"unit", "dimension":"kg m^2 / s^3","base_value":"745.7 kg m^2 / s^3"}, ...]}
Error handling lacks recovery guidance. Tools report errors (isError) but do not provide actionable next steps for LLMs. E.g., 'unknown unit' errors do not suggest calling find_units() first.
Parameter 'query' in find_units lacks enum or regex constraint; description says 'short keyword' but no formal validation is visible. LLMs may pass multi-word phrases or very long strings.
Output schema (dimension, base_value fields) is documented in docstrings but not formally declared in the FastMCP tool registration. LLM clients cannot introspect the response structure programmatically.
Tool descriptions contain references to internal sections (§2.4.6, §14.1, §16, TODO §4.4) that are meaningless to LLMs. These should be removed or replaced with clear inline context.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 69 | 2026-07-28+ | v2 |
Discovery / health-check entrypoint: report availability and version info. Returns seven keys: `status` ("available"), `name`, `version` (package version), `python` (runtime version), `mcp_sdk` (MCP SDK version, or "unknown"), `toolsets` (empty until the GNU units engine lands), and `units_db` — the bundled GNU units database's `source`, `data_version`, and `data_updated` (§2.4.6 / §5.4), read from the shipped file's own header so it can't drift. Example: {"status":"available","name":"mcp-gnu-units","version":"0.0.1", "python":"3.12.3","mcp_sdk":"1.28.0","toolsets":[], "units_db":{"source":"GNU units","data_version":"3.26","data_updated":"2026-02-25"}}