From 810e3ad34b9941a024181c12e68bf797583defa2 Mon Sep 17 00:00:00 2001 From: Corneliu Croitoru Date: Wed, 29 Jul 2026 15:08:37 +0200 Subject: [PATCH] feat(examples): upgrade mcp-shop-server to mcp 2.x, add TS/Python consumption snippets The shop server now runs on MCPServer (mcp 2.x): it serves MCP protocol 2026-07-28 and still answers legacy clients through the handshake, so the Swift sample keeps working unchanged. host/port move from the constructor to run(), per the v2 API; decorators are unchanged. The README gains MCPToolProvider snippets for TypeScript and Python over streamable-http, closing the loop on the 2026-07-28 series: verified live with the provider on both mcp 2.0 (modern era) and mcp 1.29 (legacy handshake) against this server. Closes #635 Code written by Claude (Fable 5), architected and approved by @cornelcroi. --- examples/mcp-shop-server/README.md | 30 +++++++++++++++++++++++ examples/mcp-shop-server/requirements.txt | 5 ++-- examples/mcp-shop-server/shop_server.py | 20 +++++++++------ 3 files changed, 44 insertions(+), 11 deletions(-) diff --git a/examples/mcp-shop-server/README.md b/examples/mcp-shop-server/README.md index 6712633f..5ae02c79 100644 --- a/examples/mcp-shop-server/README.md +++ b/examples/mcp-shop-server/README.md @@ -4,12 +4,17 @@ A tiny [MCP](https://modelcontextprotocol.io) server for the [ChatGPTStyleChat]( Swift sample. It exposes an order-lookup tool that advertises a **UI widget**, over streamable HTTP, so the native app can point at it instead of its built-in in-app tool. +Built on `mcp` 2.x, so it serves MCP protocol **2026-07-28** and still answers older clients +through the legacy handshake — the same server works for every consumer below, old or new. + It shows the same contract ChatGPT Apps use: a tool returns `structuredContent` and advertises `_meta.ui.resourceUri`. The app renders that widget as a native SwiftUI card, hydrated from the tool's data — no HTML, no web view. ## Run it +Requires Python >= 3.10 (the `mcp` 2.x floor). + ```bash # Optional: Set up a virtual environment python -m venv venv @@ -19,6 +24,31 @@ python shop_server.py # serves on http://127.0.0.1:8000/mcp (l HOST=0.0.0.0 python shop_server.py # bind to the LAN, for a physical device ``` +## Consume it from agent-squad (TypeScript / Python) + +`MCPToolProvider` connects over the `streamable-http` transport; the protocol era is negotiated +per server, so nothing else is configured. With the v2 SDKs installed +(`@modelcontextprotocol/client` / `mcp>=2`) the session runs on protocol 2026-07-28; with the v1 +SDKs it falls back to the legacy handshake — same code either way. + +```typescript +import { MCPToolProvider } from "agent-squad"; + +const provider = await MCPToolProvider.create([ + { type: "streamable-http", url: "http://127.0.0.1:8000/mcp" }, +]); +// get_order is offered to the model; refresh_order stays app-only. +``` + +```python +from agent_squad.tools import MCPToolProvider, MCPServerConfig + +provider = await MCPToolProvider.create([ + MCPServerConfig(type="streamable-http", url="http://127.0.0.1:8000/mcp"), +]) +# get_order is offered to the model; refresh_order stays app-only. +``` + ## Point the app at it In the Swift sample, set the toggle in `Config.swift`: diff --git a/examples/mcp-shop-server/requirements.txt b/examples/mcp-shop-server/requirements.txt index 7801bfc6..d566bd8c 100644 --- a/examples/mcp-shop-server/requirements.txt +++ b/examples/mcp-shop-server/requirements.txt @@ -1,3 +1,2 @@ -# Tested with mcp 1.28.1. `meta=` on @mcp.tool and structured_output need a recent build. -# Capped to <2: mcp 2.0.0 is a breaking release (FastMCP renamed, snake_case types). -mcp>=1.28.0,<2 +# mcp 2.x (MCPServer) serves MCP protocol 2026-07-28 and answers legacy clients too. +mcp>=2.0.0 diff --git a/examples/mcp-shop-server/shop_server.py b/examples/mcp-shop-server/shop_server.py index bea97844..e8e6497a 100644 --- a/examples/mcp-shop-server/shop_server.py +++ b/examples/mcp-shop-server/shop_server.py @@ -1,7 +1,7 @@ """A tiny MCP shop server for the ChatGPTStyleChat sample. Exposes an order-lookup tool that advertises a UI widget, over streamable HTTP so a native app -(the Swift ChatGPTStyleChat sample) can point at it with `MCPServer(url: "http://…/mcp")`. +(the Swift ChatGPTStyleChat sample) can point at it with AgentSquadMCP's `MCPServer(url: "http://…/mcp")`. pip install -r requirements.txt python shop_server.py # serves on http://127.0.0.1:8000/mcp @@ -20,19 +20,17 @@ import os -from mcp.server.fastmcp import FastMCP +from mcp.server import MCPServer from pydantic import BaseModel ORDER_CARD_URI = "ui://shop/order-card" -# Loopback by default (Simulator reaches it). For a physical device, bind to the LAN with -# `HOST=0.0.0.0 python shop_server.py` and point the app at your Mac's LAN IP. -mcp = FastMCP("shop", host=os.environ.get("HOST", "127.0.0.1"), port=int(os.environ.get("PORT", "8000"))) +mcp = MCPServer("shop") class Order(BaseModel): - """The order shape. A typed return makes FastMCP emit it as `structuredContent` — the render-only - data the native card hydrates from.""" + """The order shape. A typed return makes the server emit it as `structuredContent` — the + render-only data the native card hydrates from.""" orderId: str status: str @@ -81,4 +79,10 @@ def order_card_resource() -> str: if __name__ == "__main__": - mcp.run(transport="streamable-http") + # Loopback by default (Simulator reaches it). For a physical device, bind to the LAN with + # `HOST=0.0.0.0 python shop_server.py` and point the app at your Mac's LAN IP. + mcp.run( + transport="streamable-http", + host=os.environ.get("HOST", "127.0.0.1"), + port=int(os.environ.get("PORT", "8000")), + )