MCP Reference
Quackback's MCP server exposes 23 tools and 5 resources. Tools perform actions (search, create, update, delete). Resources provide lookup data (boards, statuses, tags) that tools reference by ID.
Tools
search
Search feedback posts or changelog entries. Returns paginated results with a cursor for the next page.
| Parameter | Type | Default | Description |
|---|---|---|---|
entity | "posts" | "changelogs" | "posts" | Entity type to search |
query | string | - | Text search across titles and content |
boardId | string | - | Filter posts by board TypeID (ignored for changelogs) |
status | string | - | Filter by status slug. Posts: "open", "in_progress", etc. Changelogs: "draft", "published", "scheduled", "all" |
tagIds | string[] | - | Filter posts by tag TypeIDs (ignored for changelogs) |
sort | "newest" | "oldest" | "votes" | "newest" | Sort order. "votes" only applies to posts |
showDeleted | boolean | false | Show soft-deleted posts (team only, last 30 days) |
dateFrom | string | - | ISO 8601 date. Filter posts created on or after this date |
dateTo | string | - | ISO 8601 date. Filter posts created on or before this date |
limit | number (1-100) | 20 | Max results per page |
cursor | string | - | Pagination cursor from a previous response |
Scope: read:feedback
search({ query: "dark mode", sort: "votes", limit: 10 })
search({ entity: "changelogs", status: "published" })
search({ boardId: "board_01abc...", status: "open" })
search({ dateFrom: "2026-01-01", dateTo: "2026-02-01" })
search({ showDeleted: true })
get_details
Get full details for any entity by TypeID. The entity type is auto-detected from the ID prefix. No need to specify whether it's a post or changelog.
| Parameter | Type | Description |
|---|---|---|
id | string | TypeID of the entity (e.g., post_01abc..., changelog_01xyz...) |
Scope: read:feedback
Returns all fields including comments (for posts), linked posts (for changelogs), tags, official response, and timestamps.
get_details({ id: "post_01abc..." })
get_details({ id: "changelog_01xyz..." })
triage_post
Update a post's status, tags, or owner. All fields except postId are optional. Only provided fields are updated.
| Parameter | Type | Description |
|---|---|---|
postId | string | Post TypeID to update |
statusId | string | New status TypeID |
tagIds | string[] | Replace all tags with these TypeIDs |
ownerPrincipalId | string | null | Assign to a team member TypeID, or null to unassign |
Scope: write:feedback + team role (admin or member)
triage_post({ postId: "post_01abc...", statusId: "status_01xyz..." })
triage_post({ postId: "post_01abc...", ownerPrincipalId: "principal_01xyz..." })
triage_post({ postId: "post_01abc...", tagIds: ["tag_01a...", "tag_01b..."] })
vote_post
Toggle a vote on a feedback post. Call once to vote, call again to unvote.
| Parameter | Type | Description |
|---|---|---|
postId | string | Post TypeID to vote on |
Scope: write:feedback
Returns the current vote state and total vote count.
vote_post({ postId: "post_01abc..." })
proxy_vote
Add or remove a vote on behalf of another user. Use this to record votes from external channels (support tickets, Slack messages, sales calls) with source attribution for traceability.
| Parameter | Type | Default | Description |
|---|---|---|---|
action | "add" | "remove" | "add" | Whether to add or remove the proxy vote |
postId | string | - | Post TypeID to vote on |
voterPrincipalId | string | - | Principal TypeID of the user to vote on behalf of |
sourceType | string | - | Attribution source type (e.g. "zendesk", "slack", "intercom") |
sourceExternalUrl | string | - | URL linking to the originating record |
Scope: write:feedback + team role (admin or member)
Adding a vote is idempotent — calling it twice for the same user has no effect. Removing a vote works for any vote type (proxy, integration, or direct).
proxy_vote({ postId: "post_01abc...", voterPrincipalId: "principal_01xyz..." })
proxy_vote({
postId: "post_01abc...",
voterPrincipalId: "principal_01xyz...",
sourceType: "zendesk",
sourceExternalUrl: "https://support.example.com/tickets/1234"
})
proxy_vote({ action: "remove", postId: "post_01abc...", voterPrincipalId: "principal_01xyz..." })
add_comment
Post a comment on a feedback post. Supports threaded replies via parentId.
| Parameter | Type | Description |
|---|---|---|
postId | string | Post TypeID to comment on |
content | string | Comment text (max 5,000 characters) |
parentId | string | Parent comment TypeID for a threaded reply |
Scope: write:feedback
add_comment({ postId: "post_01abc...", content: "Thanks for the feedback!" })
add_comment({
postId: "post_01abc...",
content: "Good point.",
parentId: "comment_01xyz..."
})
update_comment
Edit a comment's content. Team members can edit any comment. Authors can edit their own.
| Parameter | Type | Description |
|---|---|---|
commentId | string | Comment TypeID to edit |
content | string | New comment text (max 5,000 characters) |
Scope: write:feedback
update_comment({ commentId: "comment_01abc...", content: "Updated response." })
delete_comment
Hard-delete a comment and all its replies. This cannot be undone. Authors can delete their own comments. Team members can delete any comment.
| Parameter | Type | Description |
|---|---|---|
commentId | string | Comment TypeID to delete |
Scope: write:feedback
Deleting a comment also deletes all replies. This action is permanent.
delete_comment({ commentId: "comment_01abc..." })
react_to_comment
Add or remove an emoji reaction on a comment.
| Parameter | Type | Description |
|---|---|---|
action | "add" | "remove" | Whether to add or remove the reaction |
commentId | string | Comment TypeID to react to |
emoji | string | Emoji character (e.g., "👍", "❤️", "🎉") |
Scope: write:feedback
react_to_comment({ action: "add", commentId: "comment_01abc...", emoji: "👍" })
react_to_comment({ action: "remove", commentId: "comment_01abc...", emoji: "👍" })
create_post
Submit new feedback on a board. Requires a board ID and title. Content, status, and tags are optional.
| Parameter | Type | Description |
|---|---|---|
boardId | string | Board TypeID (use quackback://boards resource to find IDs) |
title | string | Post title (max 200 characters) |
content | string | Post body (max 10,000 characters) |
statusId | string | Initial status TypeID (defaults to board default) |
tagIds | string[] | Tag TypeIDs to apply |
Scope: write:feedback
Use the quackback://boards resource to look up board IDs before calling create_post.
create_post({ boardId: "board_01abc...", title: "Add dark mode" })
create_post({
boardId: "board_01abc...",
title: "Add dark mode",
content: "Would love a dark theme option.",
statusId: "status_01xyz...",
tagIds: ["tag_01a..."]
})
delete_post
Soft-delete a feedback post. The post is hidden from public views but can be restored within 30 days.
| Parameter | Type | Description |
|---|---|---|
postId | string | Post TypeID to delete |
Scope: write:feedback + team role (admin or member)
delete_post({ postId: "post_01abc..." })
restore_post
Restore a soft-deleted post. Posts can only be restored within 30 days of deletion.
| Parameter | Type | Description |
|---|---|---|
postId | string | Post TypeID to restore |
Scope: write:feedback + team role (admin or member)
restore_post({ postId: "post_01abc..." })
merge_post
Merge a duplicate post into a canonical post. Votes are combined. Reversible via unmerge_post.
| Parameter | Type | Description |
|---|---|---|
duplicatePostId | string | Post TypeID of the duplicate to merge away |
canonicalPostId | string | Post TypeID of the canonical post to merge into |
Scope: write:feedback + team role (admin or member)
Use search to find potential duplicates first, then merge them to consolidate votes.
merge_post({
duplicatePostId: "post_01abc...",
canonicalPostId: "post_01xyz..."
})
unmerge_post
Restore a merged post to independent state. Recalculates vote counts for both posts.
| Parameter | Type | Description |
|---|---|---|
postId | string | Post TypeID of the merged post to restore |
Scope: write:feedback + team role (admin or member)
unmerge_post({ postId: "post_01abc..." })
manage_roadmap_post
Add or remove a post from a roadmap.
| Parameter | Type | Description |
|---|---|---|
action | "add" | "remove" | Whether to add or remove the post |
roadmapId | string | Roadmap TypeID |
postId | string | Post TypeID |
Scope: write:feedback + team role (admin or member)
Use the quackback://roadmaps resource to look up roadmap IDs.
manage_roadmap_post({ action: "add", roadmapId: "roadmap_01abc...", postId: "post_01xyz..." })
manage_roadmap_post({ action: "remove", roadmapId: "roadmap_01abc...", postId: "post_01xyz..." })
create_changelog
Create a changelog entry. Saves as a draft by default. Set publish: true to publish immediately.
| Parameter | Type | Default | Description |
|---|---|---|---|
title | string | - | Changelog entry title (max 200 characters) |
content | string | - | Changelog content, markdown supported (max 50,000 characters) |
publish | boolean | false | Set to true to publish immediately |
Scope: write:changelog + team role (admin or member)
create_changelog({ title: "v2.1 Release", content: "## New features\n- Dark mode..." })
create_changelog({ title: "v2.1 Release", content: "...", publish: true })
update_changelog
Update an existing changelog entry's title, content, publish state, or linked posts.
| Parameter | Type | Description |
|---|---|---|
changelogId | string | Changelog TypeID to update |
title | string | New title (max 200 characters) |
content | string | New content, markdown supported (max 50,000 characters) |
publish | boolean | true to publish, false to revert to draft |
linkedPostIds | string[] | Replace linked posts with these post TypeIDs |
Scope: write:changelog + team role (admin or member)
update_changelog({ changelogId: "changelog_01abc...", title: "v2.1.1 Patch" })
update_changelog({
changelogId: "changelog_01abc...",
publish: true,
linkedPostIds: ["post_01a...", "post_01b..."]
})
delete_changelog
Soft-delete a changelog entry.
| Parameter | Type | Description |
|---|---|---|
changelogId | string | Changelog TypeID to delete |
Scope: write:changelog + team role (admin or member)
delete_changelog({ changelogId: "changelog_01abc..." })
list_suggestions
List AI-generated feedback suggestions. Suggestions are created when feedback is ingested from external sources (Slack, email, API) and processed by the AI pipeline.
Three suggestion types:
create_post- AI extracted new feedback and suggests creating a postvote_on_post- AI matched feedback to an existing post and suggests adding a voteduplicate_post- AI detected two existing posts that may be duplicates
| Parameter | Type | Default | Description |
|---|---|---|---|
status | "pending" | "dismissed" | "pending" | Filter by suggestion status |
suggestionType | "create_post" | "vote_on_post" | "duplicate_post" | - | Filter by type |
sort | "newest" | "relevance" | "newest" | Sort order |
limit | number (1-100) | 20 | Max results per page |
cursor | string | - | Pagination cursor from a previous response |
Scope: read:feedback + team role (admin or member)
Each suggestion includes the original raw feedback item, matched post (if applicable), AI signal data (summary, evidence, confidence), and source metadata.
list_suggestions()
list_suggestions({ suggestionType: "create_post" })
list_suggestions({ status: "dismissed", sort: "relevance" })
accept_suggestion
Accept an AI-generated suggestion. The result depends on the suggestion type:
- create_post: Creates a new post from the extracted feedback. Optional edits override the suggested title, body, or board.
- vote_on_post: Adds a proxy vote to the matched existing post.
- duplicate_post: Merges the source post into the target post. Use
swapDirectionto reverse which post is kept.
| Parameter | Type | Description |
|---|---|---|
id | string | Suggestion TypeID (feedback_suggestion_xxx or merge_sug_xxx) |
edits | object | Optional. Override title, body, boardId, or statusId before accepting (create_post only) |
swapDirection | boolean | Optional. Reverse merge direction (duplicate_post only) |
Scope: write:feedback + team role (admin or member)
accept_suggestion({ id: "feedback_suggestion_01abc..." })
accept_suggestion({
id: "feedback_suggestion_01abc...",
edits: { title: "Better title" }
})
accept_suggestion({ id: "merge_sug_01abc...", swapDirection: true })
dismiss_suggestion
Dismiss an AI-generated suggestion. The suggestion can be restored later via restore_suggestion.
| Parameter | Type | Description |
|---|---|---|
id | string | Suggestion TypeID (feedback_suggestion_xxx or merge_sug_xxx) |
Scope: write:feedback + team role (admin or member)
dismiss_suggestion({ id: "feedback_suggestion_01abc..." })
dismiss_suggestion({ id: "merge_sug_01abc..." })
restore_suggestion
Restore a dismissed suggestion back to pending status.
| Parameter | Type | Description |
|---|---|---|
id | string | Suggestion TypeID (feedback_suggestion_xxx or merge_sug_xxx) |
Scope: write:feedback + team role (admin or member)
restore_suggestion({ id: "feedback_suggestion_01abc..." })
get_post_activity
Get the activity log for a post. Shows status changes, merges, tag changes, owner assignments, proxy votes, comment pins, and other events in reverse chronological order (limited to the 200 most recent).
| Parameter | Type | Description |
|---|---|---|
postId | string | Post TypeID |
Scope: read:feedback + team role (admin or member)
Each activity entry includes the event type, actor name, metadata (e.g., old/new status), and timestamp.
get_post_activity({ postId: "post_01abc..." })
Resources
Resources provide lookup data for boards, statuses, tags, roadmaps, and team members. Use them to find IDs before calling tools like triage_post or create_post.
All resources require the read:feedback scope.
| URI | Returns | Fields |
|---|---|---|
quackback://boards | All boards | id, name, slug |
quackback://statuses | All statuses | id, name, slug, color |
quackback://tags | All tags | id, name, color |
quackback://roadmaps | All roadmaps | id, name, slug |
quackback://members | Team members | id, name, role |
A typical workflow: read quackback://statuses to find the "planned" status ID, then call triage_post with that status ID.