Keyless US grid carbon + power cost by ZIP: eGRID Scope 2, Scope 1 fuels, site ranking, clean hours
io.github.rozetyp/emission-factors — Model Context Protocol (MCP) Server
The io.github.rozetyp/emission-factors MCP server provides keyless U.S. grid carbon and power cost data by ZIP. Its dataset is based on eGRID Scope 2 and includes Scope 1 fuels, as well as site ranking and “clean hours.”
🛠️ Key Features
Keyless access
U.S. grid carbon and power cost by ZIP
eGRID Scope 2 inclusion
Scope 1 fuels coverage
Site ranking
Clean hours
🚀 Use Cases
Estimating carbon and power cost characteristics for specific ZIP codes
Comparing sites using the provided ranking
Using “clean hours” for time-based analysis
⚡ Developer Benefits
Provides structured, ZIP-based emission and cost context for integrations
Includes both Scope 2 and Scope 1 related data fields
Adds ranking and clean-hours attributes for downstream logic
⚠️ Limitations
Available coverage is limited to U.S. grid carbon and power cost by ZIP.
Look up EPA eGRID electricity emission factors for a US ZIP code. Returns CO2e (kg/kWh and lb/MWh), CO2, CH4, N2O, NOx, SO2, non-baseload rate, carbon-free %, generation mix (coal/gas/nuclear/hydro/wind/solar etc.), eGRID subregion code, the data year, and the Green-e residual mix rate (the market-based Scope 2 factor). For Scope 2 emissions from a kWh total, use calculate_emissions, which does the arithmetic for both methods.
Parameters2
zip
string
required
5-digit US ZIP code (e.g. "94105"); ZIP+4 accepted
year
string
optional
eGRID edition: 2023 (default, official EPA) or 2024 (EPA's public eGRID code run on 2024 data by Cornerstone; EPA has not published eGRID2024)
Raw schema
{
"type": "object",
"properties": {
"zip": {
"type": "string",
"description": "5-digit US ZIP code (e.g. \"94105\"); ZIP+4 accepted",
"pattern": "^\\d{5}(-?\\d{4})?$"
},
"year": {
"type": "string",
"enum": [
"2023",
"2024"
],
"description": "eGRID edition: 2023 (default, official EPA) or 2024 (EPA's public eGRID code run on 2024 data by Cornerstone; EPA has not published eGRID2024)"
}
},
"required": [
"zip"
]
}
lookup_by_coordinates
Look up emission factors by latitude/longitude. Uses US Census Geocoder to resolve to ZIP first, then returns the same data as lookup_emission_factor. Useful when you have a facility address or lat/lon but no ZIP.
Look up emission factors for up to 100 ZIP codes in one call (split longer lists). Returns one compact row per ZIP - subregion, CO2e kg/kWh (location-based), residual mix (market-based), carbon-free %, utility - unless full is true, which returns every field (about 2 KB per ZIP).
Parameters2
zips
array
required
Array of US ZIP codes (5 digits or ZIP+4)
full
boolean
optional
Return complete candidate records (all pollutants, generation mix) instead of compact rows. Default false.
Raw schema
{
"type": "object",
"properties": {
"zips": {
"type": "array",
"items": {
"type": "string",
"pattern": "^\\d{5}(-?\\d{4})?$"
},
"description": "Array of US ZIP codes (5 digits or ZIP+4)",
"maxItems": 100
},
"full": {
"type": "boolean",
"description": "Return complete candidate records (all pollutants, generation mix) instead of compact rows. Default false."
}
},
"required": [
"zips"
]
}
calculate_emissions
Calculate Scope 2 CO2e for a facility from its ZIP and kWh, using both GHG Protocol methods: location-based (eGRID subregion rate) and market-based (Green-e residual mix applied to kWh not covered by RECs, PPAs or green tariffs). Returns kg CO2e for each method with the factors used.
Parameters4
zip
string
required
5-digit US ZIP code (ZIP+4 accepted)
kwh
number
required
Electricity consumption in kWh
renewable_kwh
number
optional
Optional: kWh covered by contractual instruments (RECs, PPAs, green tariff). Counted at zero in the market-based result. Default 0.
{
"type": "object",
"properties": {
"zip": {
"type": "string",
"description": "5-digit US ZIP code (ZIP+4 accepted)",
"pattern": "^\\d{5}(-?\\d{4})?$"
},
"kwh": {
"type": "number",
"description": "Electricity consumption in kWh",
"minimum": 0
},
"renewable_kwh": {
"type": "number",
"description": "Optional: kWh covered by contractual instruments (RECs, PPAs, green tariff). Counted at zero in the market-based result. Default 0.",
"minimum": 0
},
"year": {
"type": "string",
"enum": [
"2023",
"2024"
],
"description": "eGRID edition (default 2023). Market-based needs 2023."
}
},
"required": [
"zip",
"kwh"
]
}
hourly_intensity
Get hourly grid carbon intensity (kg CO2e per kWh) for any US ZIP code, derived from EIA-930 hourly fuel-mix data. Data lags up to about a day (not real-time). Returns time series with per-hour fuel mix, total generation, and carbon intensity. For timing and analysis (demand response, load shifting, grid patterns), not inventory reporting: it uses fixed per-fuel combustion factors on in-BA generation (no imports), so its values don't match eGRID's annual factors. For live or forecast intensity, WattTime or Electricity Maps are better options.
Parameters4
zip
string
optional
5-digit US ZIP code (or use ba parameter)
ba
string
optional
Balancing authority code directly (e.g. CISO, ERCO, PJM, MISO, NYIS). Use this OR zip.
hours
integer
optional
Number of most recent hours to return (default 24, max 168 = 1 week).
aggregate
string
optional
Optional: return the 24-hour average profile over the last 7 days (168 hours) instead of the hourly series. Buckets are UTC hours; for a local-time scheduling window use cleanest_hours.
Raw schema
{
"type": "object",
"properties": {
"zip": {
"type": "string",
"description": "5-digit US ZIP code (or use ba parameter)",
"pattern": "^\\d{5}(-?\\d{4})?$"
},
"ba": {
"type": "string",
"description": "Balancing authority code directly (e.g. CISO, ERCO, PJM, MISO, NYIS). Use this OR zip."
},
"hours": {
"type": "integer",
"description": "Number of most recent hours to return (default 24, max 168 = 1 week).",
"minimum": 1,
"maximum": 168
},
"aggregate": {
"type": "string",
"enum": [
"hour_of_day"
],
"description": "Optional: return the 24-hour average profile over the last 7 days (168 hours) instead of the hourly series. Buckets are UTC hours; for a local-time scheduling window use cleanest_hours."
}
}
}
plant_emissions
Get emissions from EPA Clean Air Markets Division (CAMD) for a specific US power plant or a state: fossil units over 25 MW reporting to the Acid Rain Program and CSAPR. Per facility returns total CO2 (short tons), gross generation (MWh), heat input (mmBtu), NOx and SO2 (lb), primary fuel type, operating hours, and derived emissions rate (kg CO2/MWh). CAMD publishes by quarter, so the default window is the last 7 days of the latest published quarter (latest_published_date in the response); later dates are not available yet. Default output is a per-facility summary from daily data; format=hourly returns unit-hour records for small windows. Use for plant-specific carbon accounting, state-level fossil emissions and "dirtiest plants in [state]" queries.
Parameters7
facility_id
integer
optional
EPA CAMD/ORIS facility code (e.g. 3 for Barry, AL). Find codes in the summary_by_facility of a state query, or at https://campd.epa.gov/.
state
string
optional
2-letter US state code for state-wide aggregate (e.g. TX, CA, PA).
days
integer
optional
Number of most recent days to include (1-90, default 7).
begin
string
optional
Custom begin date YYYY-MM-DD (optional, overrides days).
end
string
optional
Custom end date YYYY-MM-DD (optional, overrides days).
format
string
optional
"summary" (default) aggregates by facility; "hourly" returns raw CAMD unit-hour records, about 0.8 KB each (a 9-unit plant-day was 172 KB), so use it with facility_id and 1-2 days.
limit
integer
optional
Summary only: return the top N facilities by CO2 (default 25); facilities_total gives the full count.
Raw schema
{
"type": "object",
"properties": {
"facility_id": {
"type": "integer",
"description": "EPA CAMD/ORIS facility code (e.g. 3 for Barry, AL). Find codes in the summary_by_facility of a state query, or at https://campd.epa.gov/."
},
"state": {
"type": "string",
"description": "2-letter US state code for state-wide aggregate (e.g. TX, CA, PA)."
},
"days": {
"type": "integer",
"description": "Number of most recent days to include (1-90, default 7).",
"minimum": 1,
"maximum": 90
},
"begin": {
"type": "string",
"description": "Custom begin date YYYY-MM-DD (optional, overrides days).",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$"
},
"end": {
"type": "string",
"description": "Custom end date YYYY-MM-DD (optional, overrides days).",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$"
},
"format": {
"type": "string",
"enum": [
"summary",
"hourly"
],
"description": "\"summary\" (default) aggregates by facility; \"hourly\" returns raw CAMD unit-hour records, about 0.8 KB each (a 9-unit plant-day was 172 KB), so use it with facility_id and 1-2 days."
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 500,
"description": "Summary only: return the top N facilities by CO2 (default 25); facilities_total gives the full count."
}
}
}
utility_tariff
Get the actual utility-specific electricity rate (not state average) for a US ZIP code or named utility. Returns the current default tariff with effective rate ($/kWh), fixed monthly charge, tier count, TOU indicator, and effective date. Data source: OpenEI URDB (NREL-hosted). With a ZIP, matches the ZIP's utility by EIA ID. Returns currently-effective tariffs; when URDB has none flagged as default (common for Commercial/Industrial) it returns the most recent ones and says so in warnings, including when the newest available tariff has expired. Does not cover Texas retail electric providers (deregulated market) - use electricity_rate there.
Parameters5
zip
string
optional
5-digit US ZIP code
utility
string
optional
Utility name (e.g. "Pacific Gas & Electric Co", "Consolidated Edison Co-NY Inc")
{
"type": "object",
"properties": {
"zip": {
"type": "string",
"description": "5-digit US ZIP code",
"pattern": "^\\d{5}(-?\\d{4})?$"
},
"utility": {
"type": "string",
"description": "Utility name (e.g. \"Pacific Gas & Electric Co\", \"Consolidated Edison Co-NY Inc\")"
},
"eiaid": {
"type": "integer",
"description": "EIA utility ID (joins with EIA Form 861)"
},
"sector": {
"type": "string",
"enum": [
"Residential",
"Commercial",
"Industrial",
"Lighting",
"RES",
"COM",
"IND"
],
"description": "Default \"Residential\" (case-insensitive; RES/COM/IND codes accepted)"
},
"limit": {
"type": "integer",
"description": "Max tariffs to return (1-20, default 5)",
"minimum": 1,
"maximum": 20
}
}
}
electricity_rate
Get the latest monthly average retail electricity rate ($/kWh and cents/kWh) for any US ZIP code, broken out by sector (residential, commercial, industrial, etc.). Data is state-level from EIA Form 861 - a ballpark, not utility- or ZIP-specific tariffs (use utility_tariff for those).
Compare and rank 2-25 candidate US sites (ZIP codes) for a facility, data center or EV/flexible load on grid carbon and electricity cost in one call. Per site: eGRID CO2e kg/kWh (location-based), Green-e residual mix (market-based), carbon-free %, $/kWh for the sector (the ZIP's utility average where exactly one full-service utility serves it, otherwise (several utilities, or retail choice) the state average; all EIA-861 2023, see rate_basis), and the cleanest daily window from the 7-day hourly profile of its balancing authority. With annual_kwh, also annual tCO2e and cost. Returns competition ranks by carbon, cost and combined, gap percentages, and best_* = null with *_tied lists when sites tie.
Parameters4
zips
array
required
Candidate US ZIP codes (5 digits or ZIP+4)
annual_kwh
number
optional
Optional annual consumption in kWh (e.g. 87,600,000 for a 10 MW constant load) to get annual tCO2e and cost per site
sector
string
optional
Retail rate sector. Default COM (commercial); use IND for industrial/data-center loads.
duration
integer
optional
Length of the cleanest daily window in hours (default 4)
Raw schema
{
"type": "object",
"properties": {
"zips": {
"type": "array",
"items": {
"type": "string",
"pattern": "^\\d{5}(-?\\d{4})?$"
},
"minItems": 2,
"maxItems": 25,
"description": "Candidate US ZIP codes (5 digits or ZIP+4)"
},
"annual_kwh": {
"type": "number",
"minimum": 0,
"description": "Optional annual consumption in kWh (e.g. 87,600,000 for a 10 MW constant load) to get annual tCO2e and cost per site"
},
"sector": {
"type": "string",
"enum": [
"COM",
"IND",
"RES",
"ALL",
"Commercial",
"Industrial",
"Residential"
],
"description": "Retail rate sector. Default COM (commercial); use IND for industrial/data-center loads."
},
"duration": {
"type": "integer",
"minimum": 1,
"maximum": 12,
"description": "Length of the cleanest daily window in hours (default 4)"
}
},
"required": [
"zips"
]
}
cleanest_hours
Find the cleanest (lowest grid carbon) contiguous window of N hours in the day to run a flexible load (batch jobs, EV charging, pumping, HVAC pre-cooling) at a US ZIP code or balancing authority. Based on the hour-of-day pattern of the last 7 days (168 hours) of EIA-930 data, in local time. Returns the cleanest and dirtiest windows, % saved vs the daily average, and all hours ranked. A scheduling guide from recent history, not a forecast.
Parameters3
zip
string
optional
5-digit US ZIP code (or use ba)
ba
string
optional
Balancing authority code (e.g. CISO, ERCO, PJM, MISO, NYIS). Use this OR zip.
duration
integer
optional
Window length in hours (default 4)
Raw schema
{
"type": "object",
"properties": {
"zip": {
"type": "string",
"description": "5-digit US ZIP code (or use ba)",
"pattern": "^\\d{5}(-?\\d{4})?$"
},
"ba": {
"type": "string",
"description": "Balancing authority code (e.g. CISO, ERCO, PJM, MISO, NYIS). Use this OR zip."
},
"duration": {
"type": "integer",
"minimum": 1,
"maximum": 12,
"description": "Window length in hours (default 4)"
}
}
}
calculate_fuel_emissions
Calculate Scope 1 stationary-combustion emissions (CO2, CH4, N2O and CO2e) for fuels burned on site, using the GHG Emission Factors Hub 2026 (Cornerstone, successor to EPA's Hub; IPCC AR6 GWPs) by default, or EPA's 2025 edition (AR5) with edition=2025. Pass one or more items with fuel, quantity and unit, e.g. natural gas in therms/ccf/mcf/scf, propane/diesel/heating oil in gallons, coal in short tons. Biomass CO2 is reported separately (biogenic). Stationary sources only: for vehicle fuel the CO2 per gallon is the same, but CH4/N2O factors differ and are not included. Returns per-item and total CO2e. Pair with calculate_emissions for a facility's electricity (Scope 2).
Parameters2
items
array
required
edition
string
optional
Hub edition: 2026 (default; Cornerstone, AR6 GWPs) or 2025 (EPA, AR5 GWPs). Fuel factors are the same; CO2e differs slightly.
Give Claude, Cursor, Cline, or any MCP client live access to US electricity data by ZIP code - grid-carbon emission factors, retail rates, hourly grid carbon intensity, power-plant emissions, and utility tariffs.
Backed by emission-factors.com, which wraps EPA eGRID, EIA-861, EIA-930, EPA CAMD, and OpenEI URDB into one ZIP-keyed API.
Free. No API key, no signup. The API is rate-limited per IP (2,000 requests/hour).
What you can ask
Once connected, your agent can answer things like:
"My HQ in ZIP 94105 uses 1.2M kWh/year. What's our Scope 2 carbon footprint and annual electricity cost?"
"Compare Denver, Austin, and Columbus for a new data center on grid carbon intensity and electricity price."
"What hour of the day is cleanest to run a 500 kW batch job in California this week?"
"Enrich this list of 40 store ZIP codes with each site's emission factor and carbon-free percentage."
"Which are the dirtiest power plants in Texas by CO2 over the last week?"
"Rank Ashburn VA, Abilene TX and The Dalles OR for a 10 MW data center on carbon and power cost."
"Our plant burns 40,000 therms of gas and 3,000 gallons of diesel a year - what's our Scope 1?"
"What's the actual PG&E residential tariff for 94105, not the state average?"
Why use it
Scope 2 carbon accounting - GHG Protocol location- and market-based emission factors for 33,700+ US ZIP codes (CDP, CSRD, California SB 253 inputs).
Site selection - compare candidate locations on both carbon intensity and electricity cost in one conversation.
Demand-response and load-shifting analysis - hourly grid carbon from EIA-930 (fixed per-fuel factors on in-BA generation: for timing, not inventory reporting).
Plant-level emissions - EPA CAMD data for fossil units over 25 MW: per-facility summaries or unit-hour records, published quarterly.
Agents and automation - a clean tool surface so an LLM can fetch authoritative government data instead of hallucinating factors.
Quick start
There are two ways to run this. Most people want Option A.
Option A - Remote server (recommended, zero install)
Nothing to install, always up to date. The hosted endpoint is https://emission-factors.com/mcp (Streamable HTTP, no key).
Claude (web, desktop app, mobile) - Add to Claude. The link opens Claude's custom-connector dialog with the name and URL filled in; select Add, then Connect. By hand: Customize -> Connectors -> Add custom connector, URL https://emission-factors.com/mcp, OAuth fields empty.
Claude Code
bash
claude mcp add --transport http emission-factors https://emission-factors.com/mcp
Cline / Continue / Zed / other clients - add a remote (Streamable HTTP) MCP server with URL https://emission-factors.com/mcp. No key needed.
Claude Desktop's claude_desktop_config.json only starts local (stdio) servers - a "url" entry there does nothing. Use the connector link above, or Option B.
Option B - Local stdio server (this package)
Runs the server as a local process that proxies the same public API. Useful for clients that only support stdio transport, or if you want to self-host.
Run straight from GitHub (builds on install, requires Node 18+):
Optional environment variable: EMISSION_FACTORS_API_BASE (defaults to https://emission-factors.com) if you run your own instance of the API.
Tools
Eleven tools, keyed by US ZIP code (or a direct code where noted). The remote server and this stdio build expose the same set.
Tool
Purpose
Key inputs
lookup_emission_factor
EPA eGRID CO2e + full generation mix for a ZIP
zip
lookup_by_coordinates
Same, resolved from lat/lon via Census geocoder
lat, lon
lookup_batch
Emission factors for up to 100 ZIPs at once
zips[]
calculate_emissions
Scope 2 CO2e for a ZIP + kWh, location-based and market-based (Green-e residual mix)
zip, kwh, renewable_kwh
hourly_intensity
Hourly grid carbon intensity (EIA-930, ~24h lag)
zip or ba, hours
plant_emissions
Plant emissions (EPA CAMD): facility summaries or unit-hour records
facility_id or state, days
utility_tariff
Utility-specific tariff, not state average (OpenEI URDB)
zip, utility, or eiaid
electricity_rate
State-average retail rate by sector (EIA-861)
zip
compare_sites
Rank 2-25 candidate sites on grid carbon, $/kWh and cleanest daily window
zips[], annual_kwh, sector
cleanest_hours
Cleanest N-hour window of the day to run a flexible load, in local time
zip or ba, duration
calculate_fuel_emissions
Scope 1 CO2e for fuels burned on site (EPA GHG Emission Factors Hub)
items[]: fuel, quantity, unit
All tools return JSON. See full API docs for exact response shapes.
Data sources
Data
Source
Notes
Grid emission factors
EPA eGRID2023 Rev2 (+ eGRID2024 from Cornerstone via year=2024)
Annual, location-based, 27 subregions
Residual mix (market-based Scope 2)
Green-e Residual Mix 2025 (2023 data)
Per eGRID subregion
Fuel combustion factors (Scope 1)
GHG Emission Factors Hub 2026 (Cornerstone, successor to EPA's Hub); EPA 2025 via edition
63 fuels, AR6 GWPs (AR5 for 2025)
Retail electricity rates
EIA Form 861
State-level monthly average by sector
Hourly grid carbon intensity
EIA-930
Derived from hourly fuel mix, ~24h lag
Plant-level emissions
EPA CAMD
fossil units >25 MW, published quarterly (45+ days after quarter end)
Utility-specific tariffs
OpenEI URDB (NREL)
ZIP matched to its utility by EIA ID
ZIP / lat-lon resolution
US Census (ZCTA + Geocoder)
ZIP -> eGRID subregion mapping
Rate limits and auth
No API key, no signup. Every request is anonymous.
2,000 requests/hour per IP. Generous for interactive use; if you hit it you get an HTTP 429 with a retryAfter hint.
The external-data endpoints are cached server-side (24h rates, 1h hourly intensity, 7d tariffs, 24h plant emissions), so repeated calls are fast and don't burn upstream quotas.
Also available
REST API - the same data over plain HTTP: curl "https://emission-factors.com/api/lookup?zip=94105". See the API docs and OpenAPI spec.
npm install # install deps and build (prepare -> tsc)
npm run build # compile TypeScript to dist/
npm run dev # watch mode
npm start # run the built server over stdio
The server is a thin proxy: each tool maps to one /api/* endpoint on emission-factors.com, validates inputs, and returns the JSON response. There is no local state and no key handling.
License
MIT - see LICENSE. Data belongs to its respective US government sources (EPA, EIA, Census) and NREL/OpenEI; this project and the API are an unofficial wrapper, not affiliated with those agencies.