MCP Apps Development¶
Create and test MCP Apps using the included development environment.
Prerequisites¶
- Docker (only dependency needed)
Quick Start¶
git clone https://github.com/txn2/mcp-data-platform
cd mcp-data-platform
docker compose -f docker-compose.dev.yml up
This starts:
| Component | URL | Purpose |
|---|---|---|
| Test Harness | http://localhost:8000 | App development and testing |
| MCP Server | http://localhost:3001 | MCP protocol (SSE) |
| MCP Inspector | http://localhost:6274 | Protocol debugging |
| Trino | http://localhost:8090 | Query engine |
Development Workflow¶
1. Open Test Harness¶
Open http://localhost:8000/test-harness.html
The test harness provides:
- Left panel: Editable JSON test data
- Right panel: Live app preview
- Send Test Data: Sends data to the app
- Reload App: Reloads after editing source files
2. Edit and Test¶
- Edit
./apps/query-results/index.html - Click Reload App in the test harness
- Click Send Test Data
- See changes immediately
Changes are served instantly - no restart needed.
3. Test with Real Queries¶
To test with actual Trino queries:
- Open http://localhost:6274 (MCP Inspector)
- Connect to:
http://mcp-server:3001/sse - Run
trino_query:
Creating New Apps¶
App Structure¶
my-app/
├── index.html # Entry point (required)
├── styles.css # Optional
├── app.js # Optional
└── assets/ # Optional
MCP Apps Protocol¶
Apps communicate with the host via postMessage:
// Initialize on load
window.parent.postMessage({
jsonrpc: '2.0',
id: 1,
method: 'ui/initialize',
params: {
protocolVersion: '2025-01-09',
appInfo: { name: 'My App', version: '1.0.0' }
}
}, '*');
// Listen for tool results
window.addEventListener('message', (event) => {
if (event.data?.method === 'ui/notifications/tool-result') {
const data = JSON.parse(event.data.params.content[0].text);
// Render your UI
}
});
Minimal Example¶
<!DOCTYPE html>
<html>
<head><title>My App</title></head>
<body>
<div id="results"></div>
<script>
window.addEventListener('message', (event) => {
if (event.data?.method === 'ui/notifications/tool-result') {
const data = JSON.parse(event.data.params.content[0].text);
document.getElementById('results').innerHTML =
`<pre>${JSON.stringify(data, null, 2)}</pre>`;
}
});
window.parent.postMessage({
jsonrpc: '2.0',
id: 1,
method: 'ui/initialize',
params: { protocolVersion: '2025-01-09' }
}, '*');
</script>
</body>
</html>
Add to Development Environment¶
-
Create your app directory under
apps/: -
Add configuration to
configs/dev-mcpapps.yaml: -
Restart the dev environment:
Test Queries¶
All queries use Trino's memory catalog (no database setup needed).
Simple data:
{"sql": "SELECT 1 as id, 'Product A' as name, 15000.50 as revenue UNION ALL SELECT 2, 'Product B', 23000.75 UNION ALL SELECT 3, 'Product C', 8500.25"}
More rows:
{"sql": "SELECT n as id, 'Item ' || CAST(n AS VARCHAR) as name, ROUND(RANDOM() * 10000, 2) as value FROM UNNEST(SEQUENCE(1, 20)) AS t(n)"}
Date series:
{"sql": "SELECT DATE '2024-01-01' + INTERVAL '1' DAY * n as date, ROUND(RANDOM() * 1000, 2) as sales FROM UNNEST(SEQUENCE(0, 29)) AS t(n)"}
Architecture¶
graph LR
subgraph "Browser"
TH[Test Harness<br/>:8000]
MI[MCP Inspector<br/>:6274]
end
subgraph "Docker"
MCP[MCP Server<br/>:3001]
T[Trino<br/>:8090]
end
TH <-->|postMessage| MCP
MI <-->|MCP Protocol| MCP
MCP <-->|SQL| T
Debugging¶
- Open browser DevTools (F12)
- Console tab shows
[MCP-APP]prefixed logs - Network tab shows MCP protocol messages
Troubleshooting¶
| Problem | Solution |
|---|---|
| Changes not appearing | Click Reload App, or hard refresh (Cmd+Shift+R) |
| "No results to display" | Check browser console for errors |
| Trino not responding | Wait for startup: curl http://localhost:8090/v1/info |
| Port already in use | docker compose -f docker-compose.dev.yml down |