Skip to content

MCP Reference

Quackback's MCP server exposes 40 tools and 6 resources. Tools perform actions (search, create, update, delete). Resources provide lookup data (boards, statuses, tags) that tools reference by ID.

Tools

Search feedback posts or changelog entries. Returns paginated results with a cursor for the next page.

ParameterTypeDefaultDescription
entity"posts" | "changelogs" | "articles""posts"Entity type to search
querystring-Text search across titles and content
boardIdstring-Filter posts by board TypeID (ignored for changelogs)
statusstring-Filter by status slug. Posts: "open", "in_progress", etc. Changelogs: "draft", "published", "scheduled", "all"
tagIdsstring[]-Filter posts by tag TypeIDs (ignored for changelogs)
sort"newest" | "oldest" | "votes""newest"Sort order. "votes" only applies to posts
showDeletedbooleanfalseShow soft-deleted posts (team only, last 30 days)
dateFromstring-ISO 8601 date. Filter posts created on or after this date
dateTostring-ISO 8601 date. Filter posts created on or before this date
limitnumber (1-100)20Max results per page
cursorstring-Pagination cursor from a previous response

Scope: read:feedback for posts and changelogs; read:article when entity is "articles"

search({ query: "dark mode", sort: "votes", limit: 10 })
search({ entity: "changelogs", status: "published" })
search({ entity: "articles", query: "getting started", 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.

ParameterTypeDescription
idstringTypeID of the entity (e.g., post_01abc..., changelog_01xyz...)

Scope: read:feedback for posts and changelogs; read:article for article_* / kb_article_* / kb_category_* IDs

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..." })
get_details({ id: "article_01abc..." })
get_details({ id: "kb_category_01abc..." })

triage_post

Update a post's status, tags, or owner. All fields except postId are optional. Only provided fields are updated.

ParameterTypeDescription
postIdstringPost TypeID to update
statusIdstringNew status TypeID
tagIdsstring[]Replace all tags with these TypeIDs
ownerPrincipalIdstring | nullAssign to a team member TypeID, or null to unassign

Scope: write:feedback + team role

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.

ParameterTypeDescription
postIdstringPost 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.

ParameterTypeDefaultDescription
action"add" | "remove""add"Whether to add or remove the proxy vote
postIdstring-Post TypeID to vote on
voterPrincipalIdstring-Principal TypeID of the user to vote on behalf of
sourceTypestring-Attribution source type (e.g. "zendesk", "slack", "intercom")
sourceExternalUrlstring-URL linking to the originating record

Scope: write:feedback + team role

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.

ParameterTypeDescription
postIdstringPost TypeID to comment on
contentstringComment text (max 5,000 characters)
parentIdstringParent 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.

ParameterTypeDescription
commentIdstringComment TypeID to edit
contentstringNew 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.

ParameterTypeDescription
commentIdstringComment 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.

ParameterTypeDescription
action"add" | "remove"Whether to add or remove the reaction
commentIdstringComment TypeID to react to
emojistringEmoji 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.

ParameterTypeDescription
boardIdstringBoard TypeID (use quackback://boards resource to find IDs)
titlestringPost title (max 200 characters)
contentstringPost body (max 10,000 characters)
statusIdstringInitial status TypeID (defaults to board default)
tagIdsstring[]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.

ParameterTypeDescription
postIdstringPost TypeID to delete

Scope: write:feedback + team role

delete_post({ postId: "post_01abc..." })

restore_post

Restore a soft-deleted post. Posts can only be restored within 30 days of deletion.

ParameterTypeDescription
postIdstringPost TypeID to restore

Scope: write:feedback + team role

restore_post({ postId: "post_01abc..." })

merge_post

Merge a duplicate post into a canonical post. Votes are combined. Reversible via unmerge_post.

ParameterTypeDescription
duplicatePostIdstringPost TypeID of the duplicate to merge away
canonicalPostIdstringPost TypeID of the canonical post to merge into

Scope: write:feedback + team role

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.

ParameterTypeDescription
postIdstringPost TypeID of the merged post to restore

Scope: write:feedback + team role

unmerge_post({ postId: "post_01abc..." })

create_changelog

Create a changelog entry. Saves as a draft by default. Set publish: true to publish immediately.

ParameterTypeDefaultDescription
titlestring-Changelog entry title (max 200 characters)
contentstring-Changelog content, markdown supported (max 50,000 characters)
publishbooleanfalseSet to true to publish immediately

Scope: write:changelog + team role

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.

ParameterTypeDescription
changelogIdstringChangelog TypeID to update
titlestringNew title (max 200 characters)
contentstringNew content, markdown supported (max 50,000 characters)
publishbooleantrue to publish, false to revert to draft
linkedPostIdsstring[]Replace linked posts with these post TypeIDs

Scope: write:changelog + team role

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.

ParameterTypeDescription
changelogIdstringChangelog TypeID to delete

Scope: write:changelog + team role

delete_changelog({ changelogId: "changelog_01abc..." })

accept_suggestion

Accept a post-to-post merge suggestion, merging the source post into the target. Use swapDirection to reverse which post is kept.

ParameterTypeDescription
idstringMerge suggestion TypeID (post_merge_sug_xxx)
swapDirectionbooleanOptional. Reverse which post is kept

Scope: write:feedback + team role

accept_suggestion({ id: "post_merge_sug_01abc..." })
accept_suggestion({ id: "post_merge_sug_01abc...", swapDirection: true })

dismiss_suggestion

Dismiss a merge suggestion. Restore it later with restore_suggestion.

ParameterTypeDescription
idstringMerge suggestion TypeID (post_merge_sug_xxx)

Scope: write:feedback + team role

dismiss_suggestion({ id: "post_merge_sug_01abc..." })

restore_suggestion

Restore a dismissed merge suggestion back to pending.

ParameterTypeDescription
idstringMerge suggestion TypeID (post_merge_sug_xxx)

Scope: write:feedback + team role

restore_suggestion({ id: "post_merge_sug_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).

ParameterTypeDescription
postIdstringPost TypeID

Scope: read:feedback + team role

Each activity entry includes the event type, actor name, metadata (e.g., old/new status), and timestamp.

get_post_activity({ postId: "post_01abc..." })

Help Center Tools

Help center tools are only available when the Help Center module is on in Admin → Settings → General. See Help Center for setup.

create_article

Create a new help center article as a draft.

ParameterTypeDescription
categoryIdstringCategory TypeID to place the article in
titlestringArticle title (max 200 characters)
slugstringURL slug (lowercase, hyphens only)
contentstringArticle body in Markdown
descriptionstringShort description for search results and SEO

Scope: write:article + team role

Articles are created as drafts. Use update_article with publish: true to publish.


update_article

Update an existing help center article. Publish or unpublish by setting the publish parameter.

ParameterTypeDescription
articleIdstringArticle TypeID to update
titlestringNew title
contentstringNew content in Markdown
descriptionstringNew description
slugstringNew URL slug
categoryIdstringMove to a different category
publishbooleantrue to publish, false to unpublish

Scope: write:article + team role

All fields except articleId are optional. Only provided fields are updated.


delete_article

Soft-delete a help center article.

ParameterTypeDescription
articleIdstringArticle TypeID to delete

Scope: write:article + team role


manage_category

Create, update, or delete a help center category.

ParameterTypeDescription
action"create" | "update" | "delete"Operation to perform
categoryIdstringCategory TypeID (required for update/delete)
namestringCategory name (required for create)
slugstringURL slug (required for create)
descriptionstringCategory description
iconstringIcon identifier
parentIdstringParent category TypeID for nesting

Scope: write:article + team role


Conversation Tools

Work the support inbox programmatically: list and read conversations, reply to visitors, and change conversation status. All conversation tools require a team role and the support inbox to be enabled.

list_conversations

List support-inbox conversations, newest activity first. Returns a compact, paginated list.

ParameterTypeDefaultDescription
status"open" | "snoozed" | "closed"-Filter by conversation status
priority"none" | "low" | "medium" | "high" | "urgent"-Filter by priority
assignedAgentPrincipalIdstring-Filter to a specific assigned agent (principal TypeID)
limitnumber (1-100)20Max results per page
cursorstring-Pagination cursor from a previous response

Scope: read:chat + team role

list_conversations({ status: "open" })
list_conversations({ assignedAgentPrincipalId: "principal_01xyz...", priority: "high" })

get_conversation

Get a conversation and its most recent messages.

ParameterTypeDefaultDescription
conversationIdstring-Conversation TypeID
includeInternalbooleanfalseInclude agent-only internal notes
cursorstring-Cursor from a previous response to fetch older messages

Scope: read:chat + team role

Internal notes are excluded unless includeInternal is true. Anonymous visitors' synthetic emails are never returned.

get_conversation({ conversationId: "conversation_01abc..." })
get_conversation({ conversationId: "conversation_01abc...", includeInternal: true })

reply_to_conversation

Send an agent reply in a conversation (visible to the visitor). Auto-assigns the conversation to the calling agent if it's unassigned.

ParameterTypeDescription
conversationIdstringConversation TypeID
contentstringReply text sent to the visitor (max 4000 characters)
fileIdsstring[]Optional. Up to 10 file IDs from upload_file to attach

Scope: write:chat + team role

reply_to_conversation({ conversationId: "conversation_01abc...", content: "Thanks for reaching out, we're on it." })

set_conversation_status

Change a conversation's status. Snoozing defers it until the next visitor reply; closing stamps the resolution time; a later reply reopens it.

ParameterTypeDescription
conversationIdstringConversation TypeID
status"open" | "snoozed" | "closed"New status

Scope: write:chat + team role

set_conversation_status({ conversationId: "conversation_01abc...", status: "closed" })

suggest_post

Suggest to the support team (not the visitor) that a resolved conversation be tracked as a feedback post. Appears as an internal note; a teammate confirms with one click.

ParameterTypeDescription
conversationIdstringConversation TypeID (must be resolved)
boardIdstringSuggested board TypeID
titlestringSuggested post title
contentstringSuggested post body

Scope: write:chat + team role

suggest_post({ conversationId: "conversation_01abc...", boardId: "board_01abc...", title: "Add dark mode", content: "Customer asked for a night theme." })

share_post

Embed an existing feedback post as a card in the conversation so the visitor can view and upvote it.

ParameterTypeDescription
conversationIdstringConversation TypeID
postIdstringPost TypeID

Scope: write:chat + team role

share_post({ conversationId: "conversation_01abc...", postId: "post_01xyz..." })

Ticket Tools

Tickets share the conversation scopes: reads need read:chat, writes need write:chat. All ticket tools require a team role.

list_tickets

List support tickets. A service key sees every ticket; a human caller sees the tickets their role can view.

ParameterTypeDescription
type"customer" | "back_office" | "tracker"Filter by ticket type
ticketTypeIdstringFilter by registry ticket-type TypeID
statusCategory"open" | "pending" | "closed"Filter by internal status category
stage"received" | "in_progress" | "awaiting_requester" | "resolved"Filter by customer-facing stage
requesterPrincipalIdstringFilter to a requester
companyIdstringFilter to a company
sort"recent" | "oldest" | "created" | "priority"Sort order (default recent)
limitnumber (1-100)Max results (default 20)

Scope: read:chat + team role

list_tickets({ type: "customer", statusCategory: "open" })

get_ticket

Get one ticket and its thread.

Scope: read:chat + team role

get_ticket({ ticketId: "ticket_01abc..." })

create_ticket

Open a support ticket. type is customer (a requester's request), back_office (an internal task), or tracker (an umbrella others link to).

ParameterTypeDescription
type"customer" | "back_office" | "tracker"Ticket object type (default customer)
ticketTypeIdstringRegistry ticket-type TypeID
titlestringShort summary
descriptionstringOpening message body (Markdown)
priority"none" | "low" | "medium" | "high" | "urgent"Triage priority
requesterPrincipalIdstringRequester principal TypeID
companyIdstringAssociated company TypeID

Scope: write:chat + team role

create_ticket({ type: "customer", title: "Refund not received", description: "Customer reports a missing refund." })

reply_to_ticket

Post a reply on a ticket thread (visible to the requester). Pass up to 10 fileIds from upload_file to attach files.

Scope: write:chat + team role

reply_to_ticket({ ticketId: "ticket_01abc...", content: "We've issued your refund." })

add_ticket_note

Add an internal note. Never visible to the requester. Pass up to 10 fileIds from upload_file to attach files.

Scope: write:chat + team role

add_ticket_note({ ticketId: "ticket_01abc...", content: "Confirmed with billing." })

Link a customer ticket to a tracker so the tracker's stage changes cascade onto it.

Scope: write:chat + team role

link_ticket({ trackerTicketId: "ticket_01tracker...", ticketId: "ticket_01customer..." })

Remove a customer ticket from a tracker.

Scope: write:chat + team role

unlink_ticket({ trackerTicketId: "ticket_01tracker...", ticketId: "ticket_01customer..." })

File and Widget Tools

upload_file

Upload a file so you can attach it to a conversation reply, ticket reply, or ticket note. Returns a fileId to pass in fileIds on reply_to_conversation, reply_to_ticket, or add_ticket_note.

ParameterTypeDescription
namestringFile name, including its extension
contentBase64stringFile bytes, base64-encoded (max 5 MB decoded)

Scope: write:chat + team role

upload_file({ name: "invoice.pdf", contentBase64: "JVBERi0xLjQK..." })

widget_install_status

Check whether the widget is connected on your site. Returns whether the snippet has been seen, whether the widget is enabled, the last detected time, the origin host, and the SDK version. Never returns the signing secret.

Scope: read:feedback + team role

widget_install_status()

Resources

Resources provide lookup data for boards, statuses, tags, roadmaps, team members, and help-center categories. Use them to find IDs before calling tools like triage_post or create_post.

Feedback resources require read:feedback. The help-center category list requires read:article and a team role.

URIScopeReturnsFields
quackback://boardsread:feedbackAll boardsid, name, slug
quackback://statusesread:feedbackAll statusesid, name, slug, color
quackback://tagsread:feedbackAll tagsid, name, color
quackback://roadmapsread:feedbackAll roadmapsid, name, slug
quackback://membersread:feedbackTeam membersid, name, role
quackback://help-center/categoriesread:article + teamCategories with article countsid, slug, name, description, icon, parentId, isPublic, position, articleCount

A typical workflow: read quackback://statuses to find the "planned" status ID, then call triage_post with that status ID.