MCP tools
Numbers checked against the live data on
The MCP server at https://mcp.open-climate.ai/mcp exposes 15 tools: 12 for the model and 3 that only the in-chat widgets call. One, search_emission_factors, answers a question about one item. The rest take a file of purchase or activity lines, match each line to an emission factor and return the totals. To connect, see Connect over MCP.
A platform that mounts the server behind its own reaches a narrower set, without search_emission_factors: see Integrate our MCP.
How the tools chain#
For one to five items, call search_emission_factors once per item. For more items, a ledger or a file, use the chain:
| step | tool | returns |
|---|---|---|
| 1. Get the lines in | upload_inline_rows (50 rows or fewer) or prepare_upload (a file) |
upload_id |
| 2. Read the file's shape | plan_emission_factor_mapping |
suggested sheet, header row, columns, file context |
| 3. Decode jargon, optional | create_lexicon |
domain, lexicon |
| 4. Start the job | map_procurement_items_to_emission_factors |
job_id |
| 5. Wait | check_emission_factor_mapping_progress |
status, stage, percent |
| 6. Read the result | get_emission_factor_mapping_result, then read_emission_factor_mapping_result_file |
download URL, report_stats, rows |
Every later tool takes the upload_id or job_id verbatim. Never pass a file path or URL in their place. No tool returns where a file is stored: an upload is named by its upload_id and its filename, a result by its job_id and its download URL.
The shared envelope#
prepare_upload, plan_emission_factor_mapping, create_lexicon and get_emission_factor_mapping_result return these five fields beside their own.
| field | type | meaning |
|---|---|---|
next_step |
object or null | The next call, when exactly one is unambiguous and required. |
requires_followup |
object or null | The client must compute a value and forward it on its next call, for example the file context. |
plan_id |
string or null | A handle to a server-side artefact the next tool consumes. Lives at most 1 hour. |
warnings |
array of string | Notes that do not block the next call. |
needs_clarification |
array of string | Questions to ask the user before you continue. When it is not empty, next_step is absent. |
Each tool also returns a prose content[0].text that says what to do next, so a client can act on the text alone.
get_emission_factor_mcp_server_info#
Reports which build of the server you reached and which tools it registered. Read-only, no side effects. Use it to check a new connection.
Inputs. None.
Output.
| field | type | meaning |
|---|---|---|
name |
string | Server name. |
package_version |
string | Version of the server package. |
git_sha |
string or null | Short commit at start, when known. |
git_dirty |
boolean or null | Whether the source tree had uncommitted changes at start. |
started_at |
string | UTC time the process started. |
pid |
integer | Process id. |
transport |
string | http or stdio. |
tool_names |
array of string | Every registered tool. |
search_emission_factors#
Finds emission factors for one item, such as "a factor for a laptop", "hotel night in Spain" or "steel rebar per tonne". It reads the same ranking and licence rules as the factor explorer. Read-only, no side effects.
Call it once per item, for up to five items. For more, or for a ledger or a file, use the chain: it maps every line in one job.
Inputs.
| input | type | required | default | meaning |
|---|---|---|---|---|
query |
string | yes | The one item, in plain words, 1 to 200 characters. | |
alternative_phrasings |
array of string | no | [] |
Up to 3 other wordings of the same item: a synonym, the LCA or trade term, a translation. Their rankings are fused into one list. Never a different item. |
location |
string or null | no | A country or region name to favour, such as France, up to 80 characters. It boosts, it never filters. |
|
unit_family |
array of string or null | no | Keep only factors per this kind of quantity: monetary, mass, energy, count, area, volume, distance, length, freight, passenger, freight_container, duration, area_time, accommodation or length_time. |
|
region_code |
array of string or null | no | Exact region codes: ISO 3166 alpha-2, GLOBAL, EUROPE or EU27. FR does not match an EU27 or GLOBAL factor, so add GLOBAL as a fallback. |
|
library |
array of string or null | no | Library codes, such as desnz or ademe. Set it only when the user names a library. |
|
boundary_preset |
array of string or null | no | Life-cycle scope: cradle_to_gate, cradle_to_shelf, full_lifecycle, direct_only, energy_full_chain, upstream_slice, production_slice, use_slice, eol_slice, end_of_life_waste, supply_chain_only or credit. |
|
is_epd |
boolean or null | no | true for product-specific EPDs only, false for no EPDs. |
|
year |
integer or null | no | Reference year, 1990 to 2100. Omitted, each factor's latest year. | |
limit |
integer | no | 10 | Factors to return, 1 to 25. |
Note. Settle the quantity first and pass it as
unit_family. A laptop has factors per piece (count), per kg (mass) and per euro spent (monetary), and they are not interchangeable.
Output.
| field | type | meaning |
|---|---|---|
phrasings |
array of string | The phrasings searched, query first, repeats removed. |
total_matches |
integer or null | Top-level factors the first phrasing matched in all. |
results |
array | The factors, best first, one row per top-level factor. Fields below. |
hint |
string or null | What to try next when the results are empty or thin. |
Each entry in results:
| field | type | meaning |
|---|---|---|
slug |
string | Stable factor id, the key of its page. |
url |
string | The factor's public page: method, source and parts. |
activity |
string or null | What the factor measures. |
parent_activity |
string or null | The top-level factor this row is a part of, when it is one. |
library |
string | Publishing library code. |
region_code |
string or null | Geography the factor is for. |
kgco2e_per_unit |
number or null | kg CO2e per one unit_code, AR6 GWP100 where derivable. Null when value_withheld_reason is set. |
unit_code |
string or null | The denominator unit. |
unit_family |
string or null | The denominator's kind. |
system_boundary |
string or null | Life-cycle stages covered. |
reference_year |
integer or null | Year the value describes. |
license_tier |
string | open, copyleft, restricted or prohibited. |
value_withheld_reason |
string or null | Why the value is not served, licence or pending. Null when it is served. |
found_by |
array of integer or null | Indexes into phrasings of the phrasings that ranked this factor. |
prepare_upload#
Mints a short-lived upload URL for a .csv, .xls or .xlsx file. Use it when the model cannot see every row, or when there are more than 50. In a host that renders MCP Apps widgets, a drag-and-drop widget appears. Other clients get a curl one-liner in the text.
Inputs. None. The widget reads the file name when the user picks the file.
Output. The envelope, plus:
| field | type | meaning |
|---|---|---|
upload_id |
string | The UUID every later tool takes. |
upload_url |
string | Where to POST the file as multipart/form-data, field file. Bound to you for 1 hour. |
upload_token |
string | Capability token the widget forwards to upload_inline_file. |
widget_url |
string | The upload widget. Headless clients ignore it. |
expires_at |
string | UTC time the URL and token stop working. |
fallback_curl |
string | The curl command for a headless client. |
max_inline_bytes |
integer | Largest file the widget sends inline. A bigger file opens widget_url in a new tab. |
Wait until the upload has finished before you call plan_emission_factor_mapping.
upload_inline_rows#
Stores rows the model can already see as a CSV and registers them like a file. Use it for 50 rows or fewer, whether the user pasted them or attached a small file.
Inputs.
| input | type | required | meaning |
|---|---|---|---|
rows |
array of object | yes | One object per row, {column: value}. Strict cap of 50 rows. Send every row; never sample. |
header |
array of string | yes | Column names in source order. |
filename |
string | yes | Name for display. The stored object is always <stem>.csv. |
Output.
| field | type | meaning |
|---|---|---|
upload_id |
string | The UUID every later tool takes. |
filename |
string | Stored name, <stem>.csv. |
row_count |
integer | Rows stored. |
bytes_stored |
integer | Size of the CSV. |
plan_emission_factor_mapping#
Profiles an uploaded file and proposes how to read it: sheet, header row, trailing rows to drop, useful columns. One short model call also infers the file's currency, the buyer's country and a two-to-three sentence description. Read-only.
Inputs.
| input | type | required | default | meaning |
|---|---|---|---|---|
upload_id |
string | yes | From prepare_upload or upload_inline_rows. |
|
skip_file_context |
boolean | no | false | Skip the currency, country and description inference. Set it only when the user has stated them. |
Output. The envelope, plus:
| field | type | meaning |
|---|---|---|
upload_id |
string | Echoed. |
filename |
string | File name. |
format |
string | xlsx, xls or csv. |
size_bytes |
integer | File size. |
sheets |
array | Per sheet: header candidates, per-column profile, preview rows. |
suggested |
object or null | Best-guess shape, with a nested file_context. Null when no sheet looked like data. |
confidence |
number | Confidence in the header pick, 0 when there is none. |
Watch out. The profiler assumes one header row and one table per sheet. Check
suggestedagainst the preview rows. A total row whose amount a block of the file's own rows adds up to is skipped asaggregate_row. A total the job cannot check, because it has no label or sits on a separate summary sheet, double counts: drop it.
On some deployments suggested.file_context is null and requires_followup is set. The client then infers the currency, country and description itself and passes them to the mapping tool.
create_lexicon#
Decodes a file's opaque vocabulary once, such as brand names, internal abbreviations and dense technical terms, so each row is matched with those terms already explained. Optional. Call it when the descriptions are full of codes; skip it for plain language.
Inputs.
| input | type | required | default | meaning |
|---|---|---|---|---|
upload_id |
string | yes | The upload to scan. | |
force_refresh |
boolean | no | false | Rebuild instead of reusing a cached lexicon. |
Output. The envelope, plus:
| field | type | meaning |
|---|---|---|
upload_id |
string | Echoed. |
domain |
string or null | The file's domain. Null when the client builds the lexicon. |
lexicon |
array | Decoded entries. Empty when the client builds the lexicon, or when nothing was opaque. |
lexicon_audit |
object or null | How the lexicon was built. |
On most deployments this tool returns requires_followup instead: the client reads the file with read_procurement_input_file, builds the lexicon, and forwards domain and lexicon in file_context.
read_procurement_input_file#
Returns the uploaded rows as objects with the original columns, so the client can scan every row. Read-only.
Inputs.
| input | type | required | default | meaning |
|---|---|---|---|---|
upload_id |
string | yes | The upload to read. | |
row_limit |
integer | no | 5000 | Rows to return, 1 to 20000. |
Output.
| field | type | meaning |
|---|---|---|
upload_id |
string | Echoed. |
filename |
string | File name. |
row_count |
integer | Rows in the file, before truncation. |
columns |
array of string | Column names in file order. |
rows |
array of object | The rows. null is an empty cell. |
truncated |
boolean | True when only the first truncation_limit rows came back. |
truncation_limit |
integer or null | The cap applied. |
map_procurement_items_to_emission_factors#
Matches every row of the upload to an emission factor. Asynchronous: it returns a job_id at once, and the result is not ready yet. Do not start a second job for the same file while one runs.
Inputs.
| input | type | required | meaning |
|---|---|---|---|
upload_id |
string | yes | From prepare_upload or upload_inline_rows. |
sheet_name |
string or null | no | Spreadsheets only. Pass suggested.sheet_name. |
header_row |
integer or null | no | Header row, counted from 0. Pass suggested.header_row. |
skip_trailing_rows |
integer or null | no | Rows to drop at the end. |
useful_columns |
array of string or null | no | Columns to read. Never pass synthetic col_N names. |
file_context |
object or null | no | File-level context, below. |
file_context fields, all optional:
| field | type | meaning |
|---|---|---|
currency |
string | ISO 4217 code, such as DKK. |
country |
string | Buyer country, ISO 3166-1 alpha-2, such as DK. |
monetary_scale |
string | thousands or millions when amounts are stated that way. |
reporting_year |
integer | Year the ledger's activity belongs to, 1990 to 2100. It is the fallback factor year for lines that state none. Set it only when known. |
input_description |
string | Two to three sentences on the company's sector and the file. |
measure_pairs |
array | Which column holds a measure's number and which its unit or currency. An empty array means no pair applies; omitting it lets the server nominate pairs. |
supplier_column |
string | Header of the supplier or vendor column, from suggested.file_context. Lines from one supplier are kept together. |
family_column |
string | Header of the product-family or category column, from suggested.file_context. Used to keep a family's lines together when no supplier column is named. |
domain |
string | From create_lexicon. |
lexicon |
array | From create_lexicon. |
Output.
| field | type | meaning |
|---|---|---|
job_id |
string | The job to poll. |
status |
string | Always queued. |
submitted_at |
string | UTC submission time. |
warnings |
array of string | Notes on how the job was queued, for example that it runs without a currency. |
message |
string | What to do next. |
check_emission_factor_mapping_progress#
Reports how far a job has got. Read-only. Wait at least retry_after_seconds between calls.
Inputs. job_id (string, required).
Output.
| field | type | meaning |
|---|---|---|
job_id |
string | Echoed. |
status |
string | queued, running, succeeded or failed. |
stage |
string or null | While running: parsing, then mapping, then auditing. |
processed_rows |
integer | Rows done. |
total_rows |
integer | Rows in the file. |
percent |
number | 100 × processed ÷ total. |
queue_position |
integer or null | Place in the queue while queued, counted from 0. |
started_at |
string or null | UTC start. |
finished_at |
string or null | UTC end. |
last_progress_at |
string or null | Time of the last progress report. |
elapsed_running_seconds |
number or null | Seconds since start. |
seconds_since_last_progress |
number or null | Seconds since the last progress report. |
retry_after_seconds |
number | 15 while the job runs, 0 once it has finished. |
error_message |
string or null | Why a job failed. |
Note. During
auditing,percentis 100 while the file-level check still runs. That is not a stuck job. In any other stage, a largeseconds_since_last_progressis.
get_emission_factor_mapping_result#
Returns the download link and a summary report for a succeeded job. It errors on any other status. In a host that renders widgets, an emissions dashboard appears from the same data.
Inputs. job_id (string, required).
Output.
| field | type | meaning |
|---|---|---|
job_id |
string | Echoed. |
status |
string | Always succeeded. |
row_count |
integer | Rows in the result. |
download_url |
string | Link to the result file. |
elapsed_seconds |
number or null | Processing time. |
report_stats |
object or null | Summary, below. Null only when the file could not be read. |
It also returns the envelope.
report_stats carries total_rows, matched_rows, unmatched_rows, match_rate_pct, by_library (rows per library), emissions_by_library (kg CO2e per library), total_emissions_kgco2e, emissions_column, rows_with_emissions, rows_missing_emissions, skip_reason_counts, no_match_reason_counts, excluded_used_good_rows, aggregate_rows_skipped (total rows skipped so the purchases they sum are not counted twice; they are inside total_rows), confidence_bucket_counts, top_emitters (the ten largest rows) and emissions_by_ef (the 15 largest factors).
read_emission_factor_mapping_result_file#
Returns result rows as objects, so the client can filter, count and sum them. The row shape depends on the factors the job matched on and on your key.
A partner key, or a job that did not match on open_ef factors, gets the uploaded columns plus a fixed set of 106 pipeline columns. A column the file lacks is left out.
- Nine describe the line:
ef_library(the route that ran, not a library),confidence,no_match_reason,reformulation_item_nature,review_reason,basis_fallback,agent_reasoning,detected_quantitiesandquantity_conversion_detail. - Eighty are sixteen columns repeated for each of the five ranked candidates, named
final_top_1_tofinal_top_5_:ef_fingerprint,ef_keyword,ef_attribute,ef_unit,ef_data_source(the library the factor came from),ef_value_kgco2e_per_native_unit,quantity_in_ef_native_unit,magnitude_applied,total_emissions_kgco2e,total_emissions_skip_reason,score,freight_distance_basis,freight_reconciled_tonne_km,dataset_name,dataset_versionandvalue_withheld_reason(licence or pending; a withheld value is null and left out of every sum, never 0). Rank 1 is the match the job chose; ranks 2 to 5 are the alternatives it weighed, which is what lets you re-rank a line without running the job again. - Two explain the library choice:
final_top_1_library_choice_reason(why rank 1 beat a candidate from another library, region or year) andfinal_top_1_value_outlier(true when rank 1's value sits far from its activity group's centre). - Fifteen identify the product and place the line in a GHG scope:
product_registry_supplier,product_registry_product,product_registry_product_id,classifier_variant,classifier_offering_kind, and tenghg_*columns, such asghg_scope_slotsandghg_scope_state.
When an open_ef job is read with a partner key, each row also carries final_top_1_open_ef_slug, final_top_1_open_ef_source_key, final_top_1_open_ef_release, final_top_1_open_ef_region_code and final_top_1_open_ef_boundary_preset.
An open_ef job read with any other key, OAuth sign-in included, returns the API's /v2/ row instead: row_index, the uploaded columns, flat final_top_1_ columns on the factor API's names (final_top_1_slug, final_top_1_factor_api_url, final_top_1_library, final_top_1_unit_code, final_top_1_value_co2e_normalized, final_top_1_quantity_in_factor_unit and more), the nine line columns above, and candidates, a list of up to five ranked factor objects.
Inputs.
| input | type | required | default | meaning |
|---|---|---|---|---|
job_id |
string | yes | A succeeded job. | |
row_limit |
integer | no | 500 | Rows to return, 1 to 2000. |
Output. job_id, filename, row_count (before truncation), columns, rows (null is empty or no match), truncated and truncation_limit, as in read_procurement_input_file.
list_emission_factor_mapping_jobs#
Lists your recent jobs, newest first. Use it to recover a lost job_id.
Inputs.
| input | type | required | default | meaning |
|---|---|---|---|---|
limit |
integer | no | 20 | Jobs to return, 1 to 200. |
status |
string or null | no | Only jobs in this status: queued, running, succeeded or failed. |
Output. jobs, an array with job_id, status, created_at, started_at, finished_at, processed_rows, total_rows, filename and error_message per job. filename is the name of the uploaded file.
Widget-only tools#
These three are declared for the in-chat widgets. A host that honours the declaration keeps them away from the model, and a model should not call them.
upload_inline_file#
The upload widget sends a picked file's bytes through the host with this tool, so the bytes never enter the conversation.
| input | type | required | meaning |
|---|---|---|---|
upload_id |
string | yes | From prepare_upload. |
upload_token |
string | yes | From prepare_upload. |
filename |
string | yes | The picked file's name, no path separators. |
data_base64 |
string | yes | The bytes, standard base64. |
content_type |
string or null | no | MIME type, echoed only. |
Returns upload_id, filename, content_type and bytes_stored.
get_upload_status#
The widget calls this when a conversation reopens, to redraw a finished upload. Read-only.
Inputs: upload_id and upload_token, both required. Returns upload_id, is_resolved, and once the bytes have landed filename, content_type and bytes_stored (all null before).
download_emission_factor_mapping_result_file#
The dashboard's download button fetches the result file with this tool. A model shares download_url from get_emission_factor_mapping_result instead.
Input: job_id, required. Returns job_id, filename, mime_type and base64_content.
Related#
- Connect over MCP
- Call the API
- API reference: the generated contract for the same
/v2/endpoints the tools call, with a console that sends a real request to the sandbox or production from your browser, using your own key.