Skip to main content
Glama
jinhyunan

ccpp-tools-mcp

by jinhyunan
README.md
# ccpp-tools-mcp

[![ci](https://github.com/jinhyunan/ccpp-tools-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/jinhyunan/ccpp-tools-mcp/actions/workflows/ci.yml)
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](pyproject.toml)

**Deterministic, standards-traceable engineering calculations for combined-cycle
power plant (CCPP) balance-of-plant design — exposed as an MCP server.**

LLM agents are excellent at orchestrating an engineering workflow in natural
language and terrible at arithmetic. This server splits the work accordingly:
any MCP client (Claude Desktop, Claude mobile, Claude Code, Cursor, or an
internal agent) drives the conversation, while every number comes from a pure,
tested Python function that returns its **evidence** — the governing standard,
the equation evaluated, the assumptions you must own, and the warnings you must
not ignore.

```text
"Verify this fuel-oil transfer system: 60 m³/h diesel at 40 °C,
 180 m discharge run rising 18 m, flooded suction, NPSHr 4 m…"

        Claude (orchestration, no arithmetic)
          │ tank_capacity        → 3,240 m³ working → 2 × 1,800 m³
          │ fluid_props_liquid   → ρ 819.8 kg/m³, μ 1.97 mPa·s  [ASTM D341]
          │ pipe_size_select     → NPS 4 SCH 40, 2.03 m/s ✓ (1–3 band)
          │ dp_segment_liquid    → Re 8.6e4, f 0.0205, 9.76 m    [Crane TP-410]
          │ pump_tdh             → TDH 28.8 m → rate at 32 m
          │ pump_npsha           → NPSHa 13.0 m vs NPSHr 4.0 ✓
          └ valve_cv_liquid      → Cv 11.9, not choked           [ISA 75.01]
```

The full conversation, produced by a real Claude client calling this server end
to end, is preserved verbatim in
[docs/cases/case-01-transcript.md](docs/cases/case-01-transcript.md), and an
**[interactive overview](https://jinhyunan.github.io/ccpp-tools-mcp/)** lets you
step through the tool chain response by response.

## Why trust the numbers

Every calculation is held by **two independent legs**
([docs/verification.md](docs/verification.md)):

1. **Golden tests from the governing documents.** The IAPWS-IF97 water/steam
   implementation is written from the release itself (regions 1/2/4 +
   R12-08 viscosity, stdlib only) and locked by the release's own
   computer-program verification tables at 8–9 significant figures.
2. **Cross-validation against independent implementations.** ~1,800 swept
   assertions compare the runtime core against `fluids` and `iapws` — which
   are *test-only* dependencies. The runtime has **zero** third-party
   calculation code, so the comparison is never circular.

The harness has already earned its keep: it caught a wall-thickness
transcription error (NPS 18 SCH 80, 23.88 → 23.83 mm) and rejected five
golden values written from memory instead of the document. Both incidents are
kept in the verification log on purpose.

## Quick start

```bash
uvx ccpp-tools-mcp                 # stdio (once published to PyPI)
# or from a checkout:
uv run ccpp-tools-mcp              # stdio
uv run ccpp-tools-mcp --transport streamable-http --port 8899   # HTTP
```

**Claude Desktop** (`claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "ccpp-tools": {
      "command": "uvx",
      "args": ["ccpp-tools-mcp"]
    }
  }
}
```

**Claude Code:**

```bash
claude mcp add ccpp-tools -- uvx ccpp-tools-mcp
```

**Claude mobile / web:** run the HTTP transport, expose it (e.g.
`cloudflared tunnel --url http://localhost:8899`), and add
`https://<your-tunnel>/mcp` as a custom connector.

Then paste the demo prompt from
[docs/cases/case-01-fuel-oil-transfer.md](docs/cases/case-01-fuel-oil-transfer.md)
and watch the tool chain run.

## Tools (v1)

| Tool | What it computes | Standard basis |
|------|------------------|----------------|
| `fluid_props_liquid` | ρ, ν/μ, Pv, SG for petroleum liquids (preset or custom 2-point fit) | API gravity / ASTM D341 |
| `fluid_props_steam` | water/steam v, h, s, cp, μ; saturation states | IAPWS-IF97 / R12-08 (own implementation) |
| `tank_capacity` | working/nominal volume, residence time | volume balance (ahead of API 650/620) |
| `pipe_size_select` | smallest NPS/SCH meeting a velocity limit | ASME B36.10M + continuity |
| `pipe_wall_thickness` | pressure-design wall vs selected schedule | ASME B31.1 §104.1.2 |
| `dp_segment_liquid` | Darcy friction + Crane fitting losses, Re/velocity flags | Crane TP-410 / Colebrook-White |
| `list_crane_fittings` | accepted fitting keys and their K basis | Crane TP-410 |
| `pump_tdh` | total dynamic head balance | Hydraulic Institute |
| `pump_npsha` | NPSH available + margin vs NPSHr | HI 9.6.1 concepts |
| `pump_power` | hydraulic / shaft power | ρgQH |
| `valve_cv_liquid` | required Cv/Kv + choked-flow check | ISA 75.01 / IEC 60534-2-1 |

## The response envelope

Every tool returns the same contract — a number you can defend:

```json
{
  "result":     { "npsha_m": 12.99, "margin_m": 8.99 },
  "method":     { "standard": "Hydraulic Institute (HI 9.6.1 concepts)",
                  "equation": "NPSHa = (P_surface,abs - Pv)/(rho g) + z_static - h_f,suction" },
  "assumptions": [ "atmospheric pressure 101.325 kPa(a)",
                   "vapor pressure 0.5 kPa(a) at pumping temperature" ],
  "warnings":   [],
  "validity":   "ok"
}
```

Warnings are load-bearing: an undersized line answers with the number **and**
a velocity flag; a deep-turndown case flags the laminar–turbulent transition;
a near-saturation valve sizing reports choked flow. The orchestrating agent is
expected to surface every warning to the user — the Case 01 transcript shows
that happening.

## Architecture

```mermaid
flowchart LR
    subgraph clients [MCP clients]
        A[Claude Desktop / mobile]
        B[Claude Code / Cursor]
        C[internal plant agent]:::private
    end
    subgraph server [ccpp-tools-mcp]
        E[slim envelope<br/>result + method + assumptions + warnings]
        subgraph core [stdlib-only calculation core]
            P[pipe: B36.10M · B31.1]
            H[hydro: Colebrook · Crane K]
            Q[equipment: pump · tank · ISA 75.01]
            F[props: ASTM D341 · IAPWS-IF97]
        end
    end
    subgraph oracles [test-only oracles]
        O1[fluids]
        O2[iapws]
        O3[official verification tables]
    end
    A & B & C -->|stdio / streamable-http| E --> core
    core -.->|cross-validated in CI| oracles
    classDef private stroke-dasharray: 5 5,stroke:#888,color:#888;
```

The internal orchestrating agent shown dashed is a private, out-of-scope
deployment; everything demonstrated here runs on generic public MCP clients.

## Scope and honest limits

- **Decision support, not engineering of record.** Results carry their
  assumptions; the responsible engineer owns criterion selection, margins,
  and code compliance.
- v1 is liquid-service only; compressible dP, heat-exchanger rating, and
  parallel-flow distribution arrive in v1.1 with their own validated cases.
- IF-97 regions 3 (near-critical) and 5 are deliberately not implemented —
  out-of-range inputs raise instead of extrapolating.
- The bundled diesel preset is a representative ASTM D975 sample, not project
  fuel data, and says so in every response.
- Full gap list: [docs/verification.md](docs/verification.md).

## Development

```bash
uv sync --dev
git config core.hooksPath .githooks   # forbidden-token pre-commit gate
uv run pytest -q -m "not cross"       # unit + golden
uv run pytest -q -m cross tests/cross # sweeps vs fluids / iapws
uv run ruff check . && uv run mypy    # lint + strict types
```

## License

Apache-2.0. Crane TP-410, ASME, ISA, HI, ASTM, and IAPWS are referenced as
public standards; bring your own licensed copies for engineering use.

TDQS

B3.3/5.0

Scored across 11 tools

Disambiguation5/5

Each tool targets a distinct calculation or resource: fluid properties (liquid vs steam), tank sizing, pipe sizing/wall thickness/pressure drop, pump TDH/NPSHA/power, and valve Cv. No two tools overlap in purpose; even fluid_props_liquid and fluid_props_steam cover different fluids.

Naming Consistency4/5

Tool names mostly follow a consistent object_attribute pattern (e.g., fluid_props_liquid, pipe_wall_thickness, pump_tdh). The one deviation is list_crane_fittings, which starts with a verb rather than a noun, but it is still clear and matches the underscore-separated lowercase style.

Tool Count5/5

With 11 tools, the set is well-scoped for a chemical/process engineering domain. Each tool covers a distinct design step, and the count is within the ideal 3-15 range without feeling sparse or bloated.

Completeness4/5

The toolset covers a complete liquid piping and pump design workflow: fluid properties, tank capacity, pipe sizing, wall thickness, pressure drop, pump head/NPSH/power, and valve Cv. Minor gaps exist for gas/compressible flow calculations, but the domain appears intentionally liquid-focused.

Maintenance

ActivityStale
ResponsivenessNo issues