MCP
Chat, memory & skills
Source: orchestration/mcp-gateway/tools.ts (ChatSchema, plungeaiChat, MemorySchema, plungeaiMemory, LearnSchema, plungeaiLearn), orchestration/mcp-gateway/chat.ts, orchestration/mcp-gateway/tools-bots.ts (the bot actions of 10.4), orchestration/mcp-gateway/extras.ts (registrySigned), orchestration/mcp-gateway/index.ts (argument pre-screen), orchestration/mcp-gateway/server.ts (TOOL_DEFS), core/core-memory/core-memory.ts and core/core-memory/CLAUDE.md, agents/agents/harness-agent/runtime.ts (run journal write).
Three tools keep something for you across calls: a conversation, a memory, a skill. The examples use https://mcp.plungeai.com/v1. https://api.plungeai.com/v1/mcp is the same server.
| Tool | Keeps | Also seen in | Read-only |
|---|---|---|---|
plungeai_chat | conversations with the PlungeAI assistant | Studio's Think tab, ocean-cli chat sessions | no |
plungeai_memory | your long-term memory (notes and a user profile); also reads the run journal | every mission recalls it at start; Studio's harness uses the same store | no (remember writes) |
plungeai_learn | your private skill library | registry skill cards only you can see | no (learn and forget change state) |
Full parameter tables are in the Tool reference.
10.1 Chat: plungeai_chat
A persistent conversation with the platform assistant. One tool, four actions:
action | Needs | Does | Answer |
|---|---|---|---|
send | message; optional conversation_id | sends one turn and waits for the whole reply | the reply, then _(conversation: `<id>`)_ |
new | optional message | creates an empty conversation; message only sets its title | Created conversation `<id>`. Send messages with action "send" and this conversation_id. |
list_sessions | nothing | your 20 most recently updated conversations | # Your conversations (N) and a table: Title, ID, Messages. Or No conversations yet. |
history | conversation_id | the whole conversation | # <title> and every turn as **User:** / **Assistant:** |
The assistant is harness-agent on Anthropic claude-sonnet-4-5, with up to 15 turns and 8,192 output tokens per reply. Its tools are web_search, registry_search, registry_lookup and task_complete. It is told to verify current facts with web search, cite source URLs, and use the registry to find platform agents when relevant. It cannot run workflows or save anything: it has no execute or save tool. When a design is settled, ask your client to build it, and it calls plungeai_build_workflow (Workflows).
One account, three surfaces. A conversation is stored the way Studio stores its plan conversations. The same conversation shows up in Studio's Think tab and in the CLI's ocean-cli chat sessions, and a thread started there can be continued here by its id.
Titles. send without a conversation_id starts a new conversation titled with the first 50 characters of your message. new titles it with the first 50 characters of message, or New conversation when there is none. That title stays: a later first send does not rename it.
Live status. A send reports Thinking…, then Streaming… <n> chars as the reply arrives (Protocol & transport).
Errors (all isError: true):
| Answer | Cause |
|---|---|
message is required for send. | send without message |
conversation_id is required for history. | history without an id |
Conversation not found. | history for an unknown id, or one that is not yours |
Chat error: Conversation not found or not yours | send to an unknown or foreign conversation_id |
Chat error: Harness agent error (HTTP <n>): … | the assistant could not be reached |
One writer per conversation. Two send calls on the same conversation at the same time can lose a turn: the conversation store has no compare-and-swap. Send turns one after another.
Chat or something else?
| You want | Use |
|---|---|
| an open-ended thread with the platform assistant | plungeai_chat |
| a conversation with one specific agent | plungeai_execute_agent with session_id (Agents & missions) |
| more on one finished run, with its context | plungeai_followup (Runs, results & follow-ups) |
Try asking: "Let's design a due-diligence workflow together." The thread persists, so you can come back to it from Studio or the CLI. When you are happy with the design, say "build it".
Send a turn. This runs a model and costs credits (not verified here):
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_chat","arguments":{"user_request":"let us design a due-diligence workflow together","action":"send","message":"Let us design a due-diligence workflow together. What steps would you include?"}}}'List your conversations:
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_chat","arguments":{"user_request":"show my conversations","action":"list_sessions"}}}'Read one back (replace <conversation_id>):
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_chat","arguments":{"user_request":"show me that conversation","action":"history","conversation_id":"<conversation_id>"}}}'10.2 Memory: plungeai_memory
Long-term memory is scoped to you. It has two curated stores:
target | Holds | Default size budget |
|---|---|---|
memory (the default) | notes: facts, preferences and decisions worth keeping | 2,200 characters |
user | a profile of you | 1,375 characters |
The budgets are per-user settings; the numbers above are the defaults.
Who reads it. Every mission (plungeai_run_mission, Agents & missions) recalls both stores at the start of its run and can write to them. This is the same mechanism Studio's harness uses, so a note saved here is known to every later run. The recall is a snapshot taken once per run: a write during a run is saved, but it does not change that run's prompt.
What it is not. Memory is not your run history. There are three separate things:
| Store | What is in it | Read with |
|---|---|---|
| memory | the curated notes and profile above | recall, remember with operation: "read" |
| run journal | the goal and full result of each run the harness agent finished | search_runs, get_run |
| execution history | every execution on your account | plungeai_executions (9.4) |
recall deliberately leaves the run journal out.
Actions.
action | Needs | Does | Answer |
|---|---|---|---|
recall | nothing | returns both stores, memory first, then the user profile | the entries, or No memory recorded yet. |
remember | depends on operation (below) | writes the store that recall reads | Saved to memory (<usage>). recall will see it immediately. or Saved to your user profile (<usage>)… |
search_runs | query; optional limit (default 10) | keyword search over the run journal | # Matching runs and one line per run: `<run id>` — <goal> |
get_run | run_id | one journal entry in full | the stored goal and result, or Run not found. |
forget | exactly one of entry_id or content | entry_id (mem_…, the id GET /v1/memory lists) removes that one entry from its store; content removes every entry containing it from both stores. The same body as One API POST /v1/memory/forget | Forgot <n> memory entries. (entry for one). An id your stores do not hold is Memory entry not found.; both or neither is forget takes exactly one of entry_id or content. (both isError: true) |
recall has no query: it returns all of both stores and your client picks what is relevant.
remember operations (operation defaults to add, target to memory):
operation | Needs | Effect |
|---|---|---|
add | content | appends an entry. An identical entry is not added twice |
replace | old_text and content | replaces the one entry that contains old_text |
remove | old_text | removes the one entry that contains old_text |
read | nothing | lists the entries as # Memory (<target>) with the store's usage |
When a write is refused (all isError: true):
| Answer | Cause | What to do |
|---|---|---|
content is required for remember (what to store; old_text identifies the entry for replace/remove). | a write with neither content nor old_text | pass them |
replace requires old_text and content / remove requires old_text | a half-specified change | pass both |
no entry matched '<text>' | old_text is in no entry | read the store first |
'<text>' matches N entries — use a more specific substring. … | old_text is in several entries | use a longer substring |
Memory at <n>/<limit> chars. … Consolidate now: … followed by Current entries | the write would exceed the budget | replace overlapping entries with shorter ones or remove stale ones, then retry |
blocked: content matched threat pattern '<name>' | the content looks like an instruction-injection attempt | rephrase it as a plain fact |
<target> store failed the round-trip integrity check (externally modified or oversized entry). Current bytes backed up to <path>. … (or entry-size) | the stored file was changed outside the memory tool; its bytes were backed up | repair the file with the raw memory editor, then retry |
search_runs matches the words of your query that are longer than two characters against the goals in the journal, and ranks runs by how many words match. If no word matches, it returns your most recent runs instead of nothing. No matching runs. means the journal is empty. query is required for search_runs. and run_id is required for get_run. are isError: true.
Try asking:
- "What do you remember about Circle's acquisitions?" →
recall - "Remember that our fiscal year ends in June." →
remember - "Find my past runs about Tesla." →
search_runs, then "Show me that run." →get_run - "Forget my old office address." →
forgetwithcontent
Recall (read-only):
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_memory","arguments":{"user_request":"what do you remember about Circle acquisitions?","action":"recall"}}}'Read the raw memory store (read-only):
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_memory","arguments":{"user_request":"show my memory entries","action":"remember","operation":"read","target":"memory"}}}'Save a note. This writes to your memory (not verified here):
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_memory","arguments":{"user_request":"remember that our fiscal year ends in June","action":"remember","content":"Our fiscal year ends in June."}}}'Change it later with "operation":"replace","old_text":"fiscal year","content":"Our fiscal year ends in July.".
Search the run journal (read-only):
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_memory","arguments":{"user_request":"find my past runs about Tesla","action":"search_runs","query":"Tesla","limit":5}}}'10.3 Skills: plungeai_learn
plungeai_learn manages your private skill library. A skill is a reusable piece of know-how, distilled from a source, that you inject into later missions.
action | Needs | Does | Answer |
|---|---|---|---|
learn (the default) | source; optional name, mode | distills the source into a skill with the learn pre-built agent | async (the default): ok with Started distilling `<id>` (async). Poll plungeai_get_workflow_status with this id, then fetch output with plungeai_get_result once completed. and the execution footer. Sync: the run's result |
list | nothing | your learned skills, up to 50 | ok: N learned skill(s). and one line per skill: `<id>` — <description>. Or No learned skills yet. |
forget | name | deletes one of your skills | ok: Forgot skill `<name>`. |
source is a URL, text or Markdown to distill (up to 65,536 characters), or a description of what you just did, such as a workflow you ran. name is the skill id in kebab-case: picked for you on learn when you leave it out, required on forget (take it from list).
How learn runs. It starts a one-task harness workflow named learn whose task points at the learn pre-built agent card. The card is resolved live when the run starts, so an edit to the card changes every later call without a redeploy. The run is a full agent loop (fetch, summarize, save), so it defaults to mode:"async": poll plungeai_get_workflow_status with the execution id, then read the result with plungeai_get_result (Runs, results & follow-ups). It creates an execution in your history and runs a model.
Where skills go. A learned skill is a registry skill card tagged with your user id as its owner. Only you can list it or delete it.
Using a skill. Pass its id in skills on plungeai_run_mission to inject it into the mission (Agents & missions).
Answers. Every answer is the structured outcome envelope (Tools), because the tool declares an outputSchema:
status | Summary | Cause |
|---|---|---|
needs_input | `plungeai_learn` was not called — its arguments do not match the tool's schema. `source`: `source` is required to learn a skill. | learn without source; the gateway checks this before the tool runs |
needs_input | `forget` needs `name` (the skill id from `action: list`). | forget without name |
error | No skill named `<name>`. Use `action: list` to see yours. | no such skill |
unavailable | Not yours to delete: `<name>`. | the skill belongs to someone else |
error | Registry refused the delete (<status>). | the registry failed the delete |
Try asking:
- "Learn a skill from https://developers.cloudflare.com/durable-objects/ (opens in a new tab)."
- "Turn what we just did into a skill called weekly-brief."
- "What skills have I learned?"
- "Forget the weekly-brief skill."
List your skills (read-only):
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_learn","arguments":{"user_request":"what skills have I learned?","action":"list"}}}'Learn one. This starts an agent run and costs credits (not verified here):
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_learn","arguments":{"user_request":"learn a skill from the Durable Objects docs","action":"learn","source":"https://developers.cloudflare.com/durable-objects/","name":"durable-objects-basics"}}}'10.4 Bot chats: bindings, inbox and groups
A saved bot is talked to outside these tools too. Three kinds of conversation around a bot are read and managed with plungeai_workflow (the full action table is 8.6):
| Conversation | action | What it is |
|---|---|---|
| Paired chats | bindings, bind, unbind | the Telegram, WhatsApp, Discord or Teams chats bound to the bot, so that chat talks to it. Pair the chat first; bindings answers a plain "not enabled yet" until the message gateway supports it |
| Bot-to-bot messages | inbox | what other bots queued for this bot's next run |
| A bot group | groups, group_set, group_delete, group_thread | a named set of 2 to 6 of your bots and the thread they share |
Try asking:
- "Which chats are bound to my Outreach bot?" The client runs
bindings. - "Show me what the Sales group has been saying." The client runs
group_threadwithgroup: "Sales".
Reading a group's shared thread is read-only (not run by the docs verifier; it needs a group you made):
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_workflow","arguments":{"user_request":"show me what the Sales group has been saying","action":"group_thread","group":"Sales"}}}'