pinterest-business-mcp
# Pinterest Business MCP
Local [Model Context Protocol](https://modelcontextprotocol.io/) server for Pinterest Business workflows. This repository includes a stdio MCP server, Pinterest OAuth connection tools, encrypted local token storage, and server status reporting.
## Requirements
- Node.js 22+
- [pnpm](https://pnpm.io/) 11+
- A Pinterest developer app with the redirect URI below
## Pinterest developer dashboard setup
1. Sign in at [Pinterest Developers](https://developers.pinterest.com/apps/).
2. Create or open your app.
3. Under **Configure**, add this exact redirect URI:
`http://127.0.0.1:3333/oauth/callback`
4. Copy your **App ID** and **App secret key**.
5. Request the scopes your workflow needs. At minimum, connection testing commonly uses read scopes such as `boards:read`, `pins:read`, and `user_accounts:read`.
6. For sandbox testing, keep `PINTEREST_ENVIRONMENT=sandbox`. Pinterest uses the same OAuth authorize page for both environments; token exchange uses the sandbox API host when sandbox is selected.
## Local setup
```bash
pnpm install
cp .env.example .env
```
Edit `.env` and set at minimum:
```env
PINTEREST_ENVIRONMENT=sandbox
PINTEREST_APP_ID=your-app-id
PINTEREST_APP_SECRET=your-app-secret
PINTEREST_TOKEN_ENCRYPTION_KEY=your-base64-key
PINTEREST_OAUTH_SCOPES=boards:read,pins:read,user_accounts:read
```
Generate an encryption key:
```bash
openssl rand -base64 32
```
## Development
```bash
pnpm dev # watch mode (tsx)
pnpm build # compile to dist/
pnpm start # run compiled server
pnpm verify # typecheck, lint, test, build
```
## MCP client configuration (Cursor)
Add a project-scoped MCP server entry in `.cursor/mcp.json` (recommended) or your user MCP settings. Do **not** commit real secrets.
```json
{
"mcpServers": {
"pinterest-business": {
"command": "node",
"args": ["/absolute/path/to/pinterest-business-mcp/dist/index.js"],
"env": {
"PINTEREST_ENVIRONMENT": "sandbox",
"PINTEREST_APP_ID": "your-app-id",
"PINTEREST_APP_SECRET": "your-app-secret",
"PINTEREST_TOKEN_ENCRYPTION_KEY": "your-base64-key",
"PINTEREST_OAUTH_SCOPES": "boards:read,pins:read,user_accounts:read",
"PINTEREST_WRITES_ENABLED": "false",
"LOG_LEVEL": "info"
}
}
}
}
```
Restart Cursor after changing MCP configuration.
## Connecting your Pinterest Business account
1. Start the MCP server in Cursor.
2. Call `pinterest_get_authorization_url`.
3. Open the returned authorization URL in your browser.
4. Approve the Pinterest app when prompted.
5. Wait for the local callback page at `http://127.0.0.1:3333/oauth/callback` to report success.
6. Call `pinterest_connection_status` to confirm the connection.
The MCP server never asks for your Pinterest password. Authentication happens only on Pinterest's official OAuth page.
## Sandbox setup
- Set `PINTEREST_ENVIRONMENT=sandbox`.
- Use the same redirect URI: `http://127.0.0.1:3333/oauth/callback`.
- OAuth authorization still starts at `https://www.pinterest.com/oauth/`.
- Token exchange and refresh use `https://api-sandbox.pinterest.com/v5/oauth/token`.
## Tools
### `pinterest_server_status`
Returns server metadata and configuration flags only — never credential values.
### `pinterest_get_authorization_url`
Starts the local callback listener on `127.0.0.1:3333`, creates a single-use OAuth state value, and returns the Pinterest authorization URL plus safe instructions. Tokens are never returned by this tool.
Optional input:
- `scopes`: array of official Pinterest scopes. If omitted, `PINTEREST_OAUTH_SCOPES` is used.
### `pinterest_connection_status`
Reports whether a Pinterest account is connected locally, including scope and expiry metadata. Tokens are never returned. Expired access tokens are refreshed automatically when a valid refresh token is available.
### `pinterest_disconnect`
Securely removes locally stored OAuth authorization data. To revoke access on Pinterest itself, remove the app from Pinterest settings under **Security and logins → Apps**.
## Environment variables
See [`.env.example`](.env.example) for the full list.
| Variable | Required | Description |
| -------------------------------- | -------- | ------------------------------------------------------------------- |
| `PINTEREST_ENVIRONMENT` | Yes | `sandbox` or `production` |
| `PINTEREST_APP_ID` | OAuth | Pinterest app ID |
| `PINTEREST_APP_SECRET` | OAuth | Pinterest app secret |
| `PINTEREST_TOKEN_ENCRYPTION_KEY` | OAuth | Base64 or passphrase used for AES-256-GCM token encryption |
| `PINTEREST_TOKEN_STORE_PATH` | No | Encrypted token file path (default: `.tokens/pinterest-oauth.enc`) |
| `PINTEREST_OAUTH_SCOPES` | OAuth | Default scopes unless overridden by the authorization tool |
| `PINTEREST_WRITES_ENABLED` | No | `true` or `false` (default: `false`) |
| `LOG_LEVEL` | No | `debug`, `info`, `warn`, or `error` |
## Troubleshooting
| Problem | What to check |
| ------- | ------------- |
| Callback port already in use | Another OAuth attempt or process is using `127.0.0.1:3333`. Wait for it to finish or stop the other process. |
| Redirect URI mismatch | The Pinterest app must contain the exact URI `http://127.0.0.1:3333/oauth/callback`. |
| Missing scopes | Set `PINTEREST_OAUTH_SCOPES` or pass `scopes` to `pinterest_get_authorization_url`. |
| Connection not stored | Confirm `PINTEREST_TOKEN_ENCRYPTION_KEY` is set and writable, then repeat the OAuth flow. |
| Sandbox token exchange failed | Keep `PINTEREST_ENVIRONMENT=sandbox` so token exchange uses the sandbox API host. |
| Refresh failed | Reconnect with `pinterest_get_authorization_url` if the refresh token expired or was revoked. |
## Token revocation and disconnect
- Local disconnect: call `pinterest_disconnect`.
- Pinterest-side revocation: open Pinterest settings → **Security and logins → Apps** and remove this app.
- Pinterest's remote revocation endpoint is unreliable in some app states, so local disconnect plus manual app removal is the supported recovery path.
## Security
See [SECURITY.md](SECURITY.md) for credential handling and threat boundaries.
## License
MIT
TDQS
Scored across 4 tools
Each tool addresses a distinct aspect of OAuth lifecycle: server config status, authorization URL retrieval, connection status, and disconnection. There is no overlap in their purposes, making misselection unlikely.
All tools share the 'pinterest_' prefix and use lowercase with underscores, but verb usage is inconsistent. 'server_status' and 'connection_status' are noun phrases, while 'get_authorization_url' uses a verb and 'disconnect' is a bare verb. This mixed convention is readable but not fully predictable.
With 4 tools, the server is tightly scoped to OAuth connection management. Each tool is essential and there is no bloat, making the count ideal for the apparent purpose.
The tool set covers the main lifecycle: check server config, initiate authorization, verify connection, and disconnect. A minor gap is the absence of an explicit token refresh or explicit callback handling, but these are likely handled implicitly or are beyond the server's intended scope.