Files
EvgenyandEvgeny @ SimpleX Chat 46eb5cc001 packages: SimpleX Chat MCP server (#7752)
* packages: simplex-chat MCP server

* update

* standing approvals per chat, leave tool, simplify

* fixes

* add error messages

* LICENSE

* specification

* migration

* update simplex-chat, tests, fixes

* update simplex-chat libraries

* use agent peer type

* better server and tool descriptions

* short readme

* reference

* images

* update readme

* update readme

* update

* change links to master

* fix links to point to master branch

---------

Co-authored-by: Evgeny @ SimpleX Chat <259188159+evgeny-simplex@users.noreply.github.com>
2026-10-19 22:57:25 +01:00

31 KiB
Raw Permalink Blame History

SimpleX MCP server: API

The five MCP tools, the agent control chat commands, replies and cards, and the CLI of @simplex-chat/mcp 0.1.0.

Related specs: README | Architecture | Flows

Source: tools.ts | control.ts | cli.ts | messages.ts | actions.ts


Table of contents

  1. Tools
  2. Agent control chat
  3. CLI

1. Tools

1.1 Common rules

Rule Code
Tools are registered on each per-request McpServer with description, input schema, output schema and, in mode host, _meta: {"anthropic/requiresUserInteraction": true} for connect, send and leave tools.ts:355-365
Tool descriptions and server instructions; the instructions name the agent's display name tools.ts:301-332, serve.ts:109
Arguments are validated by the SDK with Ajv; a failure is a result with isError: true and the text Input validation error: Invalid arguments for tool NAME: ERRORS mcp-BumlNux0.cjs:1812-1817
additionalProperties: false is set in every input schema tools.ts:177, :192, :203, :206, :214
A result is sent as structuredContent and as its JSON in one text item tools.ts:370
A tool error is sent as isError: true with one text item: the ToolError text, or the errorText of other errors tools.ts:372, log.ts:39-43
With a progressToken in _meta, notifications/progress is sent at the start of each wait and every 60 s, with progress 0, 1, 2, ... and a message tools.ts:1011-1021, messages.ts:200-204
The call is aborted when the client closes the response stream or sends notifications/cancelled; the action is kept src-BhnGYybN.cjs:6338-6341, :6425
A call with the same tool and action fields as an action in memory is attached to it tools.ts:1003-1005
Messages are marked read after the last wait of a call that is not aborted tools.ts:460-461, :598-600, :679-680

Action fields of the key:

Tool Fields
connect target
incognito (default false)
message (default null)
send chat
text
reply_to (default null)
mention (default null)
leave chat

Result status of the three action tools:

Status Meaning Extra fields
done performed per tool
failed failure of the card post, the counter write or the perform, or loss of the control chat error
rejected an approver sent /reject
expired no decision before the expiry time
known connect only: the target is an existing chat past the prepared state; no action chat fields

1.2 connect

Handler: AgentTools.connect. Perform: performConnect. Schemas: input, output.

Input:

Field Type Range Default Rule
target string 1 character or more required SimpleX link (https://..., simplex:/...), contact name @name.simplex or channel name #name.simplex; whitespace refused
incognito boolean false true: incognito=on in the connect command
message string 1 to 2000 characters first message of a contact request; plans with takesMessage only
wait number 0 to 86400 60 seconds from the approval: for the other side to accept and, with message, for its first reply
idle number 1 to 300 30 seconds without a new message, after which the server ends the wait for messages

Output fields by case:

Case Fields Code
known status, chat fields of the known chat tools.ts:417
done, chat unknown action, status, type, connected: false, plan fields name, peer_type, description, welcome, commands, known_as when present tools.ts:428, :899-905
done, chat known action, status, chat fields, messages tools.ts:444-464
failed action, status, error tools.ts:435
rejected, expired action, status tools.ts:435

Chat fields (chatFields):

Field Contact Group, business chat or channel
chat @contactId #groupId
type contact business with businessChat; channel with useRelays or group type channel; otherwise group
name profile display name group display name
simplex_name @ + contactDomain.domain when verified # + groupDomainClaim.domain when verified
peer_type profile peer type, when present from the plan, when present
description profile shortDescr group shortDescr
welcome from the plan: link data message group description
commands profile preferences.commands groupPreferences.commands
known_as incognito: customUserProfile of /_info @C incognito: the membership's display name
role the agent's member role
connected active connection status ready membership status connected or complete

messages: message items among the last 50 items of the chat when the result is built, replaced by their collected copies, followed by the items collected since the connection; live items are left out; new items are marked read (tools.ts:446, :456-463).

Tool errors:

Text Condition Code
Not a SimpleX link or name: TARGET whitespace in target, or invalidConnReq from the plan command tools.ts:468, :474
an app error text, for example Name not found: This SimpleX name is not registered. Please check the name., or SimpleX error: CHAIN: DETAILS other errors of the plan command, or a plan of type error tools.ts:475, :826, log.ts:45-47
TARGET can't be joined now: PLAN. invitationLink ownLink or connecting
contactAddress ownLink or connectingProhibit
groupLink ownLink, connectingProhibit, noRelays or updateRequired
tools.ts:817, :830, :848, :870
message: TARGET is not a contact or business address with short link data, or its contact exists without a connection. message given and the plan has takesMessage: false tools.ts:419
refusals see 1.8

takesMessage is true for a contact address with short link data, for a known prepared contact, and for a known prepared business group (tools.ts:821, :841, :859).

1.3 send

Handler: AgentTools.send. Result: sendResult. Perform: performSend. Schemas: input, output.

Input:

Field Type Range Default Rule
chat string required @N or #N of the agent
text string 1 to 12000 characters required sent as one text message
reply_to integer 1 or more item ID in chat
mention integer array 1 to 3, unique, each 1 or more member IDs of a group; names missing from text are prefixed as @name
wait number 0 to 86400 60 seconds from the send; from the call when it attaches to a done action
idle number 1 to 300 30 seconds without a new response, once one arrived
limit integer 1 to 100 50 most responses returned

Output:

Field Presence Value
action always action number
status always done, failed, rejected, expired
chat done the chat reference
item done item ID of the sent message
responses done received message items with IDs above item, in arrival order, live items left out, at most limit
more done collected responses not returned, live ones and overflow included
error failed error text

Tool errors:

Text Condition Code
No chat CHAT. list shows the agent's chats. invalid reference, the control chat, or a store error when the chat is read tools.ts:714-721
The agent has role ROLE in CHAT and can't post. membership role observer or relay tools.ts:576-579
reply_to: CHAT has no item N. the read of around=N fails, or the item is absent from it tools.ts:723-728
mention: CHAT is a contact chat; mentions apply to groups and channels. mention with @N tools.ts:731
mention: CHAT has no member N. ID absent from /_members tools.ts:735
refusals see 1.8

1.4 receive

Handler: AgentTools.receive. Schemas: input, output.

Input:

Field Type Range Default Rule
chat string required @N or #N of the agent
wait number 0 to 86400 0 seconds to wait when no message is new
limit integer 1 to 100 50 most messages returned

Output (all fields always present):

Field Value
chat the chat reference
messages unread received messages in chat order, then received messages that arrived during the call; live items left out; at most limit
more new messages not returned, overflow, and unread items left unread by the page reads

Tool errors: No chat CHAT. list shows the agent's chats. for an invalid reference, the control chat, or a store error while the unread items are read (tools.ts:655, :659-661); other chat errors as their error text (log.ts:39-47).

Messages are read by receive without an action or an approval.

1.5 list

Handler: AgentTools.listChats. Schemas: input, output.

Input: an empty object.

Output:

Field Item fields
chats chat
type
name
simplex_name, when verified
peer_type, when present
incognito
known_as, when incognito
connected
unread: chatStats.unreadCount
approved: true, only under a standing approval in mode requests
actions action
tool
input: the input of the creating call
state
open: true while a call waits on it

chats: the contacts and groups from /_get chats USER pcc=off, paged by 100 with before=CHAT_TS, except the control chat (tools.ts:698-712). actions: every action in memory (tools.ts:694).

1.6 leave

Handler: AgentTools.leave. Perform: performLeave. Schemas: input, output.

Input: chat, string, required, @N or #N of the agent.

Output:

Field Presence Value
action always action number
status always done, failed, rejected, expired
chat done the deleted chat
error failed error text

Perform:

Chat Commands
@N /_delete @N full
#N /_leave #N while the membership is current, pending_approval or pending_review
/_delete #N full

Tool errors: No chat CHAT. list shows the agent's chats. when no action with the same key is in memory and the chat is invalid, the control chat or unknown (tools.ts:634-636); refusals.

1.7 Message and command objects

Message (Message, toMessage, schema):

Field Type Presence Source
chat string always chat reference of the item
item integer always meta.itemId
from string always groupRcv: member display name
directRcv: contact display name
channelRcv: channel display name
sent items in connect: the agent's name in that chat
from_member integer groupRcv groupMemberId
from_type string when the profile has a peer type sender's peerType; the agent's own for its non-incognito items in connect
time string always meta.itemTs
text string always msgContent.text
new boolean always item status rcvNew when read
reply_to object quoted item with an ID {chat, item: quotedItem.itemId}
mentions_me boolean always meta.userMention

Only received message items (rcvMsgContent) are returned by send and receive; connect also returns sent ones (sndMsgContent) (messages.ts:73, :123-125).

Command (commandsOf, schema):

Form Fields
command keyword
label
params, when present
menu label
commands: commands and menus

1.8 Action refusals

Refusals of a new connect, send or leave action, first match (actions.ts:136, control.ts:105-111):

Text Condition
The server is stopping. Actions.stop has started
The agent lost its control chat. The person who runs it has to restart it with --reset-owners. control chat lost
20 actions are pending; wait for the owner's decisions. 20 actions in state pending
text: too long for its approval card; shorten it. send whose largest card form exceeds 15000 bytes
The agent has no owner. The person who runs it has to join its control chat with the link the server printed. no approver, --owners absent
The agent has no approving owner. The person who runs it has to restart it with the --owners options it printed. no approver, --owners given

Largest card form (control.ts:476-484): the maximum of the creation form, the done form and a failed form with an error of 600 × €, with the action's own decider or the longest current approver name; each form is measured as JSON-escaped UTF-8: ", \, \n, \r, \t 2 bytes, other characters below U+0020 6 bytes.


2. Agent control chat

2.1 Commands and replies

Accepted text (parseCommand, ownerRequest):

message   one line, an optional trailing newline
line      spaces, "/", KEYWORD, PARAMS
KEYWORD   characters up to the first whitespace
PARAMS    the rest, trimmed, split on whitespace
CHAT      @N or #N, 1 to 15 digits
requests
  approve N
  approve CHAT N
  reject N
  reject CHAT N
  approve CHAT all
  revoke CHAT
  pending
  list

The server ignores other text. It answers a command with a reply that quotes it (control.ts:142), and it runs the expiry check before each command (control.ts:164).

Request Condition Reply Code
one-line / text outside the requests any sender Commands: /approve, /reject, /revoke, /pending, /list. Each card shows its commands. control.ts:15, :166
any request sender not an approver, --owners absent Only owners approve actions. control.ts:167
any request sender not an approver, --owners given Only the owners listed in --owners approve actions. control.ts:167
approve, reject action N absent, not pending, or without a card Action N is not pending. control.ts:182
approve CHAT N, reject CHAT N action N is a connect, or for another chat Action N is not for CHAT. control.ts:183
approve, reject accepted none; the card is edited at the outcome control.ts:184-187
approve CHAT all CHAT unknown or the control chat No chat CHAT. /list shows the agent's chats. control.ts:194
approve CHAT all accepted Approved for KIND NAME (CHAT) by APPROVER. /'revoke CHAT' control.ts:202
revoke CHAT CHAT unknown, or without a standing approval Messages to CHAT have no standing approval. control.ts:207
revoke CHAT accepted Messages to KIND NAME (CHAT) need approval again. control.ts:210
pending no pending action with a card No pending actions. control.ts:171
pending otherwise one line per action: N WHAT expires YYYY-MM-DD HH:MM UTC control.ts:170, :472-474
list no chats No chats. control.ts:220
list otherwise one line per chat: CHAT KIND NAME, then , approved for this chat by APPROVER and , not connected when applicable control.ts:213-221

KIND is contact, bot, agent, business, group or channel (tools.ts:928-935). WHAT is connect to SUBJECT, send to SUBJECT, delete SUBJECT or leave SUBJECT (actions.ts:268-278). Names are shown by safeName (control.ts:498-501).

2.2 Cards

Card text: request lines, then one last line (cardText, requestLines).

Request lines:

Tool First line Further lines
connect I want to connect to SUBJECT, as myself. or , incognito.
done and connected: I connected to ...
done and not connected: I asked to connect to ...
link description, one code span per line
welcome, one code span per line
with message: With the message: and its lines
send I want to send a message to SUBJECT:, with , where I am incognito before the colon in incognito chats
done: I sent a message to ...
text, one code span per line
replying to NAME: QUOTE with reply_to
mentioning @A, @'B C' with mention
leave I want to delete KIND NAME (@N). or I want to leave KIND NAME (#N).
done: I deleted ... or I left ...

SUBJECT is KIND NAME, or an unnamed KIND, followed by (SIMPLEX_NAME) when known (actions.ts:263-266). For connect, SIMPLEX_NAME is the target when it is a name; for send, the chat's verified SimpleX name.

Last line:

State Condition Last line
pending command line
pending interrupted Cancelled: the server stopped.
performing interrupted DECIDER; interrupted: the server stopped.
done standing Approved for this chat by NAME. /'revoke CHAT'
done DECIDER.
failed DECIDER; failed: `ERROR`.
rejected Rejected by NAME.
expired Expired.

DECIDER is Performed without approval (mode host) in mode host, Approved for this chat by NAME for a standing send, and Approved by NAME otherwise (control.ts:419).

Command lines (commandsLine):

Tool Command line
connect /'approve N' or /'reject N'
send /'approve CHAT N', /'approve CHAT all' or /'reject CHAT N'
leave /'approve CHAT N' or /'reject CHAT N'

The app shows /'approve N' as the tappable command /approve N (PLAN, What the owner sees).

2.3 Membership messages

Posted in the chat and logged; in the chat, names are shown by safeName and the --owners ... part is a code span; in the log, names are folded to one line (control.ts:322-325, :64-65).

Situation Text Code
owner joined, --owners absent I'm your agent. I ask here before I connect or send. (chat only) control.ts:19, :270
member joined, --owners without a list NAME joined (member ID). Restart the server with --owners ENTRIES control.ts:275-278
start with --owners without a list and humans present A joined (member ID). B joined (member ID). Restart the server with --owners ENTRIES control.ts:242-245
a human became owner outside the list NAME (member ID) is now an owner and can't approve actions yet. Restart the server with --owners ENTRIES control.ts:283-287
a listed owner stopped being a human owner NAME (member ID) is no longer an owner. Restart the server with --owners ENTRIES
none remains: NAME (member ID) is no longer an owner. No owners remain: restart the server with --reset-owners --owners
control.ts:288-293

ENTRIES: ID:NAME of each human, or of each human owner, joined by commas; an entry with characters other than letters, digits, _ and - is quoted for the shell (control.ts:581-591).

2.4 Group profile

Field Value Code
display name the agent's display name, updated at start when it differs control.ts:91-93
full name empty control.ts:377
description Supervise your AI agent here: approve or reject its connections and messages with one tap. control.ts:378
history on control.ts:379
command menu /pending "Pending actions"
/list "Chats and approvals"
updated at start when it differs
control.ts:10-13, :91-93

3. CLI

Binary: simplex-mcp, compiled dist/cli.js (package.json:5-7). Help text: cli.ts:10-35.

simplex-mcp --help
simplex-mcp serve NAME [options]
simplex-mcp register NAME [options]

NAME: 1 to 32 characters of [a-z0-9] and single hyphens, starting with a letter or digit (cli.ts:142-144).

3.1 serve

Option Value Default Rule Code
--data folder ~/.simplex-mcp/NAME resolved to an absolute path; dataGiven is set cli.ts:65-68
--display-name text NAME when the user is created must equal validName(text) cli.ts:69-71, :146-150
--approve requests or host requests cli.ts:72-74
--owners absent value, or ID:NAME,... absent the value is absent when the next argument is missing or starts with --; entries match ^([1-9]\d*):(.+)$ cli.ts:75-77, :167-171
--expire hours 23 integer 1 to 23 cli.ts:78-80
--reset-owners flag off refused with an --owners list cli.ts:81-83, :97-99
--new-token flag off cli.ts:84-86
--port number 5226 integer 1 to 65535 cli.ts:87-89
--qr-code small or large small cli.ts:90-92

3.2 register

Option Value Default Code
--scope user or local user cli.ts:107-109
--data folder ~/.simplex-mcp/NAME cli.ts:110-112

Entry (registryEntry):

Field Value
type http
url http://127.0.0.1:PORT/mcp
headersHelper cat DATA/headers.json, Windows type DATA\headers.json, path shell-quoted
timeout (expireHours + 24) × 3600000 + 600000 ms

Server name: simplex-NAME (register.ts:33).

3.3 Exit codes and messages

Code Message Code location
0 --help text on stdout; a stop after a signal cli.ts:194-196, serve.ts:53
2 Usage: simplex-mcp serve NAME [options] or simplex-mcp register NAME [options]. Run simplex-mcp --help. cli.ts:45
2 NAME: 1 to 32 lowercase letters, digits and single hyphens, starting with a letter or digit. cli.ts:46
2 OPTION: a value expected. cli.ts:131
2 Unknown option OPTION. Run simplex-mcp --help. cli.ts:184
2 --display-name: not a valid SimpleX name; try VALID cli.ts:148
2 --approve: requests or host expected, got VALUE cli.ts:153
2 --qr-code: small or large expected, got VALUE cli.ts:158
2 --scope: user or local expected, got VALUE cli.ts:163
2 --owners: ID:NAME expected, got ENTRY cli.ts:169
2 --expire: hours from 1 to 23 expected, got VALUE cli.ts:79, :175
2 --port: a port from 1 to 65535 expected, got VALUE cli.ts:88, :175
2 --reset-owners takes --owners without a list: member IDs change in a new agent control chat. cli.ts:98
2 --owners: member ENTRY is not in the agent control chat. Start with --reset-owners --owners, or use the IDs of current members. control.ts:251
1 Another server uses DATA (PID N). files.ts:21, :23
1 Port PORT is in use. Start with --port N. serve.ts:205
1 Agent "NAME" was never started. Start it with: npx -y @simplex-chat/mcp serve NAME register.ts:32
1 Add this entry under LOCATION in ~/.claude.json: {"simplex-NAME": ENTRY} register.ts:52-55
1 claude mcp add-json failed: STDERR register.ts:39
1 simplex-mcp: ERROR for other errors, stop: ERROR for a failed stop cli.ts:210-211, serve.ts:55-56

LOCATION is "mcpServers" for scope user, and "projects" > "PROJECT" > "mcpServers" for scope local (register.ts:53).

3.4 Terminal lines

stdout (log.ts:31-33):

Moment Line Code
start SimpleX MCP server VERSION, agent "NAME"
Data folder: DATA
Approval mode: MODE
serve.ts:72-74
control chat created Agent control chat "DISPLAY" created. control.ts:383
link opened Join the agent control chat in the SimpleX app. The link works once:
QR code
link
small QR code: If the QR code does not scan, restart with --qr-code large, or paste the link into the app.
role line
control.ts:304-310
listening Listening on http://127.0.0.1:PORT/mcp serve.ts:120
owner setup done Add the agent to Claude Code:
npx -y @simplex-chat/mcp register NAME [--data DATA]
serve.ts:164-166
owner joined NAME joined (member ID) and is now an owner. The link is deleted. control.ts:271
listed owners set Owners: ENTRIES. control.ts:262
approvers gone, --owners absent No owners in the agent control chat. control.ts:20, :157, :238
control chat lost The agent lost its control chat. Restart the server with --reset-owners. control.ts:298
action created Action N: WHAT with , as itself or , incognito for connect and (CHAT) for send and leave actions.ts:140-141, :268-278
perform ended, mode requests Action N approved by NAME: RESULT. with RESULT sent, deleted, left, connected, connection requested or failed: ERROR actions.ts:238, :284-291
perform ended, mode host Action N: performed without approval (mode host)., or ...; failed: ERROR. actions.ts:286
rejected Action N rejected by NAME. actions.ts:188
expired Action N expired. actions.ts:158
stop Cancelled K action. or Cancelled K actions. when K > 0
Stopped.
serve.ts:155, :159
membership messages see 2.3

stderr: CONTEXT: ERROR from logError (log.ts:35-37), with CONTEXT one of action N, action N card, control chat command, EVENT in the agent control chat, EVENT event, MCP, HTTP request, stop, simplex-mcp. The library's download lines are written to stderr, and its event processing errors to stdout (libs.ts:114, api.ts:187).