Skip to main content
ClaudeWave

AI read-it-later & personal knowledge base

MCP ServersRegistry oficial2 estrellas0 forks● TypeScriptActualizado today
ClaudeWave Trust Score
62/100
· OK
Passed
  • ✓Actively maintained (<30d)
  • ✓Clear description
  • ✓Documented (README)
Flags
  • !No standard license detected
Last scanned: 10/2/2026
Install in Claude Code / Claude Desktop
Method: Manual
Claude Code CLI
git clone https://github.com/nublson/purl
claude_desktop_config.json (Claude Desktop)
{
  "mcpServers": {
    "purl": {
      "command": "node",
      "args": ["/path/to/purl/dist/index.js"],
      "env": {
        "DATABASE_URL": "<database_url>",
        "NEXT_PUBLIC_SUPABASE_URL": "<next_public_supabase_url>",
        "NEXT_PUBLIC_SUPABASE_ANON_KEY": "<next_public_supabase_anon_key>",
        "SUPABASE_SERVICE_ROLE_KEY": "<supabase_service_role_key>",
        "GOOGLE_CLIENT_SECRET": "<google_client_secret>",
        "GITHUB_CLIENT_SECRET": "<github_client_secret>"
      }
    }
  }
}
1. Run the command above in your terminal (Claude Code), or paste the JSON config into claude_desktop_config.json (Claude Desktop).
2. Replace any <placeholder> values with your API keys or paths.
3. Restart Claude. The MCP server and its tools appear automatically.
💡 Clone https://github.com/nublson/purl and follow its README for install instructions.
Detected environment variables
DATABASE_URLNEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_ANON_KEYSUPABASE_SERVICE_ROLE_KEYGOOGLE_CLIENT_SECRETGITHUB_CLIENT_SECRET
Casos de uso

Resumen de MCP Servers

<p align="center">
  <img src="thumbnail.jpeg" alt="Purl — Save Anything. Keep what matters. A home for your links, PDFs, video, and audio." width="920" />
</p>

# Purl

**Save anything. Keep it in one place.**

**Live preview:** [https://purl.nublson.com](https://purl.nublson.com)

Purl is a read-it-later app — 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`](src/lib/limits.ts)).

The product goal: one place to stash material you care about.

## 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](https://www.better-auth.com/) (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`](docs/production-outbound-proxy.md).
- **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` and an MCP server (`save_link`, `list_saved_items`, `get_link`) 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](public/manifest.json) plus a [Serwist](https://serwist.pages.dev/) service worker ([`src/app/sw.ts`](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`](src/app/~offline/page.tsx). **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`](src/lib/server-detect-content-type.ts) (SSRF-safe `HEAD` / sniff) plus [`scrapeLinkMetadata`](src/lib/links.ts) (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`](src/lib/realtime-broadcast.ts) 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](https://serwist.pages.dev/) (`@serwist/next`), web manifest + precache / offline fallback

## CI / GitHub Actions

Automation lives under [`.github/workflows/`](.github/workflows/). Every PR and manual release is gated by these pipelines.

### PR checks — [`pr-checks.yml`](.github/workflows/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.

<p align="center">
  <img src="prCheckPipeline.png" alt="GitHub Actions graph for pr-checks.yml: Setup, Prisma, Lint & Type Check, Test & Build" width="920" />
</p>

### Release — [`release.yml`](.github/workflows/release.yml)

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

<p align="center">
  <img src="releasePipeline.png" alt="GitHub Actions graph for release.yml: merge develop into main, then build validation" width="920" />
</p>

## 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`](src/lib/safe-outbound-fetch.ts): 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`](AGENTS.md).
- **Authentication & route gating** — [Better Auth](https://www.better-auth.com/) sessions; Next.js [`proxy`](src/proxy.ts) 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`](src/lib/proxy-rate-limit.ts)). Without Upstash, limits are disabled — fine locally, not ideal for production.
- **Secrets & client exposure** — `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](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability) 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)
NEXT_PUBLIC_SUPABASE_URL="https://YOUR_PROJECT.supabase.co"
NEXT_PUBLIC_SUPABASE_ANON_KEY="eyJ..."
SUPABASE_SERVICE_ROLE_KEY="eyJ..."

# 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 <onboarding@resend.dev>"
```

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](https://portless.sh/).** 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.

**PW

Lo que la gente pregunta sobre purl

¿Qué es nublson/purl?

+

nublson/purl es mcp servers para el ecosistema de Claude AI. AI read-it-later & personal knowledge base Tiene 2 estrellas en GitHub y su última actualización registrada es del 2026-10-01.

¿Cómo se instala purl?

+

Puedes instalar purl clonando el repositorio (https://github.com/nublson/purl) o siguiendo las instrucciones del README en GitHub. ClaudeWave también te ofrece bloques de instalación rápida en esta misma página.

¿Es seguro usar nublson/purl?

+

Nuestro agente de seguridad ha analizado nublson/purl y le ha asignado un Trust Score de 62/100 (tier: OK). Revisa el desglose completo de comprobaciones superadas y flags en esta página.

¿Quién mantiene nublson/purl?

+

nublson/purl es mantenido por nublson. La última actividad registrada en GitHub es del 2026-10-01, con 1 issues abiertos.

¿Hay alternativas a purl?

+

Sí. En ClaudeWave puedes explorar mcp servers similares en /categories/mcp, ordenados por popularidad o actividad reciente.

Despliega purl en tu cloud

Lleva este repo a producción en minutos. Cada plataforma genera su propio entorno con variables de entorno editables.

¿Mantienes este repo? Añade un badge a tu README

Pega el badge en tu README de GitHub para mostrar que está auditado por ClaudeWave. Cada badge enlaza de vuelta a esta página y muestra el Trust Score actual.

Featured on ClaudeWave: nublson/purl
[![Featured on ClaudeWave](https://claudewave.com/api/badge/nublson-purl)](https://claudewave.com/repo/nublson-purl)
<a href="https://claudewave.com/repo/nublson-purl"><img src="https://claudewave.com/api/badge/nublson-purl" alt="Featured on ClaudeWave: nublson/purl" width="320" height="64" /></a>

Más MCP Servers

Alternativas a purl