Skip to main content
Glama
rossshannon

Pinboard MCP Server

by rossshannon
pinboard_mcp_server_prd.md9.6 kB
# Pinboard MCP Server – Product Requirements Document (PRD) ## 1. Document Meta | Field | Value | | ----- | ----- | | | | | **Project Name** | Pinboard MCP Server | | ---------------- | ------------------------------------------------------ | | **Version** | 1.0.0 | | **Authors** | | | **Last Updated** | | | **Stakeholders** | Product • Engineering • QA • DevOps • Security • Legal | ## 2. Purpose & Background Large‑Language‑Model (LLM) chat sessions benefit from personalised context. This project delivers a **local read‑only MCP server** that surfaces a user’s Pinboard.in bookmarks—via the Pinboard v1 API and the `pinboard.py` wrapper—so an LLM can search, filter and retrieve metadata (URL, tags, description, save‑date) at inference time. Motivations: - Let LLMs silently enrich answers with historical links the user has already deemed useful. - Enable “what was I researching this week?” style prompts. FastMCP 2.0 provides the scaffolding (Tool abstraction, async FastAPI server, JSON‑Schema validation) while `pinboard.py` simplifies API calls and error handling. **Pinboard field nomenclature** – The upstream API re-uses the vestigial Delicious vocabulary: `description` is the bookmark title and `extended` is the free-form notes. The `pinboard.py` wrapper preserves these names. Throughout this PRD we map them to the more intuitive `title` and `notes` fields returned by the MCP. ## 3. Personas & Use Cases | Persona | Need | Example Flow | | -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | | **Context Enrichment** | Ask an LLM about *Synology NAS* and get relevant bookmarks from any time in the past (tagged `synology`, `nas`, or text match), including the date each link was saved. | Prompt → LLM client → **Pinboard MCP Server** → Pinboard API → Matching bookmarks → LLM → Response | | **Conversational Starter** | Kick‑off a chat based on recent interests. Pull bookmarks from the last 7 days, summarise themes, then continue the conversation. | LLM client requests `listRecentBookmarks(days=7)` before greeting the user | ## 4. Goals & Non‑Goals ### 4.1 Goals - Expose **read‑only** Pinboard data via MCP tools (`searchBookmarks`, `listRecentBookmarks`, `listBookmarksByTags`, `listTags`). - P50 latency < 250 ms for cached responses; < 600 ms cold (single‑user localhost). - Respect Pinboard's unofficial guideline of **≤ 1 request every 3 s**; implement caching + `posts/update` polling. - Provide OpenAPI 3.1 docs for every endpoint. - Ship CI (lint, type‑check, tests, container) and observability hooks. ### 4.2 Non‑Goals - Creating, editing or deleting bookmarks/tags. - Full‑text indexing (initial release performs in‑memory filtering). ## 5. Functional Requirements ### 5.1 Tool Catalogue | Tool | Verb | Description | Params | Returns | | --------------------- | ----- | ----------------------------------------------------------- | ------------------------------------------------------------- | ------- | | `searchBookmarks` | `GET` | Keyword search across description, extended notes and tags. | `query` (str), `limit` (int≤100, default 20) | List  | | `listBookmarksByTags` | `GET` | Fetch bookmarks filtered by up to 3 tags. | `tags[]` (list [str] 1‑3), `from_date?`, `to_date?`, `limit?` | List  | | `listRecentBookmarks` | `GET` | Return bookmarks saved in the last *n* days (default 7). | `days` (int 1‑30), `limit?` | List  | | `listTags` | `GET` | Retrieve all tags with counts. | — | List  | ### 5.1.1 Implementation Notes - `searchBookmarks` is served from an in-memory cache seeded by `posts/all`, reducing Pinboard traffic at the cost of RAM (see § 12.4). - Cache invalidation relies on `posts/update`, a lightweight endpoint that returns the timestamp of the last change; if unchanged, we skip re-download. - Field-mapping reminder: Pinboard's `description` → `title`, `extended` → `notes`. - v0.1 is deliberately **read-only**. Write operations (`posts/add`, `posts/delete`, tag rename, etc.) are deferred to a future MCP release (see Appendix D). ### 5.2 Authentication & Authorisation - Users supply a **Pinboard API token** (format `username:hex`) via `PINBOARD_TOKEN` environment variable or macOS keychain. - Server rejects requests if token absent or invalid → HTTP 401. ### 5.3 Session & Context Handling - Optional `session_id` from MCP client is logged for traceability. - The service keeps an **LRU cache** of the last 1000 query results keyed by `(search query, tags, date range)` to be able to give more complete responses given the rate limiting. ### 5.4 Caching & Rate Limiting - When making a call to Pinboard, obey at least **3 s** between requests and back‑off on HTTP 429. ## 6. Non‑Functional Requirements | Category | Requirement | | ------------------------ | ----------------------------------------------------------------------------- | | **Performance** | P50 < 250 ms cached; P95 < 600 ms cold; throughput 30 RPS burst (single user) | | **Reliability** | ≥ 99 % uptime (local daemon) | | **Security** | Token never logged; transport over HTTPS | | **Privacy** | No bookmark content leaves machine except to Pinboard servers | | **Observability** | JSON logs, Prometheus `/metrics`, OpenTelemetry traces | | **Internationalisation** | UTF‑8; returns dates in ISO‑8601 Zulu | ## 7. API Contract & Schemas ### 7.1 Bookmark ```json { "type": "object", "required": ["id", "url", "title", "tags", "saved_at"], "properties": { "id": {"type": "string", "format": "uuid"}, "url": {"type": "string", "format": "uri"}, "title": {"type": "string"}, "tags": {"type": "array", "items": {"type": "string"}}, "notes": {"type": "string"}, "saved_at": {"type": "string", "format": "date-time"} } } ``` ### 7.2 TagCount ```json { "type": "object", "required": ["tag", "count"], "properties": { "tag": {"type": "string"}, "count": {"type": "integer"} } } ``` ## 8. Error Handling | Condition | HTTP Status | Example Message | | -------------- | ----------- | ---------------------------------------- | | Missing token |  401 | "PINBOARD\_TOKEN env var not set" | | Pinboard 429 |  429 | "Upstream rate limit hit – retry in 5 s" | | Invalid param |  400 | "days must be between 1 and 30" | | Upstream error |  502 | "Pinboard service unavailable" | | Internal error |  500 | "Unexpected server error" | ## 9. Testing Requirements - **Unit**: Mock `pinboard.Pinboard` with `pytest‑monkeypatch`; ≥ 90 % coverage. - **Integration**: Spin up server, use `vcr.py` cassettes to replay real API samples. - **Load**: k6 to 30 RPS, ensure < 1 % errors. ## 10. Metrics & Success | Metric | Target | | ----------------- | ------------------- | | P50 / P95 Latency | < 250 ms / < 600 ms | | Cache Hit Ratio | ≥ 80 % | | 4xx Rate | < 1 % | | 5xx Rate | < 0.1 % | ## 11. Dependencies & Tech Stack - **FastMCP 2.0** – MCP scaffolding. - **pinboard.py ≥ 2.0.0** – Pinboard client wrapper. - **FastAPI**, **Uvicorn/Gunicorn**, **Poetry**. - **pytest, pytest‑asyncio, responses, vcr.py** – testing. - **redis‑lite** (optional) – cache backend. - **ruff, mypy**, **OpenTelemetry**. ## 12. Open Questions & Risks 1. Should we implement local full‑text index (Whoosh/Lunr) for faster multi‑keyword search? 2. Pinboard API v2 is draft—risk of breaking changes. 3. Handling private vs public bookmarks—should privacy flag be exposed to LLM? 4. Memory footprint: `posts/all` may return 100 k+ bookmarks for power users. ## 13. Appendices - **A. Example Pinboard Calls** – `posts/recent`, `tags/get`, `posts/all?fromdt=…`. - **B. Sequence Diagram** – Prompt → MCP client → Pinboard MCP → Cache? → Pinboard API. - **C. Rate‑Limit Table** – 1 req / 3 s guideline; 429 back‑off strategy. - **D. Field Mapping & Future Write Tools** – Mapping of Pinboard to MCP fields and roadmap items.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rossshannon/pinboard-bookmarks-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server