You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Let MCP clients list, view, create, update and delete Insights boards, add, change and remove the reports on them, and render the numbers a board shows.
Report params have no backend schema: the Control Plane stores them opaquely and only the dashboard interprets them. pkg/mcp/boards ports the dashboard's rules - param validation and defaults, the translation of a report into the org-scoped /insights/* query that renders it, and the board layout - so what the tools write renders and edits in the dashboard. The Control Plane's HandlerClient uses the same package, and testdata/translation_cases.json pins the translation.
Boards are organization-scoped and the Control Plane refuses API tokens on every board endpoint. The APIClient refuses a tkcapi_ token before sending anything, and the tools return an error that points to testkube login. Every write reads the board first and resends its description, because the Control Plane clears the description of any update that omits it; removing a report sends the recomputed layout, because the Control Plane leaves the report's cell behind.
Let MCP clients list, view, create, update and delete Insights boards,
add, change and remove the reports on them, and render the numbers a
board shows.
Report params have no backend schema: the Control Plane stores them
opaquely and only the dashboard interprets them. pkg/mcp/boards ports
the dashboard's rules - param validation and defaults, the translation
of a report into the org-scoped /insights/* query that renders it, and
the board layout - so what the tools write renders and edits in the
dashboard. The Control Plane's HandlerClient uses the same package, and
testdata/translation_cases.json pins the translation.
Boards are organization-scoped and the Control Plane refuses API tokens
on every board endpoint. The APIClient refuses a tkcapi_ token before
sending anything, and the tools return an error that points to
`testkube login`. Every write reads the board first and resends its
description, because the Control Plane clears the description of any
update that omits it; removing a report sends the recomputed layout,
because the Control Plane leaves the report's cell behind.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
[Medium risk] Adds Insights board management tools to the MCP server.
The PR appears safe to merge based on the reviewed changes.
Summary
The PR adds nine Insights board tools, shared report/query rules, and conditional board updates. The changes since the previous review clarify API-token handling, preserve report-description clearing, pin retries to a board ID, and make rendering and debug collection follow the board layout. No new actionable issue was established.
…nditional
render_board anchored relative report ranges to midnight UTC, while the
dashboard anchors them to the viewer's local midnight, so a user outside
UTC got a shifted interval and different numbers. It now takes an IANA
timeZone and computes the dashboard's boundary there, subtracting the
duration in fixed minutes as the dashboard does across a daylight-saving
change. The time zone database is embedded for images without one.
Every board write resent a description, and report removal a layout,
taken from an earlier read, so a concurrent edit between the read and
the write was silently overwritten. Writes now go through writeBoard:
each sends expectedUpdatedAt, the updatedAt it read; the Control Plane
refuses a stale write with 409, both clients turn that into
ErrBoardChanged, and the write is rebuilt from a fresh read, up to
three times. A Control Plane that predates the field ignores it.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A conditional board write compared updatedAt, but updatedAt is not a
safe concurrency token: two writes can land on the same timestamp, so a
write could leave behind the very token a stale request still holds,
and that request would then pass the check and overwrite the newer
edit.
The Control Plane now keeps a version that every write to a board
increments. Board writes send expectedVersion, the version they read,
instead of expectedUpdatedAt, and send none when the board came back
without a version, so against an older Control Plane they stay
unconditional as before.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The docs said every board write is conditional on the version it read,
but delete_board is not, and deliberately: it resends nothing it read,
deletes by the ID it resolved, and the Control Plane checks delete
rights against the board as it is at delete time. Say that the
guarantee covers updates, and that a delete removes the board whatever
changed since the read, as deleting in the dashboard does.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
After a write lost the race, writeBoard read the board again by what
the caller passed. When that was a slug and the concurrent change was
to the slug, the retry failed to find the board, or found another board
that had taken the old slug over and rebuilt the write against it. The
retry now reads the board by the ID the first read resolved.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1a59d74 dropped omitempty from ReportDraft.Description, so a report
create or update now always carries its description and an empty one
clears the report's. The request-shape test still expected the field
to be absent.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
render_board runs its report queries in parallel on one context, and
both clients record each call in that context's DebugInfo, whose Data
map is not safe for concurrent use. With debug on, rendering a board
with several reports could crash with concurrent map writes, and the
recorded URL and status were whichever query finished last.
Each report query now gets its own DebugInfo when debugging is on, and
they are merged into the call's under "reports", keyed by report ID,
once all are done. DebugInfo moves to the mcpcontext leaf package so
the tools can use it; package mcp keeps an alias and its functions, so
existing callers, the Control Plane's included, are unchanged.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
OrderedReports appends unplaced reports after the placed ones, so this loop currently queries and returns data for reports that the dashboard does not show. That contradicts render_board's purpose of returning the board's displayed numbers; keep unplaced in the response but exclude those reports from the default render (while still allowing an explicitly requested reportId to render).
Update stale conflict token comment
pkg/mcp/tools/boards.go:39
This comment still describes the conflict token as updatedAt, but the request now carries ExpectedVersion and the retry logic is explicitly version-based. Please update the comment so it does not document a field that is no longer used.
render_board rendered every report on the board, including those the
layout leaves out, which the dashboard does not show. The default
render now covers the placed reports only; the left-out ones are still
named under "unplaced", and one asked for with reportId is rendered.
Also correct the ErrBoardChanged comment, which still described the
conflict token as updatedAt.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…thods
The insight endpoints accept API tokens, so nothing was exposed, but
QueryBoardInsights is a board method and was the only one on the
APIClient that did not refuse a tkcapi_ token before sending. The
Control Plane's client already refuses it; now both do.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Make slug uniqueness checks atomic with board creation
pkg/mcp/tools/boards.go:285
This availability check is not atomic with the subsequent create. Since the Control Plane does not validate a supplied slug on create, two concurrent calls can both observe available=true and create boards with the same slug, making slug-based board operations ambiguous. Slug uniqueness needs an atomic server-side check, or the create path must handle a race by retrying with a generated/different slug.
…ption
The Control Plane now keeps a board's description when an update omits
it (testkube-cloud-api 686e25242). The tools still resend it, since
older Control Planes clear it; say that instead of describing the
clearing as current behavior.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Make this branch identical to origin/feat/mcp-boards/6-docs (c526ef6), the top of the
stacked branches that replace it, so both carry the same code.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Let MCP clients list, view, create, update and delete Insights boards, add, change and remove the reports on them, and render the numbers a board shows.
Report params have no backend schema: the Control Plane stores them opaquely and only the dashboard interprets them. pkg/mcp/boards ports the dashboard's rules - param validation and defaults, the translation of a report into the org-scoped /insights/* query that renders it, and the board layout - so what the tools write renders and edits in the dashboard. The Control Plane's HandlerClient uses the same package, and testdata/translation_cases.json pins the translation.
Boards are organization-scoped and the Control Plane refuses API tokens on every board endpoint. The APIClient refuses a tkcapi_ token before sending anything, and the tools return an error that points to
testkube login. Every write reads the board first and resends its description, because the Control Plane clears the description of any update that omits it; removing a report sends the recomputed layout, because the Control Plane leaves the report's cell behind.Pull request description
Checklist (choose whats happened)
Breaking changes
Changes
Fixes