Skip to content

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.

  1. Install the package.

    Terminal window
    pip install nimblebrain-synapse # or: uv add nimblebrain-synapse

    It pairs with the mcp Python package (2.x), which you use to define the server and its tools.

  2. 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). The synapse-ui-data script is the data slot: the served copy leaves the marker in place, so the client reads null and takes the host’s push. A template without <!--__SYNAPSE_SDK__--> is refused with a ValueError.

  3. Declare the component.

    from nimblebrain_synapse import SynapseUI
    forecast_ui = SynapseUI(
    uri="ui://weather/forecast",
    template=TEMPLATE,
    )

    uri is the resource id the host loads.

  4. Hand the component to the server as an extension.

    from mcp.server.mcpserver import MCPServer
    mcp = 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 the ui:// resource, under the MCP Apps MIME text/html;profile=mcp-app, with the client SDK inlined. tool_meta points the tool at that resource (ui.resourceUri), which is all a host needs: it reads the component and renders it with the tool’s structuredContent, 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.

  5. Run the server. Start it however you normally run an MCPServer (stdio or HTTP). In a host that supports embedded UIs, calling get_forecast now renders your component. A plain MCP client that renders no UI ignores the resource and still reads the tool’s structuredContent, so the same server works everywhere.

  • SynapseUI described one component once: a URI and a data-free template.
  • extensions=[forecast_ui] published it as a ui:// resource with the client SDK inlined, so the component is fully self-contained.
  • tool_meta wired the component to a tool, so its result is delivered both as structuredContent (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.