os-mcp

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

OS MCP — Railway Deploy

OS MCP — Railway 部署

This skill deploys the Relay MCP v2 server to the user's own Railway account. The MCP source is bundled at
${CLAUDE_PLUGIN_ROOT}/skills/os-mcp/reference/relay-mcp-server/
— copy from there, do not fetch from anywhere else. The deployed server lets Claude clients (Claude Code or claude.ai) read/write the user's Obsidian vault by talking to the Relay.md sync protocol.
此 skill 会将 Relay MCP v2 server 部署到用户自己的 Railway 账户。MCP 源码位于
${CLAUDE_PLUGIN_ROOT}/skills/os-mcp/reference/relay-mcp-server/
——应从此处复制,不要从其他任何位置获取。部署后的 server 可让 Claude clients(Claude Code 或 claude.ai)通过 Relay.md sync protocol 读写用户的 Obsidian vault。

What the user provides

用户需提供的内容

One thing: a Railway account token — created at
https://railway.com/account/tokens
.
That's it. After deploy, the user signs in with their Relay.md credentials via OAuth; the MCP then auto-discovers their relay vault and the folders inside it via PocketBase. No vault GUIDs, no folder maps.
仅需一项:Railway account token——在
https://railway.com/account/tokens
创建。
仅此而已。部署后,用户需使用其 Relay.md credentials 通过 OAuth 登录;随后 MCP 会通过 PocketBase 自动发现其 relay vault 及其中的 folders。无需 vault GUID,也无需 folder map。

Values set automatically by the skill

由 skill 自动设置的值

VarSourceValue
RELAY_API_URL
preset
https://api.system3.md
PB_AUTH_URL
preset
https://auth.system3.md
PB_COLLECTION
preset
users
DATA_DIR
preset
/data
PORT
preset
3000
JWT_SECRET
auto-generated
openssl rand -hex 32
STATIC_MCP_BEARER
auto-generated
openssl rand -hex 24
ALLOWED_EMAILS
presetblank (any authenticated Relay.md user)
RELAY_AUTH_TOKEN
presetblank (OAuth-only; no static fallback)
RELAY_ID
not setauto-discovered at runtime per user
PUBLIC_URL
derivedfrom
railway domain
after first deploy
Save the generated
STATIC_MCP_BEARER
in the chat for the user — they'd use it for any CLI/script access bypassing OAuth.
If the user has multiple Relay vaults, the MCP auto-picks the first one. They can call the
vault_relays
tool after connecting to see which is active and pin a different one by setting
RELAY_ID
in
railway variables
.

变量来源值
RELAY_API_URL
预设
https://api.system3.md
PB_AUTH_URL
预设
https://auth.system3.md
PB_COLLECTION
预设
users
DATA_DIR
预设
/data
PORT
预设
3000
JWT_SECRET
自动生成
openssl rand -hex 32
STATIC_MCP_BEARER
自动生成
openssl rand -hex 24
ALLOWED_EMAILS
预设空白(任何已通过身份验证的 Relay.md 用户)
RELAY_AUTH_TOKEN
预设空白(仅 OAuth;无静态回退)
RELAY_ID
未设置运行时按用户自动发现
PUBLIC_URL
派生首次部署后通过
railway domain
获得
将生成的
STATIC_MCP_BEARER
保存在聊天记录中供用户使用——他们会将其用于任何绕过 OAuth 的 CLI/script 访问。
如果用户拥有多个 Relay vaults,MCP 会自动选择第一个。连接后,用户可以调用
vault_relays
工具查看当前生效的 vault,也可通过设置
railway variables
中的
RELAY_ID
固定到其他 vault。

Workflow

工作流

Execute in order. Confirm each step before moving on.
按顺序执行。每一步都要先确认,再继续下一步。

Step 1 — Verify Railway CLI

第 1 步 — 验证 Railway CLI

bash
railway --version
If missing:
  • macOS:
    brew install railway
  • Anywhere:
    npm i -g @railway/cli
Re-run to confirm.
bash
railway --version
如果未安装:
  • macOS:
    brew install railway
  • 任意平台:
    npm i -g @railway/cli
重新运行以确认。

Step 2 — Get Railway token from the user

第 2 步 — 从用户处获取 Railway token

Tell the user:
Open
https://railway.com/account/tokens
, click Create Token, name it
os-mcp-deploy
, copy the value, and paste it here.
When pasted:
bash
export RAILWAY_API_TOKEN="<paste>"
railway whoami
railway whoami
should print the user's Railway email. If it errors, the token is wrong — ask them to regenerate.
告诉用户:
打开
https://railway.com/account/tokens
,点击 Create Token,命名为
os-mcp-deploy
,复制其值并粘贴到这里。
粘贴后:
bash
export RAILWAY_API_TOKEN="<paste>"
railway whoami
railway whoami
应输出用户的 Railway 邮箱。如果报错,则说明 token 有误——请用户重新生成。

Step 3 — Deploy the bundled source

第 3 步 — 部署随附源码

bash
cd "${CLAUDE_PLUGIN_ROOT}/skills/os-mcp/reference/relay-mcp-server"
bash
cd "${CLAUDE_PLUGIN_ROOT}/skills/os-mcp/reference/relay-mcp-server"

Create a new Railway project (interactive — let user pick name)

Create a new Railway project (interactive — let user pick name)

railway init
railway init

Persistent volume for clients.json + sessions.enc

Persistent volume for clients.json + sessions.enc

railway volume add --mount-path /data
railway volume add --mount-path /data

Upload source, build via Dockerfile, deploy

Upload source, build via Dockerfile, deploy

railway up

Wait for the deploy. Tail logs if useful: `railway logs`.
railway up

等待部署完成。如有需要,可跟踪日志:`railway logs`。

Step 4 — Wire env vars

第 4 步 — 配置环境变量

Generate the secrets:
bash
JWT_SECRET=$(openssl rand -hex 32)
STATIC_MCP_BEARER=$(openssl rand -hex 24)
Set everything in one shot (note:
RELAY_ID
is intentionally NOT set — it auto-discovers):
bash
railway variables \
  --set "RELAY_API_URL=https://api.system3.md" \
  --set "PB_AUTH_URL=https://auth.system3.md" \
  --set "PB_COLLECTION=users" \
  --set "DATA_DIR=/data" \
  --set "PORT=3000" \
  --set "JWT_SECRET=$JWT_SECRET" \
  --set "STATIC_MCP_BEARER=$STATIC_MCP_BEARER"
Service auto-redeploys after
--set
. Wait for it to come back up.
生成密钥:
bash
JWT_SECRET=$(openssl rand -hex 32)
STATIC_MCP_BEARER=$(openssl rand -hex 24)
一次性设置全部变量(注意:故意不设置
RELAY_ID
——它会自动发现):
bash
railway variables \
  --set "RELAY_API_URL=https://api.system3.md" \
  --set "PB_AUTH_URL=https://auth.system3.md" \
  --set "PB_COLLECTION=users" \
  --set "DATA_DIR=/data" \
  --set "PORT=3000" \
  --set "JWT_SECRET=$JWT_SECRET" \
  --set "STATIC_MCP_BEARER=$STATIC_MCP_BEARER"
执行
--set
后,服务会自动重新部署。等待其恢复运行。

Step 5 — Set PUBLIC_URL and final redeploy

第 5 步 — 设置 PUBLIC_URL 并最终重新部署

bash
railway domain                      # assigns + prints public domain
Copy the URL, then:
bash
railway variables --set "PUBLIC_URL=https://<the-domain>"
railway up                          # final redeploy so OAuth issuer/audience match
bash
railway domain                      # assigns + prints public domain
复制 URL,然后:
bash
railway variables --set "PUBLIC_URL=https://<the-domain>"
railway up                          # final redeploy so OAuth issuer/audience match

Step 6 — Verify

第 6 步 — 验证

bash
curl https://<the-domain>/health
Expect
200 OK
with JSON
{"status":"ok","version":"2.0.0",...}
.
bash
curl https://<the-domain>/health
预期返回
200 OK
,JSON 为
{"status":"ok","version":"2.0.0",...}
。

Step 7 — Connect from Claude

第 7 步 — 从 Claude 连接

Print these for the user:
Claude Code:
claude mcp add --transport http vault https://<the-domain>/mcp
Claude.ai (web): Settings → Connectors → Add custom connector → paste
https://<the-domain>/mcp
. Sign in with their Relay.md credentials when the OAuth window opens.
Also tell them: their
STATIC_MCP_BEARER
is
<value>
— keep it for any CLI/script access that needs to bypass OAuth.
为用户输出以下内容:
Claude Code:
claude mcp add --transport http vault https://<the-domain>/mcp
Claude.ai(网页): Settings → Connectors → Add custom connector → 粘贴
https://<the-domain>/mcp
。OAuth 窗口打开时,使用其 Relay.md credentials 登录。
还要告诉用户:其
STATIC_MCP_BEARER
为
<value>
——请保留它,以供任何需要绕过 OAuth 的 CLI/script 访问使用。

Step 8 — Test discovery

第 8 步 — 测试发现功能

In a fresh Claude conversation, ask Claude to call
vault_relays
(or have the user say "list my Relay vaults"). Expect at least one vault, with
*
next to the active one.
Then call
vault_folders
— expect a non-empty list of folder names. If empty, the user may not have folder access in that relay.
If the user has multiple relays and the wrong one is active, pin the right one:
bash
railway variables --set "RELAY_ID=<the-vault-guid-from-vault_relays>"
(One redeploy and the next OAuth session will use that relay.)

在新的 Claude 对话中,让 Claude 调用
vault_relays
(或让用户说“列出我的 Relay vaults”)。预期至少显示一个 vault,当前 vault 旁会有
*
标记。
随后调用
vault_folders
——预期返回非空的 folder 名称列表。如果为空,用户可能没有该 relay 的 folder 访问权限。
如果用户拥有多个 relays,而当前生效的不是目标 relay,可固定正确的 relay:
bash
railway variables --set "RELAY_ID=<the-vault-guid-from-vault_relays>"
(重新部署一次后,下一次 OAuth session 将使用该 relay。)

Troubleshooting

故障排除

railway whoami
fails after pasting Railway token.
Token expired or wrong scope. Regenerate at https://railway.com/account/tokens.
Build fails with TypeScript errors. Don't modify the bundled
package.json
/
tsconfig.json
. Re-copy fresh from
${CLAUDE_PLUGIN_ROOT}/skills/os-mcp/reference/relay-mcp-server/
.
/health
returns 5xx.
railway logs
will name the missing env var (
assertRequiredConfig
lists what's missing on boot).
vault_relays
returns "No relays accessible to this user".
The signed-in Relay.md account doesn't own or belong to any relay. Have them create one in the Relay.md Obsidian plugin first.
vault_folders
returns empty but
vault_relays
shows the vault.
Folders are stored in the
shared_folders
PocketBase collection — the user may not have any folders in that relay yet, or the active relay isn't the one they meant. Check
vault_relays
output for the active marker.
OAuth sign-in loops.
PUBLIC_URL
doesn't match the actual Railway domain. Re-run Step 5.
Want to gate access to specific emails.
railway variables --set "ALLOWED_EMAILS=email1@x.com,email2@x.com"
then redeploy.
Want to start over.
railway down
to tear down, then re-run from Step 3.
粘贴 Railway token 后,
railway whoami
失败。
Token 已过期或权限范围错误。请在 https://railway.com/account/tokens 重新生成。
构建因 TypeScript errors 失败。 不要修改随附的
package.json
/
tsconfig.json
。请从
${CLAUDE_PLUGIN_ROOT}/skills/os-mcp/reference/relay-mcp-server/
重新复制最新源码。
/health
返回 5xx。
railway logs
会指出缺失的环境变量(
assertRequiredConfig
会在启动时列出缺失项)。
vault_relays
返回 "No relays accessible to this user"。
登录的 Relay.md account 不拥有或不属于任何 relay。先让用户在 Relay.md Obsidian plugin 中创建一个 relay。
vault_folders
返回空结果,但
vault_relays
显示了 vault。
Folders 存储在
shared_folders
PocketBase collection 中——用户可能尚未在该 relay 中创建任何 folders,或者当前生效的 relay 并非目标 relay。检查
vault_relays
输出中的 active 标记。
OAuth 登录进入循环。
PUBLIC_URL
与实际 Railway domain 不一致。请重新执行第 5 步。
希望将访问权限限定给特定 emails。 执行
railway variables --set "ALLOWED_EMAILS=email1@x.com,email2@x.com"
,然后重新部署。
想从头开始。 运行
railway down
拆除部署,然后从第 3 步重新执行。