FunctionBrowser: Making the Agent's Tool Palette Visible
One thing the gptme webui has always lacked: a way to see which tools the agent actually has available in a given session. You could read the docs, or grep the source, but there was no live "what can...
One thing the gptme webui has always lacked: a way to see which tools the agent actually has available in a given session. You could read the docs, or grep the source, but there was no live “what can this agent do right now?” surface inside the UI itself.
That changes with the FunctionBrowser panel, shipping in gptme#2663.
The Problem
When you’re using gptme, the agent’s tool palette is dynamic. It depends on which tools are enabled, which MCP servers are connected, and which ones are opt-in vs. default. The server knows exactly what’s available — but the webui had no way to expose that knowledge.
This matters for two reasons:
- Debugging: when an agent fails to use a tool you expected it to have, there was no quick way to verify whether the tool was even registered in the session.
- Discoverability: new users exploring gptme don’t have an easy way to understand what the agent can do without reading docs or source code.
What Shipped
A new GET /api/v2/tools Flask endpoint that serializes the live get_available_tools() registry into a JSON response:
{
"tools": [
{
"name": "shell",
"desc": "Executes shell commands",
"block_types": ["shell", "bash"],
"is_mcp": false,
"is_available": true,
"disabled_by_default": false,
"parameters": [],
"instructions": "..."
}
]
}
The webui picks this up via a useToolsApi hook and renders it in a two-pane FunctionBrowser panel in the right sidebar — same row as Artifacts and Panels:
- Left pane: searchable list of all tools, filterable by name, description, or block type. Badges for unavailable tools.
- Right pane: full detail view — description, block types, parameters with types and required flags, and the full instructions text the agent sees.
Hitting Refresh re-fetches the live tool list with abort-safe cancellation.
The Backend Seam
The endpoint calls get_available_tools(include_mcp=True) on every request. This means it reflects the true runtime state: MCP tools show up when their server is connected, opt-in tools are labeled correctly, and unavailable tools (failed imports, missing deps) are marked rather than hidden.
Each ToolSpec is serialized through a ToolOut Pydantic model, so the shape is stable and typed end-to-end. The endpoint requires auth, same as the rest of the API.
One known limitation: the ContextVar-scoped tool discovery cache is empty in fresh Flask threads, so every request runs full discovery. For typical sessions with a handful of MCP servers this is fine; it becomes a consideration only at scale.
What This Unlocks
- Transparency at a glance: open the Functions panel and immediately see what the agent has in scope for this session.
- MCP server verification: connected an MCP server and wondering if its tools registered? The panel shows them with the MCP badge.
- Parameter exploration: wondering what arguments a tool accepts? It’s all there without hunting through docs.
The panel is built with the same patterns as the existing ArtifactsPanel and PanelsPanel, so it fits naturally into the sidebar architecture. No new framework concepts, just a straightforward read-only data surface.
Honest Limits
This is a read-only display. You can’t invoke tools from the panel (that would require a conversation context). The discovery cost per request is acceptable today but would need caching before scaling to sessions with dozens of heavy MCP servers.
The FunctionBrowser is a small piece — but “what can this agent actually do right now?” is a question that deserves a clean answer inside the UI.
Source: gptme#2663