# qlim8 MCP Tools Reference

Full reference for all **31 tools**, **3 resources**, and **3 prompts** exposed by the qlim8
MCP server. For setup and connection examples see [mcp-quickstart.md](./mcp-quickstart.md).

This document is generated to match the server's single source of truth
(`server/mcp/lib/catalog.ts`). The same data is served, unauthenticated, at
`GET https://app.qlim8.com/api/mcp/schema`.

All tool names, descriptions, and parameter names are in English and optimised for LLM
consumption. All dates are ISO 8601 UTC. All CO2e values are in kilograms (kg) unless noted.

---

## Conventions

These apply to every list-returning tool:

- **Pagination.** List tools return `{ items: [...], next_cursor: string|null }`. A non-null
  `next_cursor` means more rows exist: pass it back verbatim as the `cursor` argument to fetch
  the next page. Cursors are opaque — never construct, parse, or modify them.
- **Dates.** Date filters (`from`/`to`) are ISO 8601 datetimes and are **inclusive on both
  ends**, compared against each record's transaction date.
- **Scopes.** Each tool requires the scope shown. A `403 auth.scope_required` result means the
  key lacks it — mint a key with the needed scope. Enterprise-tier tools also require the named
  plan feature.
- **Errors.** Execution failures return a normal result with `isError: true` and a JSON body
  `{ code, title, detail }`. Read `code` to branch (e.g. `resource.not_found`,
  `auth.scope_required`, `request.validation_failed`).

### Annotations

Every tool carries MCP behavioural hints:

| Hint | Meaning |
|---|---|
| `readOnlyHint` | Tool does not mutate tenant state — safe to auto-run. |
| `destructiveHint` | Only meaningful when `readOnlyHint=false`; `false` everywhere (writes are additive). |
| `idempotentHint` | Repeating with the same args has no additional effect. |
| `openWorldHint` | `false` everywhere — tools touch only this tenant's data. |

Read-only tools draw from the read rate-limit bucket (600/min); the rest draw from the write
bucket (60/min). Sandbox keys are 10× stricter.

---

## Layer 1 — Core emissions & operations

### `get_emissions_summary`

> Returns total CO2e (market-based, in kg) aggregated by GHG scope for this tenant. Use to answer questions about total emissions, scope 1/2/3 breakdown, or year-over-year comparisons. Pass `group_by:"month"` for a calendar-month time series instead. For category breakdowns use `get_emissions_by_category` or `get_emissions_by_scope3_category`.

**Scope:** `emissions:read` · **Annotations:** `readOnlyHint`

**Input example**
```json
{ "from": "2024-01-01T00:00:00Z", "to": "2024-12-31T23:59:59Z" }
```
Accepts `from`, `to`, and optional `group_by` (only value: `"month"`).

**Returns** — totals by scope (default):
```json
{
  "total_co2e_kg": 128400.5,
  "by_scope": { "1": 21000, "2": 47400.5, "3": 60000 },
  "entry_count": 842
}
```

**Returns** — with `group_by:"month"`, a calendar-month series keyed `YYYY-MM` by
transaction date:
```json
{
  "total_co2e_kg": 128400.5,
  "by_month": { "2024-01": 9800, "2024-02": 11200.5 },
  "entry_count": 842
}
```

---

### `get_emissions_by_scope3_category`

> Returns this tenant's Scope 3 emissions broken down by the 15 standard GHG Protocol categories (1 Purchased goods and services .. 15 Investments). Use for CSRD/VSME-style Scope 3 category reporting. Amounts that can't be matched to one of the 15 categories are returned separately as unclassified, not silently dropped.

**Scope:** `emissions:read` · **Annotations:** `readOnlyHint`

**Input example**
```json
{ "from": "2024-01-01T00:00:00Z", "to": "2024-12-31T23:59:59Z" }
```

**Returns**
```json
{
  "total_co2e_kg": 60000,
  "by_category": {
    "1": { "name": "Purchased goods and services", "co2e_kg": 42000, "entry_count": 310 },
    "6": { "name": "Business travel", "co2e_kg": 8000, "entry_count": 45 }
  },
  "unclassified_co2e_kg": 0,
  "unclassified_entry_count": 0,
  "entry_count": 355
}
```

Categorisation is keyword-matched against the same calculation-category field the VSME report
generator uses, so totals here match the report's Environmental Disclosures D30–D44 breakdown.

---

### `get_emissions_by_category`

> Returns emissions broken down by the internal calculation category (the vocabulary from list_emission_categories / the factor used, e.g. 'Electricity', 'Natural gas', 'Business travel - flights'), sorted by CO2e descending. Use to answer 'what are my biggest emission sources' style questions. Optionally filter to one GHG scope first.

**Scope:** `emissions:read` · **Annotations:** `readOnlyHint`

**Input example**
```json
{ "from": "2024-01-01T00:00:00Z", "to": "2024-12-31T23:59:59Z", "scope": "1" }
```
Accepts `from`, `to`, and optional `scope` (`"1"`/`"2"`/`"3"`).

**Returns**
```json
{
  "total_co2e_kg": 21000,
  "by_category": { "Natural gas": 15000, "Diesel": 6000 },
  "entry_count": 210
}
```

---

### `list_emissions`

> Returns a cursor-paginated list of emission entries (each linked to an activity/invoice). Use for detailed audits or exporting raw emission data. Page with next_cursor.

**Scope:** `emissions:read` · **Annotations:** `readOnlyHint`

**Input example**
```json
{ "scope": "1", "limit": 50 }
```
Accepts `from`, `to`, `scope` (`"1"`/`"2"`/`"3"`), `cursor`, `limit` (1–200).

**Returns** `{ "items": [ { emission entry } ], "next_cursor": "…"|null }`.

---

### `get_emission_lineage`

> Returns the full data lineage for one emission entry: source activity/invoice, the emission factor used, category-change history, and cryptographic audit hashes for independent verification. Use for auditor self-service and traceability.

**Scope:** `emissions:read` · **Annotations:** `readOnlyHint`

**Input example**
```json
{ "id": "8b1f0c2e-1d34-4a77-9c0e-3a2b1c4d5e6f" }
```

**Returns** the emission entry, its activity split + source activity, the emission factor, and
a `history` block with category changes and the audit-event hash chain.

---

### `list_activities`

> Returns a cursor-paginated list of activities (invoices and transactions) for this tenant. Each activity is a source document that may produce one or more emission entries after categorization.

**Scope:** `activities:read` · **Annotations:** `readOnlyHint`

**Input example**
```json
{ "from": "2024-01-01T00:00:00Z", "limit": 25 }
```

**Returns** `{ "items": [ { activity } ], "next_cursor": … }`.

---

### `list_reports`

> Returns all previously generated compliance reports for this tenant (VSME, CSRD, etc.) with file size and creation date. Use get_report_status for in-progress jobs or generate_report to start a new render.

**Scope:** `reports:read` · **Annotations:** `readOnlyHint`

**Input:** none.

**Returns** an array of generated reports (`report_year`, `standard_type`, `filename`,
`file_size_bytes`, `created_at`).

---

### `get_report_status`

> Returns the status of a report render job (queued, running, completed, failed). Poll after generate_report until status is 'completed'.

**Scope:** `reports:read` · **Annotations:** `readOnlyHint`

**Input example**
```json
{ "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479" }
```

**Returns** the job with `status` (`queued` → `running` → `completed` | `failed`),
timestamps, and `generated_report_id` once complete.

---

### `generate_report`

> Triggers an async report render job and returns a job id. Poll get_report_status until completed. Idempotent: the same year + standard_type + format returns the existing job if one is already queued or running.

**Scope:** `reports:generate` · **Annotations:** `idempotentHint` (write, non-destructive)

**Input example**
```json
{ "report_year": 2024, "standard_type": "vsme_basic", "format": "pdf" }
```
`standard_type`: `vsme_basic`, `vsme_bp`, `vsme_comprehensive`, `csrd`. `format`: `pdf`
(default) or `xlsx`.

> Long-running. Returns a 202-style job — do not block; poll `get_report_status`.

---

### `list_data_sources`

> Returns the tenant's accounting-system connectors (e-conomic, Dinero, …) with sync status, pending invoice counts, and last-sync timestamps. Use to diagnose 'why didn't invoices sync?' or which connector is paused. Read-only — connect/sync actions are not exposed.

**Scope:** `data_sources:read` · **Annotations:** `readOnlyHint`

**Input:** none.

---

### `get_quota_status`

> Returns the tenant's current invoice-ingestion quota: limit, used, available, period dates and tier. Use to decide whether to throttle a sync or warn about an approaching cap. Enterprise/sandbox tenants report 'unlimited'.

**Scope:** `quota:read` · **Annotations:** `readOnlyHint`

**Input:** none.

---

### `list_emission_categories`

> Returns the emission category taxonomy (Danish + English names, hierarchy level, parent, default scope, factor value). This is the vocabulary the system uses to classify activities — read it before reasoning about categories or emissions breakdowns.

**Scope:** `factors:read` · **Annotations:** `readOnlyHint`

**Input example**
```json
{ "level": 1 }
```

> Tip: the same taxonomy is available as the `qlim8://emission-categories` resource.

---

## Layer 2 — Value chain, targets, factors, scenarios

### `list_suppliers` _(Enterprise)_

> Returns all Scope 3 supplier connections for this tenant with disclosure status (active, pending, invited). Enterprise plan required. Use get_value_chain_coverage for an aggregated summary.

**Scope:** `suppliers:read` · **Tier:** Enterprise · **Annotations:** `readOnlyHint`

**Input example**
```json
{ "year": 2024 }
```

---

### `get_value_chain_coverage` _(Enterprise)_

> Returns the percentage of total supplier spend covered by active Scope 3 disclosures for a reporting year. Enterprise plan required. coverage_pct of 100 means all supplier trade is disclosed.

**Scope:** `suppliers:read` · **Tier:** Enterprise · **Annotations:** `readOnlyHint`

**Input example**
```json
{ "year": 2024 }
```

**Returns** `report_year`, `coverage_pct`, supplier counts, and covered/total trade amounts.

---

### `get_value_chain_exposure` _(Enterprise)_

> Returns suppliers sorted by trade amount descending — which suppliers represent the largest Scope 3 emission risk. Enterprise plan required. Use to prioritise disclosure outreach.

**Scope:** `suppliers:read` · **Tier:** Enterprise · **Annotations:** `readOnlyHint`

**Input example**
```json
{ "year": 2024 }
```

---

### `list_targets`

> Returns all CO2 reduction targets for this tenant (baseline year, target year, reduction percent). Use to assess climate-commitment progress or compare targets against get_emissions_summary.

**Scope:** `targets:read` · **Annotations:** `readOnlyHint`

**Input:** none.

---

### `create_target`

> Creates a new CO2 reduction target for this tenant and returns it with its assigned id. Requires targets:write scope.

**Scope:** `targets:write` · **Annotations:** write (non-idempotent, non-destructive)

**Input example**
```json
{ "name": "SBTi 2030", "baseline_year": 2019, "baseline_emissions": 1000, "target_year": 2030, "target_reduction_percent": 46.2, "scope": "1+2" }
```
`scope`: `"1"`, `"2"`, `"3"`, `"1+2"`, or `"all"`.

---

### `list_emission_factors`

> Returns the emission factor catalog used to convert activities into CO2e. Each factor maps category + region + year to a kg CO2e per unit value. Use to understand how calculations are derived.

**Scope:** `factors:read` · **Annotations:** `readOnlyHint`

**Input example**
```json
{ "category": "Electricity", "region": "DK" }
```
Also accepts `cursor`, `limit`.

**Returns** `{ "items": [ { factor } ], "next_cursor": … }`.

---

### `get_factor_citations`

> Returns how many of this tenant's emission entries used a specific factor, plus a sample of entry ids. Use for auditor self-service to verify which invoices contributed to a factor's footprint.

**Scope:** `factors:read` · **Annotations:** `readOnlyHint`

**Input example**
```json
{ "id": "1f2e3d4c-5b6a-7980-1234-567890abcdef" }
```

**Returns** the factor, a `citation_count`, and `sample_emission_entry_ids`.

---

### `list_scenarios` _(scenarioBuilder)_

> Returns the reduction-planning scenarios visible to this key (a scenario groups reduction initiatives = 'tiltag'). Tenant keys see real + pending-review scenarios; consultant keys also see their own drafts. Requires the scenarioBuilder plan feature.

**Scope:** `scenarios:read` · **Feature:** `scenarioBuilder` · **Annotations:** `readOnlyHint`

**Input:** none.

---

### `get_scenario` _(scenarioBuilder)_

> Returns one scenario plus its reduction initiatives (tiltag). 404 if it is not visible to this key. Requires the scenarioBuilder feature.

**Scope:** `scenarios:read` · **Feature:** `scenarioBuilder` · **Annotations:** `readOnlyHint`

**Input example**
```json
{ "id": "2b3c4d5e-6f70-4811-9a2b-3c4d5e6f7081" }
```

---

### `list_tiltag` _(scenarioBuilder)_

> Returns the reduction initiatives (tiltag) belonging to a scenario, including any cost annotations. Requires the scenarioBuilder feature.

**Scope:** `scenarios:read` · **Feature:** `scenarioBuilder` · **Annotations:** `readOnlyHint`

**Input example**
```json
{ "scenario_id": "2b3c4d5e-6f70-4811-9a2b-3c4d5e6f7081" }
```

---

### `create_scenario_draft` _(scenarioBuilder)_

> Creates a reduction scenario. From a consultant (third-party) key it is created as a DRAFT awaiting client review; from a tenant key it is created as 'real'. Requires scenarios:write + the scenarioBuilder feature.

**Scope:** `scenarios:write` · **Feature:** `scenarioBuilder` · **Annotations:** write

**Input example**
```json
{ "name": "2030 fleet electrification plan", "description": "Phased EV transition" }
```

---

### `add_tiltag` _(scenarioBuilder)_

> Adds a manual reduction initiative (tiltag) to a scenario with an optional cost annotation. Does NOT run the AI composition engine — it records a labelled initiative only. Requires scenarios:write + the scenarioBuilder feature.

**Scope:** `scenarios:write` · **Feature:** `scenarioBuilder` · **Annotations:** write

**Input example**
```json
{ "scenario_id": "2b3c4d5e-6f70-4811-9a2b-3c4d5e6f7081", "label": "Switch to green electricity", "annual_cost": 50000, "currency": "DKK" }
```

---

### `submit_scenario_for_review` _(scenarioBuilder)_

> Consultant (third-party) keys only: transitions a draft scenario to pending_review and notifies the client's admins. Requires scenarios:write + the scenarioBuilder feature.

**Scope:** `scenarios:write` · **Feature:** `scenarioBuilder` · **Annotations:** write

**Input example**
```json
{ "id": "2b3c4d5e-6f70-4811-9a2b-3c4d5e6f7081" }
```

---

### `list_pcf_records`

> Returns the tenant's approved product carbon footprint (PCF) records — supplier, product, value/unit, methodology and validity window. Retracted/superseded footprints are excluded. Use for Scope 3 product-level data.

**Scope:** `factors:read` · **Annotations:** `readOnlyHint`

**Input:** none.

---

### `list_departments`

> Returns the tenant's organisational units (name, code, active flag). Use to scope or roll up emissions by department/site.

**Scope:** `tenant:read` · **Annotations:** `readOnlyHint`

**Input:** none.

---

### `get_report_attestations`

> Returns the third-party consultant sign-offs (attestations) for a generated report — standards attested, consultant/client CVR, and signature date. Use to confirm a report was independently certified.

**Scope:** `reports:read` · **Annotations:** `readOnlyHint`

**Input example**
```json
{ "report_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479" }
```

---

## Layer 3 — Webhooks

**Available events** (the only values accepted in `events`): `supplier.invited`,
`supplier.connected`, `target.created`, `report.generation_started`,
`report.generation_completed`, `report.attested`, `usage.quota_threshold`,
`api_key.created`, `api_key.revoked`.

### `list_webhooks`

> Returns all webhook subscriptions for this tenant. Each receives HTTP POST callbacks for configured events (e.g. supplier.connected, report.generation_completed). Use get_webhook_deliveries to inspect attempts.

**Scope:** `webhooks:read` · **Annotations:** `readOnlyHint`

**Input:** none.

---

### `create_webhook`

> Creates a webhook subscription and returns it with a one-time signing_secret — store it securely, it is not shown again. Verify incoming payloads with HMAC-SHA256. Requires webhooks:manage scope. URL must be HTTPS in live.

**Scope:** `webhooks:manage` · **Annotations:** write

**Input example**
```json
{ "url": "https://example.com/hooks/qlim8", "events": ["report.generation_completed"], "environment": "live" }
```

> The `signing_secret` in the response is shown **once**. The endpoint is SSRF-validated:
> private/loopback hosts are rejected in live. See the
> [webhook signing guide](./guides/webhooks-signing.md) for the exact verification scheme
> (`X-Qlim8-Signature: t=<unix>,v1=<hex-hmac>`).

---

### `get_webhook_deliveries`

> Returns the 100 most recent delivery attempts for a webhook (status, HTTP response code, latency), newest first. Use to debug delivery failures.

**Scope:** `webhooks:read` · **Annotations:** `readOnlyHint`

**Input example**
```json
{ "webhook_id": "9c8b7a6d-5e4f-3210-fedc-ba9876543210" }
```

Delivery `status` values: `pending`, `delivered`, `failed`, `retrying`.

---

## Resources

Read-only reference context addressable by URI (no side effects). List with `resources/list`,
read with `resources/read`.

| URI | MIME type | Contents |
|---|---|---|
| `qlim8://emission-categories` | `application/json` | The category taxonomy used to classify activities: `id`, `name` (Danish), `name_en`, `parent_id`, `level`, `scope`, `factor_value`. |
| `qlim8://ghg-scopes` | `application/json` | GHG Protocol scope 1/2/3 definitions as qlim8 applies them. Market-based scope 2 is the default; values are in kg CO2e. |
| `qlim8://usage-guide` | `text/markdown` | Auth, scopes, pagination, date and error conventions for this server, plus tips for agents. |

---

## Prompts

Parameterised task templates that chain qlim8 tools. List with `prompts/list`, fetch with
`prompts/get`.

### `emissions_vs_target_analysis`
**Args:** `year` (e.g. `"2024"`).
Calls `get_emissions_summary` and `list_targets`, computes the linear allowed-emissions path
from baseline to target year, and produces a per-target on-track / behind verdict with the gap
in tonnes and %, plus prioritised actions.

### `year_over_year_review`
**Args:** `current_year`, `previous_year`.
Calls `get_emissions_summary` for each year, reports total and per-scope change (absolute kg
CO2e and %), and uses `list_emissions` + `list_emission_categories` to identify the largest
movers.

### `value_chain_briefing` _(Enterprise)_
**Args:** `year`.
Calls `get_value_chain_coverage` and `get_value_chain_exposure`, reports `coverage_pct` and the
top suppliers by trade amount, and recommends which suppliers to engage to raise coverage.

---

## Error reference

| `code` | Meaning | Fix |
|---|---|---|
| `auth.scope_required` | Key lacks the scope the tool needs | Mint a key with the scope shown for the tool; check `GET /api/v1/me`. |
| `subscription.feature_required` | Tool needs an Enterprise feature (`supplyChain`) or `scenarioBuilder` | Upgrade the plan / enable the feature. |
| `resource.not_found` | The id you passed doesn't exist or isn't visible to this key | Verify the id; list first. |
| `request.validation_failed` | Bad/missing argument (e.g. malformed UUID) | Read the `detail`/`issues` and correct the arguments. |

These arrive **in-band** (`isError: true` result with a JSON body), not as JSON-RPC errors.
Protocol-level failures (`-32001` auth/session/rate, `-32603` internal) use the JSON-RPC error
channel. See the [quickstart error model](./mcp-quickstart.md#error-model).
