rdyrct

io.github.baronunread由 GitHub 帳號 baronunread 發布v1.1.0更新於 Nov 2, 2026

Create and manage short links and QR codes, and read click analytics, on your own domain.

已驗證Streamable HTTP可網頁執行資料與分析商業與電商

概覽

AI 產生的概覽

rdyrct 的遠端 MCP 伺服器,這是一套自架短連結服務,讓助理在你自己的網域上建立短連結與 QR 碼並讀取點擊統計。

可以做什麼
  • 建立與管理短連結,支援自訂或隨機短碼、UTM 參數與額外別名
  • 為連結產生 QR 碼,可選中央標誌,並可下載 PNG/SVG
  • 讀取重視隱私的點擊統計:每日點擊、熱門連結、國家、來源與裝置
  • 在組織內協作,由角色決定誰管理連結、網域與帳務
適用情境
當你已運行 rdyrct 實例,希望助理不必開啟網頁就能縮短連結、產生 QR 碼或取得點擊資料時適用。若你並未自架 rdyrct,則幫助不大。
執行需求
透過 streamable HTTP 連線到 rdyrct.com 的遠端端點,需要 OAuth 登入。實例本身部署於 Cloudflare Workers,使用 D1、KV、R2 與佇列;選用功能需要 Resend、Polar、Google、Cloudflare 與 Turnstile 的憑證。
安裝前請注意
伺服器會在你的帳號上建立與修改連結及 QR 碼,寫入操作會影響線上轉址。QR 碼屬付費方案功能,帳務由 Polar 處理。統計聲稱不儲存 IP 位址,但仍會蒐集點擊資料。OAuth 授權會開放對組織連結與統計的存取。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 rdyrct,將其新增到工作區。
  2. 連接 所需的 憑證。它們會被私密儲存,絕不會在公開頁面上展示。
  3. 為需要使用其工具的對話啟用該服務。

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

交給代理程式安裝

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

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

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

其他 MCP 客戶端

把它新增到你客戶端的 mcpServers 設定中。 客戶端會在首次連接時完成 OAuth 登入。

{
  "mcpServers": {
    "rdyrct": {
      "type": "http",
      "url": "https://rdyrct.com/api/mcp"
    }
  }
}

README

rdyrct

Organization-based link shortener + QR codes, running entirely on Cloudflare's edge.

[License: MIT] [Built on Cloudflare Workers] [Bun] [React 19]


Deploy in one click

[Deploy to Cloudflare]

Cloudflare copies this repository to your GitHub account, creates the database, storage and queues, and asks for one thing: the email of the account that becomes the platform admin. Leave every other value as it is. The first build serves your copy on its workers.dev address, generates the session key and applies the migrations; each push to your copy deploys it again. When you want your own domain, see Move to your own domain.

Prefer a terminal? bun run setup does the same from a clone: see Deploy to Cloudflare Workers.


Features

  • Short links with custom or random slugs, optional UTM parameters (source, medium, campaign, term, content) applied at redirect time.
  • Grouped link addresses: renaming a link keeps the old slug redirecting for 48 hours before it's freed, and a link can carry extra aliases that all redirect to the same destination.
  • QR codes per link (paid plans), with an optional logo in the center, live preview, and PNG/SVG download.
  • Custom domains (Pro): connect links.yourbrand.com via Cloudflare for SaaS, with slugs namespaced per domain.
  • Organizations with owner / admin / member roles: admins manage the team, domains, and billing; members manage links.
  • Magic-link invites: single-use, valid for 7 days, sent by email.
  • Privacy-friendly analytics: clicks per day, top links, countries, referrers, devices. No IP addresses are ever stored.
  • Per-user Free/Hobby/Pro billing through Polar, which acts as Merchant of Record and handles tax/VAT.
  • Secret-pinned superadmin console: the account matching SUPERADMIN_EMAIL gets a cloud-console panel for usage, org drill-down, and plan management. It 404s for everyone else.

Stack

rdyrct is built Cloudflare-first: the entire product runs in a single Worker with no separate backend to host:

  • Cloudflare Workers: one Worker serves the API, the redirect hot path, and the static React app.
  • D1: SQLite at the edge, source of truth for auth, orgs, links, clicks, and domains.
  • KV: slug → destination lookups on the redirect hot path, so a click never waits on D1.
  • R2: QR logo images, keyed by org, served immutable and cached.
  • Cloudflare for SaaS: custom hostnames for Pro orgs' own short-link domains.
  • Workers Rate Limiting: separate abuse controls for auth, email, writes, uploads, domains, billing, and click recording.

Application layer:


Local development

What you need

  • Bun 1.4 or newer.
  • Node 24 or newer. Bun runs the scripts, but portless and wrangler run on Node.
  • macOS or Linux. Dev servers run behind portless (installed with the project), which gives each one a stable HTTPS name instead of a port.
  • Optional: the Polar CLI, only to receive sandbox billing webhooks.

First run

sh
bun installbun run dev

That is the whole setup. On the first run bun run dev:

  1. creates .dev.vars from .dev.vars.local.example, with an auth secret of its own (every other value works locally as it is);
  2. applies the local database migrations (it does this on every run, so a pull never leaves you a migration behind);
  3. starts the app, a local email inbox and a local Google sign-in, each behind portless (portless may ask for your password once, to listen on port 443 and trust its own certificate);
  4. prints the addresses once the app answers:
  rdyrct     https://rdyrct.localhost  scenarios  https://rdyrct.localhost/__dev/scenarios  inbox      https://rdyrct-mail.localhost/emails  (header: authorization: Bearer test_token_admin)  google     https://rdyrct-google.localhost

Then, in a second terminal, fill the database with fake organizations, links and clicks:

sh
bun run db:seed:local

and open the scenarios page. It signs you in as a seeded account in each state the app has: pro-owner, hobby-owner, free-owner, fresh (a brand-new account), member, viewer, over-plan, grace-ended, locked-org, click-cap and admin. /__dev/scenarios/<name>?to=/links opens a page directly.

Ctrl+C stops everything. If one of the three crashes, the other two stop with it.

Day to day

  • One name per checkout. The main checkout is rdyrct, rdyrct-mail, rdyrct-google; a git worktree gets the branch in its names (rdyrct-<branch>, rdyrct-<branch>-mail…), so any number of checkouts run side by side. bun scripts/dev-hosts.ts prints this checkout's addresses.

  • Email. Sign-up codes and every other mail land in the local inbox, never a real one:

    sh
    curl "$(bun scripts/dev-hosts.ts mail)/emails" -H 'authorization: Bearer test_token_admin'
  • Google sign-in goes through the local emulator with two accounts, [email protected] and [email protected].

  • The admin console. Open the admin scenario. (Or set SUPERADMIN_EMAIL in .dev.vars and sign up with that address.)

  • Start the database over: bun run db:reset:local, then bun run dev and bun run db:seed:local again.

  • rdyrct.com's own pages. The dev server runs the self-hosted app. Add VITE_RDYRCT_SITE=1 to .env to work on the landing and marketing pages.

From another computer or a phone

Switch portless to LAN mode once:

sh
sudo portless service install --lan

The addresses then end in .local (https://rdyrct.local) and any device on the same network opens them; bun run dev says so when it starts. The first visit from another device shows a certificate warning, because that device does not trust portless's certificate: continue past it. Every name is a single word before .local on purpose: Windows finds only those on a network. On Linux, LAN mode needs avahi-utils.

Integrations

ServiceLocallyWhat to do
Email (Resend)the local inboxnothing
Google sign-inthe local emulatornothing
Bot check (Turnstile)Cloudflare's always-pass test keysnothing
Custom domains (Cloudflare for SaaS)simulated: DNS is ready after ~3 s and TLS after ~12 s (CF_DEV_ENV=simulated; instant skips the wait)nothing
Billing (Polar)your Polar sandboxplan limits work as they are; checkout needs the sandbox token and product ids in .dev.vars. Run bun run polar:listen beside bun run dev to receive webhooks. bun run dev gives the app the secret polar listen signs them with, so there is nothing to copy
Blog (/blog)proxied to the rdyrct-blog dev serverrun that repo's dev server; BLOG_ORIGIN_URL points at it

When something is off

  • ".dev.vars sets this checkout's addresses": bun run dev works out APP_URL, APP_HOST, SHARED_LINK_HOST, RESEND_BASE_URL and GOOGLE_EMULATOR_URL itself. Delete the lines it lists from .dev.vars (an old copy has them).
  • "Invalid origin" when saving or signing out: open the address bun run dev printed, not localhost:<port>.
  • A page will not load at all: bunx portless doctor checks the proxy, and bunx portless list shows what is running.
  • The seed stops with a 500: the local database is busy (a browser test run, say). Run it again when it is quiet.

Tests

sh
bun run test          # fast unit testsbun run test:worker   # Worker routes with local D1 and KV bindingsbun run e2e:install   # install Chromium for Playwright oncebun run e2e:smoke     # real-browser baseline regression checksbun run verify        # types, lint, formatting, unit, and Worker tests

Playwright owns the local server lifecycle and never resets or seeds local Cloudflare state, so the browser tests run with or without bun run dev. The browser and Worker tests bring their own settings, so your .dev.vars and .env never change what they see. Failed browser tests keep a screenshot and trace in test-results/.


Deploy to Cloudflare Workers

sh
git clone https://github.com/baronunread/rdyrctcd rdyrct && bun installbun run setup

Setup asks three things: a name for the worker (Enter keeps rdyrct), a domain on your Cloudflare account (or Enter, for a free *.workers.dev address) and the email of the account that becomes the platform admin. It stops if your account already runs a worker by that name, so it never deploys over one. Then it:

  • rewrites your copy of wrangler.jsonc: your domain in APP_URL and APP_HOST, and rdyrct.com's own ids and settings (mail sender, Polar products, Cloudflare zone, Sentry) taken out;
  • has Wrangler create the D1 database, KV namespace, R2 bucket and queues on your account, each named after the worker, since a binding with no id gets a new resource on the first deploy;
  • generates BETTER_AUTH_SECRET, sets it and SUPERADMIN_EMAIL as secrets, builds, deploys, applies the migrations and attaches your domain.

Commit the rewritten wrangler.jsonc to your fork. After that, bun run deploy ships each update: it applies new migrations, then deploys. Every build is the self-hosted app, which opens on sign-in and carries none of rdyrct.com's marketing pages, analytics or search tags. Only VITE_RDYRCT_SITE=1 builds rdyrct.com itself, and bun run deploy refuses it for any host but rdyrct.com.

Everything else is optional. Each piece says what it adds:

SettingAdds
RESEND_API_KEY, MAIL_FROMEmail: sign-up verification codes, password reset, invites, notices. Without it, sign-up skips verification (see below).
POLAR_*Selling Hobby and Pro plans. Without it, nobody is capped and billing is hidden.
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET"Continue with Google".
CF_API_TOKEN, CF_ZONE_IDCustomers' own domains through Cloudflare for SaaS.
SHARED_LINK_HOSTA second, shorter host for new shared-domain links.
TURNSTILE_SITE_KEY, TURNSTILE_SECRET_KEYCloudflare Turnstile in front of sign-up, password reset and the report form. Set both in one wrangler secret bulk call: one without the other refuses those forms. Cloudflare then sees those visitors.
WEB_RISK_API_KEYGoogle Web Risk as a second destination check. A listed destination puts its link on hold.
SENTRY_DSNError reports to your Sentry project.
SITE_NAMEThe name every tab shows, such as "Acme links". Without it, tabs show your copy's host.

With no email provider and no Google sign-in, accounts are not verified and passwords cannot be reset. That is fine for a private instance and not recommended for a public one. The admin console says so while it is true.

Vars go in wrangler.jsonc. Set secrets one by one with bunx wrangler secret put <NAME>, or in bulk with cp prod.secrets.env.example prod.secrets.env, fill it in, then:

sh
bunx wrangler secret bulk prod.secrets.env && rm prod.secrets.env

Move to your own domain

Started on workers.dev, from the button or from setup? Clone your copy, run bun run setup and give it the domain (it has to be on your Cloudflare account), then commit wrangler.jsonc and push. Setup attaches the domain and keeps your data, your secrets and the session key. By hand instead: Cloudflare dashboard → Workers → your worker → Settings → Domains & Routes → Add → Custom domain, then set APP_URL and APP_HOST in wrangler.jsonc, remove the vars that are rdyrct.com's (MAIL_FROM, WELCOME_FROM, POLAR_*, CF_ZONE_ID, SENTRY_DSN) and bun run deploy. Short links live at the root (https://links.example.com/<slug>); the app is served on every other path. Keep routes out of wrangler.jsonc: a routes list replaces whatever is attached in the dashboard, and committing yours would hand it to every fork. The */* route is only for customers' own domains (below).

Email (optional)

Set RESEND_API_KEY and MAIL_FROM (a sender at a domain you verified in Resend). Without them no mail goes out: sign-up skips the verification code and signs the user in, and the password-reset form says it needs an email provider. Sending lives in one function, sendEmail() in src/worker/email.ts, so another provider is a change there.

Selling plans (optional)

Skip this section to run with no caps and no billing. To sell plans, set POLAR_SERVER=sandbox (or production when live), POLAR_PRO_PRODUCT_ID and POLAR_HOBBY_PRODUCT_ID (recurring products you create in Polar), and the secrets POLAR_ACCESS_TOKEN and POLAR_WEBHOOK_SECRET.

Polar setup: create an Organization Access Token with scopes checkouts:write and customer_sessions:write. Add a webhook endpoint at https://rdyrct.com/api/webhooks/polar and subscribe to all five events the Worker handles. Miss one and billing state drifts:

EventWhat it does
subscription.activeStarts the subscription: plan, customer, price, and access
subscription.updatedThe full subscription snapshot: status, product, cancellation state, period end
subscription.canceledMarks it as ending at the period end; access continues until then
subscription.uncanceledClears a scheduled cancellation
subscription.revokedEnds it: the subscription and its access go away

Which subscription statuses keep access is one decision, in src/worker/entitlement.ts. active, trialing and past_due keep it, because Polar retries a failed payment for days and sends subscription.revoked when it gives up. unpaid, canceled, incomplete and incomplete_expired do not, and a status with no rule keeps nothing.

Paid access an admin grants by hand is a comp, stored apart from the subscription and never counted as a subscriber. A comp outranks the subscription underneath it, so revoking a subscription cannot take away access an admin gave.

The admin console reports counts, never money: how many people hold a paid plan, how many pay for it, and how many are comped. Who is cancelling shows on their own row in the user list, where it names someone. Revenue is read in the Polar dashboard, which knows what it charged net of discounts, tax and refunds.

Second shared-domain host (optional). Attach a shorter domain the same way, check that https://<it>/ answers with a redirect, and only then turn it on with bunx wrangler secret put SHARED_LINK_HOST. It takes effect without a deploy, and bunx wrangler secret delete SHARED_LINK_HOST turns it off. In that order because every new link starts using it at once: set before the domain resolves, it hands out links that go nowhere. Old links keep working on both hosts, since a shared-domain slug's KV key has no host in it. Unset, shared links use APP_HOST.

Review the rate-limiting policies, monitoring, WAF rule, and rollback steps before the first production deploy.

Review the architecture, data flows, and improvement priorities before changing link, domain, logo, or organization delete flows.

Customer custom domains (Pro): to let orgs use links.theirbrand.com, enable Cloudflare for SaaS on the rdyrct.com zone, create an originless proxied fallback origin (e.g. fallback.rdyrct.com AAAA 100::), and add a Worker route */* pointing at the rdyrct worker. The CF_API_TOKEN needs permission Zone → SSL and Certificates → Edit scoped to the zone. Also verify your sending domain (e.g. mail.rdyrct.com) in Resend so transactional email isn't blocked.


Configuration

NameKindPurpose
BETTER_AUTH_SECRETsecretSigns sessions and tokens
SUPERADMIN_EMAILsecretThe account that becomes the platform admin
RESEND_API_KEYsecretResend API key for transactional email
POLAR_ACCESS_TOKENsecretPolar API access token (scopes: checkouts:write, customer_sessions:write)
POLAR_WEBHOOK_SECRETsecretVerifies Polar webhook signatures; endpoint https://rdyrct.com/api/webhooks/polar
CF_API_TOKENsecretCloudflare token with Zone → SSL and Certificates → Edit (custom domains)
APP_URLvarFull public URL of the app, e.g. https://rdyrct.com
APP_HOSTvarPublic host, e.g. rdyrct.com
SHARED_LINK_HOSTsecret (opt.)Second shared-domain host for new links, e.g. rdyr.cc; set after it resolves
MAIL_FROMvarFrom address for outgoing email
RESEND_BASE_URLvar (dev only)Points at the local Resend emulator
POLAR_SERVERvarsandbox or production
POLAR_PRO_PRODUCT_IDvarPolar product id for the Pro plan
POLAR_HOBBY_PRODUCT_IDvarPolar product id for the Hobby plan
CF_ZONE_IDvarZone id used for Custom Hostnames
CF_DEV_ENVvar (dev only)simulated fakes the Custom Hostnames API on a timer, instant without one

Secrets are set with wrangler secret put NAME or wrangler secret bulk prod.secrets.env in production; locally they all come from .dev.vars (see .dev.vars.local.example).


Project layout

migrations/            D1 schema (numbered SQL migrations, applied in order)scripts/               Local dev utilities (e.g. seed-local.ts)src/worker/            Hono API, BetterAuth, KV publishing, redirect hot path  routes/              auth/user, orgs, links, qr-logos, domains, billing, admin  better-auth.ts plan.ts util.ts guards.ts org-role.ts rate-limit.ts session.ts  email.ts password.ts kv.ts storage.ts alerts.ts clicks.ts workflows.tssrc/shared/types.ts    DTOs + PLAN_LIMITS (shared worker ↔ app)src/app/               React SPA  routes/              page-level route components  ui/                  design-system primitives  components/          feature components  lib/                 client utilities, API hooks.agents/skills/        Agent skills (react-doctor).claude/skills/        Claude skills (fallow, react-doctor)

License

MIT © Andrea Bruno. See LICENSE.

來源:README.md,提交 269c039

工具

0
該伺服器需要登入,因此 SourceWeft 無法在沒有帳號的情況下讀取其工具,也未收錄。已連接帳號所能看到的內容可能因帳號及其權限而異。

版本歷史

1
  1. v1.1.0最新Oct 26, 2026

評分

已滿足適用檢查項的 85%

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

  • 近 30 天內可連通必需25 分
  • 已宣告認證方式必需10 分
  • 已列出工具15 分

    請讓伺服器在無憑證時回應 tools/list,或發布可在沙箱中無憑證啟動的軟體包。

  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分