withfeedback-mcp
MCP (Model Context Protocol) server for withfeedback.com: lets AI assistants (Claude, Cursor, …) list and moderate feedback submissions, create and bulk-import testimonials, inspect widgets and embed codes, and read NPS survey results.
Transports: stdio (default) and streamable HTTP (withfeedback-mcp --http
or WITHFEEDBACK_MCP_TRANSPORT=http). HTTP mode binds 127.0.0.1 only —
see the security note below before changing that.
Install
pip install withfeedback-mcp
# or run without installing:
uvx withfeedback-mcp
Quick start with a personal access token (PAT)
The recommended setup for a local/stdio MCP server:
- Log in at your withfeedback.com instance and open Account → API Tokens
(
/accounts/tokens/). - Create a token with the scopes you need (see the table below). Copy it — it is shown only once.
- Configure your MCP client with
WITHFEEDBACK_TOKEN(examples below).
API access requires a plan that includes the API/CLI/MCP feature (Pro and above). Requests from lower plans return HTTP 403.
Claude Desktop / Claude Code configuration
Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"withfeedback": {
"command": "uvx",
"args": ["withfeedback-mcp"],
"env": {
"WITHFEEDBACK_TOKEN": "spd_your_token_here"
}
}
}
}
Prefer the OAuth2 device flow over a PAT? Omit WITHFEEDBACK_TOKEN — the
official public client id 7yQMsnY2Is2f5tCuwwgItoQu3fRkEX2wnzIRj0Vh is the
built-in default (shown here explicitly; only needed to override):
{
"mcpServers": {
"withfeedback": {
"command": "uvx",
"args": ["withfeedback-mcp"],
"env": {
"WITHFEEDBACK_CLIENT_ID": "7yQMsnY2Is2f5tCuwwgItoQu3fRkEX2wnzIRj0Vh"
}
}
}
}
Claude Code:
claude mcp add withfeedback --env WITHFEEDBACK_TOKEN=spd_your_token_here -- uvx withfeedback-mcp
Cursor configuration
~/.cursor/mcp.json (or the project's .cursor/mcp.json):
{
"mcpServers": {
"withfeedback": {
"command": "uvx",
"args": ["withfeedback-mcp"],
"env": {
"WITHFEEDBACK_TOKEN": "spd_your_token_here"
}
}
}
}
OAuth2 device flow (alternative to a PAT)
If WITHFEEDBACK_TOKEN is not set, the server falls back to the OAuth2
device flow using the official public client id
7yQMsnY2Is2f5tCuwwgItoQu3fRkEX2wnzIRj0Vh (public by design — device-flow
clients carry no secret). Set WITHFEEDBACK_CLIENT_ID to use a different
client (e.g. on a self-hosted instance). On the first tool call the server
prints a verification URL and a short code on stderr (and tries to open your
browser):
- The server calls
POST /o/device-authorization/with the client id. - You open the printed URL, enter the code, and approve the requested scopes.
- The server polls
POST /o/token/until approval and then uses the access token for all API calls.
Request a custom scope set with WITHFEEDBACK_SCOPES (space-separated).
Note on Dynamic Client Registration: open DCR (POST /o/register/) is
disabled in production (DCR_ENABLED=False is the production default) —
the endpoint is unauthenticated and unthrottled, so withfeedback.com does not
expose it. Use the published official client id (or a PAT); self-hosted
instances can register additional clients via Django admin or the
create_oauth2_app management command.
Environment variables
| Variable | Default | Purpose |
|---|---|---|
WITHFEEDBACK_API_URL |
https://withfeedback.com |
API base URL (self-hosted/staging override) |
WITHFEEDBACK_TOKEN |
— | Personal access token (primary auth for stdio) |
WITHFEEDBACK_CLIENT_ID |
official public client id | OAuth2 client id for the device-flow fallback |
WITHFEEDBACK_SCOPES |
all tool scopes | Scopes requested during device flow |
WITHFEEDBACK_MCP_TRANSPORT |
stdio |
Set to http for streamable HTTP |
WITHFEEDBACK_MCP_HOST |
127.0.0.1 |
HTTP bind address (loopback only by default) |
WITHFEEDBACK_MCP_PORT |
8000 |
HTTP bind port |
WITHFEEDBACK_MCP_ALLOW_REMOTE |
unset | Must be 1 to allow a non-loopback HTTP bind (read the security note first) |
On startup the server checks GET /.well-known/speedpy.json once and warns
(never fails) when the manifest is unreachable or the API is older than the
minimum this client expects.
HTTP transport security
The streamable HTTP transport has no per-caller authentication: the process holds a single account token (your PAT or device-flow grant), and every HTTP caller acts as that account. Therefore:
- HTTP mode binds
127.0.0.1by default and is intended for local clients on the same machine. - Binding a non-loopback address is refused unless you explicitly set
WITHFEEDBACK_MCP_ALLOW_REMOTE=1, and even then the server prints a prominent warning: only do this behind a reverse proxy that authenticates callers before they can reach the port. - A properly multi-tenant remote MCP server with per-user OAuth is a future server-side deployment of withfeedback.com — it is not something this package provides. Do not expose this process to the internet.
Tools and required scopes
Give your PAT (or device-flow grant) the scopes for the tools you plan to use:
| Tool | Endpoint(s) | Required scope |
|---|---|---|
list_teams |
GET /api/v1/teams/ |
read:teams |
list_projects |
GET /api/v1/teams/{team}/projects/ |
read:feedback |
list_submissions |
GET …/projects/{id}/submissions/ |
read:feedback |
get_submission |
GET …/submissions/{id}/ |
read:feedback |
approve_submission |
POST …/submissions/{id}/approve/ |
moderate:submissions |
reject_submission |
POST …/submissions/{id}/reject/ |
moderate:submissions |
create_testimonial |
POST …/projects/{id}/submissions/ |
write:testimonials |
import_testimonials |
POST …/projects/{id}/submissions/ (looped, ≤100 items) |
write:testimonials |
list_widgets |
GET …/projects/{id}/widgets/ |
read:widgets |
get_widget_embed_code |
GET …/widgets/{id}/embed-code/ |
read:widgets |
get_nps_summary |
GET …/surveys/ + GET …/surveys/{id}/results/ |
read:surveys |
Notes:
- Moderation is explicit and audited.
approve_submission/reject_submissioncall the dedicated action endpoints;write:*scopes cannot approve — onlymoderate:submissionscan. Responses include the submissionid,status,moderated_by_id, andmoderated_at, so agent actions stay attributable in the moderation audit trail. - Nothing is auto-published.
create_testimonialandimport_testimonialsalways create pending submissions that a moderation step (human or explicit approve call) must publish. - API errors surface as readable tool errors: HTTP 402 = plan quota/billing block, HTTP 403 = missing scope/role/plan feature, HTTP 409 = invalid moderation state transition.
Development
uv run --with pytest --with httpx --with mcp pytest packages/withfeedback-mcp/
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file withfeedback_mcp-0.1.0.tar.gz.
File metadata
- Download URL: withfeedback_mcp-0.1.0.tar.gz
- Upload date:
- Size: 20.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d0704eda8a1463f9fe1b9f578d076ad3f03e7162329bcf71a08ef0fa2e9d62a6
|
|
| MD5 |
4e1bb023075286fa227a38a5a34f1f66
|
|
| BLAKE2b-256 |
94ee90ebb32b32d141cba0093517f7ee68d36ad72179ccd242391a35c6d8925e
|
File details
Details for the file withfeedback_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: withfeedback_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e616815bc5dd0427b8ba8311f8686f5cddd364b02d2d85117ec48b1d02ff75a8
|
|
| MD5 |
b68557c46ea8a925c81674783a46aa4a
|
|
| BLAKE2b-256 |
fc70905bc50dc22f098ca8aed3228458b46c213c54f606bc5bc8cffc2f051087
|