---
id: w6/m2/t005
title: "MCP tools: list_workspaces / select_workspace / get_selected_workspace (session-scoped)"
worker: worker6
status: done
estimate: 30m
depends_on: [w6/m2/t002]
---

## Objective

Clone Render's official MCP workspace trio under their exact names and schemas (pinned in t001): `list_workspaces` (no params), `select_workspace` (required `ownerID` string), `get_selected_workspace` (no params). Selection is stateful per MCP session and scopes every subsequent tool call (list services, logs, deploys) to the selected workspace — replacing the current implicit default-workspace behavior.

## Context

- MCP adapter: `lego/backend/internal/api/` (serves MCP alongside REST/GraphQL; also `BEX_MCP_STDIO`/`api mcp-stdio` mode).
- Supersedes inbox note `w2/002.md` (annotated to point here).
- Per-session state: keyed on the MCP session/connection; stdio mode = one session. Unselected sessions fall back to the caller's default workspace (matching pre-m1 behavior).
- Consumers: w2/m2 (deploy-from-chat) and Render-CLI-style agent flows.

## Steps

1. Register the three tools with Render's names/descriptions/param schemas.
2. Session store for the selection; thread selected `ownerId` into the core-call context all existing tools use.
3. Validate `select_workspace` against the caller's memberships (unknown/foreign id → tool error).

## Files

- `lego/backend/internal/api/` (MCP tool registry + session context)

## Acceptance criteria

- [x] Tool names, params (`ownerID`), and result shapes match t001's pinned schemas
- [x] After `select_workspace`, `list services`-class tools return only that workspace's resources; `get_selected_workspace` echoes it
- [x] Selecting a workspace the caller isn't a member of fails without changing the selection

## Out of scope

- New non-workspace MCP tools; dashboard surfaces.
