Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@ server.registerResource(resourceUri, resourceUri, {}, async () => {
"utf-8",
);
return {
contents: [{ uri: resourceUri, mimeType: "text/html+mcp", text: html }],
contents: [
{ uri: resourceUri, mimeType: "text/html;profile=mcp-app", text: html },
],
};
});

Expand Down
6 changes: 3 additions & 3 deletions examples/basic-host/src/implementation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ async function getUiResourceHtml(serverInfo: ServerInfo, uri: string): Promise<s

const content = resource.contents[0];

// Per the MCP App specification, "text/html+mcp" signals this resource is
// indeed for an MCP App UI.
if (content.mimeType !== "text/html+mcp") {
// Per the MCP App specification, "text/html;profile=mcp-app" signals this
// resource is indeed for an MCP App UI.
if (content.mimeType !== "text/html;profile=mcp-app") {
throw new Error(`Unsupported MIME type: ${content.mimeType}`);
}

Expand Down
6 changes: 3 additions & 3 deletions examples/basic-server-react/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ const server = new McpServer({

return {
contents: [
// Per the MCP App specification, "text/html+mcp" signals to the Host
// that this resource is indeed for an MCP App UI.
{ uri: resourceUri, mimeType: "text/html+mcp", text: html },
// Per the MCP App specification, "text/html;profile=mcp-app" signals
// to the Host that this resource is indeed for an MCP App UI.
{ uri: resourceUri, mimeType: "text/html;profile=mcp-app", text: html },
],
};
},
Expand Down
6 changes: 3 additions & 3 deletions examples/basic-server-vanillajs/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ const server = new McpServer({

return {
contents: [
// Per the MCP App specification, "text/html+mcp" signals to the Host
// that this resource is indeed for an MCP App UI.
{ uri: resourceUri, mimeType: "text/html+mcp", text: html },
// Per the MCP App specification, "text/html;profile=mcp-app" signals
// to the Host that this resource is indeed for an MCP App UI.
{ uri: resourceUri, mimeType: "text/html;profile=mcp-app", text: html },
],
};
},
Expand Down
49 changes: 49 additions & 0 deletions examples/budget-allocator-server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Example: Budget Allocator App

An interactive budget allocation tool demonstrating real-time data visualization with MCP Apps.

## Features

- **Interactive Sliders**: Adjust budget allocation across 5 categories (Marketing, Engineering, Operations, Sales, R&D)
- **Donut Chart**: Real-time visualization of allocation distribution using Chart.js
- **Sparkline Trends**: 24-month historical allocation data per category
- **Percentile Badges**: Compare your allocation vs. industry benchmarks
- **Stage Selector**: Switch between Seed, Series A, Series B, and Growth benchmarks
- **Budget Presets**: Quick selection of $50K, $100K, $250K, or $500K totals

## Running

1. Install dependencies:

```bash
npm install
```

2. Build and start the server:

```bash
npm start
```

The server will listen on `http://localhost:3001/mcp`.

3. View using the [`basic-host`](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-host) example or another MCP Apps-compatible host.

## Architecture

### Server (`server.ts`)

Exposes a single `get-budget-data` tool that returns:

- Category definitions with colors and default allocations
- Historical data (~120 data points) - 24 months of allocation history per category
- Industry benchmarks (~60 data points) - Aggregated percentile data by company stage

The tool is linked to a UI resource via `_meta[RESOURCE_URI_META_KEY]`.

### App (`src/mcp-app.ts`)

- Uses Chart.js for the donut chart visualization
- Renders sparkline trends using inline SVG
- Computes percentile rankings client-side from benchmark data
- Updates all UI elements reactively on slider changes
36 changes: 36 additions & 0 deletions examples/budget-allocator-server/mcp-app.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Budget Allocator</title>
</head>
<body>
<div class="app-container">
<header class="header">
<h1 class="title">Budget Allocator</h1>
<select id="budget-selector" class="budget-select"></select>
</header>

<section class="chart-section">
<canvas id="budget-chart"></canvas>
</section>

<section class="sliders-section" id="sliders-container"></section>

<footer class="footer">
<div id="status-bar" class="status-bar">
Allocated: $0 / $0
</div>
<div class="comparison-bar">
<span id="comparison-summary">Loading benchmarks...</span>
<label class="stage-label">
Stage:
<select id="stage-selector" class="stage-select"></select>
</label>
</div>
</footer>
</div>
<script type="module" src="/src/mcp-app.ts"></script>
</body>
</html>
30 changes: 30 additions & 0 deletions examples/budget-allocator-server/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "budget-allocator-server",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"build": "INPUT=mcp-app.html vite build",
"watch": "INPUT=mcp-app.html vite build --watch",
"serve": "bun server.ts",
"start": "NODE_ENV=development npm run build && npm run serve",
"dev": "NODE_ENV=development concurrently 'npm run watch' 'npm run serve'"
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "../..",
"@modelcontextprotocol/sdk": "^1.22.0",
"chart.js": "^4.4.0",
"zod": "^3.25.0"
},
"devDependencies": {
"@types/cors": "^2.8.19",
"@types/express": "^5.0.0",
"@types/node": "^22.0.0",
"concurrently": "^9.2.1",
"cors": "^2.8.5",
"express": "^5.1.0",
"typescript": "^5.9.3",
"vite": "^6.0.0",
"vite-plugin-singlefile": "^2.3.0"
}
}
Loading