pinterest-mcp-docker 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pinterest_mcp_docker-0.2.0/.gitignore +35 -0
- pinterest_mcp_docker-0.2.0/CHANGELOG.md +34 -0
- pinterest_mcp_docker-0.2.0/LICENSE +23 -0
- pinterest_mcp_docker-0.2.0/NOTICE.md +21 -0
- pinterest_mcp_docker-0.2.0/PKG-INFO +455 -0
- pinterest_mcp_docker-0.2.0/README.md +411 -0
- pinterest_mcp_docker-0.2.0/pyproject.toml +102 -0
- pinterest_mcp_docker-0.2.0/src/pinterest_mcp/__init__.py +36 -0
- pinterest_mcp_docker-0.2.0/src/pinterest_mcp/_version.py +24 -0
- pinterest_mcp_docker-0.2.0/src/pinterest_mcp/app.py +84 -0
- pinterest_mcp_docker-0.2.0/src/pinterest_mcp/auth.py +101 -0
- pinterest_mcp_docker-0.2.0/src/pinterest_mcp/cli.py +49 -0
- pinterest_mcp_docker-0.2.0/src/pinterest_mcp/client.py +386 -0
- pinterest_mcp_docker-0.2.0/src/pinterest_mcp/config.py +167 -0
- pinterest_mcp_docker-0.2.0/src/pinterest_mcp/http_app.py +87 -0
- pinterest_mcp_docker-0.2.0/src/pinterest_mcp/logging_setup.py +112 -0
- pinterest_mcp_docker-0.2.0/src/pinterest_mcp/security.py +238 -0
- pinterest_mcp_docker-0.2.0/src/pinterest_mcp/server.py +11 -0
- pinterest_mcp_docker-0.2.0/src/pinterest_mcp/stdio_main.py +49 -0
- pinterest_mcp_docker-0.2.0/src/pinterest_mcp/tools.py +374 -0
- pinterest_mcp_docker-0.2.0/tests/__init__.py +0 -0
- pinterest_mcp_docker-0.2.0/tests/test_client_respx.py +152 -0
- pinterest_mcp_docker-0.2.0/tests/test_config_logging.py +55 -0
- pinterest_mcp_docker-0.2.0/tests/test_dispatch.py +120 -0
- pinterest_mcp_docker-0.2.0/tests/test_security.py +133 -0
- pinterest_mcp_docker-0.2.0/tests/test_tools.py +145 -0
- pinterest_mcp_docker-0.2.0/tests/test_transport.py +90 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Python & Build
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.egg-info/
|
|
6
|
+
dist/
|
|
7
|
+
build/
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
.pytest_cache/
|
|
11
|
+
.ruff_cache/
|
|
12
|
+
.coverage
|
|
13
|
+
coverage.xml
|
|
14
|
+
htmlcov/
|
|
15
|
+
*.sarif
|
|
16
|
+
bandit-results.json
|
|
17
|
+
|
|
18
|
+
# Local configuration & credentials
|
|
19
|
+
.env
|
|
20
|
+
.env.*
|
|
21
|
+
!.env.template
|
|
22
|
+
.pinterest_token.json
|
|
23
|
+
|
|
24
|
+
# OpenSpec workflow files
|
|
25
|
+
openspec/
|
|
26
|
+
.openspec/
|
|
27
|
+
|
|
28
|
+
# AI Agent directories & workspace metadata
|
|
29
|
+
.agent/
|
|
30
|
+
.agents/
|
|
31
|
+
.claude/
|
|
32
|
+
.codex/
|
|
33
|
+
.cursor/
|
|
34
|
+
.devin/
|
|
35
|
+
.gemini/
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `pinterest-mcp-docker` will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.2.0] - 2026-08-02
|
|
9
|
+
|
|
10
|
+
### ⚠️ BREAKING CHANGES
|
|
11
|
+
|
|
12
|
+
- **Token Path Location & Permissions:** Default token storage path has moved from `./.pinterest_token.json` (relative CWD) to `$XDG_STATE_HOME/pinterest-mcp/token.json` (defaulting to `~/.local/state/pinterest-mcp/token.json` on Linux/macOS and container-writable volume under `/home/app`).
|
|
13
|
+
- *Migration:* Existing users should move `.pinterest_token.json` to the new path, or set the `PINTEREST_TOKEN_PATH` environment variable.
|
|
14
|
+
- Token directory permissions are created with `0700` and token files are written atomically with `0600` file permissions.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **Multi-Transport Server Support:** The MCP server now supports both standard input/output (`stdio`) and Streamable HTTP (`http`) via Starlette and Uvicorn.
|
|
19
|
+
- **OWASP Application Security Hardening:**
|
|
20
|
+
- SSRF protections on `image_url` fetching with scheme allowlists, public IP DNS checks, IP-pinned HTTP transport, manual redirect handling (max 3 hops), and automatic `Authorization` header stripping across origins.
|
|
21
|
+
- Path traversal protections on `image_path` using `Path.resolve()`, containment checks against `PINTEREST_ALLOWED_IMAGE_DIR`, maximum file size caps, and magic-byte image format sniffing (JPEG, PNG, GIF, WebP).
|
|
22
|
+
- Secret redaction filter applied to all logging output and MCP error messages (`sanitize_error`).
|
|
23
|
+
- Bearer token authentication middleware for HTTP transport mode.
|
|
24
|
+
- **Pydantic Tool Input Registry:** All 11 tools are declared in a strict `ToolSpec` registry enforcing `extra="forbid"`, string/array length bounds, enum validation, `YYYY-MM-DD` date validation, and max batch caps. Removed the dead `dry_run_pin` branch.
|
|
25
|
+
- **Hardened Multi-Stage Docker Container:**
|
|
26
|
+
- Three-stage build on digest-pinned `python:3.12-slim` producing a minimal runtime image running as unprivileged user `10001` (`app`).
|
|
27
|
+
- Full read-only rootfs compatibility with `/tmp` tmpfs mount and container healthcheck.
|
|
28
|
+
- Multi-architecture builds (`linux/amd64` and `linux/arm64`).
|
|
29
|
+
- **Comprehensive CI/CD & Security Pipelines:**
|
|
30
|
+
- GitHub Actions workflows for matrix testing (Python 3.11, 3.12, 3.13), CodeQL SAST, Semgrep, Bandit, pip-audit, Trivy (FS & Container), OpenSSF Scorecard, and Dependabot.
|
|
31
|
+
- **Release Automation & Attribution:**
|
|
32
|
+
- Automated tag releases publishing to GHCR, Docker Hub, and PyPI via Trusted Publishing.
|
|
33
|
+
- SPDX SBOM, SLSA provenance, and keyless cosign image signatures.
|
|
34
|
+
- Prominent upstream attribution to Carlos Lugtu (`clugtu/pinterest-mcp`) in `NOTICE.md`, `LICENSE`, `pyproject.toml`, and OCI image labels.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Carlos Lugtu
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2026 sanjay s (modifications in this fork; see NOTICE.md)
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
in the Software without restriction, including without limitation the rights
|
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
SOFTWARE.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Notice
|
|
2
|
+
|
|
3
|
+
## Upstream Project Attribution
|
|
4
|
+
|
|
5
|
+
This software is a modified derivative of **pinterest-mcp**, originally created and authored by **Carlos Lugtu** (`clugtu/pinterest-mcp`).
|
|
6
|
+
|
|
7
|
+
- **Original Project:** https://github.com/clugtu/pinterest-mcp
|
|
8
|
+
- **Original Author:** Carlos Lugtu
|
|
9
|
+
- **Original License:** MIT License
|
|
10
|
+
|
|
11
|
+
## Fork Modifications
|
|
12
|
+
|
|
13
|
+
This repository (`sinalkar/pinterest-mcp-docker`) extends and hardens the upstream project with:
|
|
14
|
+
|
|
15
|
+
1. **Multi-Transport Support:** Runs as stdio or Streamable HTTP (via Starlette/Uvicorn) with bearer token auth.
|
|
16
|
+
2. **OWASP Security Hardening:** SSRF defenses (public IP resolution, scheme allowlist, custom IP-pinned transport, redirect policy), path traversal guards, input validation via Pydantic, token permission hardening (0600 file / 0700 dir), and error/log secret redaction.
|
|
17
|
+
3. **Containerization:** Multi-stage, digest-pinned non-root Docker container with read-only rootfs compatibility and healthcheck.
|
|
18
|
+
4. **CI/CD & Security Workflows:** CodeQL, Semgrep, Bandit, pip-audit, Trivy, Scorecard, and Dependabot automation.
|
|
19
|
+
5. **Release Publishing:** Automated multi-arch builds (GHCR & Docker Hub), SPDX SBOM, SLSA provenance, and keyless cosign signatures.
|
|
20
|
+
|
|
21
|
+
All original copyrights are preserved in `LICENSE`.
|
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pinterest-mcp-docker
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Hardened, containerized MCP server for Pinterest API v5 — create pins, manage boards, track analytics
|
|
5
|
+
Project-URL: Homepage, https://github.com/sinalkar/pinterest-mcp-docker
|
|
6
|
+
Project-URL: Repository, https://github.com/sinalkar/pinterest-mcp-docker
|
|
7
|
+
Project-URL: Issues, https://github.com/sinalkar/pinterest-mcp-docker/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/sinalkar/pinterest-mcp-docker/blob/main/CHANGELOG.md
|
|
9
|
+
Project-URL: Upstream, https://github.com/clugtu/pinterest-mcp
|
|
10
|
+
Author: Carlos Lugtu
|
|
11
|
+
Maintainer: sanjay s
|
|
12
|
+
License: MIT
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
License-File: NOTICE.md
|
|
15
|
+
Keywords: ai,docker,mcp,model-context-protocol,pinterest,social-media
|
|
16
|
+
Classifier: Development Status :: 3 - Alpha
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Topic :: Security
|
|
23
|
+
Requires-Python: >=3.11
|
|
24
|
+
Requires-Dist: anyio>=4.0.0
|
|
25
|
+
Requires-Dist: httpx>=0.27.0
|
|
26
|
+
Requires-Dist: mcp>=1.9.0
|
|
27
|
+
Requires-Dist: pydantic-settings>=2.2.0
|
|
28
|
+
Requires-Dist: pydantic>=2.7.0
|
|
29
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: bandit>=1.7.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: pip-audit>=2.7.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: respx>=0.21.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: ruff>=0.4.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: starlette>=0.37.0; extra == 'dev'
|
|
39
|
+
Requires-Dist: uvicorn>=0.30.0; extra == 'dev'
|
|
40
|
+
Provides-Extra: http
|
|
41
|
+
Requires-Dist: starlette>=0.37.0; extra == 'http'
|
|
42
|
+
Requires-Dist: uvicorn>=0.30.0; extra == 'http'
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
44
|
+
|
|
45
|
+
# 📌 Pinterest MCP Server Docker (`pinterest-mcp-docker`)
|
|
46
|
+
|
|
47
|
+
[](https://github.com/sinalkar/pinterest-mcp-docker/actions/workflows/ci.yml)
|
|
48
|
+
[](https://github.com/sinalkar/pinterest-mcp-docker/actions/workflows/security.yml)
|
|
49
|
+
[](https://hub.docker.com/r/sinalkar/pinterest-mcp-docker)
|
|
50
|
+
[](https://pypi.org/project/pinterest-mcp-docker/)
|
|
51
|
+
[](LICENSE)
|
|
52
|
+
|
|
53
|
+
> [!NOTE]
|
|
54
|
+
> **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.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 🎯 Overview & Key Features
|
|
59
|
+
|
|
60
|
+
**`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.
|
|
61
|
+
|
|
62
|
+
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.
|
|
63
|
+
|
|
64
|
+
### 🧰 Available MCP Tools (11 Total)
|
|
65
|
+
|
|
66
|
+
| Category | Tool Name | Description |
|
|
67
|
+
| -------- | --------- | ----------- |
|
|
68
|
+
| 📌 **Pins** | `create_pin` | Create a single Pinterest pin (via image URL or local image path) |
|
|
69
|
+
| 📌 **Pins** | `bulk_create_pins` | Batch create up to 50 pins in a single call |
|
|
70
|
+
| 📌 **Pins** | `get_pin` | Retrieve detailed metadata for a specific pin ID |
|
|
71
|
+
| 📌 **Pins** | `delete_pin` | Delete a pin by ID |
|
|
72
|
+
| 📋 **Boards** | `list_boards` | List all Pinterest boards in the user's account |
|
|
73
|
+
| 📋 **Boards** | `create_board` | Create a new Pinterest board with privacy controls |
|
|
74
|
+
| 📋 **Boards** | `get_board` | Get details and metadata for a specific board ID |
|
|
75
|
+
| 📋 **Boards** | `delete_board` | Delete a board by ID |
|
|
76
|
+
| 🔍 **Search** | `search_pins` | Search Pinterest pins by keyword query |
|
|
77
|
+
| 📊 **Analytics** | `get_pin_analytics` | Retrieve impressions, saves, clicks, and engagement metrics |
|
|
78
|
+
| 👤 **User Profile** | `get_user_account` | Get authenticated user profile details |
|
|
79
|
+
|
|
80
|
+
### 🔒 Enterprise Security Features
|
|
81
|
+
|
|
82
|
+
- 🛡️ **SSRF Protection:** Validates outbound URLs against public IP ranges (`IPv4`/`IPv6`), blocking access to loopback, private networks, CGNAT, link-local, and cloud metadata endpoints (`169.254.169.254`).
|
|
83
|
+
- 📁 **Path Traversal Guards:** Restricts local image uploads to specified allowed directories (`PINTEREST_ALLOWED_IMAGE_DIR`), verifies canonical paths, caps file sizes (10MB default), and validates image headers (JPEG, PNG, GIF, WebP).
|
|
84
|
+
- 🔑 **Atomic Token Storage:** Stores OAuth tokens in `$XDG_STATE_HOME/pinterest-mcp/token.json` with strict `0600` file permissions and `0700` parent directory permissions.
|
|
85
|
+
- 🧹 **Log Secret Redaction:** Automatically scrubs OAuth access tokens, client secrets, and base64 payloads from server logs and error output.
|
|
86
|
+
- 🐳 **Hardened Docker Container:** Runs on digest-pinned `python:3.12-slim` under unprivileged UID/GID `10001` with full `--read-only` rootfs compatibility and capability dropping (`--cap-drop ALL`).
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 🏗️ Architecture & Data Flow
|
|
91
|
+
|
|
92
|
+
The following diagram illustrates how AI applications interact with `pinterest-mcp-docker` over `stdio` or `HTTP` transport modes:
|
|
93
|
+
|
|
94
|
+
```mermaid
|
|
95
|
+
graph TD
|
|
96
|
+
subgraph ClientLayer["🤖 AI Client Layer"]
|
|
97
|
+
A1["Claude Desktop Client"]
|
|
98
|
+
A2["Cursor / IDE Assistant"]
|
|
99
|
+
A3["Custom LLM Agent"]
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
subgraph TransportLayer["🌐 Transport & Authentication Layer"]
|
|
103
|
+
B1["Stdio Transport (IPC / Standard I/O)"]
|
|
104
|
+
B2["Streamable HTTP Transport (Port 8080)"]
|
|
105
|
+
AUTH["Bearer Token Middleware (hmac.compare_digest)"]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
subgraph ServerCore["⚙️ Pinterest MCP Server"]
|
|
109
|
+
DISPATCH["Tool Dispatcher (11 Pydantic Input Models)"]
|
|
110
|
+
SEC["Security Guards (SSRF & Path Traversal)"]
|
|
111
|
+
REDACT["Redacting Logger"]
|
|
112
|
+
TOKENSTORE[("💾 Token State Volume (~/.local/state/pinterest-mcp)")]
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
subgraph ExternalAPI["☁️ Pinterest Cloud API"]
|
|
116
|
+
PINAPI["Pinterest API v5 (OAuth 2.0 / REST)"]
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
A1 -->|"JSON-RPC / stdio"| B1
|
|
120
|
+
A2 -->|"HTTP / mcp"| B2
|
|
121
|
+
A3 -->|"HTTP / mcp"| B2
|
|
122
|
+
|
|
123
|
+
B1 --> DISPATCH
|
|
124
|
+
B2 --> AUTH
|
|
125
|
+
AUTH -->|"Authorized"| DISPATCH
|
|
126
|
+
|
|
127
|
+
DISPATCH --> SEC
|
|
128
|
+
SEC --> REDACT
|
|
129
|
+
SEC <--> TOKENSTORE
|
|
130
|
+
SEC -->|"HTTPS Outbound (IP-Pinned Transport)"| PINAPI
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 📋 Step-by-Step Setup Guide
|
|
136
|
+
|
|
137
|
+
Follow this guide to get `pinterest-mcp-docker` up and running in under 5 minutes.
|
|
138
|
+
|
|
139
|
+
### Step 1: Obtain Pinterest API Credentials
|
|
140
|
+
|
|
141
|
+
To connect to Pinterest API v5, you need a Client ID and Client Secret:
|
|
142
|
+
|
|
143
|
+
1. Go to the [Pinterest Developers Portal](https://developers.pinterest.com/) and log in.
|
|
144
|
+
2. Click **My Apps** -> **Create App**.
|
|
145
|
+
3. Fill in your app name and description.
|
|
146
|
+
4. Copy your **App ID** (`PINTEREST_CLIENT_ID`) and **App Secret Key** (`PINTEREST_CLIENT_SECRET`).
|
|
147
|
+
5. Set the **Redirect URI** to `http://localhost:8089/callback` (used during the OAuth setup flow).
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
### Step 2: Choose Your Deployment Method
|
|
152
|
+
|
|
153
|
+
You can run `pinterest-mcp-docker` using **Docker** (recommended) or **Native Python**.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
### Option A: Running via Docker (Recommended)
|
|
158
|
+
|
|
159
|
+
Docker provides an isolated, read-only environment without requiring Python setup.
|
|
160
|
+
|
|
161
|
+
#### Volume Mapping Overview
|
|
162
|
+
- 💾 **Token Persistence Volume:** Saves OAuth access and refresh tokens across container restarts. Map a named volume or host directory to `/home/app/.local/state/pinterest-mcp`.
|
|
163
|
+
- 🖼️ **Local Image Folder Volume (Optional):** If you want the AI agent to upload local images using `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`.
|
|
164
|
+
|
|
165
|
+
#### 1. Docker Stdio Mode (Default for Claude Desktop)
|
|
166
|
+
|
|
167
|
+
##### macOS / Linux (Bash / Zsh)
|
|
168
|
+
```bash
|
|
169
|
+
docker run -i --rm \
|
|
170
|
+
-e PINTEREST_CLIENT_ID="your_client_id" \
|
|
171
|
+
-e PINTEREST_CLIENT_SECRET="your_client_secret" \
|
|
172
|
+
-e PINTEREST_ACCESS_TOKEN="your_access_token" \
|
|
173
|
+
-v pinterest_token_data:/home/app/.local/state/pinterest-mcp \
|
|
174
|
+
ghcr.io/sinalkar/pinterest-mcp-docker:latest
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
##### Windows (PowerShell)
|
|
178
|
+
```powershell
|
|
179
|
+
docker run -i --rm `
|
|
180
|
+
-e PINTEREST_CLIENT_ID="your_client_id" `
|
|
181
|
+
-e PINTEREST_CLIENT_SECRET="your_client_secret" `
|
|
182
|
+
-e PINTEREST_ACCESS_TOKEN="your_access_token" `
|
|
183
|
+
-v pinterest_token_data:/home/app/.local/state/pinterest-mcp `
|
|
184
|
+
ghcr.io/sinalkar/pinterest-mcp-docker:latest
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
##### With Local Image Directory Mounted
|
|
188
|
+
```bash
|
|
189
|
+
docker run -i --rm \
|
|
190
|
+
-e PINTEREST_CLIENT_ID="your_client_id" \
|
|
191
|
+
-e PINTEREST_CLIENT_SECRET="your_client_secret" \
|
|
192
|
+
-e PINTEREST_ACCESS_TOKEN="your_access_token" \
|
|
193
|
+
-e PINTEREST_ALLOWED_IMAGE_DIR="/home/app/images" \
|
|
194
|
+
-v pinterest_token_data:/home/app/.local/state/pinterest-mcp \
|
|
195
|
+
-v /path/to/your/images:/home/app/images \
|
|
196
|
+
ghcr.io/sinalkar/pinterest-mcp-docker:latest
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
#### 2. Docker HTTP Mode (Streamable HTTP Server)
|
|
202
|
+
|
|
203
|
+
Run as an HTTP service listening on port `8080`:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
docker run -d --name pinterest-mcp \
|
|
207
|
+
-p 8080:8080 \
|
|
208
|
+
-e MCP_TRANSPORT=http \
|
|
209
|
+
-e MCP_HOST=0.0.0.0 \
|
|
210
|
+
-e MCP_AUTH_TOKEN="your_secure_bearer_token" \
|
|
211
|
+
-e PINTEREST_CLIENT_ID="your_client_id" \
|
|
212
|
+
-e PINTEREST_CLIENT_SECRET="your_client_secret" \
|
|
213
|
+
-e PINTEREST_ACCESS_TOKEN="your_access_token" \
|
|
214
|
+
--read-only \
|
|
215
|
+
--cap-drop ALL \
|
|
216
|
+
--security-opt no-new-privileges:true \
|
|
217
|
+
--tmpfs /tmp:rw,noexec,nosuid,size=64m \
|
|
218
|
+
-v pinterest_token_data:/home/app/.local/state/pinterest-mcp \
|
|
219
|
+
ghcr.io/sinalkar/pinterest-mcp-docker:latest
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Verify health:
|
|
223
|
+
```bash
|
|
224
|
+
curl http://localhost:8080/healthz
|
|
225
|
+
# Output: {"status":"ok","version":"0.2.0","transport":"http"}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
#### 3. Docker Compose Setup
|
|
231
|
+
|
|
232
|
+
1. Copy `.env.template` to `.env`:
|
|
233
|
+
```bash
|
|
234
|
+
cp .env.template .env
|
|
235
|
+
```
|
|
236
|
+
2. Open `.env` and configure your credentials (`PINTEREST_CLIENT_ID`, `PINTEREST_CLIENT_SECRET`, etc.).
|
|
237
|
+
3. Start the container:
|
|
238
|
+
```bash
|
|
239
|
+
docker-compose up -d
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
### Option B: Running Without Docker (Native Python)
|
|
245
|
+
|
|
246
|
+
#### Prerequisites
|
|
247
|
+
- **Python 3.11+** installed (`python3 --version`).
|
|
248
|
+
|
|
249
|
+
#### 1. Install Package
|
|
250
|
+
|
|
251
|
+
##### From PyPI:
|
|
252
|
+
```bash
|
|
253
|
+
pip install pinterest-mcp-docker
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
##### From Source:
|
|
257
|
+
```bash
|
|
258
|
+
git clone https://github.com/sinalkar/pinterest-mcp-docker.git
|
|
259
|
+
cd pinterest-mcp-docker
|
|
260
|
+
pip install -e .
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
#### 2. Run Interactive OAuth Setup CLI (`pinterest-mcp-auth`)
|
|
264
|
+
|
|
265
|
+
If you don't have pre-generated OAuth tokens, run the interactive helper CLI:
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
pinterest-mcp-auth
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
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`.
|
|
272
|
+
|
|
273
|
+
#### 3. Launch Server by Platform
|
|
274
|
+
|
|
275
|
+
##### macOS / Linux (Bash / Zsh)
|
|
276
|
+
```bash
|
|
277
|
+
# Set environment variables
|
|
278
|
+
export PINTEREST_CLIENT_ID="your_client_id"
|
|
279
|
+
export PINTEREST_CLIENT_SECRET="your_client_secret"
|
|
280
|
+
export PINTEREST_ACCESS_TOKEN="your_access_token"
|
|
281
|
+
|
|
282
|
+
# Run in stdio mode (default)
|
|
283
|
+
pinterest-mcp
|
|
284
|
+
|
|
285
|
+
# Or run in HTTP mode
|
|
286
|
+
export MCP_TRANSPORT="http"
|
|
287
|
+
export MCP_HOST="127.0.0.1"
|
|
288
|
+
export MCP_PORT="8080"
|
|
289
|
+
pinterest-mcp
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
##### Windows (PowerShell)
|
|
293
|
+
```powershell
|
|
294
|
+
# Set environment variables
|
|
295
|
+
$env:PINTEREST_CLIENT_ID="your_client_id"
|
|
296
|
+
$env:PINTEREST_CLIENT_SECRET="your_client_secret"
|
|
297
|
+
$env:PINTEREST_ACCESS_TOKEN="your_access_token"
|
|
298
|
+
|
|
299
|
+
# Run in stdio mode
|
|
300
|
+
pinterest-mcp
|
|
301
|
+
|
|
302
|
+
# Or run in HTTP mode
|
|
303
|
+
$env:MCP_TRANSPORT="http"
|
|
304
|
+
$env:MCP_HOST="127.0.0.1"
|
|
305
|
+
$env:MCP_PORT="8080"
|
|
306
|
+
pinterest-mcp
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
##### Windows (Command Prompt - `cmd.exe`)
|
|
310
|
+
```cmd
|
|
311
|
+
set PINTEREST_CLIENT_ID=your_client_id
|
|
312
|
+
set PINTEREST_CLIENT_SECRET=your_client_secret
|
|
313
|
+
set PINTEREST_ACCESS_TOKEN=your_access_token
|
|
314
|
+
|
|
315
|
+
pinterest-mcp
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
## 💻 AI Client Configuration
|
|
321
|
+
|
|
322
|
+
### Claude Desktop (`claude_desktop_config.json`)
|
|
323
|
+
|
|
324
|
+
Locate your Claude Desktop config file:
|
|
325
|
+
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
326
|
+
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
327
|
+
|
|
328
|
+
#### Using Docker (Recommended):
|
|
329
|
+
```json
|
|
330
|
+
{
|
|
331
|
+
"mcpServers": {
|
|
332
|
+
"pinterest": {
|
|
333
|
+
"command": "docker",
|
|
334
|
+
"args": [
|
|
335
|
+
"run",
|
|
336
|
+
"-i",
|
|
337
|
+
"--rm",
|
|
338
|
+
"-e", "PINTEREST_CLIENT_ID=your_client_id",
|
|
339
|
+
"-e", "PINTEREST_CLIENT_SECRET=your_client_secret",
|
|
340
|
+
"-e", "PINTEREST_ACCESS_TOKEN=your_access_token",
|
|
341
|
+
"-v", "pinterest_token_data:/home/app/.local/state/pinterest-mcp",
|
|
342
|
+
"ghcr.io/sinalkar/pinterest-mcp-docker:latest"
|
|
343
|
+
]
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
#### Using Native Python:
|
|
350
|
+
```json
|
|
351
|
+
{
|
|
352
|
+
"mcpServers": {
|
|
353
|
+
"pinterest": {
|
|
354
|
+
"command": "pinterest-mcp",
|
|
355
|
+
"env": {
|
|
356
|
+
"PINTEREST_CLIENT_ID": "your_client_id",
|
|
357
|
+
"PINTEREST_CLIENT_SECRET": "your_client_secret",
|
|
358
|
+
"PINTEREST_ACCESS_TOKEN": "your_access_token"
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
### Cursor / Remote HTTP Client
|
|
368
|
+
|
|
369
|
+
To connect Cursor or a custom client to a running HTTP instance of `pinterest-mcp-docker`:
|
|
370
|
+
|
|
371
|
+
```json
|
|
372
|
+
{
|
|
373
|
+
"mcpServers": {
|
|
374
|
+
"pinterest-http": {
|
|
375
|
+
"url": "http://localhost:8080/mcp",
|
|
376
|
+
"headers": {
|
|
377
|
+
"Authorization": "Bearer your_secure_bearer_token"
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
## ⚙️ Environment Variables Reference
|
|
387
|
+
|
|
388
|
+
| Variable | Purpose | Required | Default | Secret |
|
|
389
|
+
| -------- | ------- | -------- | ------- | ------ |
|
|
390
|
+
| `PINTEREST_CLIENT_ID` | Pinterest API v5 App Client ID | **Yes** | None | **Yes** |
|
|
391
|
+
| `PINTEREST_CLIENT_SECRET` | Pinterest API v5 App Client Secret | **Yes** | None | **Yes** |
|
|
392
|
+
| `PINTEREST_ACCESS_TOKEN` | OAuth Access Token | Optional | None | **Yes** |
|
|
393
|
+
| `PINTEREST_REFRESH_TOKEN` | OAuth Refresh Token for auto-renewal | Optional | None | **Yes** |
|
|
394
|
+
| `MCP_TRANSPORT` | Transport mode (`stdio` or `http`) | No | `stdio` | No |
|
|
395
|
+
| `MCP_HOST` | Bind address for HTTP mode | No | `127.0.0.1` | No |
|
|
396
|
+
| `MCP_PORT` | Listen port for HTTP mode | No | `8080` | No |
|
|
397
|
+
| `MCP_PATH` | Endpoint path for HTTP route | No | `/mcp` | No |
|
|
398
|
+
| `MCP_AUTH_TOKEN` | Bearer token for HTTP mode | Conditional | None | **Yes** |
|
|
399
|
+
| `PINTEREST_TOKEN_PATH` | Path to persistent token JSON file | No | `~/.local/state/pinterest-mcp/token.json` | No |
|
|
400
|
+
| `PINTEREST_ALLOWED_IMAGE_DIR` | Allowed root dir for local image path | No | Home directory (`~`) | No |
|
|
401
|
+
| `PINTEREST_ALLOW_LOCAL_PATHS` | Allow local image paths in HTTP mode | No | `false` | No |
|
|
402
|
+
| `PINTEREST_MAX_IMAGE_BYTES` | Maximum image size limit in bytes | No | `10485760` (10MB) | No |
|
|
403
|
+
| `PINTEREST_HTTP_TIMEOUT` | Outbound HTTP request timeout (seconds) | No | `30.0` | No |
|
|
404
|
+
| `LOG_LEVEL` | Logging level (`INFO`, `DEBUG`, etc.) | No | `INFO` | No |
|
|
405
|
+
| `LOG_FORMAT` | Log format (`text` or `json`) | No | `text` | No |
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
## ❓ Frequently Asked Questions (FAQ / AEO & GEO)
|
|
410
|
+
|
|
411
|
+
### Q: What is Pinterest MCP?
|
|
412
|
+
**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.
|
|
413
|
+
|
|
414
|
+
### Q: How do I connect Claude Desktop to Pinterest?
|
|
415
|
+
**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.
|
|
416
|
+
|
|
417
|
+
### Q: Can I upload local images from my computer using AI?
|
|
418
|
+
**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.
|
|
419
|
+
|
|
420
|
+
### Q: How does `pinterest-mcp-docker` protect against security threats?
|
|
421
|
+
**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.
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
## 📦 Container Tags & Cosign Signature Verification
|
|
426
|
+
|
|
427
|
+
### Container Image Tags
|
|
428
|
+
|
|
429
|
+
| Tag | Type | Description |
|
|
430
|
+
| --- | ---- | ----------- |
|
|
431
|
+
| `latest` | Moving | Points to the latest production release |
|
|
432
|
+
| `0.2.0`, `0.2`, `0` | SemVer | Automatically updated for patch and minor updates |
|
|
433
|
+
| `sha-<short>` | Immutable | Exact git commit build tag |
|
|
434
|
+
|
|
435
|
+
### Verifying Image Signatures
|
|
436
|
+
|
|
437
|
+
Image releases are signed keylessly with [Cosign](https://github.com/sigstore/cosign) OIDC:
|
|
438
|
+
|
|
439
|
+
```bash
|
|
440
|
+
cosign verify \
|
|
441
|
+
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
|
|
442
|
+
--certificate-identity-regexp "https://github.com/sinalkar/pinterest-mcp-docker/.github/workflows/release.yml@refs/tags/v.*" \
|
|
443
|
+
ghcr.io/sinalkar/pinterest-mcp-docker:latest
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
## 📄 License & Attribution
|
|
449
|
+
|
|
450
|
+
Distributed under the **[MIT License](LICENSE)**.
|
|
451
|
+
|
|
452
|
+
- **Original Author:** Carlos Lugtu ([`clugtu/pinterest-mcp`](https://github.com/clugtu/pinterest-mcp))
|
|
453
|
+
- **Fork Maintainer:** sanjay s ([`sinalkar/pinterest-mcp-docker`](https://github.com/sinalkar/pinterest-mcp-docker))
|
|
454
|
+
|
|
455
|
+
See [NOTICE.md](NOTICE.md) for full licensing details and modifications summary.
|