> ## Documentation Index
> Fetch the complete documentation index at: https://www.plungeai.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting & gotchas

> extras.ts, activity-log.ts, core/core-base/provider-ids.ts, core/agent-core/index.ts, agents/agents/one-agent/call-config.ts, orchestration/api-gateway/routes/mcp.ts, live registry and registry cards (2026-09-24), live /health, /v1/info, 401/405/413 responses (2026-09-24).


Source: `orchestration/mcp-gateway/index.ts`, `auth-middleware.ts`, `server.ts`, `session-do.ts`,
`tools.ts`, `tool-exec.ts`, `tool-outcome.ts`, `execution.ts`, `leg-state.ts`, `resources.ts`,
`extras.ts`, `activity-log.ts`, `core/core-base/provider-ids.ts`, `core/agent-core/index.ts`,
`agents/agents/one-agent/call-config.ts`, `orchestration/api-gateway/routes/mcp.ts`, live registry and
registry cards (2026-09-24), live `/health`, `/v1/info`, 401/405/413 responses (2026-09-24).

Most problems fall into one of three groups: the key, the transport, or which id you used. This
chapter starts with five checks that settle most of them, then maps symptoms to causes, then lists
the gotchas that come up in real use. Every row was checked against the code or a live response.
The endpoint is `https://mcp.plungeai.com/v1`; `https://api.plungeai.com/v1/mcp` is the same
server, and where it behaves differently the row says so.

## 15.1 Five first checks

1. **Is the platform up?** No key needed. `status` is `healthy`, or `degraded` with HTTP 503 when
   the database, key store or registry probe fails:

   ```bash
   curl -s "https://mcp.plungeai.com/health?cb=$(date +%s)"
   ```

2. **Which server and protocol version am I talking to?** No key needed:
   `curl -s https://mcp.plungeai.com/v1/info` ([4.2](/mcp/protocol#42-endpoint-paths-headers-and-methods)).
3. **Does my key work, and whose is it?** Ask *"Who am I, what tier am I on, and how much of my rate
   limit have I used?"*, or call it directly:

   ```bash
   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_whoami","arguments":{"user_request":"who am I"}}}' \
     | sed -n 's/^data: //p'
   ```

4. **What did my client actually send?** Your activity log shows every request with its arguments,
   your own words (`user_request`), and the answer or error
   ([13.10](/mcp/errors-limits#1310-the-activity-log)). It is the fastest way to see that a client sent
   `{folder: "Finance"}` when you asked something else.
5. **Is the tool list stale?** Clients read `tools/list` once, when they connect, and this server
   never pushes a change notification. After a platform update, **restart or reconnect your client**
   to pick up new or changed tools.

## 15.2 Symptoms and fixes

| Symptom | Cause | Fix |
|---|---|---|
| `401` on every call | The key is wrong, replaced, revoked or expired, or the header is wrong. The message is the same for all of these: `No valid authentication provided…`. A Bearer token that does not start with `ozk_` is never accepted. | Check the header (`Authorization: Bearer ozk_…` or `X-API-Key`). Mint a new key at **Dashboard → One API → Keys** (`https://dashboard.plungeai.com`) and revoke the old one. |
| `401 API key not permitted from <ip>`, or `401` only from a new place | The key is restricted to certain network locations | Use it from an allowed network, or ask the account owner who issued it to update the fence. |
| `429 Rate limit exceeded: Rate limit: <n> requests/minute` (or `/day`) with `Retry-After` | Your tier's limit ([13.7](/mcp/errors-limits#137-rate-limits)) | Wait the `Retry-After` seconds. Ask *"how much of my rate limit have I used?"*. |
| `429 Too many failed authentication attempts` | Many failed logins from your IP, often a client retrying with a bad key | Fix the key in the client config, then wait for the window to reset. |
| `Tool not permitted for this key: <name>` | Your key is limited to a subset of tools | Use a key that allows the tool, or ask the account owner. |
| Fewer tools than expected | A restricted key (fenced tools never appear in `tools/list`), or a stale client list | Check with `tools/list`. Reconnect the client. |
| `Tool not found: <name>`, or your client doesn't know a tool | The client's tool list predates a platform update, or the name is misspelled | Reconnect to refresh the tool list. |
| `405 Method not allowed.` on `GET` | Your client tried to open a standalone SSE stream. The server is stateless and offers none ([4.5](/mcp/protocol#45-stateless-by-default-opt-in-sessions)). | Nothing, for spec-compliant clients: they continue with `POST`. |
| `404 Session not found` | The client sent an `Mcp-Session-Id` that is stale, expired (10 min idle) or from another key. Normal keys never get one. | Drop the header and re-initialize. |
| `400 Parse error` | The body is not valid JSON, usually shell quoting | Check the quotes around `-d '…'`. Inside single quotes, write an apostrophe as `'"'"'`. |
| `413 Request body too large (1 MiB max)` | Body over 1,048,576 bytes | Shrink it: save a long workflow first and run it by id, or split the work. |
| `403 Invalid Host header` | A proxy between you and the server rewrote the `Host` header | Call `https://mcp.plungeai.com/v1` directly. |
| curl prints `event: message` and `data: {…}` lines | `tools/call` answers as Server-Sent Events | Keep the `data:` lines: `… \| sed -n 's/^data: //p'` ([4.6](/mcp/protocol#46-toolscall-over-sse-progress-and-keepalive)). |
| A long run returns an id instead of a result | Background mode: `mode:"async"`, or `plungeai_run_mission` / `plungeai_learn`, which default to it | Normal. Ask *"is that still running?"* and then *"show me the result"* ([Runs, results & follow-ups](/mcp/runs-results)). |
| `This run failed: …` | The run genuinely failed, and that is the reason | Fix the input and rerun. Don't keep polling. |
| A background run shows `Interrupted (run did not complete)` | The run stopped sending a heartbeat for 16 minutes and was marked failed ([4.7](/mcp/protocol#47-async-mode)) | Rerun it, run it in the foreground, or split it into smaller steps. |
| `Run was killed 3 times in a row without yielding a checkpoint…` | One step ran longer than a 10-minute leg, crashed repeatedly, or kept getting interrupted by deploys | Split the work or shorten the step, then rerun. |
| `…is not status:active` / `No such agent: <id>` (`🚫 UNAVAILABLE`) | The agent is not in the live catalog, or the id was guessed | Pick a listed alternative, or search: *"which agent should I use to …"*. |
| `That is a scheduler run id, which this tool cannot resolve…` | An `exec_…` id from the scheduler | Ask for the job's run history (`plungeai_schedule` `runs`) and use its **Execution ID** column. |
| `No result found for <id>, or it is not one of your executions.` | A workflow id where an execution id belongs, or another account's id | Ask *"show me my recent executions"* and use an id from there ([15.3](#153-gotchas-worth-knowing)). |
| `Execution not found.` from a status check or `plungeai_executions` | No run of yours has that id: it is unknown, belongs to another account, or is a workflow id where an execution id belongs | Ask *"show me my recent executions"* and use an id from there. |
| `Execution is completed, not running — nothing to cancel.` | Cancel only applies to running executions | Nothing to do. |
| Your client shortens or paraphrases a long result | The client's own behaviour. The server's instructions ask it to relay results verbatim. | Add *"show it verbatim, don't summarize"*. |
| `/health` answers `503` with `"status":"degraded"` | A platform dependency probe failed | Platform-side. Retry later. |

Need a new key? Self-serve one at **Dashboard → One API → Keys** (`https://dashboard.plungeai.com`).
For a shared team key, or anything else, ask the account owner.

## 15.3 Gotchas worth knowing

These come from real failures.

**"Category" and "folder" are different things.** Your *folders* (Finance, Personal, …) hold
**your workflows**. *Categories* are the global agent taxonomy, and the finance one is called
`financials`, not `finance`. On 2026-09-24 the registry answered `category=finance` with 0 results
and `category=financials` with `sec-agent` (live-verified). Say *"agents for financial analysis"*
and let the semantic search work. Or read `plungeai://agents/categories` for the real names
([Prompts & resources](/mcp/prompts-resources)).

**Results need the execution id, not the workflow id.** A workflow id identifies the recipe, and
each run gets its own **execution id**. Every run result ends with its execution id. If a result
lookup comes back empty, ask *"show me my recent executions"* first and use that id. When you refer
to a row by number ("show me #2"), the server tells clients to resolve it against the list you were
shown, not a fresh one, because new runs keep shifting a newest-first list.

**Don't ask for "all agents".** An unfiltered listing is large: about 150 KB for the 92 active
agents on 2026-09-24 (live-verified), in one go into your context. `plungeai://agents/list` is the
same listing. Filter by search term, category or kind instead. Everything the catalog lists is live
and callable. Names from outside it (memory, another platform, a guess) are refused with
`🚫 UNAVAILABLE` before anything runs, so when in doubt, search first.

**Some agents are forms, not chats.** Agents such as `markitdown`, `weather-agent` or
`google-gmail` take specific fields (a URL, a place, a message id), not a sentence. Your client
handles this itself: it fetches the agent's **contract** (every field typed, with a worked example)
and fills it in before running ([Tools](/mcp/tools)). If something is still missing, the answer names
the exact fields and shows the form. It never comes back as a bare error, so *"do what it
suggests"* is always enough. A prose prompt sent to an agent with several operations and no
`operation` runs its **default** operation, and the answer says so with a `⚠️ structured agent: …`
warning.

**Writing workflow YAML by hand? Quote your colons.** A value like `prompt: DD: memo` breaks YAML.
Write `prompt: "DD: memo"`, or put long text in a block (`prompt: |`). Never hard-wrap a value
across lines. On invalid YAML, `plungeai_execute_workflow` adds exactly this tip to its answer.
The top-level `workflow:` wrapper is optional: bare `name:` + `tasks:` at the top level is accepted
and wrapped for you. Easier still, describe the goal and let *"build me a workflow that…"* write the
YAML ([Workflows](/mcp/workflows)). On a `one-agent` task you can leave `provider` out to get the
default (`gemini`, model `gemini-3.1-flash-lite`). The provider resolver maps `google` to `gemini`
(`core/core-base/provider-ids.ts`). Any other unknown provider is refused: `Unsupported provider: <x>`,
or `provider "<x>" is not available on llm-agent` (call mode keeps the legacy wording) when the
provider exists but the agent has no binding for it.

**"Needs a connected account" means exactly that.** Google, Microsoft and similar agents act as
*you*, so they need your account connected once in Studio → Connectors. The platform checks this
**before** running anything. If the connection is missing or expired, you are told exactly which
service to connect and where (`🔌 NEEDS CONNECTION`): no run is started, and nothing half-happens.
The same goes for bring-your-own-key agents (wallets, private APIs, `🔑 NEEDS API KEY`): save your
key once in Studio and every surface can use it. Ask *"what does this agent need, and am I
connected?"* and the contract's **Credentials** section shows the live status: `✅ connected as
you@…`, `⚠️ NOT connected`, `⚠️ expired — reconnect`, or `🔐 platform-managed`.

**Broad questions about the platform's own structure can be slow.** A question like *"what are all
the categories and how many agents in each?"* can make a client fetch agent cards one at a time.
The `plungeai://agents/categories` resource answers it in one read. Otherwise ask a narrower
question.

**Background runs return immediately.** A long workflow answers with an execution id, not a result.
That is normal. Ask for the result once it has finished ([4.7](/mcp/protocol#47-async-mode)).

**A quiet client is not a stalled run.** If you see no live status while something takes a while,
the run is still fine. Some clients do not display the progress channel at all. Two ways to tell:
the result arrives normally when the call ends, and the run is in your execution history as
`running` the whole time (*"is that still running?"*, or Studio's results sidebar).

**Results are already formatted, so ask for them "in full".** Everything the server returns is
finished Markdown (tables, headings, links), including a step index for multi-step runs and the
whole conversation thread for runs you have followed up on. Chat clients sometimes summarize long
answers anyway. Adding *"show it verbatim, don't summarize"* stops that.

**Give financial agents a company name, ticker or CIK.** `sec-agent` resolves the company from what
you pass, in the order CIK → ticker → name → prompt (its registry card, 2026-09-24). A bare
fragment inside a long sentence resolves worst. *"Latest annual revenue for ticker CRCL"* or
*"Apple insider trading Form 4"* work.

**Data providers run out.** An agent whose upstream plan hit its quota reports that itself. You
get `🚫 UNAVAILABLE` with the agent's own reason, not a broken-looking error ([13.2](/mcp/errors-limits#132-the-structured-feedback-contract)).
Retry later, or use another agent that reads the same data (for company figures, filings via
`sec-agent`).

**Claude Desktop caps a single tool call at about 4 minutes.** For anything longer, ask for it to
run "in the background". You get an execution id at once, and you can ask for its status or result
at any time. The server sends a keepalive line every 15 seconds, but that does not extend a
client's own cap.

**Always let your client pass your words.** Every tool takes `user_request`, the sentence you
actually typed. It shows up at the top of each entry in your activity log (`> **Asked:** …`), which
turns a puzzling call into an obvious one when you debug.
