This quickstart builds a weather MCP App directly with the open MCP packages. The Apps SDK (preview) will shorten this to one file. The server it builds has three parts:
  • get_temperature: a data tool with no UI.
  • show_weather: a render tool whose result is displayed in a View.
  • ui://weather/card.html: the View, served as an MCP resource.
The server runs over streamable HTTP and is written in TypeScript with the official MCP SDK v2 (@modelcontextprotocol/server, @modelcontextprotocol/client) and @modelcontextprotocol/ext-apps. SDK v2 speaks MCP 2026-07-28 (stateless: server/discover, a _meta envelope on every request) and still answers clients that open with the older initialize handshake, so one server works with both. Allternit pins @modelcontextprotocol/server and @modelcontextprotocol/client at 2.3.1 and @modelcontextprotocol/ext-apps at 2.0.3.
This server has no authentication so the example stays short. A server that reads or changes user data must require OAuth. See Authentication.

1. Create the project

"type": "module" is required because the sample uses ES module imports. SDK v2 needs Node.js 20 or later and Zod 4.2 or later.

2. Write the server

Save this as server.ts:
server.ts
Things to notice:
  • createMcpHandler makes the server dual-era: a 2026-07-28 client gets server/discover and stateless requests, an older client gets the initialize handshake, from the same buildServer().
  • Tools are listed in registration order, so tools/list is the same on every request.
  • registerAppTool copies _meta.ui.resourceUri to the older flat key _meta["ui/resourceUri"], so hosts that only read the older key still find the View.
  • The render tool returns both content (text the model reads) and structuredContent (data the View reads).
  • The View uses only the standard bridge: ui/initialize, ui/notifications/initialized, ui/notifications/tool-result, and ui/notifications/size-changed. It has no dependencies.
  • The resource declares an empty csp, so the View gets no network access. See Build: MCP App UI.

3. Run it

Check it with any MCP client. This script uses the SDK client to list the tools, call the render tool, and read the View:
client.ts
You should see show_weather listed with _meta.ui.resourceUri set, a result whose structuredContent is { city: "Tokyo", temperatureC: 22 }, and the MIME type text/html;profile=mcp-app.

4. Make the server reachable

Allternit connects to your server from its own infrastructure, so the URL must be public and use https. Connector URLs that resolve to loopback, private, or link-local addresses are refused. During development, expose your local port through a tunnel and use the tunnel’s https URL, for example https://<your-tunnel-host>/mcp.
If you run your own Allternit API for development, set ALLTERNIT_MCP_ALLOW_PRIVATE_CONNECTORS=1 on it to allow connectors that resolve to a local address.

5. Connect it in Allternit

Add the server as a connector. This request uses the connector API:

6. See it render

Start a chat and ask: “Show me the weather in Tokyo.” The model calls show_weather. When the call completes, Allternit reads ui://weather/card.html, loads it into the sandbox, and shows the card in the conversation. Change the theme between light and dark and the card follows, because the View applies the styles.variables the host sends. If the card does not appear, see Troubleshooting.

Next steps