v1.1.0: First Chair
Opening day at v1.0.0 was pure chaos, and we loved it!
A crowd flooded the lift station with their apps, and we handed a ski pass to everyone who showed up. Now the lifts are running and v1.1.0 is ready for the ride 🚠
This release is about giving your apps more capability and an easier descent!
- View tools: model can now talk directly to your view instead of just interacting with the server
- Saved inputs: let you replay your favorite tool calls without climbing the same hill twice
- Mixed auth: servers let you keep the bunny slope open to everyone while gating the black diamonds behind a sign-in
- TSDoc: The whole public API is now documented inline, so your IDE reads like a trail map
- Vercel deploys: the fourth deploy target (yes, that one) even though it cost us a little dignity
Clip in. Here's what's new on the mountain 🏔️
View tools
Until now the traffic was one-way: the model called your server, your server returned results plus a view, and the view just sat there looking pretty. For the model to interact with that view, you had to call tools on the server and either swap in a new view or update the existing one through polling or push.
With view-provided tools the view can register its own tools. These tools are handlers that run inside the view iframe, against the view's live state, called by the model directly, and without the additional round-trip to the server. You can register tools from your view component using the new useRegisterViewTool hook.
import { useRegisterViewTool } from "skybridge/web";
import * as z from "zod";
function Counter() {
const [count, setCount] = useState(0);
useRegisterViewTool(
{
name: "counter_increment",
description: "Increment the on-screen counter by an amount.",
inputSchema: { by: z.number().int().default(1) },
},
({ by }) => {
setCount((c) => c + by);
return {
content: [{ type: "text", text: `Counter is now ${count + by}.` }],
structuredContent: { count: count + by },
};
},
);
return <span>{count}</span>;
}The tool registers on mount, unregisters on unmount, and validates arguments against inputSchema before your handler ever runs. View tools are an experimental feature of MCP Apps: Alpic's playground and the MCPJam emulator are the only compatible hosts for now. Have a look at the new chess example for a full demonstration app leveraging this feature.
Saved input
Testing an app means calling the same tool with the same arguments over and over. The DevTools now let you save a tool call input and replay it in one click. Dial in the inputs once, hit save, and your favorite calls are waiting for you in the sidebar next session.
No code required: it's pure DevTools UX. The thing you save is just a tool name plus the arguments you'd otherwise retype by hand.
Pin the inputs you reach for constantly, replay them across sessions, and spend your time reading output instead of refilling in forms.
Mixed auth
You used to pick a lane: a fully public app, or a fully authenticated one. Now you can run both on the same server: a few tools open to everyone, the rest gated behind sign-in. Declare each tool's requirements with securitySchemes so hosts can label it before invocation and request the right OAuth scopes, then pair it with the new optionalBearerAuth middleware, which lets unauthenticated requests through instead of shutting everyone out.
import { optionalBearerAuth } from "skybridge/server";
import * as z from "zod";
// Anonymous requests pass; bad tokens are still rejected.
server.use(optionalBearerAuth({ verifier }));
// Open to everyone.
server.registerTool(
{
name: "search_public_docs",
description: "Search public documents. No sign-in required.",
inputSchema: { q: z.string() },
securitySchemes: [{ type: "noauth" }],
},
async ({ q }) => ({ content: await search(q) }),
);
// Requires sign-in.
server.registerTool(
{
name: "search_private_docs",
description: "Search the user's private workspace.",
inputSchema: { q: z.string() },
securitySchemes: [{ type: "oauth2", scopes: ["search.read"] }],
},
async ({ q }, extra) => {
if (!extra.authInfo) {
return { content: "Sign in required.", isError: true };
}
return { content: await search(q, { user: extra.authInfo }) };
},
);The DevTools play along too: a mixed-auth server now offers deferred sign-in, so you can poke around in the public tools first and authenticate only when you reach for a gated one. securitySchemes is client-facing metadata: your handler still enforces auth, but it lets the host label each tool as public or sign-in-required before it is called.
TSDoc everywhere
We added TSDoc comments across most of Skybridge's public API. Hover over any hook, any server method, any config field, and the docs you'd otherwise hunt for on the site show up right inside your editor: signatures, parameter notes, links, everything right where you need it. Many of you told us you want to understand the code you depend on without leaving your IDE, and we listened.
Nothing to install, nothing to configure. Upgrade and your existing imports light up.
Vercel deploys
A new deploy target lands, bringing the count to four: Alpic, Cloudflare, Docker, and now Vercel. skybridge build emits a Build Output API tree under .vercel/output/ : a bundled serverless function, the static asset tree, and the routing config. Everything you need for you to ship in one command without vercel.json.
skybridge build
vercel deploy --prebuiltWhile we may have more affinities for some platforms than others, we believe that diversity and flexibility across the MCP App community win any day. The more places your app can ride, the better.
Changes
- feat: use alpic UI in everything app @paulleseute (#849)
- feat(devtools): remove outer frame @paulleseute (#854)
- fix: derive success status when tool output has no input @slackerzz (#827)
- feat: add saved inputs and run button to tool header @paulleseute (#853)
- feat(devtools): add saved queries @paulleseute (#850)
- fix(chess): notify model on UI-triggered game restart @valentinbeggi (#852)
- fix: use color-picking to display chess board in PiP mode @fredericbarthelet (#851)
- feat(infrastructure): add chess.skybridge.tech DNS record @valentinbeggi (#846)