# pinthread: full reference > pinthread lets reviewers pin threaded comments to elements of a live website. A coding agent reads those comments over MCP or HTTP, changes the code and replies. This file is the whole reference. The index is https://pinthread.dev/llms.txt. ## What it is - Reviewers click an element on your site and leave a comment. Each thread stores the page URL, the element selector and visible text, and the position or selected area. - Your agent never sees a screenshot guess. It gets the selector and the conversation. - pinthread gives the agent context. It does not run an agent, upload your repository or change your code. - Fully hosted at https://pinthread.dev. There is nothing to install or host. ## Install 1. Sign in at https://pinthread.dev/dashboard/ with Google and create a project. 2. Under Settings, add each address where the site runs. The widget loads only on approved sites. 3. Paste the script tag into the shared layout, before the closing body tag: ```html ``` The project key is public. It only tells the widget which project to load. ## Script tag attributes | Attribute | Behaviour | | --- | --- | | `src` | Required. Always https://pinthread.dev/embed.js. | | `data-project` | Required. The project key from the Install tab. | | `data-branch` | Optional. Keeps separate feedback for one branch, such as preview/navigation. Default is one shared stream. | | `defer` | Recommended. | Once loaded the tag exposes `window.pinthread` with `open()`, `close()`, `refresh()` and `destroy()`. ## Plans - Free, $0 a month: Up to 10 projects; 25 members per project; 10,000 comments per project; 100 MB of storage per project. Agent tokens and MCP access are included on every plan. ## Agent tokens Create a token in the project's Agent access tab. It starts with `ptk_`, is shown once, belongs to one project and expires after 90 days by default (at most 365). A read token lists and reads. A write token can also reply, start, resolve and reopen threads. Store it as `PINTHREAD_TOKEN`, never in the repository. ## Connect over MCP Server URL: https://pinthread.dev/mcp (streamable HTTP, bearer token). Server name: pinthread. Protocol versions: 2025-06-18, 2025-03-26, 2024-11-05. Claude Code: ```sh claude mcp add --transport http pinthread https://pinthread.dev/mcp \ --header "Authorization: Bearer $PINTHREAD_TOKEN" ``` Codex (`~/.codex/config.toml`): ```toml [mcp_servers.pinthread] url = "https://pinthread.dev/mcp" bearer_token_env_var = "PINTHREAD_TOKEN" ``` Cursor (`.cursor/mcp.json`): ```json { "mcpServers": { "pinthread": { "url": "https://pinthread.dev/mcp", "headers": { "Authorization": "Bearer ${env:PINTHREAD_TOKEN}" } } } } ``` Server instructions sent on initialize: Read design comments with list_threads and get_page_context. React to new comments with list_events and its cursor. Reply with reply_thread. Resolve a thread only after the fix is merged. ## MCP tools ### whoami Works with any token. Show the project, repository, token name and scope (read or write) this connection uses. No arguments. ### list_threads Works with any token. List design comment threads for the project, newest activity last. By default it returns every thread that is not resolved. Filter by status, assignee, priority or label. | Argument | Type | Required | Meaning | | --- | --- | --- | --- | | `status` | `unresolved \| open \| in_progress \| needs_review \| resolved \| all` | no | Default unresolved (every thread not resolved). | | `assignee` | `string` | no | Assignee id from list_assignees, or 'me'. | | `priority` | `none \| low \| medium \| high \| urgent` | no | | | `label` | `string` | no | Only threads with this label. | | `page` | `string` | no | Only threads on this page path, such as /pricing. | | `since` | `number` | no | Only threads updated after this Unix time in milliseconds. | | `limit` | `number` | no | Maximum threads to return. Default 50, maximum 300. | | `branch` | `string` | no | Comment scope. Defaults to "shared". | ### get_thread Works with any token. Read one thread with every comment, author and reaction. Includes its attachments (log and metadata text inline; screenshots, video and replay as links that expire in 15 minutes) and, for a suggested text edit, a suggestion with old, new and selector. | Argument | Type | Required | Meaning | | --- | --- | --- | --- | | `thread_id` | `string` | yes | Thread id from list_threads. | | `branch` | `string` | no | Comment scope. Defaults to "shared". | ### list_events Works with any token. Read new comment activity (new threads and replies) after a cursor, oldest first. Pass the cursor from the last call as `since`; use 'latest' to start from now. Poll this to react to new design comments without re-reading every thread. | Argument | Type | Required | Meaning | | --- | --- | --- | --- | | `since` | `string` | no | Cursor from the previous call, or 'latest'. Omit to read from the start. | | `limit` | `number` | no | Maximum events to return. Default 100, maximum 200. | | `branch` | `string` | no | Comment scope. Defaults to "shared". | ### get_page_context Works with any token. Return the open threads on one page, with their anchors, attachments and suggested edits, so you know which elements the comments point at. | Argument | Type | Required | Meaning | | --- | --- | --- | --- | | `page` | `string` | yes | Page path, such as /pricing. | | `branch` | `string` | no | Comment scope. Defaults to "shared". | ### reply_thread Needs a write token. Add a reply to a thread as this agent. Needs a write token. | Argument | Type | Required | Meaning | | --- | --- | --- | --- | | `thread_id` | `string` | yes | Thread id from list_threads. | | `body` | `string` | yes | Reply text, up to 4000 characters. | | `branch` | `string` | no | Comment scope. Defaults to "shared". | ### create_thread Needs a write token. Start a new thread on a page. The anchor says where the comment points. Needs a write token. | Argument | Type | Required | Meaning | | --- | --- | --- | --- | | `page` | `string` | yes | Page path, such as /pricing. | | `body` | `string` | yes | Comment text, up to 4000 characters. | | `anchor` | `object` | yes | Copy the anchor of an existing thread on the page, or give selector, text, x, y, width, height (0 to 1, relative to the element), pageX, pageY and viewportWidth. Add suggestion {old, new} to propose an exact text edit. | | `branch` | `string` | no | Comment scope. Defaults to "shared". | ### resolve_thread Needs a write token. Mark a thread resolved. Needs a write token. | Argument | Type | Required | Meaning | | --- | --- | --- | --- | | `thread_id` | `string` | yes | Thread id from list_threads. | | `branch` | `string` | no | Comment scope. Defaults to "shared". | ### reopen_thread Needs a write token. Reopen a resolved thread. Needs a write token. | Argument | Type | Required | Meaning | | --- | --- | --- | --- | | `thread_id` | `string` | yes | Thread id from list_threads. | | `branch` | `string` | no | Comment scope. Defaults to "shared". | ### update_thread Needs a write token. Change a thread's workflow fields: status (open, in_progress, needs_review, resolved), assignee (an id from list_assignees, 'me' for this agent, or null to clear), priority (none, low, medium, high, urgent), labels (up to 10) and dueAt (Unix milliseconds or null). Give only the fields you change. Needs a write token. | Argument | Type | Required | Meaning | | --- | --- | --- | --- | | `thread_id` | `string` | yes | Thread id from list_threads. | | `status` | `open \| in_progress \| needs_review \| resolved` | no | | | `assignee` | `string \| null` | no | Assignee id, 'me', or null. | | `priority` | `none \| low \| medium \| high \| urgent` | no | | | `labels` | `array` | no | Replaces all labels. | | `dueAt` | `number \| null` | no | Due date in Unix milliseconds, or null. | | `branch` | `string` | no | Comment scope. Defaults to "shared". | ### list_assignees Works with any token. List who can be assigned a thread: the owner, invited members and agent tokens. | Argument | Type | Required | Meaning | | --- | --- | --- | --- | | `branch` | `string` | no | Comment scope. Defaults to "shared". | ### mark_suggestion_applied Needs a write token. Mark a thread's suggested text edit as applied after you changed the code. Adds a note comment and resolves the thread. Needs a write token. | Argument | Type | Required | Meaning | | --- | --- | --- | --- | | `thread_id` | `string` | yes | Thread id from list_threads. | | `note` | `string` | no | What you changed, up to 1000 characters. | | `branch` | `string` | no | Comment scope. Defaults to "shared". | ## HTTP API `POST https://pinthread.dev/mcp` takes one JSON-RPC 2.0 message or a batch of up to 20, at most 64 KB. Methods: initialize, ping, tools/list, tools/call. Authenticate with `Authorization: Bearer ptk_…`. REST routes open to an agent token. Each needs the `project` query parameter (the project key). `/threads` and `/events` also need `branch`, for example `branch=shared`. `/config` and `/me` accept GET only. | Method | Path | Token | What it does | | --- | --- | --- | --- | | `GET` | `/threads` | read | List threads. Query: project, branch, id (one thread), cursor, offset. Returns threads and nextCursor. | | `GET` | `/events` | read | Read new activity after a cursor. Query: project, branch, since, limit. Returns events, cursor and more. | | `GET` | `/config` | read | Read the project configuration. | | `GET` | `/me` | read | Read the identity behind the token. | | `POST` | `/threads` | write | Start a thread. Body: page, body, anchor. | | `POST` | `/threads/{id}/comments` | write | Reply to a thread. Body: body. | | `POST` | `/threads/{id}/attachments` | write | Attach an image to a thread. | | `POST` | `/threads/{id}/comments/{commentId}/reactions` | write | React to a comment. | | `PATCH` | `/threads/{id}/comments/{commentId}` | write | Edit a comment the token's identity wrote. | | `DELETE` | `/threads/{id}/comments/{commentId}` | write | Delete a comment the token's identity wrote. | | `PATCH` | `/threads/{id}` | write | Resolve or reopen with { resolved: true \| false }. Mark a suggested edit applied with { applied: true, note }. Change workflow fields with any of { status, assignee, priority, labels, dueAt } (project members only, not together with resolved). Move the pin with { anchor } on its own, only on a thread the token's identity started. | Other routes return 403. Errors are JSON `{"error": "message"}`: 400 invalid input, 401 bad token, 403 read-only token or closed route, 404 not found, 405 wrong method, 413 body too large, 429 rate limited. `GET https://pinthread.dev/health` and `GET https://pinthread.dev/api/version` need no token. ## Pages Docs: https://pinthread.dev/docs/ . MCP tools: https://pinthread.dev/docs/mcp-tools/ . HTTP API: https://pinthread.dev/docs/api/ . FAQ: https://pinthread.dev/faq/ .