
Purl
io.github.nublson由 GitHub 账号 nublson 发布v0.5.1更新于 Nov 7, 2026
Save, organize and share your Purl links from any MCP client.
概览
Purl 是一个托管书签服务,其 MCP 服务器让助手保存、列出、读取、移动和删除收藏链接,并按文件夹整理。
- 可以做什么
- 保存 URL 为链接,自动识别网页、PDF、YouTube 视频和音频,并解析标题、描述、图标和缩略图。
- 列出已保存条目并查看单条链接详情。
- 在文件夹之间移动链接。
- 列出、创建、更新和删除文件夹。
- 重复保存同一 URL 会刷新其元数据并把它移到列表顶部。
- 适用场景
- 适合希望助手帮你维护一份值得回看的链接收藏,或在对话中把收藏归档、整理进文件夹而无需打开 Purl 应用的场景。
- 运行要求
- 远程 MCP 端点 purl.live,需要网络访问。必须认证:OAuth,或在 Authorization 请求头中携带在“设置 → 集成”中创建的 Purl API 密钥。需要 Purl 账号,每个账号最多保存 1,000 条链接。
安装
在 SourceWeft 中
- 打开 控制台中的 Purl,将其添加到工作区。
- 连接 所需的 凭据。它们会被私密存储,绝不会在公开页面上展示。
- 为需要使用其工具的对话启用该服务。
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
safeFetchwith optional proxy/DNS controls (seeAGENTS.md). An egress proxy can be configured viaSAFE_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 topublic/sw.js(generated onpnpm 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 inpnpm devto avoid service-worker cache surprises during development — usepnpm 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.
- Input —
POST /api/linkswith a URL (also/api/v1/linksand the MCPsave_linktool). - Classify & decorate — Server-side
detectContentType(SSRF-safeHEAD/ sniff) plusscrapeLinkMetadata(Open Graph HTML, PDFContent-Disposition/ size, YouTube oEmbed). Saving an existing URL again refreshes its metadata and moves it to the top. - Persist — A
Linkrow with title, favicon, thumbnail, domain, andcontentType(WEB,PDF,YOUTUBE, orAUDIO). - Sync —
broadcastLinksChangednotifies 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 throughsafeFetch: 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 inAGENTS.md. - Authentication & route gating — Better Auth sessions; Next.js
proxyredirects 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_URLandUPSTASH_REDIS_REST_TOKENare set, the proxy applies per-IP limits to/api/auth/*,POST /api/links, andPOST /api/feedback(seeproxy-rate-limit.ts). Without Upstash, limits are disabled — fine locally, not ideal for production. - Secrets & client exposure —
SUPABASE_SECRET_KEY(or the legacySUPABASE_SERVICE_ROLE_KEY) and similar values are server-only. The browser uses the Supabase anon key for Realtime only;.envstays 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 includespnpm-lock.yaml) - Postgres: local or hosted (Supabase works well)
1) Install dependencies
2) Configure environment variables
Create a .env file in the repo root. See .env.example for the full list; minimum for core behavior:
Notes:
DATABASE_URLis 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 fourAPPLE_*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
4) Generate Prisma client (if needed)
5) Start the dev server
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:
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.
Useful commands
More contributor notes (Prisma, outbound proxy env): see AGENTS.md.
来源:README.md,提交 a140440
工具
0版本历史
16- v0.5.1最新Nov 7, 2026
- v0.3.0Oct 29, 2026
- v0.2.0Oct 21, 2026
- v0.1.16Oct 15, 2026
- v0.1.15Oct 11, 2026
- v0.1.14Oct 10, 2026
- v0.1.13Oct 9, 2026
- v0.1.12Oct 8, 2026
- v0.1.11Oct 4, 2026
- v0.1.10Oct 3, 2026
- v0.1.9Oct 2, 2026
- v0.1.8Oct 2, 2026
- v0.1.6Oct 1, 2026
- v0.1.4Sep 25, 2026
- v0.1.3Sep 24, 2026
- v0.1.1Sep 16, 2026
评分
已满足适用检查项的 75%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通必需25 分
- 已声明认证方式必需10 分
- 已列出工具15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分
请在仓库或注册中心条目中声明许可证。