diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index ae3b757..a0a7462 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,8 +1,9 @@ { "name": "orbit", - "version": "1.0.0", + "version": "1.1.0", "description": "Discover APIs from the Postman API Network using Postman Orbit, an agent-friendly search API designed for AI-powered app design.", "skills": "./skills/", + "mcpServers": "./.mcp.json", "author": "Postman DevRel", "homepage": "https://github.com/Postman-Devrel/orbit-codex-plugin", "repository": "https://github.com/Postman-Devrel/orbit-codex-plugin", diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 0000000..0ab7401 --- /dev/null +++ b/.mcp.json @@ -0,0 +1,8 @@ +{ + "mcpServers": { + "orbit": { + "type": "streamable-http", + "url": "https://mcp.buildwithorbit.ai/mcp" + } + } +} diff --git a/README.md b/README.md index 4273724..f687611 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,19 @@ This lets agents make informed decisions about which APIs to integrate without r codex plugin add Postman-Devrel/orbit-codex-plugin ``` +The plugin bundles Orbit's MCP server, so there is nothing else to configure -- no API +key, no `codex mcp add`, no edits to `~/.codex/config.toml`. Installing the plugin +registers the `search` and `integrate` tools, and the skill drives them. + +Requires a Codex version that supports plugin-bundled MCP servers over streamable HTTP. +If your Codex only picks up stdio servers, add the server manually instead: + +```toml +# ~/.codex/config.toml +[mcp_servers.orbit] +url = "https://mcp.buildwithorbit.ai/mcp" +``` + ## Usage Run the `discover` skill with a capability query: @@ -37,19 +50,31 @@ Search for multiple capabilities at once: ### Example output ``` -### Results for: "payment processing" +### Results for: "Stripe create subscription" -**Stripe - Create Subscription** +**Create a subscription** (Stripe / Stripe Billing) - Method: `POST` - URL: `https://api.stripe.com/v1/subscriptions` -- Description: Creates a new subscription on an existing customer. -- **Evaluate Guide:** Use for: recurring billing, subscription lifecycle management, - plan upgrades/downgrades. Not supported: one-time payments (use Payment Intents), - physical goods shipping, tax calculation (use Stripe Tax). +- Description: Creates a new subscription on an existing customer. Each customer can + have up to 500 active or scheduled subscriptions. +- **Evaluate Guide:** Creates a recurring subscription for an existing customer and + determines how its initial invoice and payment are handled. + Use for: start recurring billing, configure initial payment behavior, create + scheduled subscriptions + Not supported: customer creation, one-time charges, changing existing subscription + items ``` +Note the query includes the provider name. A generic `"payment processing"` search +returns Adyen, Moneris, and Peach Payments -- not Stripe. Naming the provider is the +single biggest lever on result quality. + Results are automatically saved to the `orbit-output/` directory as markdown files for later reference. +Once you have chosen endpoints, the skill can also produce a **task brief** -- the auth +requirements, base URLs, ordered request steps, and gotchas needed to write the +integration. + ## Design process Orbit works best when you use it at the start of a project to build an API blueprint before writing code. Here's the workflow: @@ -62,27 +87,46 @@ Orbit works best when you use it at the start of a project to build an API bluep 4. **Iterate.** Use those gaps as your next round of queries. "Find me APIs that handle payment refunds" or "I need an auth provider that supports token refresh." Each round narrows the design. -5. **Save the blueprint.** The agent saves results to `orbit-output/` as a structured file you can reference throughout the project. This becomes your API design document, readable by both humans and agents. +5. **Get the task brief.** Once the endpoint set is settled, the agent sends the selected endpoints plus your task to Orbit's `integrate` tool and gets back a brief covering auth, base URLs, and the request sequence -- the implementation plan, before you write code. + +6. **Save the blueprint.** The agent saves results to `orbit-output/` as a structured file you can reference throughout the project. This becomes your API design document, readable by both humans and agents. The goal is to make API selection decisions intentionally at design time, not discover limitations mid-sprint after you've already integrated half the stack. -## The Orbit API +## How it works -The plugin calls a single endpoint: +The plugin is a thin workflow layer over Orbit's MCP server: -``` -POST https://fabric-gateway.postmanlabs.com/api/search -Content-Type: application/json +| | Provided by | +|---|---| +| `search` / `integrate` tools, request + response schemas | Orbit's MCP server (bundled) | +| Capability decomposition, gap analysis, iteration, saved blueprint | This plugin's skill | -{"q": "your search query"} -``` +Keeping the API contract on the server side means Orbit can change its parameters +without breaking installed copies of the plugin. + +### The underlying API + +No authentication is required. The MCP tools map one-to-one onto two REST endpoints on +`https://api.buildwithorbit.ai`: + +| MCP tool | REST equivalent | +|---|---| +| `search` | `POST /v1/search` | +| `integrate` | `POST /v1/integrate` | -No authentication required. The response includes: +`search` takes `q` (max 512 chars) plus optional `limit` (default 10, max 25) and +`cursor`, and returns `data[]` entries with `id`, `resourceType`, `name`, +`description`, `method`, `url`, and `evaluateGuide`, alongside `meta` carrying `q`, +`total`, and `nextCursor`. `integrate` takes a `task` and 1-10 `resources` and returns +a `taskBrief`. -- `data[]` - Array of API endpoints with `id`, `name`, `description`, `method`, `url`, and `evaluateGuide` -- `meta` - Search metadata with `q`, `total`, and `nextCursor` +If the MCP server is ever unreachable, the skill falls back to these REST endpoints, +documented in [references/orbit-api.md](skills/discover/references/orbit-api.md). ## Links +- [Orbit documentation](https://www.buildwithorbit.ai/) +- [Orbit API reference](https://www.buildwithorbit.ai/api-reference) - [Postman API Network](https://www.postman.com/explore) - [Postman](https://www.postman.com) diff --git a/skills/discover/SKILL.md b/skills/discover/SKILL.md index 2f3f123..0f68c3d 100644 --- a/skills/discover/SKILL.md +++ b/skills/discover/SKILL.md @@ -1,12 +1,14 @@ --- name: discover -description: Discover APIs from the Postman API Network using Orbit's agent-friendly search. Returns endpoints with evaluateGuide fields showing what each API can and can't do. +description: Discover APIs from the Postman API Network using Orbit's agent-friendly search. Returns endpoints with evaluateGuide fields showing what each API can and can't do, and can generate an integration task brief for the ones you pick. --- # Orbit API Discovery You are an API discovery agent. You help developers find the right APIs for their project by querying **Postman Orbit**, an agent-friendly search API built on top of the Postman API Network. +This plugin bundles Orbit's MCP server, so its tools are available with no setup and no authentication. + ## When to use Use this skill when a developer wants to: @@ -14,6 +16,7 @@ Use this skill when a developer wants to: - Compare multiple APIs that serve the same purpose - Understand what an API can and cannot do before integrating it - Discover APIs for multiple capabilities in a single session +- Get a concrete integration plan for APIs they have already chosen ## Input @@ -24,17 +27,29 @@ The user provides one or more capability queries as natural language. Examples: Parse the user's message to extract individual capability queries. If the user lists multiple capabilities, run a separate search for each one. +## Tools + +The bundled `orbit` MCP server provides two tools: + +- **`search`** — find and evaluate public API endpoints +- **`integrate`** — turn chosen endpoints into an integration task brief + +Prefer these tools. If they are unavailable in the current session, read `references/orbit-api.md` and call the equivalent REST endpoints with curl; the request and response shapes are identical. + ## How to search -For each capability query, use Bash to call the Orbit API: +Call the `search` tool once per capability query: + +- `q` — the query (required, max 512 characters) +- `limit` — results per page (optional, default 10, max 25) +- `clientName` — pass `"codex/orbit-plugin"` for anonymous usage analytics -``` -curl -s -X POST https://fabric-gateway.postmanlabs.com/api/search \ - -H "Content-Type: application/json" \ - -d '{"q": "QUERY_HERE"}' -``` +Query style materially affects result quality: -Replace `QUERY_HERE` with the capability query. Keep queries concise and descriptive. +- Include the product or provider name alongside the endpoint detail — `"PayPal create invoice"`. +- Natural language works too — `"PayPal API to create an invoice"`. +- Do **not** cram unrelated keywords into one query — `"paypal invoice payment delivery ordering"` returns worse results. +- Do **not** use `OR`-separated queries. Run a separate `search` call per intent instead. ## How to format results @@ -44,7 +59,7 @@ For each query, present results in this format: For each result in the `data` array, show: -**{name}** +**{name}** ({provider}) - Method: `{method}` - URL: `{url}` - Description: {description} @@ -57,7 +72,20 @@ The `evaluateGuide` field is the most valuable part of the response. It tells ag Always highlight the evaluateGuide content prominently. This is what differentiates Orbit from a standard API directory. -If the `meta.total` count exceeds the number of returned results, mention that more results are available. +Keep each result's `id` and `resourceType` on hand — the `integrate` tool needs them. Preserve `id` values verbatim; never parse, edit, or construct one. + +If `meta.total` exceeds the number of returned results, mention that more results are available. If `meta.nextCursor` is present, more pages exist — pass that value as `cursor` on a follow-up `search` call, but do not paginate automatically unless the user asks. Note that `nextCursor` is *absent* on the last page rather than null, and pagination stops at 40 results per query. + +## How to integrate + +When the user has a concrete task and has settled on endpoints, call the `integrate` tool: + +- `task` — what they are building (required, max 512 characters) +- `resources` — entries of `{id, type}`, where `id` is a search result's `id` and `type` is that result's `resourceType` + +The schema allows up to 10 resources, but **keep calls narrow — 2 or 3 related endpoints**. Wide calls have been observed to return a one-line restatement instead of a real brief. To cover more endpoints, make several focused calls grouped by sub-task rather than one wide call. + +The response contains a `taskBrief` covering authentication requirements, base URLs, ordered request steps, parameters, expected responses, dependencies between steps, and other considerations. Present the brief and save it alongside the search results. ## Saving results @@ -72,6 +100,7 @@ Filename pattern: `orbit-output/{slug}.md` Examples: - Single query "payment processing" -> `orbit-output/payment-processing.md` - Multiple queries "send emails" + "geocoding" -> `orbit-output/send-emails--geocoding.md` +- A task brief -> `orbit-output/{task-slug}-brief.md` The saved file should contain: - A top-level heading with the date and queries @@ -80,7 +109,8 @@ The saved file should contain: ## Guidelines - If no results are found for a query, say so clearly and suggest rephrasing. -- Do not fabricate API results. Only show what the Orbit API returns. +- Do not fabricate API results. Only show what Orbit returns. - When the user asks for multiple capabilities, run all searches and present results grouped by capability. +- Lead your summary with the "Not supported" lines — those are the design gaps worth acting on before any code is written. - Keep your commentary brief. Let the API results speak for themselves. -- If the response includes a `nextCursor` in `meta`, mention that more results are available but do not automatically paginate. +- Both tools are read-only and safe to retry. On a rate-limit error, back off and retry. diff --git a/skills/discover/references/orbit-api.md b/skills/discover/references/orbit-api.md new file mode 100644 index 0000000..5d0006f --- /dev/null +++ b/skills/discover/references/orbit-api.md @@ -0,0 +1,230 @@ +# Orbit API Reference — REST fallback + +Docs: https://www.buildwithorbit.ai/api-reference +OpenAPI: https://www.buildwithorbit.ai/openapi.json + +> **Prefer the MCP tools.** This plugin bundles Orbit's MCP server, so the `search` +> and `integrate` tools are normally available and carry live, self-describing +> schemas. Use the REST calls below only when those tools are unavailable. See +> [MCP tools](#mcp-tools) at the end for the mapping. + +**Base URL:** `https://api.buildwithorbit.ai` + +No authentication is required. Only `Content-Type: application/json` is needed. + +There are two endpoints: `/v1/search` finds candidate endpoints, `/v1/integrate` turns +the ones you pick into a task brief. + +--- + +## POST /v1/search + +Describe your goal in `q`. Returns matching public endpoints, each with an +`evaluateGuide` explaining what it does, when to use it, and its limitations. + +### Query parameters + +| Parameter | Type | Default | Notes | +|-----------|------|---------|-------| +| `limit` | integer | 10 | Results per page. Min 1, max 25. | +| `cursor` | string | — | Pass `meta.nextCursor` from the previous response. Omit for the first page. | + +### Request body + +| Field | Type | Required | Notes | +|-------|------|----------|-------| +| `q` | string | Yes | Natural language query, keywords, an API name, or a question. 1–512 characters. | + +`q` is the only accepted body field — unknown fields return `400`. + +```json +{ "q": "Add tracking details for an existing paypal order" } +``` + +### Example curl + +```bash +curl -s -X POST 'https://api.buildwithorbit.ai/v1/search?limit=10' \ + -H 'Content-Type: application/json' \ + -d '{"q": "payment processing"}' | jq . +``` + +### Response (200) + +```json +{ + "data": [ + { + "id": "urn:orbit:endpoint:v1:...:brevo:send-a-transactional-ema", + "resourceType": "endpoint", + "name": "Send a transactional email", + "description": "string", + "method": "POST", + "url": "https://api.brevo.com/v3/smtp/email", + "evaluateGuide": "string", + "provider": "Brevo", + "product": "Brevo" + } + ], + "meta": { + "q": "send transactional email", + "total": 2, + "nextCursor": "eyJmcm9tIjoyfQ==" + } +} +``` + +| Field | Description | +|-------|-------------| +| `id` | Opaque identifier of the form `urn:orbit:endpoint:v1:...`. Pass it back verbatim to `/v1/integrate` — never parse or construct it. | +| `resourceType` | Kind of entity, e.g. `endpoint`. Pass it to `/v1/integrate` as the resource's `type`. | +| `name` | Human-readable name of the endpoint | +| `description` | What the endpoint does (may be empty) | +| `method` | HTTP method used to call the endpoint | +| `url` | URL the endpoint is called at | +| `evaluateGuide` | Three-part evaluation: brief summary, recommended use cases, unsupported use cases/limitations | +| `provider` / `product` | Owning provider and product (returned by the live API; not in the published OpenAPI spec, so treat as optional) | + +`meta` carries `q`, `total`, and `nextCursor`. **`nextCursor` is absent on the last +page** — check for its presence rather than comparing to `null`. + +### Pagination + +Pass `nextCursor` as the `cursor` **query parameter** (not a body field): + +```bash +curl -s -X POST 'https://api.buildwithorbit.ai/v1/search?cursor=eyJmcm9tIjoyfQ==' \ + -H 'Content-Type: application/json' \ + -d '{"q": "payment processing"}' +``` + +Pagination stops at 40 results total; a cursor past 40 is rejected. + +### Errors + +`400` invalid input · `429` rate limited · `500` server error. +Error bodies are RFC 9457 problem details: `type`, `title`, `status`, `detail`, `instance`. + +--- + +## POST /v1/integrate + +After selecting endpoints from `/v1/search`, send them here along with the task you +want to accomplish. Returns a **task brief** with the information and steps needed to +call those endpoints. + +Takes no query parameters. + +### Request body + +| Field | Type | Required | Notes | +|-------|------|----------|-------| +| `task` | string | Yes | What you want to accomplish. 1–512 characters, must contain non-whitespace. | +| `resources` | array | Yes | Endpoints to integrate, 1–10 items. Each item needs `id` and `type`. The MCP tool schema enforces a max of 10; the published OpenAPI spec omits the limit, so assume it applies to REST too and split larger sets across calls. | +| `resources[].id` | string | Yes | The `id` from a `/v1/search` result, verbatim. | +| `resources[].type` | string | Yes | The result's `resourceType`. Currently only `endpoint`. | + +```json +{ + "task": "Build an app to post current weather to Slack", + "resources": [ + { "id": "urn:orbit:endpoint:v1:...:weatherapi-com:current-weather-json", "type": "endpoint" }, + { "id": "urn:orbit:endpoint:v1:...:slack:send-message-to-slack", "type": "endpoint" } + ] +} +``` + +### Example curl + +```bash +curl -s -X POST https://api.buildwithorbit.ai/v1/integrate \ + -H 'Content-Type: application/json' \ + -d '{ + "task": "Send a transactional email when a user signs up", + "resources": [ + { "id": "urn:orbit:endpoint:v1:...:sendmux:send-a-single-email", "type": "endpoint" } + ] + }' | jq -r '.data[0].taskBrief' +``` + +### Response (200) + +```json +{ + "data": [ + { "taskBrief": "string" } + ] +} +``` + +The `taskBrief` is a multi-line document covering FIT, AUTH (including which +credentials you must supply), BASE URL, STEPS with parameters and expected responses, +dependencies between steps, and important considerations. It is built from the +selected endpoints' schemas plus shared variables, auth settings, and descriptions +defined by their parent APIs. + +### Errors + +`400` invalid input · `404` none of the `id`s could be resolved · `429` rate limited · +`500` server error. + +--- + +## Idempotency + +Both endpoints are read-only and never create or mutate data, so retries are safe and +no idempotency key is needed. Search results may change as the public catalog changes; +task brief wording may vary between otherwise identical calls. + +## The evaluateGuide field + +`evaluateGuide` is what makes Orbit results agent-friendly. It is a newline-separated +string in three parts, so an agent can decide whether an API fits without +trial-and-error: + +- **Summary** — a concise description of the endpoint's purpose +- **`Use for:`** — specific scenarios where this endpoint is the right choice +- **`Not supported:`** — capabilities this endpoint does not cover, preventing wasted + integration effort + +Example: + +``` +Sends a transactional email through Brevo's SMTP API, enabling an agent to deliver an email payload to recipients. +Use for: send transactional messages, deliver notifications, send account emails +Not supported: inbound email processing, contact management, campaign analytics +``` + +--- + +## MCP tools + +The plugin bundles Orbit's MCP server (`https://mcp.buildwithorbit.ai/mcp`, streamable +HTTP transport, no auth) via `.mcp.json`, referenced from `.codex-plugin/plugin.json` +as `"mcpServers": "./.mcp.json"`. It exposes two tools that map one-to-one onto the +REST endpoints and return identical payloads: + +| MCP tool | REST equivalent | +|----------|-----------------| +| `search` | `POST /v1/search` | +| `integrate` | `POST /v1/integrate` | + +Differences from REST: + +- `limit` and `cursor` are ordinary tool arguments, not query parameters. +- Both tools accept an optional `clientName` string for anonymous usage analytics. + Pass `"codex/orbit-plugin"`. +- `integrate` declares `resources` as 1–10 items in its schema. + +The tool schemas are the authoritative contract — they are fetched live from the +server, so they stay correct even when this file drifts. + +### Query guidance (from the tool description) + +- Use focused keyword queries including the product or provider name plus the endpoint + detail — e.g. `"PayPal create invoice"`. +- Natural language works too — e.g. `"PayPal API to create an invoice"`. +- Avoid jumbled queries cramming unrelated keywords together — e.g. + `"paypal invoice payment delivery payments ordering"`. +- Avoid `OR`-separated queries — e.g. `"paypal invoice OR paypal create invoice"`. +- To explore multiple intents, make a separate call per intent.