Hardened, containerized MCP server for Pinterest API v5 β pins, boards, analytics
1.6K
pinterest-mcp-docker)Note
**Upstream Attribution:** This project is a hardened, containerized fork of [`clugtu/pinterest-mcp`](https://github.com/clugtu/pinterest-mcp) originally created by **Carlos Lugtu (`@clugtu`)**. This repository extends his work by adding multi-transport support (`stdio` & Streamable HTTP), OWASP application security hardening, non-root Docker containerization, CI/CD security pipelines, and automated multi-arch releases. See [NOTICE.md](NOTICE.md) for full licensing details.
pinterest-mcp-docker is a secure, production-ready Model Context Protocol (MCP) server for the Pinterest API v5. It connects AI assistantsβincluding Claude Desktop, Cursor, LibreChat, and custom LLM agentsβdirectly to Pinterest.
With pinterest-mcp-docker, AI agents can autonomously manage Pinterest boards, search pins, create single and bulk pins, analyze pin performance, and retrieve profile insights using natural language prompts.
| Category | Tool Name | Description |
|---|---|---|
| π Pins | create_pin | Create a single Pinterest pin (via image URL or local image path) |
| π Pins | bulk_create_pins | Batch create up to 50 pins in a single call |
| π Pins | update_pin | Update a pin's metadata |
| π Pins | delete_pin | Delete a pin by ID |
| π Boards | list_boards | List all Pinterest boards in the user's account |
| π Boards | create_board | Create a new Pinterest board with privacy controls |
| π Boards | get_board_pins | List pins on a board |
| π Search | search_pins | Search Pinterest pins by keyword query |
| π Analytics | get_pin_analytics | Retrieve impressions, saves, clicks, and engagement metrics |
| π Analytics | get_account_analytics | Retrieve account-level analytics |
| π Trends | get_trending | Retrieve Pinterest trend data |
IPv4/IPv6), blocking access to loopback, private networks, CGNAT, link-local, and cloud metadata endpoints (169.254.169.254).PINTEREST_ALLOWED_IMAGE_DIR), verifies canonical paths, caps file sizes (10MB default), and validates image headers (JPEG, PNG, GIF, WebP).$XDG_STATE_HOME/pinterest-mcp/token.json with strict 0600 file permissions and 0700 parent directory permissions.python:3.12-slim under unprivileged UID/GID 10001 with full --read-only rootfs compatibility and capability dropping (--cap-drop ALL).The following diagram illustrates how AI applications interact with pinterest-mcp-docker over stdio or HTTP transport modes:
graph TD
subgraph ClientLayer["π€ AI Client Layer"]
A1["Claude Desktop Client"]
A2["Cursor / IDE Assistant"]
A3["Custom LLM Agent"]
end
subgraph TransportLayer["π Transport & Authentication Layer"]
B1["Stdio Transport (IPC / Standard I/O)"]
B2["Streamable HTTP Transport (Port 8080)"]
AUTH["Bearer Token Middleware (hmac.compare_digest)"]
end
subgraph ServerCore["βοΈ Pinterest MCP Server"]
DISPATCH["Tool Dispatcher (11 Pydantic Input Models)"]
SEC["Security Guards (SSRF & Path Traversal)"]
REDACT["Redacting Logger"]
TOKENSTORE[("πΎ Token State Volume (~/.local/state/pinterest-mcp)")]
end
subgraph ExternalAPI["βοΈ Pinterest Cloud API"]
PINAPI["Pinterest API v5 (OAuth 2.0 / REST)"]
end
A1 -->|"JSON-RPC / stdio"| B1
A2 -->|"HTTP / mcp"| B2
A3 -->|"HTTP / mcp"| B2
B1 --> DISPATCH
B2 --> AUTH
AUTH -->|"Authorized"| DISPATCH
DISPATCH --> SEC
SEC --> REDACT
SEC <--> TOKENSTORE
SEC -->|"HTTPS Outbound (IP-Pinned Transport)"| PINAPI
Follow this guide to get pinterest-mcp-docker up and running in under 5 minutes.
To connect to Pinterest API v5, you need a Client ID and Client Secret:
PINTEREST_CLIENT_ID) and App Secret Key (PINTEREST_CLIENT_SECRET).http://localhost:8089/callback (used during the OAuth setup flow).You can run pinterest-mcp-docker using Docker (recommended) or Native Python.
Docker provides an isolated, read-only environment without requiring Python setup.
Published Docker Hub images are available at sinalkar/pinterest-mcp-dockerβ . Pull the current release with docker pull sinalkar/pinterest-mcp-docker:latest.
/home/app/.local/state/pinterest-mcp.image_path, mount your local image directory (e.g., -v /path/to/my/images:/home/app/images) and set PINTEREST_ALLOWED_IMAGE_DIR=/home/app/images.docker run -i --rm \
-e PINTEREST_CLIENT_ID="your_client_id" \
-e PINTEREST_CLIENT_SECRET="your_client_secret" \
-e PINTEREST_ACCESS_TOKEN="your_access_token" \
-v pinterest_token_data:/home/app/.local/state/pinterest-mcp \
ghcr.io/sinalkar/pinterest-mcp-docker:latest
docker run -i --rm `
-e PINTEREST_CLIENT_ID="your_client_id" `
-e PINTEREST_CLIENT_SECRET="your_client_secret" `
-e PINTEREST_ACCESS_TOKEN="your_access_token" `
-v pinterest_token_data:/home/app/.local/state/pinterest-mcp `
ghcr.io/sinalkar/pinterest-mcp-docker:latest
docker run -i --rm \
-e PINTEREST_CLIENT_ID="your_client_id" \
-e PINTEREST_CLIENT_SECRET="your_client_secret" \
-e PINTEREST_ACCESS_TOKEN="your_access_token" \
-e PINTEREST_ALLOWED_IMAGE_DIR="/home/app/images" \
-v pinterest_token_data:/home/app/.local/state/pinterest-mcp \
-v /path/to/your/images:/home/app/images \
ghcr.io/sinalkar/pinterest-mcp-docker:latest
Run as an HTTP service listening on port 8080:
docker run -d --name pinterest-mcp \
-p 8080:8080 \
-e MCP_TRANSPORT=http \
-e MCP_HOST=0.0.0.0 \
-e MCP_AUTH_TOKEN="your_secure_bearer_token" \
-e PINTEREST_CLIENT_ID="your_client_id" \
-e PINTEREST_CLIENT_SECRET="your_client_secret" \
-e PINTEREST_ACCESS_TOKEN="your_access_token" \
--read-only \
--cap-drop ALL \
--security-opt no-new-privileges:true \
--tmpfs /tmp:rw,noexec,nosuid,size=64m \
-v pinterest_token_data:/home/app/.local/state/pinterest-mcp \
ghcr.io/sinalkar/pinterest-mcp-docker:latest
Verify health:
curl http://localhost:8080/readyz
# Output: {"status":"ready","version":"<installed package version>","transport":"http"}
.env.template to .env:
cp .env.template .env
.env and configure your credentials (PINTEREST_CLIENT_ID, PINTEREST_CLIENT_SECRET, etc.).docker-compose up -d
python3 --version).pip install pinterest-mcp-docker
git clone https://github.com/sinalkar/pinterest-mcp-docker.git
cd pinterest-mcp-docker
pip install -e .
pinterest-mcp-auth)If you don't have pre-generated OAuth tokens, run the interactive helper CLI:
pinterest-mcp-auth
This starts a local OAuth callback listener on port 8089, opens Pinterest in your browser for authorization, and automatically saves your token to ~/.local/state/pinterest-mcp/token.json.
# Set environment variables
export PINTEREST_CLIENT_ID="your_client_id"
export PINTEREST_CLIENT_SECRET="your_client_secret"
export PINTEREST_ACCESS_TOKEN="your_access_token"
# Run in stdio mode (default)
pinterest-mcp
# Or run in HTTP mode
export MCP_TRANSPORT="http"
export MCP_HOST="127.0.0.1"
export MCP_PORT="8080"
pinterest-mcp
# Set environment variables
$env:PINTEREST_CLIENT_ID="your_client_id"
$env:PINTEREST_CLIENT_SECRET="your_client_secret"
$env:PINTEREST_ACCESS_TOKEN="your_access_token"
# Run in stdio mode
pinterest-mcp
# Or run in HTTP mode
$env:MCP_TRANSPORT="http"
$env:MCP_HOST="127.0.0.1"
$env:MCP_PORT="8080"
pinterest-mcp
cmd.exe)set PINTEREST_CLIENT_ID=your_client_id
set PINTEREST_CLIENT_SECRET=your_client_secret
set PINTEREST_ACCESS_TOKEN=your_access_token
pinterest-mcp
claude_desktop_config.json)Locate your Claude Desktop config file:
~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.json{
"mcpServers": {
"pinterest": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e", "PINTEREST_CLIENT_ID=your_client_id",
"-e", "PINTEREST_CLIENT_SECRET=your_client_secret",
"-e", "PINTEREST_ACCESS_TOKEN=your_access_token",
"-v", "pinterest_token_data:/home/app/.local/state/pinterest-mcp",
"ghcr.io/sinalkar/pinterest-mcp-docker:latest"
]
}
}
}
{
"mcpServers": {
"pinterest": {
"command": "pinterest-mcp",
"env": {
"PINTEREST_CLIENT_ID": "your_client_id",
"PINTEREST_CLIENT_SECRET": "your_client_secret",
"PINTEREST_ACCESS_TOKEN": "your_access_token"
}
}
}
}
| Client Family | Transport | Default Endpoint | Supported Auth | Status | Example Config / Notes |
|---|---|---|---|---|---|
| Claude Desktop | stdio | stdio | Environment variables | Implementation complete; desktop smoke test pending | Command: docker or pinterest-mcp |
| Cursor | http | /mcp | Bearer Token / None | Automated handshake covered; client smoke test pending | {"url": "http://localhost:8080/mcp", "headers": {"Authorization": "Bearer <token>"}} |
| VS Code (Roo/Cline) | http / stdio | /mcp | Bearer / None | Client smoke test pending | Direct SSE or Streamable HTTP endpoint |
| Windsurf | stdio / http | /mcp | Bearer / None | Client smoke test pending | Standard stdio command or HTTP endpoint |
| Claude Web Connectors | http | /mcp | OAuth 2.1 / Bearer | Server-side support complete; hosted smoke test pending | Set MCP_OAUTH_ISSUER & MCP_RESOURCE_URL |
| ChatGPT Connectors | http (JSON) | /mcp | OAuth 2.1 / Bearer | Server-side support complete; hosted smoke test pending | Set MCP_JSON_RESPONSE=true |
| Legacy SSE Clients | sse / http+sse | /sse | Bearer / None | Automated route/auth coverage; client smoke test pending | SSE stream at /sse, messages post to /messages/ |
claude_desktop_config.json)Locate your Claude Desktop config file:
~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.json{
"mcpServers": {
"pinterest": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e", "PINTEREST_CLIENT_ID=your_client_id",
"-e", "PINTEREST_CLIENT_SECRET=your_client_secret",
"-e", "PINTEREST_ACCESS_TOKEN=your_access_token",
"-v", "pinterest_token_data:/home/app/.local/state/pinterest-mcp",
"ghcr.io/sinalkar/pinterest-mcp-docker:latest"
]
}
}
}
{
"mcpServers": {
"pinterest": {
"command": "pinterest-mcp",
"env": {
"PINTEREST_CLIENT_ID": "your_client_id",
"PINTEREST_CLIENT_SECRET": "your_client_secret",
"PINTEREST_ACCESS_TOKEN": "your_access_token"
}
}
}
}
To connect Cursor or a custom client to a running HTTP instance of pinterest-mcp-docker:
{
"mcpServers": {
"pinterest-http": {
"url": "http://localhost:8080/mcp",
"headers": {
"Authorization": "Bearer your_secure_bearer_token"
}
}
}
}
For clients requiring the 2024-11-05 HTTP+SSE transport:
{
"mcpServers": {
"pinterest-sse": {
"url": "http://localhost:8080/sse"
}
}
}
Hosted Pinterest login is under development. The persistence and broker foundation is not yet an end-to-end hosted release; keep public user access disabled until the OpenSpec acceptance checks and GitHub Actions deployment are complete. See pending credential handoffβ .
| Variable | Purpose | Required | Default | Secret |
|---|---|---|---|---|
MCP_MODE | Deployment mode (local for single-user CLI/file tokens, hosted for multi-user external persistence) | No | local | No |
MCP_TRANSPORT | Transport mode (stdio, http, sse, http+sse) | No | stdio | No |
MCP_HOST | Bind address for HTTP listener | No | 127.0.0.1 | No |
MCP_PORT | Listen port for HTTP listener | No | 8080 | No |
MCP_PATH | Streamable HTTP endpoint path | No | /mcp | No |
MCP_SSE_PATH | SSE stream endpoint path | No | /sse | No |
MCP_MESSAGE_PATH | SSE message posting endpoint path | No | /messages/ | No |
DATABASE_URL | PostgreSQL connection URL for hosted credential and owner persistence | Required in hosted mode | None | Yes |
REDIS_URL | Redis URL for hosted nonce replay protection and rate budgets | No | None | Yes |
CREDENTIAL_ENCRYPTION_KEY | Authenticated encryption root key material for hosted credential storage | Required in hosted mode | None | Yes |
CREDENTIAL_KEY_ID | Key identifier for versioned credential encryption keys | No | primary | No |
BROKER_HANDOFF_SECRET | Shared HMAC secret for private broker-to-ingress credential handoff | Required in hosted mode | None | Yes |
MCP_AUTH_TOKEN | Shared Bearer authentication token | Conditional | None | Yes |
MCP_JSON_RESPONSE | Return single JSON response instead of SSE stream | No | false | No |
MCP_STATELESS | Sessionless mode (no per-client session state) | No | false | No |
MCP_RESUMABILITY | Enable event stream resumability | No | false | No |
MCP_EVENT_STORE_MAX_EVENTS | Bounded event capacity per stream | No | 1000 | No |
MCP_MAX_REQUEST_BYTES | Maximum request body limit in bytes | No | 4194304 (4MB) | No |
MCP_SESSION_IDLE_TIMEOUT | Idle session expiry timeout (seconds) | No | None | No |
MCP_SSE_RETRY_INTERVAL_MS | Advertised SSE reconnection interval (ms) | No | None | No |
MCP_DNS_REBINDING_PROTECTION | Enforce Host/Origin header validation | No | true | No |
MCP_ALLOWED_HOSTS | Comma-separated allowed Host headers | No | Loopback defaults | No |
MCP_ALLOWED_ORIGINS | Comma-separated allowed browser origins for CORS | No | Empty | No |
MCP_CORS_ALLOW_CREDENTIALS | Enable credentialed cross-origin CORS | No | false | No |
MCP_OAUTH_ISSUER | OAuth 2.1 authorization server issuer URL | No | None | No |
MCP_OAUTH_JWKS_URL | Explicit JWKS endpoint URL for OAuth | No | None | No |
MCP_RESOURCE_URL | Canonical resource server identifier URL | No | None | No |
MCP_OAUTH_REQUIRED_SCOPES | Comma-separated OAuth required scopes | No | None | No |
MCP_OAUTH_ALLOWED_SUBJECTS | Comma-separated JWT subjects permitted to use this single-account server | No | None (allow all valid subjects) | No |
LOG_LEVEL | Logging level (CRITICAL, ERROR, WARNING, INFO, DEBUG) | No | INFO | No |
LOG_FORMAT | Log format (text or json) | No | text | No |
PINTEREST_CLIENT_ID | Pinterest API v5 App Client ID | Yes | None | Yes |
PINTEREST_CLIENT_SECRET | Pinterest API v5 App Client Secret | Yes | None | Yes |
PINTEREST_ACCESS_TOKEN | OAuth Access Token | Optional | None | Yes |
PINTEREST_REFRESH_TOKEN | OAuth Refresh Token for auto-renewal | Optional | None | Yes |
PINTEREST_TOKEN_PATH | Path to persistent token JSON file | No | ~/.local/state/pinterest-mcp/token.json | No |
PINTEREST_ALLOWED_IMAGE_DIR | Allowed root dir for local image path | No | Home directory (~) | No |
PINTEREST_ALLOW_LOCAL_PATHS | Allow local image paths in HTTP mode | No | false | No |
PINTEREST_MAX_IMAGE_BYTES | Maximum image size limit in bytes | No | 10485760 (10MB) | No |
PINTEREST_HTTP_TIMEOUT | Outbound HTTP request timeout (seconds) | No | 30.0 | No |
PINTEREST_MAX_RESPONSE_BYTES | Outbound HTTP response maximum bytes | No | 33554432 (32MB) | No |
A: Pinterest MCP (pinterest-mcp-docker) is an open-source Model Context Protocol server that exposes Pinterest API v5 functionality to AI models. It enables tools like Claude Desktop and Cursor to create pins, manage boards, search content, and view analytics directly via AI chat interface.
A: Open your claude_desktop_config.json file, add an entry under mcpServers pointing to docker run -i ... ghcr.io/sinalkar/pinterest-mcp-docker:latest with your PINTEREST_CLIENT_ID and PINTEREST_CLIENT_SECRET, and restart Claude Desktop.
A: Yes. When calling create_pin with image_path, the server resolves the local file path. When using Docker, ensure your image directory is mounted as a volume (e.g. -v /path/to/images:/home/app/images) and PINTEREST_ALLOWED_IMAGE_DIR points to that mounted directory.
pinterest-mcp-docker protect against security threats?A: The server enforces strict OWASP defenses including public IP DNS resolution to prevent Server-Side Request Forgery (SSRF), realpath validation to prevent Path Traversal, atomic file permissions (0600) for tokens, automatic secret redaction in logs, and non-root read-only container isolation.
| Tag | Type | Description |
|---|---|---|
latest | Moving | Points to the latest production release |
<major>.<minor>.<patch>, <major>.<minor>, <major> | SemVer | Automatically updated for patch and minor updates |
sha-<short> | Immutable | Exact git commit build tag |
Image releases are signed keylessly with Cosignβ OIDC:
cosign verify \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp "https://github.com/sinalkar/pinterest-mcp-docker/.github/workflows/release.yml@refs/tags/v.*" \
ghcr.io/sinalkar/pinterest-mcp-docker:latest
Distributed under the MIT Licenseβ .
clugtu/pinterest-mcpβ )sinalkar/pinterest-mcp-dockerβ )See NOTICE.mdβ for full licensing details and modifications summary.
Note
**Disclaimer:** This is an unofficial Model Context Protocol (MCP) server and is not affiliated with, endorsed by, or sponsored by Pinterest, Inc.
Content type
Image
Digest
sha256:74318ae10β¦
Size
58 MB
Last updated
23 days ago
docker pull sinalkar/pinterest-mcp-docker