MCP
Discovery
Source: orchestration/mcp-gateway/server.ts (TOOL_DEFS, SERVER_INSTRUCTIONS), orchestration/mcp-gateway/tools.ts (ListAgentsSchema, listAgents), orchestration/mcp-gateway/tool-exec.ts (getToolContract), orchestration/mcp-gateway/credential-preflight.ts, orchestration/mcp-gateway/registry-cards.ts, orchestration/mcp-gateway/extras.ts (TemplatesSchema, plungeaiTemplates), core/core-base/tool-contract.ts, orchestration/registry/registry.ts (search markdown, KIND_GROUPS); registry reads live-verified 2026-09-24.
Before you run anything, find it. Discovery is three steps. Each one is a read-only tool call that costs no credits:
Find ──► plungeai_list_agents search the live registry (active agents only)
Inspect ──► plungeai_get_tool_contract typed params, operations, approval gates, YOUR credential status
Execute ──► plungeai_execute_tool · plungeai_execute_agent · an agent: task in a workflowplungeai_templates (list / get) is the fourth discovery tool. It lists ready-made workflows. All examples use https://mcp.plungeai.com/v1. https://api.plungeai.com/v1/mcp is the same server behind the One API (Overview). Every tool accepts user_request, the user's words verbatim. Always send it (Protocol & transport). Full parameter tables are in the Tool reference.
5.1 Registry agents vs your workflows
Two different things are both called "agents". The server's initialize instructions teach every client the difference (SERVER_INSTRUCTIONS in server.ts):
| Term | What it is | Tool | The user says |
|---|---|---|---|
| registry agent | A platform building block in the catalog (brave-agent, sec-agent, markitdown, …). Workflows are built from them. | plungeai_list_agents | "agents in the registry", "what can the platform do", "which agent should I use for…" |
| your workflows | Your saved CNL workflows. Users call these "my agents". | plungeai_list_workflows (8.1) | "show me my agents", "my workflows", "what's in my Finance folder" |
An unqualified "show me my agents" means your workflows. plungeai_list_agents is only for the registry: when the user says registry, discovery or platform agents, or when the client itself is choosing building blocks for a workflow.
plungeai_list_agents with kind: "workflows" searches the registry's public workflow cards. Those are not your workflows.
5.2 Search the registry — plungeai_list_agents
One tool, five modes. The mode is picked from the arguments you send:
| You send | Mode | What comes back |
|---|---|---|
search | Hybrid semantic + keyword search over live cards | The top matches (default 25) with Good at and Not for → use X instead for each |
category | Filter by registry category | Every active agent in that category (default 25) |
search + category | Both | Matches inside that category |
agent_id | One full card | The complete card markdown (5.3) |
nothing (or only kind) | Unfiltered listing | The whole catalog (default 100), headed # PlungeAI Agents (live registry) plus a refine hint |
Other arguments:
kind: which card set to search.agentsis the default. See the table below.limit: 1 to 100. It overrides the defaults above.format:"json"returns{"content": "<the same markdown>"}as text and asstructuredContent. The source is rendered registry markdown; there are no typed rows yet (tool description,server.ts).
search is semantic, so describe the capability, not a name: "web search", "convert pdf to markdown", "post to slack". The registry ranks the results. Trust the ranking.
The catalog is active-only. For kind: "agents" the gateway always adds status=active to the registry query (listAgents in tools.ts). Every agent it lists is deployed and callable. The execution tools refuse any id that is not status:active (Tools, Agents & missions). So take agent ids from a live search, never from memory, another platform, or a guess.
Try asking
- "What agents do you have for financial analysis and SEC filings?"
- "Which agent should I use to turn a PDF into markdown?" The search is semantic. For this one you get
pdf-worker,markitdownandms-office-worker, and each card says what it is not for (pdf-worker→ "Extracting text from existing PDFs → usedoc-converter"). Live-verified 2026-09-24. - "What connectors are available?" Also try personas, experts, skills and models.
- "What agents are in the registry for web search?"
curl -s https://mcp.plungeai.com/v1 \
-H "Authorization: Bearer $PLUNGE_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_list_agents","arguments":{"user_request":"Which agent should I use to turn a PDF into markdown?","search":"convert pdf to markdown","limit":3}}}'The result text is the registry's own markdown, passed through unchanged. An abridged excerpt (live registry, 2026-09-24):
# Registry search — q="convert pdf to markdown"
*3 results*
## PDF Worker (`pdf-worker`)
*agent · tools · status:active*
Generates PDF documents from Markdown content. …
**Good at:**
- Converting meeting notes in Markdown to a shareable PDF document (exportToPdf)
…
**Not for:**
- Extracting text from existing PDFs → use `doc-converter` (pdf-worker generates PDFs; it does not parse or extract content from existing PDF files)
…
## markitdown (`markitdown`)
*agent · tools · status:active*
…Each result has a heading with the name and id, a line with type, category and status, the description, Good at: and Not for:. The *N results* line counts the results on this page, not the catalog total.
Not-for redirects come from the card as written. A redirect target is not checked against the active catalog. On 2026-09-24,
sec-agent's card said "Real-time stock quotes → usealpha-vantage", andalpha-vantageisstatus:testing, so execution refuses it. Before you use a redirect target, check it withsearchoragent_id.
Kinds
kind picks the card set (KIND_GROUPS in orchestration/registry/registry.ts):
kind | Searches | Active-only filter |
|---|---|---|
agents (default) | Callable agents, the ids that go into a workflow's agent: | supported. Always applied |
personas | Digital twins (the persona of a one-agent call, see Agents & missions) | not applied (these cards carry no status:active tag) |
experts | Expert / specialist cards for mission capability injection | not applied |
skills | Skill cards (skills: on a harness task) | not applied |
models | Model cards (ids like anthropic:claude-haiku-4-5-20251001) | not applied |
connectors | Connector cards | not applied |
workflows | Public registry workflow cards, not your workflows | not applied |
The status filter applies only to agents on purpose. Almost no card in the other sets carries status:active (personas, experts and workflows none, skills 1 of 1,053 when the rule was written), so filtering would empty the list (comment in listAgents).
Categories
On 2026-09-24 the live catalog held 92 active agents in 14 categories: ai, blockchain, coding-agents, communication, ecommerce-agents, entertainment, financials, google-workspace, media, microsoft-365, payment, search, shopping, tools. Category values must match exactly. The finance category is financials: category: "finance" returns *0 results* (live-verified 2026-09-24). If you are unsure, use search ("agents for financial analysis") and let the ranking work. For counts per category, read the plungeai://agents/categories resource (Prompts & resources).
Don't ask for "all agents". An unfiltered listing is large. On 2026-09-24 the full active catalog in markdown was about 150 KB, all of it going into your client's context in one call. Always filter by
search,categoryorkind.
When the registry does not answer
| Answer | Meaning | isError |
|---|---|---|
Registry search failed (<status>). | The registry answered with a non-OK status | true |
Registry unavailable — try again shortly. | The call threw (timeout 10 s) | true |
Registry service not available. | The gateway has no registry binding | true |
These are plain text errors, not outcome envelopes. plungeai_list_agents has no outputSchema. Retry after a few seconds.
5.3 Read one full card — agent_id
agent_id returns the agent's complete card as markdown (GET /api/cards/agent/<id>?fields=full on the registry). It includes the description, Best for, the Not for table, the prompt format, operations, parameters, examples, output, credentials, demonstrations and tags. Fetch it before the first use of an unfamiliar agent. Cards are several KB each (weather-agent: about 12.7 KB, live 2026-09-24).
agent_id takes precedence: search, category and kind are ignored when agent_id is set. It always reads an agent card.
Try asking: "Show me the full card for sec-agent — what operations does it support?"
curl -s https://mcp.plungeai.com/v1 \
-H "Authorization: Bearer $PLUNGE_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_list_agents","arguments":{"user_request":"Show me the full card for the weather agent","agent_id":"weather-agent"}}}'A wrong or inactive id is not an error. The answer is guidance with live near-matches, and isError stays false:
| Case | Answer (from listAgents) |
|---|---|
| No card with that id | "No registry card with id <id> exists — ids cannot be guessed or carried over from other platforms (this one may be stale). Nothing failed; pick a live id below or refine with search." Then ## Closest live matches (the top 3 active cards) |
Card exists but is not status:active | "<id> is not available over MCP — only status:active agents are listed and callable here. Nothing failed; pick a live agent below or refine with search." Then ## Closest live matches |
The MCP server never shows a non-active card, not even when you ask for it by id.
5.4 The invocation contract — plungeai_get_tool_contract
Structured agents are forms, not chats. A card with a Parameters table (markitdown, weather-agent, the Gmail agent, …) takes typed fields, not a sentence. plungeai_get_tool_contract gives your client the exact form. It lists every typed field, the operations and which of them need approval, worked examples, and the live credential status for your account. Then the client fills the form and calls plungeai_execute_tool. The contract is the API documentation for that agent.
You can also just ask about an agent in plain language. The answer comes from its card (what it is good at, what to use instead) and its contract (the exact fields, and whether you are set up):
- "Before I use the Gmail agent — what exactly does it need from me, and am I connected?"
- "What is the x402 broker for?"
- "Can I search Amazon and pay with x402? What information do you need from me?"
curl -s https://mcp.plungeai.com/v1 \
-H "Authorization: Bearer $PLUNGE_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_get_tool_contract","arguments":{"user_request":"What does the weather agent need from me?","agent_id":"weather-agent"}}}'What comes back
The text is Markdown in this order (renderContractMarkdown in tool-contract.ts, then getToolContract in tool-exec.ts):
# <Name> (`<id>`)and the description.## Operations: one line per operation, with its purpose,(requires: …)for fields that only that operation needs, and⚠️ GATED: requires explicit user approvalon gated operations.## Parameters: one line per field, with its type,required,one of: …(enums read from the card),default: …and the description.## Examples: up to three worked CNL snippets from the card's demonstrations.**Returns:**: the card's output description.## Credentials: your live status (table below).- A closing line:
Run it: plungeai_execute_tool {agent_id: "<id>", operation: "<one of the operations above>", params: {<the parameters above>}}. Gated operations pause for user approval — relay the ⏸ block and continue with plungeai_continue.The hint is the server's own text. A gated floor operation run throughplungeai_execute_toolcomes back as a trust-fence refusal thatplungeai_continuecannot resume; it runs only from Ocean Studio (6.6).
An excerpt for weather-agent (rendered from the live card, 2026-09-24):
# Weather Agent (`weather-agent`)
Complete OpenWeatherMap client: current conditions, 5-day/3-hour forecast, … EVERY location-based operation accepts either lat/lon coordinates OR a `location` city name …
## Operations
- `current` — Real-time weather conditions
- `forecast` — 5-day forecast with 3-hour intervals
- `air-quality` — Current AQI (OWM 1-5 scale) + pollutant components
- `air-quality-history` — Historical AQI between start and end (requires: start, end)
- `one-call-timemachine` — Weather at a past/future moment (requires: dt)
…
## Parameters
- `lat` (number): Latitude - optional when `location` is given (auto-geocoded)
- `location` (string): City name auto-geocoded to coordinates, e.g. "Hamburg,DE" or "Sun Valley,ID,US" …
- `units` (string): `standard` (Kelvin) | `metric` (Celsius, default) | `imperial` (Fahrenheit)
- `start` (number): Unix start time — (operation: air-quality-history, required there)
…
## Credentials
- 🔐 Platform-managed — nothing for the user to connect.structuredContent is the outcome envelope (6.4) with the contract attached:
{
"status": "ok",
"agent_id": "weather-agent",
"summary": "Contract for weather-agent",
"contract": {
"agent_id": "weather-agent",
"name": "Weather Agent",
"description": "…",
"operations": [{ "name": "air-quality-history", "purpose": "…", "gated": false, "required_params": ["start", "end"] }],
"inputSchema": { "type": "object", "properties": { "location": { "type": "string", "description": "…" } }, "required": [], "additionalProperties": true },
"examples": [{ "title": "Current weather by city name (no coordinates)", "cnl": "agent: weather-agent\noperation: current\n…" }],
"output_type": "…",
"credentials": []
}
}With format: "json" the text becomes this same object as a JSON document. The Markdown ## Credentials lines are then not in the text, but contract.credentials carries the same data.
Contract fields
| Field | Meaning |
|---|---|
agent_id, name, description | The card's identity |
operations[] | { name, purpose?, gated, required_params? }. The values for operation on plungeai_execute_tool. Built from the card's Operations table, its per-operation parameters and its demonstrations. An empty list means no operation selector is known, not "refuse" |
inputSchema | JSON Schema for params: type: object, properties, required, additionalProperties: true (fields not on the card are legal and pass through) |
examples[] | { title, cnl }: up to three copy-paste CNL tasks |
output_type | What the agent returns, in prose |
soleRequiredParam | Present when exactly one string field is required. A prose prompt can be mapped onto it (6.3) |
credentials[] | { provider, tier, required, connected, status, accountEmail } per requirement. connected: null means the status could not be checked |
How the contract is built
The card's parameter types are free text written by people. The generator never throws: an unknown type becomes string, and the raw type is kept in the description (buildToolContract in tool-contract.ts). These rules shape what your client sees:
- Envelope names are skipped.
agent,type,id,operation,depth,user_id,executor_user_id,workflow,execution_idbelong to the task envelope. They never appear as params. The operation goes inplungeai_execute_tool's ownoperationargument. - Credential fields are never required.
access_token,api_key,apikey,bearer_token,oauth_token,refresh_tokenare shown with "(platform-injected from your connected account at runtime — do NOT supply)". - Operation-specific requireds live on
operations[].required_paramsand are enforced only when you run that operation. promptas an alias. When a card markspromptand another text field required together (for examplequery+prompt),promptis made optional.- Old multi-operation cards. On a card with two or more operations and no per-operation attribution, the fields it marks required are moved into the description as "(required by some operations — see the examples)". Otherwise every call would be refused for fields that belong to other operations.
- Gated operations are the platform floor list (
buy,purchase,fetch_paid,send,transfer,pay,send_payment,withdraw,shop) plus anygated:<op>tag on the card. See The trust fence.
Credentials section
The ## Credentials lines come from the agent's credential requirements (6.7) and a live status lookup for the calling user:
| Line | Meaning |
|---|---|
🔐 Platform-managed — nothing for the user to connect. | The agent runs on platform keys |
`<provider>`: 🔐 platform-managed. | This requirement is served by the platform |
`<provider>` (private connector): ✅ connected as you@… | Your OAuth account is connected. The email is shown when known |
`<provider>` (bring-your-own key): ⚠️ NOT connected — required; execution will stop with connect instructions until the user connects it at https://studio.plungeai.com → Connectors. | Missing. expired — reconnect replaces NOT connected for an expired connection; (optional) replaces — required; … for an optional one |
`<provider>` (<tier>): status could not be checked — execution will verify. | The lookup failed. It fails open, and the execution checks again |
Outcomes
status | When | isError |
|---|---|---|
ok | The contract was built | false |
unavailable | No card with that id (No registry card with id `<id>` exists — … Nothing was executed.), or the card is not status:active. Up to three live alternatives are included as use_alternative actions | false |
error | The registry did not answer: The registry did not answer — the contract cannot be fetched right now. with "Retry in a few seconds." | true |
The tool is read-only (readOnlyHint: true). Card lookups are cached for 60 seconds per gateway isolate (registry-cards.ts), so an agent that was just deactivated can still look active for up to a minute.
5.5 Workflow templates — plungeai_templates list and get
Templates are a platform-wide library of ready-made workflows. They are the same rows Studio's gallery shows (templates / template_versions in D1, content in KV). Three actions:
action | Needs | Returns |
|---|---|---|
list | optional category, limit (1–100, default 50) | # Workflow Templates (N): a table with Name, Kind, Category, Difficulty, Used, ID, Description (first 90 chars). Only status = 'active' workflow templates, featured first, then display order, then most used |
get | template_id | The name, description, **Category:** … · **Difficulty:** … · **Used:** N× and the full YAML in a code block |
use | template_id, optional name, folder | Copies the template into your account as a new workflow. See 8.9 |
Try asking: "What workflow templates are available? Start one from the due-diligence template." The client lists the templates, finds the due-diligence one, then calls use (Workflows).
curl -s https://mcp.plungeai.com/v1 \
-H "Authorization: Bearer $PLUNGE_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"plungeai_templates","arguments":{"user_request":"What workflow templates are available?","action":"list","limit":10}}}'To read one template's YAML, pass its id from the list:
# get needs a real template id from the list above
curl -s https://mcp.plungeai.com/v1 \
-H "Authorization: Bearer $PLUNGE_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"plungeai_templates","arguments":{"user_request":"Show me the due-diligence template","action":"get","template_id":"<template id>"}}}'| Answer | Meaning | isError |
|---|---|---|
No active workflow templates. | list matched nothing (for example an unknown category) | false |
template_id is required for this action. | get or use without an id | true |
Template not found: <id> | No active template with that id | true |
Template content missing from storage. | The row exists but its YAML is gone | true |
plungeai_templates is not marked read-only, because use writes a workflow. list and get change nothing. The tool has no format argument; its output is always Markdown.
5.6 Other discovery surfaces
- Resources.
plungeai://agents/list,plungeai://agents/categories,plungeai://personas/listand theplungeai://agents/{category}template read the same live registry (agents active-only).plungeai://docs/workflow-authoringis the full CNL authoring guide. See Prompts & resources. - The
/plungeaiprompt gives the client the whole discover → inspect → execute routine in one message (Prompts & resources). - Over HTTP. The One API has the same catalog as REST routes:
GET /v1/discovery/searchandGET /v1/tools/{id}(https://api.plungeai.com/docs#8-discovery (opens in a new tab), https://api.plungeai.com/docs#6-tools-plane (opens in a new tab)). - Skills for your client. https://skills.plungeai.com (opens in a new tab) has installable skills that teach Claude Code, Cursor and other clients these same patterns (Connecting clients).