retro

QRetro retrospectives and planning poker over MCP: boards, action items, poker games, estimates.

Should I use this

Quality & Safety

A
Description quality
97%
Schema completeness
96%
Naming quality
48%
Poisoning risk
100%
Permission match
100%
Protocol compliance
100%

Findings (34)

  • LOWTool 'retro.board.actions.list' description lacks action verbin retro.board.actions.list
  • LOWTool 'retro.board.insights.list' description lacks action verbin retro.board.insights.list
  • LOWTool 'retro.teams.list' doesn't follow camelCase/snake_casein retro.teams.list
  • LOWTool 'retro.team.members.list' doesn't follow camelCase/snake_casein retro.team.members.list
  • LOWTool 'retro.boards.list' doesn't follow camelCase/snake_casein retro.boards.list
  • LOWTool 'retro.actions.list' doesn't follow camelCase/snake_casein retro.actions.list
  • LOWTool 'retro.board.messages.list' doesn't follow camelCase/snake_casein retro.board.messages.list
  • LOWTool 'retro.board.messages.update' doesn't follow camelCase/snake_casein retro.board.messages.update
  • LOWTool 'retro.board.messages.delete_own' doesn't follow camelCase/snake_casein retro.board.messages.delete_own
  • LOWTool 'retro.board.messages.delete_own' name length outside 3-30 rangein retro.board.messages.delete_own

Based on automated analysis of tool definitions and protocol compliance.

Context Cost

~3,960Tokens (tool definitions)
~914 BTypical response size
Significant attention impact (3.09% of 128k context)

This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.

Install

One-Click Install

Add this to your `claude_desktop_config.json` file:

{
  "mcpServers": {
    "retro": {
      "url": "https://mcp.qretro.com"
    }
  }
}

Remote endpoints

https://mcp.qretro.comstreamable-http

What it can do

Tool inventory

Tools (29)

🟢 Read-only🟡 Write🔴 Delete⚪ Unknown
🟢retro.teams.list

Returns the list of teams the user belongs to. boards_count is the total number of boards in a team, finished and unfinished alike — use retro.boards.list to tell them apart.

Input Schema

{
  "type": "object",
  "properties": {}
}
🟢retro.team.members.list(team_id)

Returns the members of a team with their id, name and role (owner, admin, facilitator, member). Use the id as assign_to in retro.actions.create, retro.actions.update and retro.board.suggested_actions.promote. This is the team roster, the same one people see in team settings — it says nothing about who wrote which card. Pass team_id when several teams are available; with a single team it can be omitted.

Input Schema

{
  "type": "object",
  "properties": {
    "team_id": {
      "description": "Team to list members for. Required when more than one team is available — call retro.teams.list first.",
      "type": "string"
    }
  }
}
🟢retro.boards.list(team_id, since, until, finished_only)

Returns retrospectives (boards) of a team, newest first. Unfinished boards are included unless finished_only is set — otherwise check the is_finished flag. Filters by period via since/until. Pass team_id when several teams are available; with a single team it can be omitted.

Input Schema

{
  "type": "object",
  "properties": {
    "team_id": {
      "description": "Team to list boards for. Required when more than one team is available — call retro.teams.list first.",
      "type": "string"
    },
    "since": {
      "description": "Only boards created on or after this date (ISO 8601, for example 2026-01-01).",
      "type": "string"
    },
    "until": {
      "description": "Only boards created on or before this date (ISO 8601).",
      "type": "string"
    },
    "finished_only": {
      "description": "Return only finished retrospectives. Default: false, unfinished boards are included.",
      "type": "boolean"
    }
  }
}
🟢retro.actions.list(team_id, status, assignee, since, limit)

Returns action items across all retrospectives at once — the answer to "what did we agree on and never finish". Covers every team available unless team_id narrows it down; filters by status, assignee and date. Use this instead of walking boards one by one with retro.board.actions.list.

Input Schema

{
  "type": "object",
  "properties": {
    "team_id": {
      "description": "Narrow the search to one team. By default every available team is included.",
      "type": "string"
    },
    "status": {
      "description": "open (default), completed or all.",
      "type": "string"
    },
    "assignee": {
      "description": "Filter by assignee name, partial match.",
      "type": "string"
    },
    "since": {
      "description": "Only items created on or after this date (ISO 8601, for example 2026-01-01).",
      "type": "string"
    },
    "limit": {
      "description": "How many items to return, newest first. Default 50, maximum 200. The total field always reports the full count.",
      "type": "integer"
    }
  }
}
🟢retro.board.messages.list(board_id)

Returns all participant messages (cards) for a retrospective board, organized by template columns (e.g. "What went well", "What didn't go well"). Includes text, sentiment, category, grouping, and vote counts.

Input Schema

{
  "type": "object",
  "properties": {
    "board_id": {
      "description": "The ID of the board to get messages for.",
      "type": "string"
    }
  },
  "required": [
    "board_id"
  ]
}
⚪retro.board.messages.update(message_id, text)

Updates the text of an existing board message created by the current MCP user.

Input Schema

{
  "type": "object",
  "properties": {
    "message_id": {
      "description": "The ID of the message to update.",
      "type": "string"
    },
    "text": {
      "description": "New text content for the message.",
      "type": "string"
    }
  },
  "required": [
    "message_id",
    "text"
  ]
}
🔴retro.board.messages.delete_own(message_id)

Deletes a single board message. Access is strictly governed by API policies: users can delete their own messages, or any message if they have board update rights (requires mcp:write scope for the latter).

Input Schema

{
  "type": "object",
  "properties": {
    "message_id": {
      "description": "The ID of the message to delete.",
      "type": "string"
    }
  },
  "required": [
    "message_id"
  ]
}
🟢retro.board.summary.get(board_id)

Returns the summary of a retrospective with participant info and metadata. Works for unfinished boards too — summary is null until the retro is wrapped up, so check is_finished.

Input Schema

{
  "type": "object",
  "properties": {
    "board_id": {
      "description": "The ID of the board to get the summary for.",
      "type": "string"
    }
  },
  "required": [
    "board_id"
  ]
}
🟢retro.board.actions.list(board_id, include_completed)

Returns action items from a retrospective board, including status, priority, assignee, and due date.

Input Schema

{
  "type": "object",
  "properties": {
    "board_id": {
      "description": "The ID of the board to get action items for.",
      "type": "string"
    },
    "include_completed": {
      "description": "Whether to include completed action items. Default: false.",
      "type": "boolean"
    }
  },
  "required": [
    "board_id"
  ]
}
🟢retro.board.insights.list(board_id)

Returns insights (clusters) and suggested actions for a retrospective board. Insights include topic clusters with sentiment, urgency, and category analysis.

Input Schema

{
  "type": "object",
  "properties": {
    "board_id": {
      "description": "The ID of the board to get insights for.",
      "type": "string"
    }
  },
  "required": [
    "board_id"
  ]
}
🟢retro.board.health.get(board_id)

Returns the health check of a retrospective: score per category on a 0-10 scale, alignment between participants, turnout, and the same score across the previous retrospectives of the team. Returns health_check: null when the team did not run a health check on this board.

Input Schema

{
  "type": "object",
  "properties": {
    "board_id": {
      "description": "The ID of the board to get the health check report for.",
      "type": "string"
    }
  },
  "required": [
    "board_id"
  ]
}
🟢retro.board.roti.get(board_id)

Returns ROTI (Return on Time Invested) voting metrics for a retrospective board, including average score, distribution, and trend across previous retrospectives.

Input Schema

{
  "type": "object",
  "properties": {
    "board_id": {
      "description": "The ID of the board to get ROTI metrics for.",
      "type": "string"
    }
  },
  "required": [
    "board_id"
  ]
}
🟢retro.boards.search(query, team_id)

Search across retrospectives by keyword: board summaries, action items and participant cards. Cards hidden by private writing during an ongoing retro are excluded. Optionally filter by team.

Input Schema

{
  "type": "object",
  "properties": {
    "query": {
      "description": "Search query. Looks into board summaries, action items and participant cards.",
      "type": "string"
    },
    "team_id": {
      "description": "Optional: filter search to a specific team.",
      "type": "string"
    }
  },
  "required": [
    "query"
  ]
}
⚪retro.actions.create(board_id, text, priority, due, assign_to)

Creates a new action item on a retrospective board. Requires mcp:write scope.

Input Schema

{
  "type": "object",
  "properties": {
    "board_id": {
      "description": "The ID of the board to create the action item on.",
      "type": "string"
    },
    "text": {
      "description": "The text of the action item.",
      "type": "string"
    },
    "priority": {
      "description": "Priority: high, medium, or low. Default: medium.",
      "type": "string"
    },
    "due": {
      "description": "Due date in ISO 8601 format (e.g. 2025-03-15T00:00:00Z).",
      "type": "string"
    },
    "assign_to": {
      "description": "User ID to assign the action item to — call retro.team.members.list to get it — or \"me\" to assign to the current user.",
      "type": "string"
    }
  },
  "required": [
    "board_id",
    "text"
  ]
}
⚪retro.actions.update(action_item_id, text, priority, due, assign_to)

Updates an existing action item: text, priority, due date, or assignee. Requires mcp:write scope.

Input Schema

{
  "type": "object",
  "properties": {
    "action_item_id": {
      "description": "The ID of the action item to update.",
      "type": "string"
    },
    "text": {
      "description": "New text for the action item.",
      "type": "string"
    },
    "priority": {
      "description": "New priority: high, medium, or low.",
      "type": "string"
    },
    "due": {
      "description": "New due date in ISO 8601 format.",
      "type": "string"
    },
    "assign_to": {
      "description": "User ID to reassign to — call retro.team.members.list to get it — or \"me\" to assign to the current user.",
      "type": "string"
    }
  },
  "required": [
    "action_item_id"
  ]
}
⚪retro.actions.complete(action_item_id)

Marks an action item as completed. Requires mcp:write scope.

Input Schema

{
  "type": "object",
  "properties": {
    "action_item_id": {
      "description": "The ID of the action item to mark as completed.",
      "type": "string"
    }
  },
  "required": [
    "action_item_id"
  ]
}
⚪retro.board.suggested_actions.promote(board_id, suggested_action_id, assign_to)

Turns a pending suggested action from retro.board.insights.list into a real action item on the board and marks the suggestion accepted, keeping the wording and the link to its cluster. Requires mcp:write scope.

Input Schema

{
  "type": "object",
  "properties": {
    "board_id": {
      "description": "The ID of the board the suggestion belongs to.",
      "type": "string"
    },
    "suggested_action_id": {
      "description": "The ID of the suggested action to promote, from suggested_actions in retro.board.insights.list. Only suggestions with status \"pending\" can be promoted.",
      "type": "string"
    },
    "assign_to": {
      "description": "User ID to assign the action item to — call retro.team.members.list to get it — or \"me\" to assign to the current user.",
      "type": "string"
    }
  },
  "required": [
    "board_id",
    "suggested_action_id"
  ]
}
⚪retro.board.suggested_actions.reject(board_id, suggested_action_id)

Rejects a pending suggested action from retro.board.insights.list: the suggestion moves to rejected and no action item is created. Requires mcp:write scope.

Input Schema

{
  "type": "object",
  "properties": {
    "board_id": {
      "description": "The ID of the board the suggestion belongs to.",
      "type": "string"
    },
    "suggested_action_id": {
      "description": "The ID of the suggested action to reject, from suggested_actions in retro.board.insights.list. Only suggestions with status \"pending\" can be rejected.",
      "type": "string"
    }
  },
  "required": [
    "board_id",
    "suggested_action_id"
  ]
}
🟢poker.sources.list(team_id)

Returns the issue trackers connected to a team (Jira, Linear) and what each of them can do: search for tasks, list iterations (sprints, cycles), write estimates back. Call this first — the other poker tools depend on what is connected. An empty list means tasks can only be added manually with poker.game.tasks.add.

Input Schema

{
  "type": "object",
  "properties": {
    "team_id": {
      "description": "Team to inspect. Required when more than one team is available — call retro.teams.list first.",
      "type": "string"
    }
  }
}
🟢poker.iterations.list(team_id, source, query)

Returns the iterations of a connected issue tracker — Jira sprints (active and upcoming), and whatever a future tracker calls the same thing. Filter by name with query, for example "AFT 50". Pass the ref of the iteration you want to poker.game.tasks.import to pull its tasks into a game. Trackers without iteration support (currently Linear) return an empty list — search by text instead.

Input Schema

{
  "type": "object",
  "properties": {
    "team_id": {
      "description": "Team whose tracker is queried. Required when more than one team is available.",
      "type": "string"
    },
    "source": {
      "description": "Tracker to query, for example jira. Required only when the team has several trackers connected — see poker.sources.list.",
      "type": "string"
    },
    "query": {
      "description": "Filter iterations by name, for example \"AFT 50\". Omit to get all active and upcoming ones.",
      "type": "string"
    }
  }
}
🟢poker.games.list(team_id, limit)

Returns the planning poker games of a team, newest first, with how many tasks each of them has and how many already carry an estimate. Personal games outside a team are not exposed over MCP.

Input Schema

{
  "type": "object",
  "properties": {
    "team_id": {
      "description": "Team to list games for. Required when more than one team is available — call retro.teams.list first.",
      "type": "string"
    },
    "limit": {
      "description": "How many games to return. Default: 20, maximum: 50.",
      "type": "integer"
    }
  }
}
🟢poker.game.get(game_id)

Returns one planning poker game: its estimation scale, progress, the task currently on the table and the link participants use to join. Use poker.game.tasks.list for the tasks themselves.

Input Schema

{
  "type": "object",
  "properties": {
    "game_id": {
      "description": "The ID of the poker game.",
      "type": "string"
    }
  },
  "required": [
    "game_id"
  ]
}
🟢poker.game.tasks.list(game_id, estimated, limit)

Returns the tasks of a poker game with their estimate, individual votes, tracker key and link. needs_sync tells whether the agreed estimate still differs from the one stored in the tracker — feed those tasks to poker.game.task.sync. Filter with estimated to see what is done or what is left.

Input Schema

{
  "type": "object",
  "properties": {
    "game_id": {
      "description": "The ID of the poker game.",
      "type": "string"
    },
    "estimated": {
      "description": "true — only tasks that already have an estimate, false — only tasks still to be estimated. Omit for all of them.",
      "type": "boolean"
    },
    "limit": {
      "description": "How many tasks to return. Default: 50, maximum: 100.",
      "type": "integer"
    }
  },
  "required": [
    "game_id"
  ]
}
⚪poker.games.create(name, team_id, scale, scale_values)

Creates a planning poker game for a team and returns the link participants join with. Pick a ready-made scale — fibonacci, modified_fibonacci, tshirts, powers_of_two — or pass your own values in scale_values. Requires mcp:write scope.

Input Schema

{
  "type": "object",
  "properties": {
    "name": {
      "description": "Name of the game, for example the sprint it plans.",
      "type": "string"
    },
    "team_id": {
      "description": "Team the game belongs to. Required when more than one team is available.",
      "type": "string"
    },
    "scale": {
      "description": "Estimation scale preset: fibonacci (default), modified_fibonacci, tshirts, powers_of_two.",
      "type": "string"
    },
    "scale_values": {
      "description": "Custom scale, for example [\"1\",\"2\",\"3\",\"5\",\"?\"]. Overrides scale when given.",
      "type": "array"
    }
  },
  "required": [
    "name"
  ]
}
⚪poker.game.tasks.add(game_id, tasks)

Adds tasks to a poker game by hand — for work that lives outside an issue tracker, or when no tracker is connected. To pull tasks from Jira or Linear use poker.game.tasks.import instead. Requires mcp:write scope.

Input Schema

{
  "type": "object",
  "properties": {
    "game_id": {
      "description": "The ID of the poker game.",
      "type": "string"
    },
    "tasks": {
      "description": "Tasks to add: a list of objects with name and optional description.",
      "type": "array"
    }
  },
  "required": [
    "game_id",
    "tasks"
  ]
}
🟡poker.game.tasks.import(game_id, iteration_ref, query, source, limit)

Pulls tasks from a connected issue tracker into a poker game. Give it either iteration_ref from poker.iterations.list to take a whole sprint, or query to search by text and issue key. Tasks already in the game are skipped. Only the team owner can change a game. Requires mcp:write scope.

Input Schema

{
  "type": "object",
  "properties": {
    "game_id": {
      "description": "The ID of the poker game to import into.",
      "type": "string"
    },
    "iteration_ref": {
      "description": "The ref of an iteration from poker.iterations.list — imports every task of that sprint.",
      "type": "string"
    },
    "query": {
      "description": "Text or issue key to search for, when importing without an iteration.",
      "type": "string"
    },
    "source": {
      "description": "Tracker to import from, for example jira. Required only when the team has several trackers connected.",
      "type": "string"
    },
    "limit": {
      "description": "How many tasks to pull at most. Default: 50, maximum: 100.",
      "type": "integer"
    }
  },
  "required": [
    "game_id"
  ]
}
🟡poker.game.task.select(game_id, task_id)

Puts a task on the table: everyone looking at the game sees it as the one being estimated right now. Only the team owner can change a game. Requires mcp:write scope.

Input Schema

{
  "type": "object",
  "properties": {
    "game_id": {
      "description": "The ID of the poker game.",
      "type": "string"
    },
    "task_id": {
      "description": "The ID of the task to put on the table — see poker.game.tasks.list.",
      "type": "string"
    }
  },
  "required": [
    "game_id",
    "task_id"
  ]
}
🔴poker.game.task.reveal(game_id, task_id, reveal)

Reveals the cards of a task and computes its estimate from the votes cast — this is the only way an estimate appears, there is no way to set a number directly. Pass reveal=false to hide the cards again and drop the estimate, which also clears the votes for a re-vote. Only the team owner can change a game. Requires mcp:write scope.

Input Schema

{
  "type": "object",
  "properties": {
    "game_id": {
      "description": "The ID of the poker game.",
      "type": "string"
    },
    "task_id": {
      "description": "The ID of the task to reveal.",
      "type": "string"
    },
    "reveal": {
      "description": "true (default) — reveal the cards and compute the estimate. false — hide them, clear the votes and the estimate.",
      "type": "boolean"
    }
  },
  "required": [
    "game_id",
    "task_id"
  ]
}
🟡poker.game.task.sync(game_id, task_id)

Writes the agreed estimate back to the issue tracker — Jira story points, Linear estimate. Works only for tasks imported from a tracker and only when the integration was connected with write permissions; poker.sources.list shows whether it was. Only the team owner can change a game. Requires mcp:write scope.

Input Schema

{
  "type": "object",
  "properties": {
    "game_id": {
      "description": "The ID of the poker game.",
      "type": "string"
    },
    "task_id": {
      "description": "The ID of the task whose estimate goes to the tracker — see needs_sync in poker.game.tasks.list.",
      "type": "string"
    }
  },
  "required": [
    "game_id",
    "task_id"
  ]
}

Community

Rate this Server

Evidence

Recent observations

verifiedversion not recorded29 tools
verifiedversion not recorded29 tools