Skip to main content
Glama
trippborstel-hub

northwood-carbon MCP server

README.md
# northwood-carbon MCP server

An MCP (Model Context Protocol) server that exposes Northwood Capital Partners' portfolio
carbon data as tools any MCP-compatible agent (Claude Desktop, Claude Code, etc.) can call.

Turns carbon questions like *"Which three portcos are furthest behind their 2030 targets, and
what's the cheapest initiative for each?"* into tool calls, not data wrangling.

## Tools

| Tool | Purpose |
|---|---|
| `list_portcos` | All 10 portcos with sector, status, revenue, facilities, data grade |
| `get_portco_emissions` | Scope 1 / Scope 2 emissions for a portco, filterable by year + scope |
| `gap_to_target` | Gap analysis vs SBTi-aligned 42% by 2030 pathway |
| `list_initiatives` | Decarbonization levers with reduction, capex, status |
| `simulate_reduction` | What-if: apply initiatives, return projected emissions + capex |

## Install

```bash
# Clone
git clone <repo-url> northwood-carbon-mcp
cd northwood-carbon-mcp

# With uv (recommended)
uv sync

# Or with pip
pip install -e .
```

## Run

```bash
uv run server.py
# or
python server.py
```

The server speaks MCP over stdio, so you don't run it directly in most cases —
you register it with a client that spawns it.

## Connect to Claude Desktop / Claude Code

Add to your MCP config (`~/.claude/mcp.json` or Claude Desktop settings):

```json
{
  "mcpServers": {
    "northwood-carbon": {
      "command": "uv",
      "args": ["--directory", "/path/to/northwood-carbon-mcp", "run", "server.py"]
    }
  }
}
```

Restart the client. The five tools appear automatically.

## Example session

```
You: What are Meridian's 2024 Scope 1 emissions?

Claude → get_portco_emissions(portco="meridian", year=2024, scope=1)
       ← {"emissions": {"2024": {"scope1": 750.0}}, "units": "tCO2e", ...}

Claude: Meridian Business Solutions emitted 750 tCO2e in Scope 1 during 2024,
        primarily natural gas for space heating across 16 offices.
```

```
You: Which portcos are off-track for 2030 and what's the cheapest initiative for each?

Claude → list_portcos()
       → gap_to_target(portco=<each>)   × 10
       → list_initiatives(portco=<off-track one>, status="planned") × 3
       ← synthesizes ranked answer with capex + reduction per lever
```

## Data

Static snapshot in `data.json`, sourced from the Northwood engagement's Week 3 carbon
inventory and Week 4 decarbonization work. Drop in a live DB connection by replacing
the `DATA = json.loads(...)` line with a query layer — the tool surface stays identical.

## Structure

```
.
├── server.py       — FastMCP server, 5 tools, ~200 LOC
├── data.json       — Static data (PORTCOS, TRAJECTORY, INITIATIVES, RISK_SUMMARY, ESG_SCORES, FACILITIES)
├── pyproject.toml
└── README.md
```

TDQS

A4.3/5.0

Scored across 5 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: listing portfolio companies, retrieving emissions data, listing initiatives, simulating reductions, and computing gap to target. No overlap or ambiguity.

Naming Consistency4/5

Four tools use a consistent verb_noun pattern (list_portcos, get_portco_emissions, list_initiatives, simulate_reduction). However, 'gap_to_target' starts with a noun rather than a verb, creating a minor inconsistency.

Tool Count5/5

5 tools is an appropriate size for a focused carbon analysis server. Each tool serves a distinct function without unnecessary duplication or gaps.

Completeness4/5

The tool set covers the core analysis workflow: list companies, retrieve emissions, view initiatives, simulate reductions, and check targets. Missing write operations (e.g., create/update initiatives) but reasonable for a read/analysis-oriented server.

Maintenance

ActivityInactive
ResponsivenessNo issues