Skip to content

Add MCP UI App support#196

Merged
pushpak1300 merged 67 commits into
mainfrom
mcp_ui_support
Apr 21, 2026
Merged

Add MCP UI App support#196
pushpak1300 merged 67 commits into
mainfrom
mcp_ui_support

Conversation

@pushpak1300
Copy link
Copy Markdown
Member

MCP currently has no way to show interactive UI to users — every tool response is plain text. This adds MCP App support: a tool linked to an AppResource can render a self-contained HTML app inside a sandboxed iframe in the host.

Usage

php artisan make:mcp-app-resource DashboardApp

This generates two files. The PHP class registers the resource — the default handle() auto-infers the Blade view from the class name, so no code is needed unless you're passing server-side data:

class DashboardApp extends AppResource
{
    public function handle(Request $request): Response
    {
        return Response::view('mcp.dashboard-app', [
            'title' => $this->title(),
        ]);
    }
}

The Blade view is the entire app — HTML, JS, and CSS in one file:

<x-mcp::app title="Dashboard">
    <x-slot:head>
        <script type="module">
        createMcpApp(async (app) => {
            const result = await app.callTool('get-data');
            document.getElementById('output').textContent = result.content[0]?.text;
        });
        </script>
    </x-slot:head>
    <div id="output"></div>
</x-mcp::app>

Link a tool to display the app when called:

#[RendersApp(resource: DashboardApp::class)]
class ShowDashboard extends Tool
{
    public function handle(Request $request): Response
    {
        return Response::text('Dashboard loaded.');
    }
}

App-only tools (invisible to the model, callable only from the UI):

#[RendersApp(resource: DashboardApp::class, visibility: ['app'])]
class GetDashboardData extends Tool { ... }

Approach

  • AppResource extends Resource with ui:// URI scheme and text/html;profile=mcp-app MIME type; serves self-contained HTML via handle() which renders a Blade view
  • #[RendersApp] attribute on a tool injects _meta.ui.resourceUri into its tool listing so the host knows which resource to fetch
  • The x-mcp::app Blade component inlines the pre-bundled JS SDK so apps require no npm or Vite
  • AppMeta / Csp / Permissions provide structured configuration for iframe sandbox permissions and CSP
  • Server advertises io.modelcontextprotocol/ui capability automatically when any AppResource is registered

pushpak1300 and others added 30 commits March 26, 2026 13:08
- Use string class name for Passport ClientRepository to avoid PHPStan error (not a direct dependency)
- Change UiMeta prefersBorder default from true to null so empty instances serialize as []
- UiResource now provides a default handle() that renders mcp.<kebab-name> view, so empty subclasses work without overriding handle()
- Restore prefersBorder default to true so hosts always receive the border hint
- Update tests to expect prefersBorder in default UiMeta serialization
Import Route class and use short name in docblock @method tags
instead of FQCNs to satisfy the fully_qualified_strict_types rule.
Copy link
Copy Markdown
Collaborator

@joetannenbaum joetannenbaum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall good, made some adjustments here and there, have a couple of questions. Let me know what you think.

If I changed anything that's fundamentally against your specific design or intention let me know.

Comment thread resources/js/mcp-sdk.js Outdated
Comment thread resources/js/mcp-sdk.js
Comment thread resources/js/mcp-sdk.js Outdated
Comment thread resources/js/mcp-sdk.js Outdated
Comment thread src/Server/Ui/Permissions.php Outdated
Comment thread resources/js/mcp-sdk.js
@pushpak1300
Copy link
Copy Markdown
Member Author

@pushpak1300 Documentation is 1K and the resources/js/mcp-sdk.js is .5K. Is mcp-sdk.js standardized or invented by your AI?

@wojo1206 which documentation ?

Copy link
Copy Markdown
Collaborator

@joetannenbaum joetannenbaum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just the one question, looks good otherwise.

Comment thread src/Server.php Outdated
@pushpak1300 pushpak1300 marked this pull request as ready for review April 16, 2026 15:24
@vinitkadam03
Copy link
Copy Markdown

vinitkadam03 commented Apr 19, 2026

This is awesome, exactly what we needed. Really excited about it, hope the team can ship it soon. Definitely looking forward to using this!

@stuartbrameld
Copy link
Copy Markdown

Agreed. I was really concerned Laravel was behind the times a year ago, and my business depended on it. All that has changed with the push into AI. This kind of thing is fantastic.

@pushpak1300 pushpak1300 merged commit 7c3f2e7 into main Apr 21, 2026
22 of 42 checks passed
@pushpak1300 pushpak1300 deleted the mcp_ui_support branch April 21, 2026 10:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants