Files
simplex-chat/packages/simplex-chat-mcp/TESTING.md
T
Evgeny @ SimpleX Chat be668564df mcp server: files, /leave and library methods (#7962)
* bots, nodejs: document chat, connection, member contact and network commands, typed commands in library

* bots, nodejs: restore apiConnect, wrap domain once, test all connect responses

* nodejs: JSDoc for new methods

* docs: plan for bot API commands and typed Node library methods

* tests: channel prepared with a domain has a verified SimpleX name

* docs: apply review fixes to the plan for bot API commands

* docs: apply second review pass to the plan for bot API commands

* docs: refer the bot API plan to the rewritten test commit

* docs: record decisions in the plan for bot API commands

* docs: plan tests of the generated Python command strings

* python: test the generated strings of the documented commands

* docs: plan for files, /leave and library methods in the MCP server

* docs: wait at stop in the MCP plan

* docs: library methods and /leave mechanics in the MCP plan

* mcp: typed library methods for chat commands

* docs: plan the message information command for bots

* mcp: /leave CHAT owner command to leave a chat at once

* docs: file servers, GIF and video choices decided in the MCP plan

* docs: file mechanics in the MCP plan

* mcp: files of received messages

* bots, nodejs: message information with the file servers for bots

* docs: plan the relay approval option of receiving files in Node

* mcp: download of received files with owner approval

* docs: name the xftp-server test helper in the files plan

* nodejs: receive files without approving unknown relays

* docs: plan the user servers command for bots

* bots, nodejs: user servers and relays by operator for bots

* nodejs: document the message information method

* docs: plan the file upload progress event for bots

* mcp: send files with owner approval, refusing private keys

* bots: file upload progress event for bots

* mcp: /leave template in the agent control chat menu

* docs: sent copies are deleted for contacts too, at sndFileCompleteXFTP

* bots: drop the file upload progress event

* docs: drop the upload progress event plan

* nodejs: document user servers and relay approval of received files

* mcp: download cards name unknown file servers after the upload

* docs: record the wait for the file description in the files plan

* mcp: fixed wait at stop for cancelled cards, without /sql

* docs: record decision C4, a fixed wait at stop, in the files plan

* ci: test the MCP server package on pull requests

* ci: state when the MCP workflow can be dispatched

* ci: run the MCP server tests when its libraries change

* mcp: log the errors of image previews and resizing

* mcp: keep files in transfer in the data folder

* mcp: restrict sent files by the real paths of refused folders

* mcp: validate the file at the send by its inode and change time

* mcp: limit ffmpeg and ffprobe to local files and no input commands

* mcp: ask the owner for unknown file servers; read approvals at creation

* mcp: name downloaded files by their ID; return paths of downloads only

* mcp: end each download with a result for the agent and the card

* mcp: show files above their sender's size limit as failed

* mcp: refuse empty files, as without file and captions too long to send

* mcp: tell the owner about failed uploads and unposted received files

* mcp: delete resized copies left by the last run at start

* mcp: name downloads and leaving in the help and greeting, align docs

* mcp: compute the download path for received files only

* mcp: send a /receive file to the owner under its name

* mcp: keep files received without a download in the chat's folder

* mcp: keep a left chat's files and delete them with /delete CHAT files

* mcp: test that sent images are resized by the core

* mcp: wait 30 minutes for a download's progress before cancelling it

* mcp: end a download as deleted only when its message is not found

* mcp: delete the copy of a /receive file whose post fails

* mcp: count the quoted content in a message's length, as the core sends it

* mcp: name received bytes, unknown-server downloads and left chat files plainly

* mcp: test refused folders, file changes and download approvals

* docs: align MCP server docs with refused folders, leaves and download waits

* mcp: move received files only in full, delete partials only of downloads

* mcp: report a received file missing from its folder as failed

* mcp: move received files of a group's member chats into its folder

* mcp: read a video's preview and duration as an MP4 or QuickTime file

* mcp: 0.2.0 on simplex-chat 7.1.0-beta.10.1

* mcp: file folders by chat type, /delete cancels downloads, files reply

* docs: MCP server specs and plan for 0.2.0

* mcp: /receive gives the agent a file, /forward sends it to the owner

* docs: MCP server specs for /receive and /forward of download cards

* docs: MCP plan records the temp folder command as a library exception

* mcp: /delete cancels resumed downloads; /forward quote fits the limit

* docs: MCP specs and plans for /forward quotes and resumed downloads

* docs: MCP specs name the source commit they are checked against

* docs: MCP PLAN states the /forward quote and move rules

* mcp: a download moves its completed file whatever its size

* mcp: /receive N all covers its card and later files, not pending ones

* docs: MCP files approval scope, reply text and README server wording

* mcp: a download approves relays only for a card naming unknown servers

* mcp: files in member chats of a group are tracked as in the main chat

* docs: MCP relay approval of downloads and files in member chats

* mcp: a rejected file gets a card again under the files approval

* docs: MCP rejected files under the files approval, README scope

* mcp: an offered file without a description gets no card or action

* docs: MCP a file without a description is not downloaded

* mcp: 0.2.0 on simplex-chat 7.1.0-beta.10.2

* ci: test the MCP server as a scope of build-linux
2026-11-06 18:38:34 +00:00

12 KiB
Raw Blame History

Testing @simplex-chat/mcp v0.2

Node.js 22. Claude Code runs on the same computer as serve: the server listens on 127.0.0.1 only.

Build

Here

All commands run in /code/simplex-chat-6/packages/simplex-chat-mcp. The dependencies are installed by npm install; simplex-chat comes from npm and downloads libsimplex and its Node.js add-on to ~/.cache/simplex-chat at the first start.

node node_modules/typescript/bin/tsc
node node_modules/jest/bin/jest.js test/unit     # about 10 s
SMP_SERVER=/code/steward/node_modules/.cache/smp-server/smp-server-v7.1.0-beta.3 XFTP_SERVER=/code/simplexmq-5/dist-newstyle/build/x86_64-linux/ghc-9.6.3/simplexmq-7.1.0.9/x/xftp-server/build/xftp-server/xftp-server node node_modules/jest/bin/jest.js test/e2e      # about 4 minutes; a local smp-server and xftp-server on free ports

node_modules is not writable here, so the end-to-end test takes the smp-server and xftp-server binaries from SMP_SERVER and XFTP_SERVER instead of downloading them to node_modules/.cache.

On your own machine

  1. Check out simplex-chat master; the package is packages/simplex-chat-mcp.
  2. In that folder: npm install, then npx tsc. tsc leaves the output of deleted sources in dist; npm pack and npm publish delete dist first and build it again (script prepack).
  3. node dist/cli.js serve my-agent --display-name "My Agent". At the first start, simplex-chat downloads libsimplex and its Node.js add-on, with a Downloading ... line each on stderr.
  4. Tests: npx jest test/unit; npx jest test/e2e downloads smp-server and xftp-server v7.1.0-beta.3 on Linux, and elsewhere takes SMP_SERVER=/path/to/smp-server XFTP_SERVER=/path/to/xftp-server.

Until the package is published, the printed hint npx -y @simplex-chat/mcp register my-agent stands for node dist/cli.js register my-agent.

Start, join, register

  1. node dist/cli.js serve my-agent --display-name "My Agent". NAME, here my-agent, names the data folder and the Claude Code entry; --display-name is the name people see in SimpleX. It prints the data folder (~/.simplex-mcp/my-agent), creates the agent control chat "My Agent", and prints a QR code and a link that works once. For a short link the QR code has 33 modules and takes 37 columns × 19 lines; --qr-code large prints it at 74 × 37. Keep it running; Ctrl-C stops it. node dist/cli.js --help lists the options.
  2. In the SimpleX app, scan the QR code, or paste the link into "Connect via link". If the code does not scan, restart with --qr-code large. The chat "My Agent" appears with I'm your agent. I ask here before I connect, send, download a file or leave a chat. The terminal prints Alice joined (member N) and is now an owner. The link is deleted. and the register hint.
  3. node dist/cli.js register my-agent. It prints Added to Claude Code: scope user, server simplex-my-agent. Run it in a terminal with the same CLAUDE_CONFIG_DIR as the one where claude runs: claude mcp add-json writes to the config of its own environment.
  4. Add "mcp__simplex-my-agent" to permissions.allow in ~/.claude/settings.json, so Claude Code does not prompt for each call; approval happens in the SimpleX app.
  5. Start claude. /mcp shows simplex-my-agent connected with 6 tools. A session started before register does not load the entry; start a new one.

Try the tools

Prompts for Claude Code, one at a time. A call that waits more than 2 minutes, for example for an approval, moves to a background task, and its result arrives as a notification.

By name, first:

  • Connect to @directory.simplex as yourself. While the name is not registered: the tool error Name not found: This SimpleX name is not registered. Please check the name., and no card. Once it is registered: the card I want to connect to bot SimpleX Directory (@directory.simplex), as myself.; after the approval, step 1 below returns status: known, with no card.

The directory by its address (docs/DIRECTORY.md):

  1. Connect to the SimpleX Directory as yourself at https://smp4.simplex.im/a#lXUjJW5vHYQzoLYgmi8GbxkGP41_kjefFvBrdwg-0Ok and tell me which commands it advertises. Card: I want to connect to bot SimpleX Directory, as myself. Tap /approve 1. The card becomes I connected to ... with Approved by Alice.; Claude gets status: done, the chat @N, commands and the welcome message.
  2. Search the directory for hiking groups. Card: I want to send a message to bot SimpleX Directory: with the text. Approve it; Claude gets the bot's answers in responses.
  3. Send /help to the directory. A bot command is sent as text.
  4. Check for new messages from the directory, waiting up to 60 seconds. receive with wait.
  5. List your chats and pending actions. list.
  6. Reject one card with its /reject @N A: the call returns status: rejected; the card ends with Rejected by Alice. /pending lists the waiting cards.

Approval of all messages to a chat, and leaving:

  1. Search the directory for Monero groups. On the card, tap /approve @N all. The reply is Approved for bot SimpleX Directory (@N) by Alice. /revoke @N, and the search is sent.
  2. Send /help to the directory. It is sent without a card; the agent control chat then gets I sent a message to bot SimpleX Directory:, `/help` and Approved for this chat by Alice. /revoke @N. list shows approved: true for the directory.
  3. Tap /list in the command menu: one line per chat; the directory's line ends with , approved for this chat by Alice.
  4. Tap /revoke @N: Messages to bot SimpleX Directory (@N) need approval again. The next send gets a card.
  5. Leave the directory. Card: I want to delete bot SimpleX Directory (@N). Approve it: the call returns status: done, and list no longer shows the directory.
  6. Join a group from the search results, then Leave that group. Card: I want to leave group <name> (#N). Approve it: the members see that the agent left.

A channel:

  1. Search the directory for channels about trail running. Take a channel link from the answers.
  2. Connect to <the channel link> as yourself. Card: I want to connect to channel <name>, as myself. Approve it; Claude gets type: channel, role: observer and the recent posts in messages.
  3. Wait up to 10 minutes for a new post in that channel. receive with wait returns the next post.

Files, in a group of yours:

  1. In the app, create a group and copy its link. Connect to <the group link> as yourself. Approve the card.
  2. Send a photo to the group from the app. Check for new messages in that group. The message has file with type: image and status: offered.
  3. Download that photo. Card: I want to download a file from Alice in group <name> (#N):, with the photo's preview, the file name, its size, and Servers: known. when the app uploaded it to servers the agent also has. For a large video asked for right after sending it, the call waits until the upload finishes, and only then the card appears.
  4. Tap /forward #N A: the photo arrives in the agent control chat, as a reply to the card when its preview and the card fit in one message, and the card stays pending; ~/.simplex-mcp/my-agent/files/group-N/ has no file, and the photo is in ~/.simplex-mcp/my-agent/forwarded/group-N/.
  5. Tap /receive #N A: the call returns status: done and the path, ~/.simplex-mcp/my-agent/files/group-N/<file ID>.jpg.
  6. Send a document, Download that file., and tap /receive #N A all on its card: the reply is Files approved for group <name> (#N) by Alice. /receive #N off, and the download completes. The next file downloads with no card; /list shows , files approved by Alice. Tap /receive #N off.
  7. Send another file, Download it., and tap /reject #N A: the call returns status: rejected.
  8. Send the photo /home/alice/trail.jpg to that group, with the text "trail map". Card: I want to send a message to group <name>:, `trail map` and attaching image `/home/alice/trail.jpg`, SIZE, with the photo's preview. Approve it: the group gets the photo, resized to at most 261120 bytes, with its preview.
  9. Send ~/.ssh/id_ed25519 to that group. The call returns the error file: /home/alice/.ssh/id_ed25519 is refused: ..., and the agent control chat gets Refused to send `/home/alice/.ssh/id_ed25519` to group <name> (#N): .... A symbolic link to the key gets the same refusal, with the key's real path.
  10. With ffmpeg installed, Send /home/alice/ride.mp4 to that group.: the card and the message show the video's first frame and its duration; without ffmpeg, a gray preview and duration 0.
  11. Tap /leave #N: after the reply, the agent posts Files from group <name> (#N) are kept in `~/.simplex-mcp/my-agent/files/group-N`: K files, SIZE. /delete #N files. Tap /delete #N files: Deleted K files from #N, SIZE.; again: No files from #N.

Incognito, as a second agent, because the first one already knows the directory:

  1. node dist/cli.js serve scout --display-name "Scout" --port 5227; join its control chat "Scout" with the printed link; node dist/cli.js register scout; add "mcp__simplex-scout" to permissions.allow; /mcp reconnect all.
  2. Using simplex-scout, connect to the directory incognito: https://smp4.simplex.im/a#lXUjJW5vHYQzoLYgmi8GbxkGP41_kjefFvBrdwg-0Ok Card: I want to connect to bot SimpleX Directory, incognito. Approve it; Claude gets known_as, a random name.
  3. Using simplex-scout, list your chats. The directory has incognito: true and the same known_as. A send card for it says where I am incognito.

Stop and restart:

  • Stop the server while a card waits: the terminal prints Stopping: sending 1 cancelled card, up to 10 s. Ctrl-C to stop now., and the card ends with Cancelled: the server stopped. A second Ctrl-C during the wait stops the server at once. With no card waiting, Ctrl-C stops it at once. After a restart, /approve of that number replies Action N is not pending., and the next card has the next number.
  • A second serve my-agent on the same data folder exits with Another server uses ... (PID N). If no server runs, remove .../lock. A port in use exits with Port 5226 is in use. Start with --port N., before any link is printed.
  • Restart with --new-token, without register: after the reconnection, list returns the chats. Checked with claude -p and an --mcp-config entry with headersHelper, Claude Code 2.1.302, 2026-10-18.

Claude Code checks

  1. C2, protocol: passed with Claude Code 2.1.302 in the default runtime, with MCP_PROTOCOL_NEGOTIATION=legacy and with MCP_SDK_GENERATION=v1. To repeat it, write c2.json with {"mcpServers": {"simplex-my-agent": {"type": "http", "url": "http://127.0.0.1:5226/mcp", "headersHelper": "cat <your home folder>/.simplex-mcp/my-agent/headers.json"}}}, and run it once as is and once with each variable before it:
    claude -p "Call the list tool and show its result." --strict-mcp-config --mcp-config c2.json --allowedTools mcp__simplex-my-agent
    
    Each run shows the chats, with the preset contact "Ask SimpleX Team".
  2. C3, subagent: Use a subagent to send "trail shoes" to the directory. While the card waits, the subagent's call stays in the foreground, with no background task; it returns after /approve.
  3. C4, reconnect: restart serve my-agent; in the running session, /mcp reconnect all; list returns the chats.
  4. C5, register again: node dist/cli.js register my-agent prints Added to Claude Code: scope user, server simplex-my-agent.; claude mcp list shows one simplex-my-agent.
  5. C6, Esc: ask for a send, and press Esc while its card waits; List your pending actions. shows the action with open: false; the same request again attaches to it, and /approve returns the result to that call.
  6. Host mode: restart with node dist/cli.js serve my-agent --approve host, then /mcp reconnect all. Send /help to the directory. makes Claude Code prompt, despite the allow rule; so does leave. After you allow it, the agent control chat gets I sent a message to bot SimpleX Directory:, `/help` and Performed without approval (mode host). A connect to a link not yet joined gets the same prompt and an outcome card; a target already joined returns status: known, with no card.