Skip to content

Commit 8b7fabe

Browse files
authored
Merge pull request #33 from IBM/new-roadmap
added ssr
2 parents 7d238bc + d6b9690 commit 8b7fabe

3 files changed

Lines changed: 44 additions & 2 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "chuk-mcp-server"
7-
version = "0.24"
7+
version = "0.25.1"
88
description = "A developer-friendly MCP framework powered by chuk_mcp"
99
readme = "README.md"
1010
license = {text = "Apache-2.0"}

src/chuk_mcp_server/protocol/handler.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ def __init__(
129129
burst = rate_limit_rps * 2 # Default burst = 2x rate
130130
self._rate_limiter = TokenBucketRateLimiter(rate=rate_limit_rps, burst=burst)
131131

132+
# SSR data cache: resource_uri → structuredContent from last tool call.
133+
# Consumed (popped) on next resources/read so the view can be server-rendered.
134+
self._view_data_cache: dict[str, Any] = {}
135+
132136
# Don't log during init to keep stdio mode clean
133137
logger.debug("MCP protocol handler initialized with chuk_mcp")
134138

@@ -266,6 +270,25 @@ def _maybe_register_view_resource(self, meta: dict[str, Any]) -> None:
266270
import httpx # noqa: F811 — lazy import, transitive dep
267271

268272
async def _fetch_view_html() -> str:
273+
# Try SSR first if we have cached data from a recent tool call
274+
cached_data = self._view_data_cache.pop(resource_uri, None)
275+
if cached_data:
276+
try:
277+
ssr_url = view_url.rstrip("/") + "/ssr"
278+
async with httpx.AsyncClient() as client:
279+
resp = await client.post(
280+
ssr_url,
281+
json={"data": cached_data},
282+
timeout=5.0,
283+
)
284+
if resp.status_code == 200:
285+
logger.debug(f"SSR render succeeded for {resource_uri}")
286+
return resp.text
287+
logger.debug(f"SSR returned {resp.status_code}, falling back to static")
288+
except Exception as ssr_err:
289+
logger.debug(f"SSR failed for {resource_uri}: {ssr_err}, falling back")
290+
291+
# Fallback: fetch static SPA HTML from CDN
269292
async with httpx.AsyncClient() as client:
270293
resp = await client.get(view_url, follow_redirects=True)
271294
resp.raise_for_status()
@@ -770,6 +793,25 @@ async def _progress_notify(
770793
tool_result["_meta"]["links"] = links
771794
set_resource_links(None)
772795

796+
# Forward _meta.ui from tool definition to tool result so
797+
# clients (Claude.ai) know this result is linked to a view resource.
798+
if "structuredContent" in tool_result:
799+
ui_meta = (tool_handler.meta or {}).get(MCP_APPS_UI_KEY, {})
800+
resource_uri = ui_meta.get(MCP_APPS_UI_RESOURCE_URI, "")
801+
if ui_meta:
802+
tool_result["_meta"] = tool_result.get("_meta", {})
803+
tool_result["_meta"][MCP_APPS_UI_KEY] = ui_meta
804+
805+
# Cache structuredContent for SSR: when resources/read is called
806+
# for this tool's view, we can server-render with the actual data.
807+
if resource_uri:
808+
self._view_data_cache[resource_uri] = tool_result["structuredContent"]
809+
# Invalidate resource cache so next read triggers SSR fetch
810+
resource = self.resources.get(resource_uri)
811+
if resource:
812+
resource._cached_content = None
813+
resource._cache_timestamp = None
814+
773815
response = {JSONRPC_KEY: JSONRPC_VERSION, KEY_ID: msg_id, KEY_RESULT: tool_result}
774816

775817
# Mark task completed

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)