Purl

io.github.nublson由 GitHub 帳號 nublson 發布v0.5.1更新於 Nov 7, 2026

Save, organize and share your Purl links from any MCP client.

已驗證Streamable HTTP可網頁執行效率與工作流檔案與儲存知識與記憶

概覽

AI 產生的概覽

Purl 是託管書籤服務,其 MCP 伺服器讓助理儲存、列出、讀取、移動和刪除收藏連結,並以資料夾整理。

可以做什麼
  • 將網址存為連結,自動辨識網頁、PDF、YouTube 影片和音訊,並解析標題、描述、圖示和縮圖。
  • 列出已儲存項目並查看單一連結的詳細資料。
  • 在資料夾之間移動連結。
  • 列出、建立、更新和刪除資料夾。
  • 重複儲存同一網址會更新其中繼資料並把它移到清單最上方。
適用情境
適合想讓助理幫忙維護一份值得回看的連結收藏,或在對話中把收藏歸檔、整理進資料夾而不必開啟 Purl 應用程式的情況。
執行需求
遠端 MCP 端點 purl.live,需要網路連線。必須驗證:OAuth,或在 Authorization 標頭中帶上於「設定 → 整合」建立的 Purl API 金鑰。需要 Purl 帳號,每個帳號最多可儲存 1,000 個連結。
安裝前請注意
Authorization 標頭帶有金鑰,請避免出現在日誌和共享紀錄中。這些工具會寫入你的帳號:儲存、移動、編輯和刪除連結與資料夾都會變更已存資料,刪除資料夾可能一併移除其中內容。儲存的網址會由 Purl 伺服器端抓取和解析,因此你加入的連結會傳送給該服務。

安裝

在 SourceWeft 中

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

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

交給代理程式安裝

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

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

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

其他 MCP 客戶端

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

{
  "mcpServers": {
    "purl": {
      "type": "http",
      "url": "https://purl.live/api/mcp"
    }
  }
}

README

[Purl — Save Anything. Keep what matters. A home for your links, PDFs, video, and audio.]

Purl

Save the links worth keeping. Share the ones worth passing on.

Live preview: https://purl.live

Purl is a calm place to save and share the links you find — a home for your "pearls". You paste URLs: web pages, PDFs, YouTube videos, and audio. Purl resolves each item's metadata (title, favicon, description, thumbnail) and keeps everything in one place, available from the app, a REST API, and an MCP server.

Purl is free, with one limit: each account can save up to 1,000 links (MAX_SAVED_LINKS in src/lib/limits.ts).

The product goal: one place to keep the links you care about, and an easy way to share the ones worth passing on.

Implemented today

  • Marketing site — Landing page (hero with a live preview), docs for the REST API and MCP server, privacy and terms.
  • Authentication — Google and GitHub sign-in on the landing page via Better Auth (Apple too when its env vars are set). Every account gets a unique username, editable in Settings, where you can also connect or disconnect sign-in methods; avatars come from the OAuth provider's profile photo.
  • Save & organize
    • Add items by URL with automatic content-type detection (web, PDF, YouTube, audio).
    • Links grouped by relative time (e.g. Today, This week, Last month).
    • Preview metadata (title, description, favicon, thumbnail where available).
  • Hardened outbound fetch — Server-side safeFetch with optional proxy/DNS controls (see AGENTS.md). An egress proxy can be configured via SAFE_OUTBOUND_HTTP_PROXY.
  • Realtime list sync — Supabase Realtime so saves and updates propagate across tabs/devices quickly.
  • Link actions — Open original, copy URL, edit metadata, delete.
  • REST API & MCP — /api/v1 (links and folders) and an MCP server (save_link, list_saved_items, get_link, move_link, list_folders, create_folder, update_folder, delete_folder) with API-key or OAuth auth.
  • Operational extras — Optional Upstash-backed API rate limiting, Vitest coverage for critical paths.
  • PWA (installable app) — Web App Manifest plus a Serwist service worker (src/app/sw.ts) that builds to public/sw.js (generated on pnpm build, gitignored). Enables Install in Chrome/Edge and similar where the platform supports it, with runtime caching via Serwist's Next.js defaults and a static offline shell at /~offline. Serwist is disabled in pnpm dev to avoid service-worker cache surprises during development — use pnpm build && pnpm start (or your production URL) to exercise installability and the SW.

Save flow

Saving a link is fully synchronous — there is no background processing.

  1. Input — POST /api/links with a URL (also /api/v1/links and the MCP save_link tool).
  2. Classify & decorate — Server-side detectContentType (SSRF-safe HEAD / sniff) plus scrapeLinkMetadata (Open Graph HTML, PDF Content-Disposition / size, YouTube oEmbed). Saving an existing URL again refreshes its metadata and moves it to the top.
  3. Persist — A Link row with title, favicon, thumbnail, domain, and contentType (WEB, PDF, YOUTUBE, or AUDIO).
  4. Sync — broadcastLinksChanged notifies other tabs/devices via Supabase Realtime.

Not implemented yet

These are called out explicitly because the repo is going public:

  • Settings breadth — Settings cover username, sign-in methods, and account deletion; broader account preferences (notification settings, etc.) are not implemented yet.

Marketing vs. product: The landing page copy mentions ideas such as collections and a weekly digest. Those are not built in the current schema or app — treat them as roadmap, not shipped features.

Tech stack

  • Web: Next.js (App Router), React, TypeScript
  • UI: Tailwind CSS, shadcn/ui
  • Auth: Better Auth
  • Database: PostgreSQL + Prisma
  • Email (optional in dev): Resend for feedback emails
  • Realtime: Supabase client (anon + service role on server)
  • PWA: Serwist (@serwist/next), web manifest + precache / offline fallback

CI / GitHub Actions

Automation lives under .github/workflows/. Every PR and manual release is gated by these pipelines.

PR checks — pr-checks.yml

Runs on pull_request to develop and main: Setup & validation → Prisma (generate client + type fixes) → Lint and type check (in parallel) → Tests and production build (in parallel, after lint and type check pass). Concurrency is per-PR so new pushes cancel stale runs.

[GitHub Actions graph for pr-checks.yml: Setup, Prisma, Lint & Type Check, Test & Build]

Release — release.yml

Runs on workflow_dispatch (manual): Merge develop into main, then build validation so production is only promoted after a green build.

[GitHub Actions graph for release.yml: merge develop into main, then build validation]

Security

Purl is built around untrusted input (arbitrary URLs). A few layers matter in production:

  • SSRF-aware outbound fetches — User-supplied URLs are not passed to raw fetch. OG/thumbnail probes, PDF fetch, content-type sniffing, and similar paths go through safeFetch: HTTP(S) only, blocked private/link-local/reserved targets, redirect handling with per-hop host checks, DNS resolution pinned before connect (mitigates classic DNS rebinding against the pre-check), optional response size caps (e.g. PDF proxy). Optional egress proxy and custom DNS servers are documented in AGENTS.md.
  • Authentication & route gating — Better Auth sessions; Next.js proxy redirects unauthenticated users away from private routes. Sign-in is OAuth-only (Google/GitHub, plus Apple when configured); there are no passwords.
  • API authorization — Sensitive routes (/api/links, /api/v1/*, MCP, etc.) resolve the session server-side and scope work to the signed-in user.
  • Rate limiting — When UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN are set, the proxy applies per-IP limits to /api/auth/*, POST /api/links, and POST /api/feedback (see proxy-rate-limit.ts). Without Upstash, limits are disabled — fine locally, not ideal for production.
  • Secrets & client exposure — SUPABASE_SECRET_KEY (or the legacy SUPABASE_SERVICE_ROLE_KEY) and similar values are server-only. The browser uses the Supabase anon key for Realtime only; .env stays gitignored.
  • Response bounds — PDF proxy streaming is size-capped (see safe-outbound-fetch).

Reporting a vulnerability: use GitHub Security Advisories for this repository so details stay private until patched.

Setup (local development)

Prerequisites

  • Node.js: recent LTS
  • Package manager: pnpm (this repo includes pnpm-lock.yaml)
  • Postgres: local or hosted (Supabase works well)

1) Install dependencies

bash
pnpm install

2) Configure environment variables

Create a .env file in the repo root. See .env.example for the full list; minimum for core behavior:

bash
DATABASE_URL="postgresql://USER:PASSWORD@HOST:5432/DBNAME"
# Supabase Realtime — cross-device instant link list sync (same project as Postgres)SUPABASE_URL="https://YOUR_PROJECT.supabase.co"SUPABASE_ANON_KEY="eyJ..."SUPABASE_SECRET_KEY="sb_secret_..."
# Sign-in (OAuth apps with callback {BETTER_AUTH_URL}/api/auth/callback/{google,github})GOOGLE_CLIENT_ID="..."GOOGLE_CLIENT_SECRET="..."GITHUB_CLIENT_ID="..."GITHUB_CLIENT_SECRET="..."
# Optional (used to send in-app feedback emails)RESEND_API_KEY="re_..."RESEND_FROM="Purl <[email protected]>"

Notes:

  • DATABASE_URL is required (Prisma + Better Auth).
  • Supabase env vars are required for realtime link list sync. Use Project Settings → API in the Supabase dashboard. The service role key must stay server-only.
  • Google/GitHub OAuth credentials are required in production; locally, a provider whose vars are missing is simply hidden. For local dev, use callback URLs http://localhost:3000/api/auth/callback/{google,github}. Apple is optional and enabled only when all four APPLE_* vars are set (see .env.example).
  • Resend is optional for local dev: without RESEND_API_KEY, in-app feedback can't be sent.
  • Better Auth secrets and URLs are in .env.example — copy those keys for a working auth setup.

3) Run database migrations

bash
pnpm prisma migrate dev

4) Generate Prisma client (if needed)

bash
pnpm prisma generate

5) Start the dev server

bash
pnpm dev

Open http://localhost:3000.

Optional: a named HTTPS URL with portless. With portless installed globally (npm install -g portless, Node.js 24+), run portless run instead of pnpm dev. It runs the dev script behind a local proxy at https://purl.localhost. Point auth at that URL in .env.local, or sign-in rejects the origin:

bash
BETTER_AUTH_URL="https://purl.localhost"BASE_URL="https://purl.localhost"

In a git worktree, portless prefixes the branch name (for example https://my-branch.purl.localhost); set both variables to that URL there.

PWA / install: With pnpm dev, the service worker is not active. After a production build, public/sw.js exists locally; run pnpm start and open the app in Chromium to use Install or to test offline navigation to /~offline.

Testing

Tests use Vitest and focus on critical logic (formatters, link grouping, auth routing, API behavior, metadata scraping). They intentionally avoid shallow UI-only wrappers.

bash
pnpm test        # run oncepnpm test:watch  # watch mode

Useful commands

bash
pnpm lintpnpm buildpnpm startpnpm test

More contributor notes (Prisma, outbound proxy env): see AGENTS.md.

來源:README.md,提交 a140440

工具

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

版本歷史

16
  1. v0.5.1最新Nov 7, 2026
  2. v0.3.0Oct 29, 2026
  3. v0.2.0Oct 21, 2026
  4. v0.1.16Oct 15, 2026
  5. v0.1.15Oct 11, 2026
  6. v0.1.14Oct 10, 2026
  7. v0.1.13Oct 9, 2026
  8. v0.1.12Oct 8, 2026
  9. v0.1.11Oct 4, 2026
  10. v0.1.10Oct 3, 2026
  11. v0.1.9Oct 2, 2026
  12. v0.1.8Oct 2, 2026
  13. v0.1.6Oct 1, 2026
  14. v0.1.4Sep 25, 2026
  15. v0.1.3Sep 24, 2026
  16. v0.1.1Sep 16, 2026

評分

已滿足適用檢查項的 75%

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

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

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

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

    請在儲存庫或註冊中心條目中宣告授權條款。