Triage product feedback in Windsurf
Feedback that arrives through the API is classified as bug, feature request, praise, billing or support. With the MCP server connected, the agent working in your codebase can read that queue, so "what are users reporting about the importer?" is answered next to the code that needs fixing.
Windsurf (now Devin Desktop) reads MCP servers from one file in your home directory, shared by every project. Remote servers take a serverUrl and optional headers.
Setup
You need a secret key (nv_live_…) from Dashboard → API keys.
01Add the server to mcp_config.json
~/.codeium/windsurf/mcp_config.json
{
"mcpServers": {
"nordva": {
"serverUrl": "https://mcp.nordva.dev",
"headers": {
"Authorization": "Bearer nv_live_..."
}
}
}
}The field is serverUrl, not url. The file is outside your repositories, so the key can sit in it; Windsurf also replaces ${env:NAME} with an environment variable if you would rather keep it out. npx nordva init writes this file for you.
02Check the connection
In Cascade, open the MCP servers settings and refresh. nordva should be listed with its tools. Ask Cascade to run setup_check.
Then ask Windsurf
- Show me the latest bug reports.
- How many feature requests came in this week, and what are they about?
- Log this as feedback from user 4812: the export button does nothing on Safari.
- Route bugs to our GitHub repo acme/app.
For “Show me the latest bug reports.” Windsurf calls list_feedback with:
{
"classification": "bug",
"limit": 20
} Returned: A list of submissions with id, text, classification, confidence and page URL, plus a cursor if there are more.
Feedback tools and arguments
submit_feedback
Submit, classify, and route user feedback
| feedback_text | required | string, max 2,000 | Verbatim user feedback text. Do not paraphrase. |
| user_id | optional | string, max 256 | Identifier of the user who submitted the feedback. |
| optional | string, max 254 | Submitter's email, if they want a reply. Never guess it. | |
| page_url | optional | string, max 2,048 | URL the user was on when leaving feedback. |
| category_hint | optional | "bug" | "feature_request" | "praise" | "billing" | "support" | Pre-classification hint when the agent is confident. |
| rating | optional | number, 1–5 | 1 to 5, only when the user gave a rating. Never inferred. |
| changelog_entry_id | optional | string, max 64 | The changelog entry this feedback is about. |
list_feedback
Read-onlyList recent feedback submissions
| limit | optional | number, 1–100 | Page size (default 25). |
| cursor | optional | string | Opaque cursor from a previous page's meta.next_cursor. |
| classification | optional | "bug" | "feature_request" | "praise" | "billing" | "support" | "uncategorised" | Filter results to one classification. |
| status | optional | string, max 40 | A lifecycle status, or "open" for everything not yet reviewed or resolved. |
| changelog_entry_id | optional | string, max 64 | Only feedback given on this changelog entry. |
get_feedback
Read-onlyRead one feedback item
| feedback_id | required | string, max 64 |
update_feedback
Mark feedback reviewed or resolved, or fix its category
| feedback_id | required | string, max 64 | Feedback id from list_feedback, e.g. "fb_...". |
| status | optional | "reviewed" | "resolved" | |
| classification | optional | "bug" | "feature_request" | "praise" | "billing" | "support" | "uncategorised" | Only to correct a wrong classification. |
| linked_entry_id | optional | string, max 64 | Changelog entry (ce_…) that answers this request, or null to unlink. The person is emailed once when it is published. |
reply_to_feedback
Confirms firstEmail a reply to the person who sent feedback
| feedback_id | required | string, max 64 | |
| body | required | string, max 5,000 | The reply, plain text. |
| subject | optional | string, max 150 | |
| channel | optional | "email" | "notification" | "none" | email (default), notification (to the feedback's user_id), or none (kept on the item only). |
| reply_to | optional | string, max 254 | Email only: inbox for the person's answer, for this reply only. |
bulk_update_feedback
Mark many feedback items at once
| ids | required | array | |
| status | optional | "reviewed" | "resolved" | |
| classification | optional | "bug" | "feature_request" | "praise" | "billing" | "support" | "uncategorised" |
export_feedback
Read-onlyExport feedback as CSV
| classification | optional | "bug" | "feature_request" | "praise" | "billing" | "support" | "uncategorised" | |
| status | optional | string, max 40 | |
| since | optional | string |
configure_feedback_routing
Configure a feedback routing destination (email/linear/github/slack)
| destination | required | "email" | "linear" | "github" | "slack" | Which destination to configure. One of: email, linear, github, slack. |
| destination_email | optional | string | [email] Address to send feedback notifications to. |
| api_key | optional | string | [linear] Linear personal or workspace API key (lin_api_...). |
| team_id | optional | string | [linear] Linear team ID (from team Settings → API). |
| assignee_id | optional | string | [linear] Linear user ID to assign created issues to. |
| personal_access_token | optional | string | [github] GitHub PAT with repo scope (or fine-grained issues:write). |
| owner | optional | string | [github] GitHub username or organisation name. |
| repo | optional | string | [github] Repository name without the owner prefix. |
| assignee | optional | string | [github] GitHub username to assign created issues to. |
| label_map | optional | object | [linear/github] Map feedback category → destination label. e.g. { bug: 'bug', feature_request: 'enhancement' } |
| webhook_url | optional | string | [slack] Incoming Webhook URL (https://hooks.slack.com/services/...). |
| categories | optional | array | [any] Only these categories go to this destination, such as ["bug"] for Linear. Leave out for every category. |
get_feedback_routing
Read-onlySee where feedback is forwarded
No arguments.
remove_feedback_routing
Confirms firstStop forwarding feedback to a destination
| destination | required | "email" | "slack" | "linear" | "github" |
Behaviour worth knowing
- Feedback works on every plan. Free takes 50 messages a month per project and sorts them by keywords; on Indie and Builder, AI sorts them and adds a one-line summary, and routing reaches Slack, Linear and GitHub as well as email.
- submit_feedback takes between 10 and 2,000 characters of text, plus an optional category_hint and a 1 to 5 rating. With AI sorting the classifier still decides and reports its own confidence; with keyword sorting (Free) the hint is the category.
- configure_feedback_routing replaces any existing configuration for the same destination. It creates and updates but does not delete.
- Routing credentials (a Linear API key, a GitHub token, a Slack webhook URL) pass through the agent. The tool description tells it to ask for consent first and never to repeat the secret back.
- The file is shared by all your projects, so it points at one Launch project at a time. Running npx nordva init in another project points it there.