Pincushion

by jcooley8

Not rated
GitHub

About

Stakeholders pin feedback on your live app; your AI coding agent reads it via MCP and fixes it

Details

Author
jcooley8
Categories
Developer Tools, Other

Setup

Install Pincushion in your MCP client (Claude Desktop, Cursor, Windsurf, and others).

Repository: https://github.com/jcooley8/pincushion-plugin

Follow the installation instructions in the repository README, then restart your MCP client.

The implementation-context layer for AI-native development. Stakeholders drop visual pins on any page of your live app; your AI coding agent reads each pin through MCP and ships the fix — in Claude Code, Cursor, VS Code, Windsurf, or any MCP client.

A pin isn't a feedback item — it's anagent work packet. Each one carries everything an agent needs to implement the change without a back-and-forth:

- URL + element selector— exactly what, exactly where
- Screenshot + viewport + DOM snippet— the visual and structural context
- Thread + project context— the conversation and the codebase it lives in
- Likely files + acceptance criteria— where to look, and how to know it's done

The loop closes itself: a stakeholder pins it → your agent reads it via MCP and fixes it in your IDE → the resolve records the commit, branch, and PR → an optional post-deploy critique verifies the fix actually landed.

This server is also how Pincushion AI runs design/copy/a11y critiques on a live page and writes the pins straight back onto it.

# npm npm install -g pincushion-mcp # pnpm pnpm add -g pincushion-mcp # yarn yarn global add pincushion-mcp
# npm npx pincushion-mcp --project-dir . # pnpm pnpm dlx pincushion-mcp --project-dir . # yarn yarn dlx pincushion-mcp --project-dir .

Download the Pincushion Chrome extension frompincushion.io/install/chrome.

Pick your AI agent below and follow the configuration for your setup.

- See all feedback:get_feedback_summary
- Find specific pins:search_annotations
- Fix and mark as done:fix_and_resolve

{ "mcpServers": { "pincushion": { "command": "npx", "args": ["pincushion-mcp", "--project-dir", "."] } } }

pnpm / yarn users:replace"command": "npx"with"command": "pnpm"and add"dlx"as the first arg, or use"command": "yarn"with"dlx"likewise.

{ "mcpServers": { "pincushion": { "command": "npx", "args": [ "pincushion-mcp", "--project-dir", ".", "--sync-url", "https://your-supabase.com/api", "--api-key", "YOUR_API_KEY" ] } } }

File:~/.config/Claude/claude_desktop_config.json(Linux/Windows) or~/Library/Application Support/Claude/claude_desktop_config.json(macOS)

{ "mcpServers": { "pincushion": { "command": "npx", "args": ["pincushion-mcp", "--project-dir", "/path/to/your/project"] } } }
{ "mcpServers": { "pincushion": { "command": "pnpm", "args": ["dlx", "pincushion-mcp", "--project-dir", "/path/to/your/project"] } } }
{ "mcpServers": { "pincushion": { "command": "yarn", "args": ["dlx", "pincushion-mcp", "--project-dir", "/path/to/your/project"] } } }
{ "mcpServers": { "pincushion": { "command": "npx", "args": [ "pincushion-mcp", "--project-dir", "/path/to/your/project", "--sync-url", "https://your-supabase.com/api", "--api-key", "YOUR_API_KEY" ] } } }

Run this command to add Pincushion to Claude Code:

claude mcp add pincushion -- npx pincushion-mcp --project-dir .
claude mcp add pincushion -- npx pincushion-mcp --project-dir . --sync-url https://your-supabase.com/api --api-key YOUR_API_KEY
{ "mcp.servers": { "pincushion": { "command": "npx", "args": ["pincushion-mcp", "--project-dir", "${workspaceFolder}"] } } }

File:~/.windsurf/mcp.jsonor~/.config/windsurf/mcp.json

{ "mcpServers": { "pincushion": { "command": "npx", "args": ["pincushion-mcp", "--project-dir", "."] } } }
{ "mcpServers": { "pincushion": { "command": "npx", "args": ["pincushion-mcp", "--project-dir", "."] } } }

For tools that don't support MCP directly, use the REST API wrapper:

This starts an HTTP server onlocalhost:3456. Endpoints:

- GET /health— Check server status
- POST /call-tool— Invoke a tool

- Body:{ "toolName": "get_feedback_summary", "args": {} }

curl -X POST http://localhost:3456/call-tool \ -H "Content-Type: application/json" \ -d '{"toolName": "get_feedback_summary", "args": {}}'
npx pincushion-mcp --project-dir /path/to/project
npx pincushion-mcp \ --project-dir /path/to/project \ --sync-url https://abcd1234.supabase.co/api \ --api-key sb_project_key_abc123...

Retrieve annotations from.feedback/. Filter by page, component, or status.

- pageUrl(string, optional) — Filter by page URL (partial match)
- componentName(string, optional) — Filter by LWC component name
- status(string, optional) — Filter byopen,in-progress, orresolved

await mcp.callTool('get_annotations', { componentName: 'wmlHomePage', status: 'open' });

Full-text search across all annotations, comments, selectors, and tags.

await mcp.callTool('search_annotations', { query: 'button label' });

High-level rollup of all feedback: counts by status, priority, page, and component.

await mcp.callTool('get_feedback_summary', {});

Get all feedback for a specific LWC component with a plain-language summary.

- componentName(string, required) — LWC component name

await mcp.callTool('get_component_feedback', { componentName: 'wmlHomePage' });

Mark an annotation as resolved after fixing the issue.

- annotationId(string, required) — Annotation ID
- comment(string, optional) — Resolution message
- resolvedBy(string, optional) — Name to attribute resolution (default: "AI Agent")

await mcp.callTool('resolve_annotation', { annotationId: 'ann_abc123', comment: 'Updated button label in line 42 of wmlHomePage.js' });

Add a reply to an annotation thread (e.g., ask clarifying questions).

- annotationId(string, required) — Annotation ID
- body(string, required) — Reply message
- author(string, optional) — Author name (default: "AI Agent")

await mcp.callTool('add_agent_reply', { annotationId: 'ann_abc123', body: 'Is this button in the main navigation or sidebar?' });

Combine fixing code and marking an annotation as resolved in one call. Optionally records commit / branch / PR metadata so the dashboard can backlink to what shipped.

- annotationId(string, required) — Annotation ID
- fixDescription(string, required) — Description of the fix
- filePath(string, optional) — File where fix was applied
- lineNumber(number, optional) — Line number of the fix
- commitSha(string, optional) — Commit SHA that landed the change
- branchName(string, optional) — Branch the commit was made on
- prUrl(string, optional) — Pull request URL (GitHub/GitLab/Bitbucket; shape-validated)

await mcp.callTool('fix_and_resolve', { annotationId: 'ann_abc123', fixDescription: 'Updated button label to match design spec', filePath: 'src/components/wmlHomePage.js', lineNumber: 42, commitSha: 'abc123def456', branchName: 'pincushion/checkout-fix', prUrl: 'https://github.com/acme/app/pull/142' });

Fetch a single implementation packet for one page URL — selector list, full pin payloads, suggested branch name, and traceability config. Use when an agent wants to batch-fix one page in a single branch.

await mcp.callTool('get_implementation_packet', { pageUrl: '/checkout' });

Dispatch a pin straight to your local coding agent. Promotes the pin toreadyif not already, markspending_implementation, and writes a.feedback/.agent-queue/<id>.jsontrigger file thatagent-loop.mjspicks up and shells out to Cursor / Claude Code / Codex.

await mcp.callTool('assign_pin_to_agent', { annotationId: 'ann_abc123' });

Attach a deploy URL to a resolved pin. Typically called by the deploy-hook edge function once production includes the fix, but available manually too.

await mcp.callTool('link_pin_deploy', { annotationId: 'ann_abc123', deployUrl: 'https://acme-app.vercel.app' });

Write Pincushion AI's post-deploy verdict back to the pin. Called by the critic agent after/critique-latest-deployruns against a fresh deploy.

await mcp.callTool('record_pin_verification', { annotationId: 'ann_abc123', status: 'verified', // or 'regressed' or 'inconclusive' notes: 'Button matches the primary token. No regression on adjacent CTAs.' });

Pro/Team feature— Free callers get sample size + upgrade hint. Median + p25/p75 of pin-to-resolve duration, with a 5-pin minimum so the metric is never noise.

await mcp.callTool('get_time_to_fix_metrics', { scope: 'project', projectId: 'pc_proj_abc' }); // → { sampleSize, thresholdMet, median, p25, p75, medianHuman, ... }

Get setup and configuration instructions for all supported agents.

await mcp.callTool('get_setup_instructions', {});

Pincushion can notify Slack or Microsoft Teams through project-scoped incoming webhooks. The defaults are intentionally quiet and Figma-inspired: notify when a pin is ready for implementation, when someone is @mentioned, and when a collaborator adds follow-up on work already being handled. Every newly dropped pin and every resolution are opt-in events.

- Developer channel:pin_readyandfollow_up
- Design or PM channel:mentionand optionallyresolved
- Launch or QA channel:pageUrlPatternspluspin_ready,follow_up, andresolved
- Temporary incident channel: enable a focused subscription, then pause it after the ship window

await mcp.callTool('configure_collaboration_integration', { projectId: 'my-project', provider: 'slack', webhookUrl: 'https://hooks.slack.com/services/...', targetLabel: '#product-feedback', events: ['pin_ready', 'mention', 'follow_up'], pageUrlPatterns: ['staging.example.com/checkout'], sendTest: true });

For Slack, usecreate_slack_install_linkwhen the hosted Slack app secrets are configured. It returns an Add-to-Slack URL; after approval, Slack returns the incoming webhook and Pincushion stores it automatically.

Uselist_collaboration_integrationsto audit configured destinations,remove_collaboration_integrationto disconnect one, andpreview_collaboration_notificationto see the payload shape before adding a real webhook. Webhook URLs are stored server-side and returned only as masked values.

For agents that don't watch the file system (Claude Code, Cursor, generic),agent-loop.mjspolls.feedback/.agent-queue/and dispatches new pins to the configured agent automatically.

# from inside the pincushion-mcp directory npm run agent-loop -- --project-dir /path/to/your/project # or directly node agent-loop.mjs --project-dir /path/to/your/project [--agent claude-code|cursor|generic] [--interval 3000]

The bridge (server.js) writes one trigger file per approved pin into.feedback/.agent-queue/. The loop reads them, builds a prompt with the pin's thread + element selector, and shells out to the chosen agent. The agent uses MCP tools (claim_pin→ fix →fix_and_resolve) and the queue file is removed when the pin closes.

detectAgent()auto-detectsclaudeorcursoron thePATH; falls back togeneric(writes the prompt to.feedback/.agent-promptand stdout). Run with--interval 3000to control poll cadence.

The server reads annotations from.feedback/in your project:

.feedback/ ├── annotations/ │ ├── example-com-login.json │ ├── example-com-dashboard.json │ └── ... └── index.json

To sync annotations with a remote Supabase database:
- Set up a Supabase project atsupabase.com
- Create anannotationstable with columns matching the annotation schema
- Generate an API key from your project settings
- Configure the server with--sync-urland--api-key

npx pincushion-mcp \ --project-dir . \ --sync-url https://your-project.supabase.co/rest/v1 \ --api-key sb_project_key_abc123...

The server merges local.feedback/files with remote data, with remote taking precedence on newer updates.

Pincushion Pro includes additional features. Activate with--license-key:

npx pincushion-mcp --project-dir . --license-key YOUR_PRO_KEY
No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.