Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Hosted at [getpluck.io](https://getpluck.io), or run your own with `docker compo
- `packages/db`: the only code that touches MongoDB. Every query is scoped to one person.
- `packages/extract`: reading pages, PDFs, email and imports.
- `packages/blob`: S3 (MinIO locally).
- `packages/mcp`: the connector's tools, resources and prompts. `packages/mcp-stdio` is `npx @getpluck/mcp`.
- `packages/mcp`: the connector's tools, resources and prompts. `packages/mcp-stdio` is `npx @getpluck/mcp` ([npm](https://www.npmjs.com/package/@getpluck/mcp)).
- `packages/shared-schemas`: every type, as a Zod schema, shared by server and clients.
- `packages/client`: the API client, offline queue and PKCE shared by the iPhone app and the extension.
- `packages/i18n`: the words in ten languages (English, Spanish, Portuguese (Brazil), French, German, Japanese, Italian, Dutch, Korean, Chinese (Simplified)).
Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Tell us what you found, how to see it, and what someone could do with it. A proo

## What is in scope

The hosted service at getpluck.io, the code in this repository (web app, API, MCP connector, browser extension, iPhone app and share extension, the Docker image), and the published `@getpluck/mcp` package.
The hosted service at getpluck.io, the code in this repository (web app, API, MCP connector, browser extension, iPhone app and share extension, the Docker image), and the published [`@getpluck/mcp`](https://www.npmjs.com/package/@getpluck/mcp) package.

Self-hosted copies are run by their owners; report problems in the code here, and the owner of that copy for problems in how it is run.

Expand Down
2 changes: 1 addition & 1 deletion docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ One Next.js app (`apps/web`) is the website, the signed-in app, the REST API for
| `apps/web/lib/email.ts`, `emails.ts`, `digest-email.ts` | `sendEmail` (SMTP to Mailpit locally, SES in production) and the email templates. |
| `packages/db` | Every collection, index and query (`collections.ts` defines them all). Every query is scoped by `userId`; `public.ts` is the only reader for public Lists. |
| `packages/mcp` | The connector's tools, resources and prompts (package `@pluck/mcp-server`). It sees the library only through `PluckLibrary`. |
| `packages/mcp-stdio` | The `npx @getpluck/mcp` bridge (package `@getpluck/mcp`, the one published to npm): stdio to the hosted connector with an API key. |
| `packages/mcp-stdio` | The `npx @getpluck/mcp` bridge (package [`@getpluck/mcp`](https://www.npmjs.com/package/@getpluck/mcp), the one published to npm): stdio to the hosted connector with an API key. |
| `packages/extract` | Guarded fetch (`fetch.ts`), page and PDF reading (`extract.ts`, Defuddle then Readability), email (`email.ts`) and imports. Its fixtures are served by `pnpm stack` so tests never touch the internet. |
| `packages/blob` | S3 through the AWS SDK; MinIO locally and for self-hosting. |
| `packages/shared-schemas` | Every type as a Zod schema, used by the server and every client. |
Expand Down
2 changes: 1 addition & 1 deletion docs/handover/design/Settings.dc.html
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ <h2 style="margin: 0; font-size: 18px; line-height: 24px; font-weight: 600">AI t
<div style="display: flex; flex-direction: column; gap: 6px"><span style="font-weight: 500">Claude Code</span>
<div style="display: flex; gap: 8px"><code style="flex: 1; min-width: 0; height: 40px; box-sizing: border-box; display: flex; align-items: center; padding: 0 12px; border-radius: 8px; background: #FFFFFF; border: 1px solid #D3D9CE; font: 13px ui-monospace, 'SF Mono', Menlo, monospace; white-space: nowrap; overflow: hidden">claude mcp add --transport http pluck https://getpluck.io/mcp</code><button type="button" style="height: 40px; padding: 0 14px; border-radius: 8px; border: 1px solid #CDD3C7; background: #FFFFFF; font: inherit">Copy</button></div></div>
<div style="display: flex; flex-direction: column; gap: 6px"><span style="font-weight: 500">Self-hosting without a public URL</span>
<code style="height: 40px; box-sizing: border-box; display: flex; align-items: center; padding: 0 12px; border-radius: 8px; background: #EDF0EA; font: 13px ui-monospace, 'SF Mono', Menlo, monospace">npx @pluck/mcp --key pk_live_••••••••3f9a</code></div>
<code style="height: 40px; box-sizing: border-box; display: flex; align-items: center; padding: 0 12px; border-radius: 8px; background: #EDF0EA; font: 13px ui-monospace, 'SF Mono', Menlo, monospace">npx @getpluck/mcp --key pk_live_••••••••3f9a</code></div>
<div style="display: flex; flex-wrap: wrap; align-items: center; gap: 12px"><button type="button" style="height: 40px; padding: 0 14px; border-radius: 8px; border: 1px solid #151A13; background: transparent; font: inherit; font-weight: 500">Test it</button><span style="color: #525A4E; font-size: 13px">Opens your AI with “What did I pluck this week?”</span></div>
</div>
<div style="flex: 0 1 300px; display: flex; flex-direction: column; gap: 8px">
Expand Down
2 changes: 1 addition & 1 deletion docs/handover/design/SiteClaude.dc.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ <h2 style="margin: 0; font-size: clamp(36px, 4.5vw, 60px); line-height: 1; font-
code: { label: "Claude Code", steps: ["Open a terminal.", "Run the one line on the right.", "Say “what did I pluck this week?” to test it."], codeLabel: "One line", code: "claude mcp add --transport http pluck https://getpluck.io/mcp", note: "Signs you in through your browser the first time." },
chatgpt: { label: "ChatGPT", steps: ["Open ChatGPT, then Settings, then Connectors.", "Choose Create and paste the link as the MCP server URL.", "Sign in to Pluck when it asks."], codeLabel: "MCP server URL", code: "https://getpluck.io/mcp", note: "Needs a plan that allows custom connectors." },
cursor: { label: "Cursor", steps: ["Open Cursor settings, then MCP.", "Add a server with the JSON on the right.", "Sign in to Pluck when it asks."], codeLabel: "mcp.json", code: "{ \"mcpServers\": { \"pluck\": { \"url\": \"https://getpluck.io/mcp\" } } }", note: "Any editor or client that supports remote MCP works the same way." },
self: { label: "Self-hosted", steps: ["Make an API key in Settings.", "Add the line on the right to your AI tool as a local (stdio) server.", "Ask it what you plucked this week."], codeLabel: "Without a public URL", code: "npx @pluck/mcp --server https://pluck.your.host --key pk_live_…", note: "The same tools and prompts, bridged to your own server." }
self: { label: "Self-hosted", steps: ["Make an API key in Settings.", "Add the line on the right to your AI tool as a local (stdio) server.", "Ask it what you plucked this week."], codeLabel: "Without a public URL", code: "npx @getpluck/mcp --server https://pluck.your.host --key pk_live_…", note: "The same tools and prompts, bridged to your own server." }
};
class Component extends DCLogic {
constructor(p) { super(p); this.state = { tab: "claude" }; }
Expand Down
2 changes: 1 addition & 1 deletion docs/handover/design/SiteOpen.dc.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ <h2 style="margin: 0; font-size: clamp(36px, 4.5vw, 60px); line-height: 1; font-
<span>cd pluck</span>
<span><span style="color: #7FD3AE">docker compose up -d</span></span>
<span style="color: #A0A898; margin-top: 10px"># then, for AI tools without a public URL</span>
<span>npx @pluck/mcp --server http://localhost:3000 --key pk_live_…</span>
<span>npx @getpluck/mcp --server http://localhost:3000 --key pk_live_…</span>
</div>
</section>

Expand Down
2 changes: 1 addition & 1 deletion docs/handover/pluck-product-spec-v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ The share sheet is the product on iOS. It saves in place, like Pocket did. The a

The connector is the product's second half. It has to feel like your AI has read your library, not like it is poking an API. Pluck speaks MCP, so Claude, ChatGPT, Cursor, Claude Code and any other MCP client use the same URL. Claude is named only as one of them.

**Setup.** Settings, AI tools: the connector URL with a copy button, install steps for Claude, Claude Code, ChatGPT, Cursor and self-hosted, a 20-second GIF, and a "Test it" button that opens your AI with "What did I pluck this week?" prefilled. Self-hosters without a public URL get `npx @pluck/mcp` with their API key.
**Setup.** Settings, AI tools: the connector URL with a copy button, install steps for Claude, Claude Code, ChatGPT, Cursor and self-hosted, a 20-second GIF, and a "Test it" button that opens your AI with "What did I pluck this week?" prefilled. Self-hosters without a public URL get `npx @getpluck/mcp` with their API key.

**The four prompts.** These are the only "AI features" Pluck has, and they live in your AI tool.

Expand Down
6 changes: 3 additions & 3 deletions docs/handover/pluck-technical-spec-v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ packages/shared-schemas Zod types, OpenAPI, error codes
packages/db the only package that touches MongoDB
packages/extract Defuddle/Readability, fixtures
packages/mcp tools, resources, prompts
packages/mcp-stdio npx @pluck/mcp bridge for self-host
packages/mcp-stdio npx @getpluck/mcp bridge for self-host
packages/ui brand tokens, Logo and Icon components, kind glyphs
infra/cdk DataStack, EmailStack, DnsStack
docs/ self-host.md, mcp.md
Expand Down Expand Up @@ -213,7 +213,7 @@ The MCP server is the product's brain socket and the only public integration sur
| Claude Code | `claude mcp add --transport http pluck https://getpluck.io/mcp` | OAuth with loopback redirect, or `--header "Authorization: Bearer pk_live_..."` |
| ChatGPT | Settings, Connectors, Create, MCP server URL | OAuth |
| Cursor and other editors | `mcp.json` with `{ "mcpServers": { "pluck": { "url": "https://getpluck.io/mcp" } } }` | OAuth or API key |
| Self-host without public HTTPS | `npx @pluck/mcp --server <url> --key pk_live_...` (stdio bridge) | API key |
| Self-host without public HTTPS | `npx @getpluck/mcp --server <url> --key pk_live_...` (stdio bridge) | API key |

**OAuth flow.** `POST /mcp` without a token returns `401` with `WWW-Authenticate: Bearer resource_metadata="https://getpluck.io/.well-known/oauth-protected-resource"`. The client reads the first `authorization_servers` entry, fetches `/.well-known/oauth-authorization-server`, uses CIMD if advertised and DCR otherwise, runs the authorisation code flow with PKCE and `resource=https://getpluck.io/mcp`, and refreshes on its own. The server validates `aud` on every request and includes `iss` in authorisation responses. Each discovery and token endpoint answers inside 10 seconds. No apex-to-www redirects on these paths.

Expand Down Expand Up @@ -370,7 +370,7 @@ Each step ends green in CI and deployable.
4. Lists: CRUD, per-list note and tick, reorder, `a` shortcut, list page, Private/Public switch, public page with the narrow projection and its test, copy, report.
5. Search with `$text`, filter chips, "Ask your AI" empty state.
6. Worker: retry queue, expiry job, archive-stale, digest email, email-in, import, export.
7. MCP server: OAuth metadata and CIMD, the 12 tools, 2 resources, 4 prompts, the end-to-end OAuth test. `npx @pluck/mcp` bridge. Settings AI tools section.
7. MCP server: OAuth metadata and CIMD, the 12 tools, 2 resources, 4 prompts, the end-to-end OAuth test. `npx @getpluck/mcp` bridge. Settings AI tools section.
8. Extension: popup, capture, list picker, all-tabs, context menus, badge, options.
9. Marketing site, privacy, terms, Connect your AI page.
10. iOS Shortcut, then the Expo app and the Swift share extension.
Expand Down
2 changes: 1 addition & 1 deletion docs/mcp.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,6 @@ Everything an AI tool changes is marked "by AI" in Pluck: its tags until the per

- `packages/mcp` holds the tools, resources and prompts. It sees the library only through `PluckLibrary` (`packages/mcp/src/library.ts`); `apps/web/lib/connector.ts` binds it to the in-process library for one person, with every write marked as made by AI.
- `apps/web/app/mcp/route.ts` authenticates (OAuth token or API key), rate limits and serves.
- `packages/mcp-stdio` is the `npx @getpluck/mcp` bridge.
- `packages/mcp-stdio` is the `npx @getpluck/mcp` bridge, published as [`@getpluck/mcp`](https://www.npmjs.com/package/@getpluck/mcp).
- Tests: `apps/web/lib/connector.test.ts` (every tool against a seeded database), `apps/web/lib/cimd.test.ts`, `packages/mcp-stdio/src/bridge.test.ts`, and `e2e/mcp.spec.ts` (the full OAuth dance, every tool, resource and prompt over HTTP, Disconnect, API keys and the stdio bridge).
- Try it by hand: `npx @modelcontextprotocol/inspector`, then connect to `http://localhost:3000/mcp`.
2 changes: 2 additions & 0 deletions packages/mcp-stdio/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# @getpluck/mcp

[npm](https://www.npmjs.com/package/@getpluck/mcp)

Your [Pluck](https://getpluck.io) library in any MCP client that speaks stdio, with an API key. Clients that connect to
a remote server (Claude, ChatGPT, Cursor) can use `https://getpluck.io/mcp` directly and need none of this.

Expand Down
Loading