Reachpad Mcp

io.github.Reachpad由 GitHub 帳號 Reachpad 發布v0.4.2更新於 Oct 24, 2026

Coding agents build full-stack apps in persistent workspaces and share them by link.

已驗證Streamable HTTP可網頁執行雲端與基礎設施開發者工具安全與監控

概覽

AI 產生的概覽

Reachpad 的 MCP 伺服器讓編碼代理在持久化雲端工作區中建置並發布全端應用程式,以連結分享,無需另外部署。

可以做什麼
建立、讀取、更新、發布與移至垃圾桶應用程式,回復到舊版本,或變更存取範圍(擁有者、組織內、含密碼與到期日的公開連結)。以電子郵件分享應用程式、列出與撤銷分享,並以圖片預覽線上連結目前呈現的內容。在資料夾中瀏覽與整理應用程式:列出、樹狀檢視、建立、移動,以及刪除空資料夾。對函式應用程式自帶的資料庫執行單一 SQL 敘述來讀取或修正資料,並讀取線上函式應用程式的近期日誌。依名稱管理組織密鑰:列出、設定(輪換到綁定的版本)與移除。查看目前登入的帳號與組織,並依名稱、slug 或頁面文字搜尋應用程式。
適用情境
適合希望代理直接產出可用的網頁應用程式並提供連結、而不只是程式碼的情境;也適合需要對應用程式做版本管理、存取控制、分享、資料夾整理,或透過 SQL 做小範圍資料修正時使用。團隊把應用程式密鑰集中存放在組織密鑰庫而非檔案中時同樣適用。
執行需求
需要 Reachpad 帳號,以及從 reachpad.dev 取得的每使用者憑證,透過環境變數 REACHPAD_IDENTITY_CREDENTIAL 提供。可作為遠端端點執行,也可作為本機 npm 套件(npx @reachpad/mcp)以 stdio 或 streamable HTTP 執行;REACHPAD_ENDPOINT 指定主機,預設為 m1.reachpad.dev。需要能存取 Reachpad 主機的網路。
安裝前請注意
此憑證對應一個帳號並代表其行事,應視為機密。發布會立即產生線上連結,存取範圍預設為組織內任何已登入使用者;公開連結則任何取得網址的人都能開啟。設定密鑰會替換其值並輪換到所有綁定它的已發布版本,移除密鑰會從這些版本中刪除。查詢工具可以修改資料列,移至垃圾桶會立即讓連結失效。連接埠連結並非私密網址。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Reachpad Mcp,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Web executable,透過 Streamable HTTP。 遠端服務在工作區中設定後即可從網頁執行環境執行。

交給代理程式安裝

把這段提示詞貼上到 Claude Code、Codex、Cursor 等代理程式,或 SourceWeft 對話中。代理程式會讀取該伺服器的安裝指南,先向你展示發布者、端點和登入方式,經你同意後再把它新增到你的客戶端。金鑰不會寫進任何命令。

閱讀 https://sourceweft.com/mcp/io.github.Reachpad%2Freachpad-mcp/install.md,並按其中說明把這個 MCP 伺服器接入我的客戶端。修改任何設定之前,先告訴我它的發布者、端點和登入方式,等我確認。不要把 API 金鑰寫進命令或我會提交的檔案;問我金鑰應從哪裡取得。

檢視代理程式所依據的安裝指南

其他 MCP 客戶端

把它新增到你客戶端的 mcpServers 設定中。

{
  "mcpServers": {
    "reachpad": {
      "type": "http",
      "url": "https://reachpad.dev/mcp"
    }
  }
}

README

@reachpad/mcp

reachpad lets Claude, Codex and other coding agents build full-stack apps in persistent workspaces and share them by link, without a separate deployment. A workspace is a cloud development computer an agent operates itself: a repo, a filesystem, installed dependencies and build state that all survive between calls, not an ephemeral sandbox that forgets. Processes are the exception; see below.

This is the MCP server. It lets Claude, ChatGPT, Cursor, OpenCode or your own agent create a workspace, run commands in it, fork it, and come back to it later, without a developer keeping a laptop open for them.

  • It persists. Pause it and the disk is sealed; the next call boots from that seal with the files, installs and git state intact, rather than rebuilding. Processes are the exception: a start is always a cold boot.
  • It forks. Twenty attempts from one prepared state cost a delta each, not twenty rebuilds — because the workspace is a snapshot chain, not a machine.
  • It can keep secrets out of the workspace. A brokered credential is called at the boundary on your behalf and its value never enters the workspace, the log or the store. A credential written into the workspace instead is readable there, by design.
  • It is agent-agnostic. The REST API is canonical; this server, the SDK and the CLI are translations of it. Bring your own agent.

The API is the product boundary, not a web UI: reachpad.dev.

Install

sh
npx -y @reachpad/mcp          # stdio, for a local client

In Claude Code:

sh
claude mcp add reachpad -e REACHPAD_IDENTITY_CREDENTIAL=… -- npx -y @reachpad/mcp

Two transports, one implementation

sh
npx @reachpad/mcp                                  # stdioREACHPAD_MCP_HTTP_PORT=8722 npx @reachpad/mcp      # streamable http

stdio is what a local client talks to; Streamable HTTP is what a remote connector talks to. Same tools, same behaviour — added rather than forked, because two implementations of one surface is how they drift.

The HTTP side answers 405 to GET: every tool here is request/response, and the spec permits declining the server-initiated stream rather than holding a connection open for traffic that never comes. There are no sessions — nothing is held across calls that a restart could not rebuild. And it carries no credential of its own: whatever authorizes the HTTP request is what authorizes reachpad.

It is authenticated by default. Set REACHPAD_MCP_HTTP_TOKEN and that is the bearer token; set nothing and one is generated for the run and printed on stderr, because a port that bridges to your account with run_command behind it should not be open to every other process on the machine:

reachpad mcp: streamable http on http://127.0.0.1:8722reachpad mcp: no REACHPAD_MCP_HTTP_TOKEN was set, so this one was generated for this run:
    Authorization: Bearer 3Qk…
reachpad mcp: it changes every restart. Set REACHPAD_MCP_HTTP_TOKEN to pin it, orreachpad mcp: REACHPAD_MCP_HTTP_NO_AUTH=1 to serve with no authentication at all.

Serving with no authentication is still available and is now something you say out loud: REACHPAD_MCP_HTTP_NO_AUTH=1.

Configure

variablemeaning
REACHPAD_ENDPOINTyour reachpad host. Plaintext http:// to anything but loopback is refused before a socket opens.
REACHPAD_IDENTITY_CREDENTIALyour per-user credential. It names one account and can act for no other — the server takes the identity from the credential's own record, never from the request.
REACHPAD_API_KEYoptional, per-workspace scoped and revocable. When set, run_command uses it and needs no identity exchange.
REACHPAD_MCP_HTTP_PORTserve HTTP instead of stdio.
REACHPAD_MCP_HTTP_HOSTdefault 127.0.0.1. This process bridges to a control plane with your credentials, so binding it to the world is a decision made on purpose, behind a proxy that terminates TLS.
REACHPAD_MCP_HTTP_TOKENbearer token, compared in constant time. Absent, one is generated for the run and printed on stderr — the endpoint is never unauthenticated by omission.
REACHPAD_MCP_HTTP_NO_AUTH1 serves with no authentication at all: every caller that can reach the port is authorized. An affirmative choice, not a default.
REACHPAD_MCP_ALLOWED_ORIGINScomma-separated. A request carrying an unlisted Origin is refused — a browser cannot forge it, which closes DNS rebinding. No Origin at all is a non-browser client and is allowed.

If several credentials are set, the narrowest wins, and a refused credential is never retried under a broader one — falling back would be privilege escalation nobody chose to perform.

Tools

toolwhat it does
get_credit_balance()remaining compute credits. One credit runs one standard workspace for one minute.
create_workspace(repo?, ref?, name?)a new workspace, optionally with a repository cloned into $HOME/work. Reachpad generates its display name when omitted.
list_workspaces()your workspaces and how many forks each has
get_workspace(workspace)what it boots from: its head snapshot, its log position and its fork tree
run_command(workspace, argv, cwd?, env?, timeout_ms?)one command, its exit code and its output. A paused workspace resumes to serve it.
checkpoint_workspace(workspace, name?)fork from the last sealed snapshot; the original is untouched
expose_port(workspace, port, check?)open a port to the web and get the link that reaches it. Idempotent per port.
list_ports(workspace)the ports this workspace has open, oldest first, with their links
revoke_port(workspace, port)close one port. Re-opening it later mints a different link.
delete_workspace(workspace)archive it and free the plan slot. Nothing is deleted — snapshots and history survive.

Renamed in 0.4.0. Six tools used to be spelled *_environment and took an environment argument, while the CLI, the manual and the dashboard all said workspace. There was only ever one object; now there is only one word for it. The old names and the old argument still work and are not advertised, so nothing that already calls them breaks — but write new calls against the workspace spelling.

Not here, deliberately: starting an agent inside the workspace. It is in reachpad's roadmap and not in the fleet yet — a tool that always fails costs a model a turn and teaches it to distrust the rest, so this server advertises nothing it cannot serve.

What a port link is, and is not

Worth reading before you hand one to somebody, because none of it is discoverable from the URL:

  • Anyone signed in to Reachpad who has the link can open it. It is not a private URL and not a secure one. Treat it like a preview deployment.
  • The link is an address, not a copy. Restart the app on the same port and the same link serves the new version.
  • A running process does not survive a pause. The workspace cold-boots with its files intact and nothing running, so after a pause the link answers with an error until something is listening on that port again. A visitor's request wakes a paused workspace; it does not restart anything inside it.
  • expose_port dials the port afterwards and tells you if nothing answered, because a link to a port nothing is serving looks exactly like a link that works. Pass check: false to skip it — the dial resumes a paused workspace.
  • With only REACHPAD_API_KEY, the key must be --role owner. A collaborator key is refused: listing hands back live tokens, and a token is a capability.

The rules it is built to

These are the ways a naive client of a streaming exec API misleads a model, and what this one does instead.

  • An unterminated stream is UNKNOWN, never success. If the response ends without a terminal event, the tool says so in those words. It is not a zero exit, and an agent must not retry a non-idempotent command on the strength of it.
  • Its deadline is looser than the server's, so a server-side answer always wins the race. A client that gives up first turns "your build finished" into "unknown", and the numbers are mirrored from the server rather than guessed.
  • Refusals carry remedies, not codes. At your plan limit you get the limit, your current count, and what to do — the numbers come from the server, because a limit hardcoded in a client is a lie the moment your plan changes.
  • Results are handles, not payloads. Output is tailed with the dropped byte count named. Build logs can be megabytes, and an MCP result that size destroys the caller's context window.
  • A refusal is a result, not a transport error, so the model can read it and act. Only an unknown tool is a protocol error.

Test

sh
node --test 'test/*.test.mjs'

No network and no credentials. The protocol suite spawns the shipped server as a child process and speaks real JSON-RPC over its stdio against a stub control plane on a real socket, so nothing under test is an internal import. One test runs the same arc against a real reachpad and skips when no endpoint is configured.

Repository

This repository is the source. It is deliberately separate from the reachpad backend: this code is public, it is published to npm, and its release workflow holds publishing rights — none of which belong in the same repository as the control plane. Nothing here can read the backend's source, and no job in the backend copies files out to here.

Two server constants are mirrored in src/client.js — the exec grace period and the default exec timeout. A mirrored constant normally rots; this one does not, because the backend's own CI fetches this published package and fails if they disagree. The check lives where the number would change.

來源:README.md,提交 a4ee8f2

工具

25

whoami

Who am I

Report the account and the organization this connection is signed in as: user id, email and name, plus org id and name, and `orgs`, every organization the account is in with the current one marked. Takes no arguments. Every app is created in the current organization and nowhere else, so call this before publishing when the person named an organization to publish into, and stop if the org id is not the one they named: switching is done at reachpad.dev/apps, from the organization name at the top of the sidebar, and this connection follows it.

無需輸入參數。

search_apps

Search apps

Find apps in the caller's organization by text. This matches substrings of the name and the slug, and whole words on the live version's page, not meaning: search for a word that appears in the title or on the page rather than describing the app. Returns ids and live URLs.

輸入參數qtypelimitcreated_byupdated_by

read_app

Read an app

Read one app before update_app: its name, type, access level and publishing mode, plus base_version_id and its files, which both describe the version the next edit builds on. Each text file carries its content, so this is how you see what an app already contains before changing it. A file marked content_omitted answer budget did not fit in this answer and read_app_file fetches it; one marked too large is past what any tool answer carries. Pass that base_version_id to update_app. version is what the link serves now, and head_version is the version base_version_id names on the apps where that is not the live one, which is every app with a version staged by publish false. pending_version is the number of that staged version, and publish_app_version is what makes it live.

輸入參數app_id必填

read_app_preview

See an app

Look at the picture of what an app's link serves right now, as an image. Use it for an app whose files you cannot read: a function app's module stays with the people who develop it, so this is how you see what the app actually shows. It is the live version only, and an app published before its picture was taken, or one whose capture has not run yet, answers that there is no picture rather than an error.

輸入參數app_id必填

list_app_versions

List versions

List an app's versions, newest first. Versions are immutable and numbered from 1. Earlier versions open for the app's editors; the live link follows the app's access setting. Pass the next_cursor from a previous call to get the next page.

輸入參數limitapp_id必填cursor

read_app_version

Read a version

Read one version by its number, with its files and each text file's content. Use it to see what an earlier publish contained, and to copy a file back out of a version you want to return to. Earlier versions open for the app's editors; the live link follows the app's access setting.

輸入參數app_id必填number必填

read_app_file

Read one file

Read one file out of an app as text, at most 256 KB. Use it for a file that read_app left out with content_omitted: "answer budget", or to fetch a single file without the rest of the app. A file that is not text, and a text file over that size, are refused rather than truncated. Reads the newest version unless you name one, which is the same version read_app lists.

輸入參數path必填app_id必填number

query_app_db

Run one SQL statement

Run one SQL statement against a function app's own database, to read rows and to fix data. Not for schema: a table or a column belongs in the version's migrations/NNNN_name.sql, and a statement that changes the schema is refused. Owners and editors only. Answers rows and rowCount for a select, and changes with lastInsertRowid for a write.

輸入參數sql必填app_id必填params

list_secrets

List secrets

List the organization's secrets: each name, who set it, when, and the apps whose versions bind it. Names only. No tool anywhere returns a secret value.

無需輸入參數。

set_secret

Set a secret

Set one organization secret, so a function can bind it by name in its manifest secrets list. Any member of the organization. Setting a name that already exists replaces the value and rotates it onto every published version that binds it. Answers the name, how many versions took the new value, and the ids of any that did not.

輸入參數name必填value必填

remove_secret

Remove a secret

Remove one organization secret and delete it from every published version that binds it. A version the deletion did not reach keeps the name in the list with that version in failed, and running this again retries exactly those.

輸入參數name必填

trash_app

Move an app to the trash

Move an app to the trash. Its link stops opening at once. Owner only. The app and its versions are kept and can be restored from Trash at reachpad.dev/apps/trash, which is also the only place an app is deleted for good.

輸入參數app_id必填

create_app

Publish a new app

Publish new files as an app and get its URL back. Version 1 goes live at once, so show the person the content and the destination before calling this. Access defaults to org_link, which lets anyone signed in to the same organization open the link.

輸入參數name必填slugtypefiles必填accessmessagemanifestvalidate

update_app

Publish a new version

Publish a new version of an existing app. Read the app first and pass the base_version_id read_app returns: it names the version this edit builds on, and a base that has moved is refused rather than overwritten. By default the new version replaces the whole file set and goes live immediately unless the app is set to review before publishing. Send mode merge to publish only the files that changed and keep the rest of that version's files, with remove for paths to drop. Two merges in a row build on each other, staged versions included. Send validate true to check the call without publishing, or publish false to stage the version and make it live later with publish_app_version.

輸入參數modefiles必填app_id必填removemessagepublishmanifestvalidatebase_version_id必填

publish_app_version

Make a version live

Make one version of an app live by its number. This is how a version staged with publish false goes on the link, and how an app is rolled back: name an older number and that version is what the link serves again. Nothing is rebuilt, the pointer moves.

輸入參數app_id必填number必填

set_app_access

Set who can open an app

Change who can open an app: restricted (only the owner and named people), org_link (anyone signed in to the organization), or public_link (anyone with the URL). A password and an expiry apply to a public link only. Owner only.

輸入參數level必填app_id必填passwordexpires_atclear_expiryclear_password

share_app

Share an app

Give one email address access to an app as a viewer or an editor. An address without an account gets a grant that starts working the first time they sign in. The owner or an editor may use this when the owner has enabled editor-managed sharing.

輸入參數role必填email必填app_id必填

list_app_shares

List shares

List the people an app is shared with, their roles, and whether the grant has attached to an account yet. The owner and editors can read this list.

輸入參數app_id必填

revoke_app_share

Remove a share

Remove one share by its id, from list_app_shares. The app itself is untouched. The owner or an editor may use this when editor-managed sharing is enabled.

輸入參數app_id必填share_id必填

ls

List a folder

List what is directly inside one folder: its subfolders and the apps filed in it. Omit folder_id for the top level. Each folder carries the updated_at that mv needs.

輸入參數limitfolder_id

tree

Read the folder tree

The whole folder tree for the organization, nested, with the number of apps filed in each folder and the count sitting at the top level. Each node carries the updated_at that mv needs.

無需輸入參數。

mkdir

Create a folder

Create a folder, at the top level or inside another one.

輸入參數name必填parent_id

mv

Move an app or folder

Move an app into a folder, or move a folder under another folder. Name exactly one of app_id or folder_id as the thing being moved, and to_folder_id as the destination, or null for the top level. Moving a folder also needs base_updated_at, the value read from ls or tree, so a move made against a stale reading is refused instead of undoing someone else's.

輸入參數app_idfolder_idto_folder_id必填base_updated_at

rmdir

Delete an empty folder

Delete an empty folder. This refuses while the folder still holds apps or subfolders, and it never deletes an app. Move the contents out first.

輸入參數folder_id必填

get_app_logs

Read app logs

Read recent log lines from the live version of a function app. An app that serves files has no process and answers that it has no logs. Function logs are not captured yet either, and the answer says so: until they are, have the function catch its own errors and return them in the response.

輸入參數limitsinceapp_id必填

版本歷史

1
  1. v0.4.2最新Sep 16, 2026

評分

已滿足適用檢查項的 100%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通必需25 分
  • 已宣告認證方式必需10 分
  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分