# National Tunnel Inventory Risk Monitor — FHWA/NTAD (`malonestar/national-tunnel-inventory-risk-monitor`) Actor

Tunnel inventory & tunnel risk screening for every US road tunnel in the FHWA National Tunnel Inventory (NTAD). One row per tunnel with a composite 0-100 risk score plus hazmat, load-posting, low-clearance and overdue-inspection flags. For freight/hazmat routing, insurers and asset managers.

- **URL**: https://apify.com/malonestar/national-tunnel-inventory-risk-monitor.md
- **Developed by:** [Kyle Maloney](https://apify.com/malonestar) (community)
- **Categories:** Developer tools, Agents, Real estate
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $4.40 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## National Tunnel Inventory Risk Monitor — FHWA / NTAD

Screen **every US road tunnel** in the **FHWA National Tunnel Inventory (NTI)** — the
official federal register of the 580 highway tunnels on public roads — and get back
**one clean row per tunnel** with a composite **0-100 tunnel risk score** and the
routing-critical facts freight, hazmat, insurance and asset teams actually need:
**hazmat restriction, posted height restriction, load posting, and inspection status.**

Data comes straight from the USDOT/BTS **National Transportation Atlas Database (NTAD)**
ArcGIS service — keyless, authoritative, refreshed by FHWA. No login, no scraping.

### Who it's for

- **Freight & hazmat routing / TMS teams** — pre-screen tunnels on a corridor for hazmat
  bans, posted height restrictions, low vertical clearance and posted load limits.
- **Insurers & reinsurers** — surface load-posted, closed or overdue-inspection tunnels
  in a book of infrastructure or transport risk.
- **Infrastructure asset managers, DOT contractors & engineers** — a ready-scored
  inventory by state, ranked worst-first, to triage inspection and rehab backlogs.
- **Journalists & analysts** — a defensible, sourced view of aging or restricted tunnels.

### What it does

1. Runs a **live drift probe** against the NTAD layer *before* anything billable: the
   layer resolves, all 69 columns it reads still exist, the national count sits in band,
   the layer still carries exactly one inventory year, load-posting codes stay inside
   their closed A/P/R/K vocabulary, a positive canary returns tunnels, a negative control
   returns exactly zero, portal coordinates are decimal degrees, and the two restriction
   columns the product rests on are still populated. If any of that fails the run **fails
   loudly and bills nothing.**
2. Pulls tunnels for the states you choose (or the whole national inventory), paging with
   the service's own `maxRecordCount` and cross-checking the row count against the
   service's own `returnCountOnly`.
3. Normalizes every record: FIPS state code -> postal + full name, epoch-ms inspection
   dates -> `YYYY-MM-DD`, coded restriction fields -> booleans, all-9s sentinels -> null.
4. Computes a composite **tunnel\_risk\_score (0-100)** and boolean risk flags.
5. Sorts worst-first, assigns a `risk_rank`, caps to `maxResults`, and only then pushes.

### Example input

```json
{
  "states": ["CA"],
  "minRiskScore": 0,
  "maxResults": 2000
}
```

- `states` — postal codes (`"CA"`), full names (`"California"`), or 2-digit FIPS
  (`"06"`). Leave empty to scan the whole national inventory (580 tunnels).
- `minRiskScore` — optional 0-100 floor; only return tunnels at or above it.
- `maxResults` — safety cap; results are taken from the highest-risk end after ranking.

### Three things this actor is careful about

**1. Over-height routing needs the owner's flag, not just a measurement.**
NTI item **L.10** is the owner-reported *posted height restriction* and it is set on
**349 of 580 tunnels**. A measurement-only test at 14 ft misses **182 of them** — the Ted
Williams and Eisenhower tunnels among them. `over_height_routing_risk` is a gated verdict
that reads **both** the validated clearance and L.10, and is `false` only when both were
checked and both are negative.

**2. A published number is not automatically a fact.**
The NTI lists the Baltimore Harbor Tunnel at a minimum vertical clearance of **135 ft**;
MDTA posts it at **13'6"**. The published value is preserved verbatim in
`height_restriction`, but `min_vert_clearance_ft_validated` is `null`,
`clearance_data_suspect` is `true`, and no verdict is computed from it.

**3. The NTI is an ANNUAL snapshot, so "overdue" needs an anchor.**
The layer carries a single inventory year and its newest reported inspection is
2025-02-20. Comparing that to *today* measures publication lag, not compliance — it puts
**78.3% of the national inventory** in "overdue" and climbs toward 100% on its own.
`overdue_inspection` is therefore anchored to `data_last_updated` (**49.7%** of the
inventory), with the run-time view kept beside it as `overdue_inspection_as_of_today`.

### Output fields (one row per tunnel) — 96 fields

| Field | Type | What it is |
|---|---|---|
| `tunnel_number` | string | FHWA NTI tunnel number (item I.1) - the tunnel's unique ID within its state. |
| `tunnel_name` | string | Common tunnel name (item I.2). |
| `state` | string | Full US state name, derived from the 2-digit FIPS state code (item I.3). |
| `state_abbr` | string | US state postal code, derived from the FIPS state code. |
| `state_fips` | string | 2-digit FIPS state code exactly as stored in the NTI (item I.3). |
| `county_code` | string | 3-digit county FIPS code (item I.4). |
| `facility_carried` | string | Road or facility carried through the tunnel (item I.10). |
| `latitude` | number | Decimal-degrees latitude of the tunnel portal (item I.13). |
| `longitude` | number | Decimal-degrees longitude of the tunnel portal (item I.14). |
| `year_built` | integer | Year the tunnel was built (item A.1). |
| `year_rehabilitated` | integer | Year of the last major rehabilitation (item A.2); null when never rehabilitated. |
| `tunnel_length_ft` | integer | Overall tunnel length in feet (item G.1). |
| `adt` | integer | Average daily traffic through the tunnel (item A.4). Reported for context only - it is NOT an input to tunnel\_risk\_score. |
| `adtt` | integer | Average daily truck traffic (item A.5). |
| `adt_year` | integer | Year the average daily traffic count was taken (item A.6). |
| `owner` | string | Owning agency decoded from the NTI owner code (item C.1). |
| `last_inspection_date` | string | Date of the last actual routine inspection (item D.2), ISO YYYY-MM-DD; null when none on record. |
| `inspection_interval_months` | integer | Designated routine inspection interval in months (item D.3), typically 24. |
| `months_since_inspection` | integer | Whole months elapsed between the last reported routine inspection and this run. Because the NTI is an annual snapshot this includes publication lag; months\_since\_inspection\_at\_vintage removes it. |
| `inventory_load_rating_factor` | number | Inventory-level load rating factor (item L.2). Below 1.0 indicates reduced capacity; 0 means not rated. Interpret alongside load\_rating\_method\_code. |
| `operating_load_rating_factor` | number | Operating-level load rating factor (item L.3) - the structural-adequacy proxy in the risk score. Interpret alongside load\_rating\_method\_code: 0 means not rated, and 65% of the inventory is method N with a 0 here. |
| `posting_load_gross_tons` | integer | Posted gross vehicle load limit in tons (item L.5) when the tunnel is load-posted. Null when not posted - NTI writes 0 for no posting and 99 as its all-9s "no limit" sentinel, and neither is emitted as a tonnage. |
| `worst_condition_rating` | string | Editorial condition label derived from load-rating factor and load-posting status (the NTI has no FHWA 0-9 component rating): Closed, Below Legal Load, Load Posted, Adequate, or Unknown. |
| `load_posting_status` | string | Decoded tunnel load posting status (item L.4): Open, no restriction / Posted for load / Posted (other than load) / Closed. |
| `load_posting_code` | string | Raw NTI load posting status letter (item L.4): A, P, R, or K. |
| `hazmat_restricted` | boolean | True when a hazardous-material routing restriction is in effect (item L.11). Null when the column was not returned - null means not checked, false means checked and negative. |
| `height_restriction` | number | Minimum vertical clearance over the tunnel roadway in FEET exactly as published (item G.2), including values that are not physically plausible. Use min\_vert\_clearance\_ft\_validated for a measurement you can act on, clearance\_data\_suspect to see which rows were rejected, and height\_restriction\_posted for the owner-reported restriction flag. |
| `overdue_inspection` | boolean | True when the last reported routine inspection was already older than the designated interval AS OF THE DATA VINTAGE (see data\_last\_updated and overdue\_basis). The NTI is an annual snapshot, so comparing it to today measures publication lag rather than compliance - overdue\_inspection\_as\_of\_today carries that run-time view separately. |
| `load_posted` | boolean | True when the tunnel is legally posted for a reduced load (status P or R). |
| `low_clearance` | boolean | True when the VALIDATED minimum vertical clearance is below 14 ft (over-height hazard vs the ~13ft 6in statutory commercial height). Null - never false - when the clearance is missing or implausible. See over\_height\_routing\_risk for the gated verdict that also reads the owner-reported item L.10 flag. |
| `tunnel_risk_score` | integer | Composite EDITORIAL screening score 0-100: condition proxy (operating load rating factor) x load-posting status x inspection staleness measured at the data vintage x restriction multiplier (hazmat, over-height, other). The NTI publishes no FHWA 0-9 condition rating, so this is a screening blend and not an official rating. ADT is not an input. |
| `risk_flags` | array | Machine-readable flags: overdue\_inspection, closed, load\_posted, below\_legal\_load, hazmat\_restricted, low\_clearance, height\_restriction\_posted, other\_restrictions. |
| `risk_rank` | integer | 1-based rank within this run's results, sorted by risk score descending (1 = highest risk). |
| `source_url` | string | NTAD ArcGIS query URL returning this tunnel's full raw NTI record. |
| `checked_at` | string | ISO 8601 timestamp of when this run read the NTI. |
| `objectid` | integer | Stable feature id within the NTAD National Tunnel Inventory layer. |
| `data_vintage_year` | integer | FHWA inventory year carried on the record itself. The layer holds exactly one year; two would double-count every tunnel and the run fails. |
| `data_last_updated` | string | ISO date the NTAD layer itself was last edited - the vintage every overdue verdict is anchored to. |
| `county_fips` | string | State FIPS + county FIPS concatenated, ready to join to Census county data. |
| `next_inspection_target_date` | string | Target date FHWA published for the reported routine inspection cycle (item D.1), ISO YYYY-MM-DD. This is the target for the inspection already reported, NOT a forward-looking next-due date. |
| `months_since_inspection_at_vintage` | integer | Whole months between the last reported routine inspection and the data vintage, with annual publication lag removed. |
| `overdue_inspection_as_of_today` | boolean | True when the last reported inspection is older than the interval measured against this run time. Grows toward true for the whole inventory as the annual snapshot ages - use overdue\_inspection for the compliance read. |
| `overdue_basis` | string | Which clock overdue\_inspection used: data\_vintage (normal) or run\_time (the layer stopped publishing an edit date). |
| `height_restriction_posted` | boolean | Owner-reported posted height restriction (item L.10) - the authoritative over-height signal, populated on 349 of 580 tunnels. Null when the column was not returned. |
| `over_height_routing_risk` | boolean | Gated over-height verdict: true when EITHER the validated clearance is below 14 ft OR the owner posts a height restriction; false only when both were checked and both are negative; null when neither could be checked. |
| `min_vert_clearance_ft_validated` | number | Item G.2 clearance in feet, or null when the published value is not a physically plausible tunnel clearance. |
| `clearance_data_suspect` | boolean | True when the published G.2 clearance is impossible (<=0 ft or >40 ft) and was therefore not used for any verdict. |
| `other_restrictions` | boolean | Item L.12 other-restrictions flag. Null when the column was not returned. |
| `closed_to_traffic` | boolean | True when the load-posting status (item L.4) is K, Closed. Null when the status was not returned. |
| `below_legal_load` | boolean | True when the operating load rating factor is above 0 and below 1.0. Null when no rating was returned. |
| `load_rating_method_code` | string | Raw item L.1 load-rating method code as published by FHWA. Essential context for the two rating-factor fields: 65% of the inventory is method N with a 0 rating. |
| `total_lanes` | integer | Total number of lanes through the tunnel (item A.3). |
| `number_of_bores` | integer | Number of tunnel bores (item S.1). |
| `roadway_width_ft` | number | Curb-to-curb roadway width in feet (item G.3). |
| `left_sidewalk_width_ft` | number | Left sidewalk width in feet (item G.4). |
| `right_sidewalk_width_ft` | number | Right sidewalk width in feet (item G.5). |
| `detour_length_miles` | integer | Detour length in miles (item A.7); null when FHWA writes its 999 sentinel. |
| `service_in_tunnel_code` | integer | Raw item A.8 code for what the tunnel carries, as published by FHWA. |
| `direction_of_traffic_code` | integer | Raw item C.3 traffic-direction code as published by FHWA. |
| `toll_code` | integer | Raw item C.4 toll code as published by FHWA. |
| `nhs_route` | boolean | True when the tunnel carries a National Highway System route (item C.5). |
| `strahnet_route` | boolean | True when the tunnel carries a Strategic Highway Network route (item C.6) - a defense-mobility corridor. |
| `functional_classification_code` | integer | Raw item C.7 functional-classification code as published by FHWA. |
| `urban_code` | integer | Census urban area code (item C.8); null when FHWA writes its 99998/99999 sentinels. |
| `route_number` | string | Route number carried through the tunnel (item I.7). |
| `route_type_code` | string | Raw item I.9 route-type code as published by FHWA. |
| `route_direction_code` | string | Raw item I.8 route-direction code as published by FHWA. |
| `highway_district` | string | State highway district (item I.6). |
| `place_code` | string | Census place code (item I.5). |
| `lrs_route_id` | string | Linear referencing system route identifier (item I.11), for joining to state roadway networks. |
| `lrs_mile_point` | number | Milepoint of the tunnel along the LRS route (item I.12). |
| `federally_owned` | boolean | True when a federal agency owns or reports the tunnel (federal\_agency = Y). |
| `operator` | string | Operating agency decoded from the NTI operator code (item C.2) - often different from the owner. |
| `under_navigable_waterway` | boolean | True when the tunnel passes beneath a navigable waterway (item N.1). |
| `navigable_waterway_clearance_ft` | number | Vertical clearance over the tunnel to the navigable waterway (item N.2), feet. |
| `portal_island_protection` | boolean | True when the tunnel or its portal island has protection works (item N.3). |
| `tunnel_shape_code` | integer | Raw item S.2 tunnel-shape code as published by FHWA. |
| `portal_shape_code` | integer | Raw item S.3 portal-shape code as published by FHWA. |
| `ground_conditions_code` | integer | Raw item S.4 ground-conditions code as published by FHWA. |
| `complex_tunnel` | boolean | True when FHWA classifies the tunnel as complex (item S.5), which drives heightened inspection requirements. |
| `in_depth_inspection_required` | boolean | Item D.4 in-depth inspection requirement flag. |
| `damage_inspection_required` | boolean | Item D.5 damage inspection requirement flag. |
| `special_inspection_required` | boolean | Item D.6 special inspection requirement flag. |
| `border_state` | string | Partner state for a tunnel on a state border (item I.15), as published (postal or FIPS). |
| `border_tunnel_number` | string | Partner state tunnel number for a border tunnel (item I.17). |
| `border_financial_responsibility_pct` | integer | Share of financial responsibility for a border tunnel (item I.16), percent. |
| `border_inspection_responsibility` | string | Raw item I.18 code for which state inspects a border tunnel. |
| `submitted_by` | string | Agency code that submitted the record to FHWA. |
| `nti_source_status` | string | Outcome of the NTI fetch for this row: ok. A run where the source did not answer fails and emits nothing. |
| `nti_layer_name` | string | Name of the NTAD FeatureServer layer this run read. |
| `nti_layer_feature_count` | integer | Total tunnels in the layer at run time, from the service's own returnCountOnly. |
| `matching_tunnel_count` | integer | Tunnels matching your filter upstream, from the service's own returnCountOnly - the exact truncation guard. |
| `result_truncated` | boolean | True when maxResults capped the run below matching\_tunnel\_count. |
| `tunnels_scanned` | integer | How many tunnel records this run actually retrieved before filtering. |
| `where_clause` | string | The ArcGIS where clause this run sent, so the answer is reproducible. |
| `drift_checks_passed` | boolean | True when every live drift assertion passed before any row was emitted. A run cannot bill a row with this false. |

### How the tunnel risk score works (editorial model)

The NTI does **not** publish an FHWA 0-9 component condition rating like the National
Bridge Inventory does, so `tunnel_risk_score` is an **editorial screening blend** — a
triage aid, **not an official FHWA rating**. It multiplies four factors and normalizes so
the worst realistic combination scores 100:

| Factor | Signal | Source item |
|--------|--------|-------------|
| Condition proxy | operating load-rating factor (< 1.0 = below legal load) | L.3 |
| Load posting | Open / Posted-for-load / Posted-other / Closed | L.4 |
| Inspection staleness | months since inspection **at the data vintage** vs interval | D.2 / D.3 |
| Restrictions | hazmat ban, over-height routing risk, other restrictions | L.10-L.12, G.2 |

`adt` is **not** an input to the score — it is reported for context only.
`worst_condition_rating` is a matching human label (Closed / Below Legal Load / Load
Posted / Adequate / Unknown). Read the two load-rating factors alongside
`load_rating_method_code`: 65% of the inventory is method `N` with a `0` rating, which
means *not rated*, not *zero capacity*.

### What "null" means here

`null` means **not checked**. `false` means **checked, and the answer is negative.**
Every restriction flag follows that contract, so an upstream column that stops publishing
produces `null` rather than a confident clear. If the source cannot be reached at all, or
a page of the query fails part-way, the run **fails** rather than emitting an arbitrary
partial inventory ranked as though it were complete — nothing is emitted and nothing is
billed. Every row also carries `nti_source_status`, `matching_tunnel_count`,
`result_truncated`, `tunnels_scanned`, `where_clause` and `drift_checks_passed` so you
can see exactly what the answer rests on.

### Use as an MCP tool

This actor is a clean, chainable tool for AI agents (Claude, Cursor, etc.) via
`mcp.apify.com`. Every input and output field is described in the schema, so an agent can
call it directly — e.g. "list the hazmat-restricted or over-height tunnels in Colorado and
Utah" — and get structured, ranked JSON back. Billing is unchanged when it is called as a
tool, and a run that cannot answer fails without billing.

### Pricing

Pay-per-result: one billable result per tunnel returned, with graduated volume discounts.
A run that fails its drift check, or that could only retrieve a partial inventory, emits
nothing and bills nothing.

### FAQ

**Where does the data come from?** The FHWA National Tunnel Inventory, published in the
USDOT/BTS National Transportation Atlas Database (NTAD) as a public ArcGIS FeatureServer.
No API key required.

**How many tunnels are there?** 580 highway tunnels on US public roads nationwide
(measured live 2026-08-10).

**Is the risk score an official FHWA rating?** No. It is an editorial screening blend of
FHWA-published fields meant for triage. Always confirm against the primary record via
`source_url`.

**Why is `overdue_inspection` different from `overdue_inspection_as_of_today`?** The NTI
is published annually. The first answers "was this tunnel already past its interval when
FHWA published?", the second "is it past its interval right now?" — which for an aging
snapshot is mostly a statement about the publication schedule.

**Does it cover rail or transit tunnels?** No — the NTI covers highway/road tunnels on
public roads and publicly accessible federal-land tunnels.

**How is it billed?** Pay-per-result: one billable result per tunnel returned. Empty
results cost only the tiny actor start.

### Related actors

- **FHWA NBI Bridge Risk Monitor** — the same treatment for the 620k-structure National
  Bridge Inventory, including FHWA's official 0-9 condition ratings and scour-critical
  screening.

### Source

FHWA National Tunnel Inventory (NTI) via NTAD:
`https://services.arcgis.com/xOi1kZaI0eWDREZv/arcgis/rest/services/NTAD_National_Tunnel_Inventory/FeatureServer/0`

Each field is a screening aid, not a determination. Confirm against the primary FHWA
record before acting on any routing, insurance or engineering decision.

# Actor input Schema

## `states` (type: `array`):

US states to scan for tunnels. Accepts postal codes ('CA'), full names ('California'), or 2-digit FIPS codes ('06'). Leave empty to scan the entire national tunnel inventory (~580 tunnels, bounded by Max results).

## `minRiskScore` (type: `integer`):

Only output tunnels whose composite tunnel\_risk\_score (0-100) is at or above this value. Applied after scoring. Leave empty to return all tunnels in the selected states.

## `maxResults` (type: `integer`):

Maximum number of tunnels to return, taken from the highest-risk end after ranking. A safety bound for cost control — each returned tunnel is one billable result.

## Actor input object example

```json
{
  "states": [
    "CA"
  ],
  "maxResults": 2000
}
```

# Actor output Schema

## `results` (type: `string`):

The default dataset of ranked, scored tunnel records.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "states": [
        "CA"
    ],
    "maxResults": 2000
};

// Run the Actor and wait for it to finish
const run = await client.actor("malonestar/national-tunnel-inventory-risk-monitor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "states": ["CA"],
    "maxResults": 2000,
}

# Run the Actor and wait for it to finish
run = client.actor("malonestar/national-tunnel-inventory-risk-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "states": [
    "CA"
  ],
  "maxResults": 2000
}' |
apify call malonestar/national-tunnel-inventory-risk-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,malonestar/national-tunnel-inventory-risk-monitor"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/rtCNrcSMtJtqhz26W/builds/rgZ2nVqLPlfOSkCif/openapi.json
