Quickstart: Python server
Synapse has two halves. The React quickstart covers the
client. This one covers the server: nimblebrain-synapse, the PyPI package that
attaches a self-contained ui:// component to an MCP Python SDK
server. From one declaration the component renders in any MCP Apps host (ChatGPT,
Claude, and the NimbleBrain runtime), with the client SDK inlined so the component
ships as one asset.
This walks you from an empty server to a tool whose result renders in a UI. It
assumes you already have an MCPServer, or can start one. The package requires
mcp 2.x; on mcp 1.x, use nimblebrain-synapse 0.5.x instead.
-
Install the package.
Terminal window pip install nimblebrain-synapse # or: uv add nimblebrain-synapseIt pairs with the
mcpPython package (2.x), which you use to define the server and its tools. -
Write a data-free template.
The component’s HTML carries no data. It carries two markers the package fills in: one for the inlined client SDK, one for the data slot.
TEMPLATE = """<div id="root"></div><!--__SYNAPSE_SDK__--><script type="application/json" id="synapse-ui-data">/*__SYNAPSE_DATA__*/</script>"""<!--__SYNAPSE_SDK__-->is replaced with the inlined client SDK<script>, so the component is self-contained (no CDN, CSP-safe). Thesynapse-ui-datascript is the data slot: the served copy leaves the marker in place, so the client readsnulland takes the host’s push. A template without<!--__SYNAPSE_SDK__-->is refused with aValueError. -
Declare the component.
from nimblebrain_synapse import SynapseUIforecast_ui = SynapseUI(uri="ui://weather/forecast",template=TEMPLATE,)uriis the resource id the host loads. -
Hand the component to the server as an extension.
from mcp.server.mcpserver import MCPServermcp = MCPServer("weather", extensions=[forecast_ui])@mcp.tool(meta=forecast_ui.tool_meta(invoking="Checking the forecast", invoked="Forecast ready"),)async def get_forecast(city: str) -> dict:return {"city": city, "high": 78, "low": 61, "summary": "Sunny"}extensions=[forecast_ui]serves theui://resource, under the MCP Apps MIMEtext/html;profile=mcp-app, with the client SDK inlined.tool_metapoints the tool at that resource (ui.resourceUri), which is all a host needs: it reads the component and renders it with the tool’sstructuredContent, and no UI HTML rides in the model-facing content. It also attaches the status strings ChatGPT shows while the tool runs and after it finishes. -
Run the server. Start it however you normally run an
MCPServer(stdio or HTTP). In a host that supports embedded UIs, callingget_forecastnow renders your component. A plain MCP client that renders no UI ignores the resource and still reads the tool’sstructuredContent, so the same server works everywhere.
What just happened
Section titled “What just happened”SynapseUIdescribed one component once: a URI and a data-free template.extensions=[forecast_ui]published it as aui://resource with the client SDK inlined, so the component is fully self-contained.tool_metawired the component to a tool, so its result is delivered both asstructuredContent(for any MCP client) and as a rendered UI (for hosts that support it).
Because the component is self-contained and the wiring is declarative, the same server renders across ChatGPT, Claude, and NimbleBrain without per-host code.
Related
Section titled “Related”- Cross-host architecture: how one component reaches three different host bridges.
- Quickstart: React app: the client half of the same app.
- The portable-app contract: what each call does on a host that lacks a capability.