Launched this week

Persona.js
Add WebMCP-native AI chat to any Frontend
595 followers
Add WebMCP-native AI chat to any Frontend
595 followers
Persona is a lightweight, open-source AI chat UI library that embeds into any website, from modern apps to static HTML. Unlike React-based chat frameworks, Persona is framework-free, backend-agnostic, and WebMCP-native, so your assistant can discover and execute tools exposed by the parent page. Add streaming chat, voice, theming, and interactive copilot experiences without rebuilding your frontend or writing bespoke APIs.








Protected params is the one that moves the needle for me, taking the value out of the model's hands beats asking it to behave. The gap I'd still watch: that locks the WHAT, but the model still picks WHICH tool and WHEN off whatever a prior getter handed it. We hit a loop where every arg was clean but a poisoned read steered the model to fire a legit mutation at the wrong moment. Do you scope which tools are even available by app state, or does the model always see the full set?
Persona.js
@dipankar_sarkar for WebMCP the default is Persona reads the active tools so you’ll get the active state of the app if, however you can override that functionality. On the Runtype side we have more server tooling to lock down tools, implement guardrails, and log requests that we found the FE alone couldn’t do.
Persona in a way just accelerates you to the point you know more about what your server needs to do, to get the right blend of UX and security.
Active-tools-reflecting-app-state is a cleaner answer than I expected, since the menu shrinks with the app instead of sitting wide open. The thing I'd watch from building agent loops: that same liveness means a tool the model planned to call two steps ago can quietly vanish when state changes under it, so a half-formed plan goes invalid mid-run. Do you surface that disappearance back to the model as a signal it can re-plan on, or does the call just fail when it reaches for the tool?
Persona.js
@dipankar_sarkar within a run, the model plans against a snapshot taken at dispatch, so there's no mid-run "tool vanished" notification, but if a tool unregisters before execution, the bridge re-reads the live registry and returns a structured isError result like:
Then the model can re-plan on in the same run without aborting.
Every client-side failure mode (unregistered, allowlist-excluded, user-declined, timeout) resolves this way, and the next turn re-snapshots the registry so the advertised toolset re-converges with app state within one turn.
The WebMCP bet makes sense and drop-in on existing sites looks like the unlock! One thing we keep hitting building agents - the token-efficiency win can flip once a page exposes 20+ tools, since every schema rides in context each turn. As far as I understand Persona could send the model the full tool list or filter to a relevant subset first to decide if the headless-browser comparison holds at scale. Anyways, congrats on the great product
Persona.js
@artstavenka1 Thanks! And yeah, since Persona picks up changes to WebMCP tools on the frontend, you can technically change what tools are registered based on the context you have in your FE. It's another way to optimize tokens over the wire.
What we've found is when you can interact with the existing app more, via the FE calls, it can cut down on what is necessary to send through the LLM as well. If you dive into the hooks.
For instance, you can have a tool call that is a lightweight "get_cart", then Persona calls that registered tool on the FE, however instead of passing it back to the LLM you decide to manually inject a new message with the API data via Persona's window API. It gives you a much faster experience while spending 0 tokens to render the result, since you created the response yourself.
The boundary I’d want to inspect in every WebMCP app is the receipt after a mutative step, not just the approval before it.
Tool name, page/app context, inputs used, approval, result, and whether it can be undone. That’s what makes the action feel debuggable instead of magical.
Persona.js
@blah_mad sounds like you've built something real before :)
So while Persona does have built-in event debugging in the UI you can optionally turn on (screenshots attached), there is also a deeper set of JS events you can listen to for messages, results, approvals etc in a lot more detail: https://github.com/runtypelabs/persona/blob/main/packages/widget/docs/PROGRAMMATIC-CONTROL.md?plain=1#L562
The messages in particular seem to be right up your alley for the deep debugging use case:
You'd get that info by hooking into Persona init and watching for the assistant messages:
Persona.js
@blah_mad your question made me realize we could have docs specifically related to tracking the mutations via these events, so I added it: https://github.com/runtypelabs/persona/blob/main/packages/widget/docs/PROGRAMMATIC-CONTROL.md?plain=1#L758
Thanks again!
WebMCP support out of the box is a massive selling point, the biggest headache right now is avoiding massive token usage for simple frontend states. congrats for shipping @runtypical👏 qq. does the built-in polyfill handle older browser fallbacks gracefully, or is there a performance hit we should watch out for?
Persona.js
@vikramp7470 great question - the polyfill is both lazy-loaded and defensive; it won't waste any resources at all if WebMCP is already discovered on the page, even if it's from another polyfill. In fact, the entire initial page weight of Persona is only about ~15kb, to minimize the performance hit when embedding.
@runtypical Great to know, appreciate the transparency on performance...
The WebMCP-native angle is the part that got me, registering frontend tools so the agent drives your real UI instead of a headless browser feels way cleaner. For an existing React/Next app, how granular can you get about which actions you expose as tools? Congrats on shipping.
Persona.js
@i_sanjay_gautam Thanks! WebMCP tool registrations can theoretically invoke any javascript function living on a page, as well as be added as a decorator to existing HTML forms.
For frameworks like Next.js or React you can use plugins to easily hook into your existing actions and expose them as WebMCP, although I'd always encourage folks to intentionally design your tools around the needs of the agents - I personally love Arcade.dev's guide on MCP tool design, and I think the same principles apply to WebMCP!
The framework-agnostic approach is what caught my attention - most chat UIs are React-first, which quietly locks your architecture. The WebMCP-native integration is the right bet as MCP becomes the standard interface layer for AI tools. Quick question: how does Persona handle auth context when the MCP server needs user-specific permissions? Does the host page manage that entirely, or is there a mechanism built into the library for passing tokens through?
Persona.js
@galdayan Great question! There are essentially two paths, which you can blend together based on where the auth checks already are.
1) Handling auth context on the API side. Usually you are already streaming LLM / AI framework calls through the backend so the state of the user is already available. Persona has examples of using a proxy to do this in the repo as well.
2) Using WebMCP to respect the auth context automatically. Since the tools are being called on the frontend when you use WebMCP, you can pass the signed in user's identity as part of the existing function calls. If your app's frontend works with signed in context today, you might not need additional backend work.