-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Add Resources API for MCP Apps Support #5430
Copy link
Copy link
Open
Labels
enhancementNew feature or requestNew feature or request
Description
🚀 Describe the new functionality needed
MCP Apps is the first official extension to the Model Context Protocol, announced on January 26, 2026. It enables MCP servers to return interactive UI components (charts, tables, dashboards) that render directly in conversation streams.
Core MCP Apps Pattern:
- Tools declare UI resources via
_meta.ui.resourceUri(e.g.,"ui://server/dashboard") - MCP servers expose UI content via the Resources API (
resources/list,resources/read) - Hosts fetch HTML/JavaScript using the
ui://URI scheme - UIs render in sandboxed iframes with bidirectional postMessage communication
This feature request is for Implementing a Resources API in llama-stack to support the [MCP Apps extension(https://modelcontextprotocol.io/docs/extensions/apps), enabling MCP servers to serve interactive UI components alongside tool execution.
Proposed Implementation
API interfaces
- Data Models
class Resource(BaseModel):
uri: str
name: str
description: str | None
mime_type: str | None
class ListResourcesResponse(BaseModel):
resources: list[Resource]
class ReadResourceResponse(BaseModel):
content: str # Text or Base64 string
mime_type: str
is_binary: bool
- API Protocol
class Resources(Protocol):
async def list_resources(
self,
mcp_endpoint: URL,
authorization: str | None = None
) -> ListResourcesResponse:
"""Fetch available resources from an MCP server."""
async def read_resource(
self,
mcp_endpoint: URL,
uri: str,
authorization: str | None = None
) -> ReadResourceResponse:
"""Retrieve content and metadata for a specific resource URI."""
New API Endpoints
| Method | Endpoint | Description |
|---|---|---|
POST |
/resources/list |
Retrieves a list of available resources (URIs, names, and descriptions) from a specific MCP server endpoint. |
POST |
/resources/read |
Fetches the content and metadata (MIME type, binary status) for a specific resource URI from an MCP server. |
💡 Why is this needed? What if we don't build it?
Platform Adoption:
- Supported by Claude, ChatGPT, VS Code, Goose, Postman, MCPJam etc
- MCP Python SDK (v1.23.0+) includes resources API:
session.list_resources(),session.read_resource() - Not yet exposed in llama-stack
MCP SDK Support: The underlying mcp Python SDK (v1.23.0+) already supports:
from mcp import ClientSession
async with session:
# List resources
resources = await session.list_resources()
# Read resource content
content = await session.read_resource("ui://server/dashboard")llama-stack just needs to expose this functionality.
Benefits
- Standards Compliance: Implements official MCP Apps extension protocol
- Platform Parity: Aligns llama-stack with Claude, ChatGPT, VS Code, Goose support
- Enhanced UX: Enables interactive dashboards, charts, forms instead of text-only responses
- Minimal Code: Leverages existing MCP SDK (
session.list_resources(),session.read_resource()) - Consistent Pattern: Mirrors existing
list_mcp_tools()/invoke_mcp_tool()architecture
Other thoughts
Use Case Example
MCP Server (Using FastMCP)
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("Kubernetes Dashboard")
@mcp.tool()
def list_namespaces() -> dict:
"""List Kubernetes namespaces.
Returns data AND declares a UI resource for interactive visualization.
"""
return {
"namespaces": ["default", "kube-system", "prod"],
"_meta": {
"ui": {
"resourceUri": "ui://kube-mcp/namespaces-dashboard"
}
}
}
@mcp.resource("ui://kube-mcp/namespaces-dashboard")
def namespace_dashboard() -> str:
"""Interactive HTML dashboard for namespace visualization."""
return """
<!DOCTYPE html>
<html>
<head>
<script type="module">
import { App } from 'https://esm.sh/@modelcontextprotocol/ext-apps@1.1.2';
const app = new App();
await app.connect();
app.ontoolresult = (result) => {
const data = JSON.parse(result.content);
document.getElementById('namespaces').innerHTML =
data.namespaces.map(ns => `<li>${ns}</li>`).join('');
};
</script>
</head>
<body>
<h1>Kubernetes Namespaces</h1>
<ul id="namespaces"></ul>
</body>
</html>
"""Client Usage
from llama_stack_client import AsyncLlamaStackClient
client = AsyncLlamaStackClient(base_url="http://localhost:8321")
# List available UI resources
resources = await client.resources.list(
mcp_endpoint={"uri": "http://localhost:8081/sse"}
)
for resource in resources.resources:
if resource.uri.startswith("ui://"):
print(f"UI Resource: {resource.name} ({resource.uri})")
# Fetch UI resource HTML
response = await client.resources.read(
mcp_endpoint={"uri": "http://localhost:8081/sse"},
uri="ui://kube-mcp/namespaces-dashboard"
)
html_content = response.content # HTML for sandboxed iframe renderingReactions are currently unavailable
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request