A Model Context Protocol (MCP) server for Canny feedback management. Connect Canny to any MCP-compatible AI client to manage customer feedback, prioritize features, and streamline product development through natural language.
- 37 Tools — Full Canny API coverage: posts, comments, votes, users, categories, tags, changelog, status changes, ideas, insights, groups, opportunities, and Jira integration
- Token-Optimized — 70–90% smaller responses than the raw API
- Jira Integration — Link posts to Jira issues
- PM Workflows — Built-in prompts for weekly triage, sprint planning, and executive reporting
- Smart Pagination — Automatic cursor/skip handling
- Batch Operations — Bulk status changes
- Configurable Toolsets — Readonly by default; enable write tools selectively
- Node.js v20.9+, v22+, or v24+ (LTS versions)
- npm v9+
- MCP Client — Claude Code, Continue.dev, or any MCP-compatible client
- Canny API Key — Get one at canny.io/admin/settings/api
The fastest way to start: run npx directly through Claude Code. No clone, no build.
- API Key — Visit canny.io/admin/settings/api
- Subdomain — Your Canny workspace URL:
https://<subdomain>.canny.io - Board ID (optional) — Find it via the Canny admin URL or by running
canny_list_boardsafter setup
claude mcp add --transport stdio canny \
--scope user \
--env CANNY_SUBDOMAIN=<COMPANY_SUBDOMAIN> \
--env CANNY_API_KEY=<CANNY_API_KEY> \
--env CANNY_DEFAULT_BOARD=<BOARD_ID> \
--env CANNY_TOOL_MODE=readonly \
-- npx -y @opensourceops/canny-mcpReplace <COMPANY_SUBDOMAIN>, <CANNY_API_KEY>, and <BOARD_ID> with your values.
Quit and reopen Claude Code for the new server to load.
Ask Claude:
List the available Canny tools.
You should see 37 tools, including canny_list_posts, canny_get_post, and canny_list_ideas.
To install the package globally:
npm install -g @opensourceops/canny-mcpThen configure your MCP client to run canny-mcp-server instead of npx:
{
"mcpServers": {
"canny": {
"command": "canny-mcp-server",
"env": {
"CANNY_API_KEY": "your_api_key",
"CANNY_SUBDOMAIN": "your_subdomain",
"CANNY_DEFAULT_BOARD": "your_board_id",
"CANNY_TOOL_MODE": "readonly"
}
}
}
}canny_list_boards— List all boardscanny_list_tags— List tags (optionally by board)canny_create_tag— Create a new tag on a boardcanny_list_categories— List categoriescanny_list_posts— List posts with filters (status, author, company, tags)canny_filter_posts— Filter by category, company, segment, tag slugs, and date rangescanny_get_post— Get full post details with comments and votescanny_list_status_changes— List post status change history for auditingcanny_create_category— Create a board category
canny_create_post— Create a post (supports images, ETA, owner)canny_update_post— Update title, description, ETA, or imagescanny_update_post_status— Change status with optional voter notificationcanny_change_category— Move a post to a different categorycanny_add_post_tag— Add a tag to a postcanny_remove_post_tag— Remove a tag from a post
canny_list_comments— List comments (filterable by company)canny_list_votes— List votescanny_create_comment— Add a comment (supports images, internal flag)canny_delete_comment— Remove a commentcanny_add_vote— Add a votecanny_remove_vote— Remove a vote
canny_get_user_details— Look up a user by ID, email, or custom userIDcanny_list_companies— List companies with MRR datacanny_find_or_create_user— Find or create a user with company associationscanny_link_company— Link a user to a company
canny_link_jira_issue— Link a Jira issue to a postcanny_unlink_jira_issue— Unlink a Jira issue
canny_list_changelog_entries— List changelog entriescanny_create_changelog_entry— Create a changelog entry to communicate product updates
canny_list_groups— List groups (cursor-based pagination)canny_get_group— Get a group by ID or URL namecanny_list_ideas— List ideas with filtering, search, and sortingcanny_get_idea— Get an idea by ID or URL namecanny_list_insights— List insights, optionally filtered by ideacanny_get_insight— Get an insight by IDcanny_list_opportunities— List Salesforce opportunities linked to Canny
canny_batch_update_status— Update multiple post statuses at once
The server runs in readonly mode by default (19 read-only tools). To enable write operations, set CANNY_TOOL_MODE:
| Mode | Tools | Description |
|---|---|---|
readonly |
19 | Read-only tools only (default) |
all |
37 | All tools, including writes |
discovery,posts |
varies | Specific toolsets (comma-separated) |
Set via environment variable or config/default.json:
{
"server": {
"toolMode": "all"
}
}Rebuild after changing config/default.json:
npm run buildCanny API (required)
| Variable | Default | Description |
|---|---|---|
CANNY_API_KEY |
-- | Your Canny API key (required) |
CANNY_BASE_URL |
https://canny.io/api/v1 |
Canny API base URL |
CANNY_SUBDOMAIN |
auto-detected | Your Canny subdomain; auto-detected from CANNY_BASE_URL if *.canny.io |
CANNY_CONFIG_PATH |
config/default.json |
Path to the JSON config file |
Workspace
| Variable | Default | Description |
|---|---|---|
CANNY_DEFAULT_BOARD |
-- | Default board ID |
CANNY_WORKSPACE_NAME |
Default |
Workspace display name |
CANNY_CUSTOM_STATUSES |
open,under review,planned,in progress,complete,closed |
Comma-separated list of valid statuses |
Jira Integration
| Variable | Default | Description |
|---|---|---|
CANNY_JIRA_ENABLED |
false |
Enable Jira integration (true/false) |
CANNY_JIRA_PROJECT_KEY |
-- | Jira project key (e.g., PROJ) |
Pagination & Display
| Variable | Default | Description |
|---|---|---|
CANNY_PAGINATION_LIMIT |
10 |
Results per page |
CANNY_PAGINATION_MAX |
50 |
Maximum total results |
CANNY_COMPACT_MODE |
true |
Return compact responses (true/false) |
Cache
| Variable | Default | Description |
|---|---|---|
CANNY_CACHE_ENABLED |
true |
Enable response caching (true/false) |
CANNY_CACHE_MAX_SIZE |
100 |
Maximum cache entries |
Rate Limiting
| Variable | Default | Description |
|---|---|---|
CANNY_RATE_LIMIT_REQUESTS |
100 |
Maximum requests per window |
CANNY_RATE_LIMIT_WINDOW |
60000 |
Rate limit window in milliseconds |
Server
| Variable | Default | Description |
|---|---|---|
CANNY_TOOL_MODE |
readonly |
readonly, all, or comma-separated toolsets |
SERVER_TRANSPORT |
stdio |
Transport mode: stdio, http, or both |
SERVER_HTTP_PORT |
3000 |
HTTP server port (when transport includes http) |
SERVER_HTTP_HOST |
0.0.0.0 |
HTTP server bind address |
Logging
| Variable | Default | Description |
|---|---|---|
LOG_LEVEL |
info |
Log level: debug, info, warn, error |
LOG_FORMAT |
json |
Log format: json or pretty |
The server ships with 5 built-in prompts (weekly_triage, sprint_planning, executive_summary, jira_sync_status, customer_impact). Add your own in config/default.json:
{
"prompts": [
{
"name": "my_workflow",
"description": "Custom triage workflow",
"template": "Analyze feedback and..."
}
]
}See Prompt Configuration for the full guide and Custom Prompts for advanced examples.
Clone the repository to modify the server, run tests, or contribute.
git clone https://github.com/opensourceops/canny-mcp-server.git
cd canny-mcp-server
npm install
npm run buildclaude mcp add --transport stdio canny \
--env CANNY_API_KEY=your_api_key \
--env CANNY_SUBDOMAIN=your_subdomain \
--env CANNY_DEFAULT_BOARD=your_board_id \
--env CANNY_CONFIG_PATH=$(pwd)/config/default.json \
-- $(which node) $(pwd)/dist/index.jsAdd to your MCP client's config file:
{
"mcpServers": {
"canny": {
"command": "node",
"args": ["/absolute/path/to/canny-mcp-server/dist/index.js"],
"env": {
"CANNY_API_KEY": "your_api_key",
"CANNY_SUBDOMAIN": "your_subdomain",
"CANNY_DEFAULT_BOARD": "your_board_id",
"CANNY_CONFIG_PATH": "/absolute/path/to/canny-mcp-server/config/default.json"
}
}
}
}Restart your MCP client, then ask:
Show me the latest feature requests from Canny.
Test your key directly:
curl https://canny.io/api/v1/boards/list --data apiKey=YOUR_API_KEYThis should return your boards.
- Rebuild after config changes:
npm run build - Restart your MCP client (quit and reopen)
- Check
CANNY_TOOL_MODE—readonlyexcludes write tools - Use absolute paths in manual JSON configuration
Use Node.js LTS versions (20.9+, 22+, or 24+). Odd-numbered releases (23, 25) are non-LTS and unsupported. Switch with nvm use 20 or nvm use 22.
Deprecated package warnings (ESLint, glob) affect only devDependencies and do not affect production runtime.
- Never commit
.envfiles or API keys - Use
readonlymode for general use - Enable write tools only when needed
- Keep
CANNY_API_KEYsecret
canny-mcp-server/
├── src/ # TypeScript source
│ ├── index.ts # Entry point
│ ├── server.ts # MCP server
│ ├── api/ # Canny API client
│ ├── tools/ # MCP tools
│ ├── prompts/ # Built-in prompts
│ └── types/ # Type definitions
├── config/
│ └── default.json # Server configuration
├── docs/ # Documentation
├── dist/ # Compiled output (generated)
├── package.json
└── tsconfig.json
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
Apache 2.0 — See LICENSE.
- Issues — GitHub Issues
- API Reference — Canny API Documentation
