# API Discovery for OpenAPI & MCP (`miacx/api-discovery`) Actor

Find API docs, OpenAPI specs and MCP links from public HTTPS URLs. Get source evidence and distinguish discovered links from checked JSON specs.

- **URL**: https://apify.com/miacx/api-discovery.md
- **Developed by:** [mia.cx](https://apify.com/miacx) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 1,000 discoveries

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## API Discovery for OpenAPI & MCP

Find a service's integration entry points before your agent starts guessing endpoint paths.
Send a service's public HTTPS URL. Get its documentation, OpenAPI, MCP, authentication and API-pricing links, each with source evidence.
Each successful bounded discovery costs $0.0025, plus $0.00005 per run start at default memory.
MCP results are observed links; the Actor never connects to or invokes those servers.

### Try it

```json
{"urls":["https://petstore3.swagger.io/api/v3/openapi.json"],"maxResults":1}
```

An empty input `{}` discovers links from `https://stripe.com`, with `maxResults: 10`.
No upstream API key is needed. Only public HTTPS hostnames on port 443 are accepted.

### Use from an agent

Add `https://mcp.apify.com?tools=miacx/api-discovery` to your MCP client and sign in to Apify.
Call the dedicated Actor tool, then use `get-dataset-items` to read the completed run's dataset.
Or set `APIFY_TOKEN` to your Apify API token and call the API for JSON rows:

```sh
curl --fail-with-body 'https://api.apify.com/v2/actors/miacx~api-discovery/run-sync-get-dataset-items' \
  -H "Authorization: Bearer $APIFY_TOKEN" -H 'Content-Type: application/json' \
  -d '{"urls":["https://petstore3.swagger.io/api/v3/openapi.json"],"maxResults":1}'
```

### What you get

The dataset contains one row per processed input, including duplicates, partial results and errors.
Read `status` first. `ok` means useful evidence was discovered without fetch or verification errors within the limits; it does not mean exhaustive coverage. Normal link and discovery caps can leave `truncated: true` on a billable `ok` row. `discovery_limited` retains partial evidence without a Discovery charge.
Inspect each entry's `verification` before treating a link as a checked JSON spec.

Output from replaying the synthetic MCP-link fixture in `test/discovery.test.ts`; timestamps are illustrative:

```json
{
  "input": "https://service.dev",
  "sourceUrl": "https://service.dev/",
  "fetchedAt": "2026-10-31T00:00:00.000Z",
  "status": "ok",
  "code": "discovered",
  "entries": [{
    "url": "https://external.dev/mcp",
    "kind": "mcp",
    "anchor": "MCP",
    "sourceUrl": "https://service.dev/",
    "fetchedAt": "2026-10-31T00:00:00.000Z",
    "verification": "candidate"
  }],
  "issues": [],
  "truncated": false
}
```

Entries use kinds `developer_docs`, `openapi`, `mcp`, `authentication` or `api_pricing`.
`candidate` means an observed link. `verified_spec` means a fetched JSON document passed lightweight structural checks.
Supported spec versions are OpenAPI 3.0/3.1 and Swagger 2; checks do not resolve references or prove semantic validity.
Declared `authSchemes` are not tested credentials. `authSchemesIncomplete` makes a result partial.

Entries sort by URL then kind; duplicate kind/URL links are removed.
An entry's `fetchedAt` belongs to its evidence source, including unfetched external links.
`verifiedAt`, when present, records the separate spec fetch.
Row `fetchedAt` is null when the initial content was not obtained.
`sourceUrl` is null on URL validation failure; otherwise it identifies the canonical or final URL.

Empty `entries` means no retained evidence. `issues` lists failed candidate checks; `truncated` identifies incomplete discovery.
The key-value record `OUTPUT` retains the full versioned report, categorical statuses, counters and limits.

### Input

| Field | Default | Accepted input |
| --- | --- | --- |
| `urls` | `["https://stripe.com"]` | 1–10 public HTTPS URLs, at most 2,048 characters each. Empty arrays are invalid. |
| `maxResults` | `10` | Integer 1–10. Processes only that prefix of input rows, including duplicates. Remaining charge allowance can lower this cap. |

URLs cannot include credentials or IP literals. Private or reserved DNS destinations are rejected.
Canonical duplicates share discovery work but retain separate dataset rows.
Different input pages on one origin share its four-document allowance.

### Pricing

One Discovery event costs $0.0025 for a successful bounded evidence-bearing result.
Ten unique successful discoveries cost $0.02505, including $0.00005 per run start at default 256 MB memory.
One thousand Discovery events cost $2.50, plus run starts.

A link-only MCP discovery can count; billing does not imply connectivity verification.
Partial, empty and error rows incur no Discovery events.
Results sharing a canonical source URL incur at most one Discovery event within a run.
The $0.00005 run start applies even with no billable discoveries at default memory.
Apify counts one start event per GB of memory, with a minimum of one event.

### Limits and data freshness

- Discovery reads robots.txt, the supplied document and up to three same-origin candidate documents in one round, prioritizing specs and documentation entry points. Links observed on fetched pages are retained without another fetch round. MCP links are never fetched.
- Each run shares 80 HTTP attempts, 16 MiB response bytes and an 18-second discovery budget. Each origin allows four content documents.
- HTML, JSON specs and robots policies cap at 4 MiB, 256 KiB and 64 KiB. Output caps at 256 KiB.
- Each document retains up to 40 links from 500 inspected anchors; parsing stops after 10,000 opening tags. Each result retains at most 40 entries.
- Specs cap at 2,000 paths and 20 authentication declarations. YAML specs, scripts, login flows and cross-origin redirects are unsupported.

Robots 404 permits access; denied or unavailable policy fails closed.
Published crawl-delay blocks the group within the synchronous workflow.
External links remain unfetched evidence. Only same-origin candidates can become verified specs.

Caching and deduplication last for the run only. Separate runs fetch fresh evidence; no stale-response fallback exists.
`not_found_within_budget` does not establish that an API, documentation or MCP service is absent.

### If a row fails

| Status or code | Next step |
| --- | --- |
| `discovery_limited` | Use retained evidence and inspect `issues`; supply a specific docs or JSON-spec URL to narrow discovery. |
| `not_found_within_budget` | Try a known documentation URL or inspect the service manually. |
| `invalid_url`, `unsafe_url`, `ip_literal_denied`, `url_too_long` | Supply a public HTTPS hostname without credentials. |
| `dns_denied`, `robots_denied` | Check DNS and published access policy. |
| `invalid_or_unsupported_spec`, `unsupported_format` | Use HTML or a supported JSON OpenAPI/Swagger spec. |
| `byte_budget` | Supply a smaller, more specific source. |

Other failures carry their machine code in `status` and `code`; inspect `OUTPUT` for request limits.
For workflows exceeding the synchronous API's 300-second wait, use [asynchronous runs](https://docs.apify.com/api/v2/actor-runs-post).

# Actor input Schema

## `urls` (type: `array`):

1-10 public HTTPS URLs on port 443, without credentials or IP literals. Omitted uses https://stripe.com; \[] is invalid. Canonical duplicates retain separate output rows but share work and Discovery charges within the run. Each URL is at most 2,048 characters.

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

Maximum input rows processed, 1-10; default 10. Processes only this prefix of urls, including duplicates. The remaining Discovery event allowance can lower this cap. Successful bounded evidence-bearing rows are billable once per canonical source URL, including normal discovery truncation; partial, empty and error rows are not.

## Actor input object example

```json
{
  "urls": [
    "https://stripe.com"
  ],
  "maxResults": 10
}
```

# Actor output Schema

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

No description

## `report` (type: `string`):

No description

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("miacx/api-discovery").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 = {}

# Run the Actor and wait for it to finish
run = client.actor("miacx/api-discovery").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 '{}' |
apify call miacx/api-discovery --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,miacx/api-discovery"
        }
    }
}
```

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/onnf5mF6DaTWJo6yk/builds/1mWdMEIkFsFqjlhuJ/openapi.json
