Skip to content

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

  1. Edit ./apps/query-results/index.html
  2. Click Reload App in the test harness
  3. Click Send Test Data
  4. See changes immediately

Changes are served instantly - no restart needed.

3. Test with Real Queries

To test with actual Trino queries:

  1. Open http://localhost:6274 (MCP Inspector)
  2. Connect to: http://mcp-server:3001/sse
  3. Run trino_query:
    {"sql": "SELECT 1 as id, 'Test' as name, 100.50 as value"}
    

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

  1. Create your app directory under apps/:

    apps/
    ├── query-results/
    └── my-new-app/
        └── index.html
    

  2. Add configuration to configs/dev-mcpapps.yaml:

    mcpapps:
      apps:
        my_new_app:
          enabled: true
          assets_path: "/apps/my-new-app"
          tools:
            - some_tool
    

  3. Restart the dev environment:

    docker compose -f docker-compose.dev.yml up
    

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

  1. Open browser DevTools (F12)
  2. Console tab shows [MCP-APP] prefixed logs
  3. 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

Cleanup

docker compose -f docker-compose.dev.yml down