Skip to content

Commit d8485a9

Browse files
[LG-5666] MCP-UI App Scaffolding (#3280)
* [LG-5666] MCP-UI App Scaffolding * Added component, sdk scaffolding, package json updates * cleanup * fixed linting * updated workspace * added tsconfig * updated build * r17 updates * updated turbo settings * added devDeps * rm sdk, changed directory structure, updated listdb styles * fix: r17 scripts (#3305) * update r17 scripts * filter apps from r17 build workflow * add mcpui to caches --------- Co-authored-by: Adam Thompson <[email protected]>
1 parent c7d6e62 commit d8485a9

File tree

26 files changed

+749
-10
lines changed

26 files changed

+749
-10
lines changed

.github/workflows/pr.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ jobs:
3232
path: |
3333
charts/*/dist/*
3434
chat/*/dist/*
35+
mcp-ui/*/dist/*
3536
packages/*/dist/*
3637
tools/*/dist/*
3738
key: ${{ runner.os }}-build-cache-${{ hashFiles('package.json', 'pnpm-lock.yaml', '**/src/') }}
@@ -64,7 +65,7 @@ jobs:
6465

6566
- name: Build
6667
if: ${{ steps.build-cache.outputs.cache-hit != 'true' }}
67-
run: pnpm build
68+
run: pnpm build:packages
6869

6970
- uses: actions/cache/save@v4
7071
name: Save build cache
@@ -73,6 +74,7 @@ jobs:
7374
path: |
7475
charts/*/dist/*
7576
chat/*/dist/*
77+
mcp-ui/*/dist/*
7678
packages/*/dist/*
7779
tools/*/dist/*
7880
key: ${{ steps.build-cache.outputs.cache-primary-key }}
@@ -111,6 +113,7 @@ jobs:
111113
path: |
112114
charts/*/dist/*
113115
chat/*/dist/*
116+
mcp-ui/*/dist/*
114117
packages/*/dist/*
115118
tools/*/dist/*
116119
key: ${{needs.build.outputs.cache-primary-key}}
@@ -150,6 +153,7 @@ jobs:
150153
path: |
151154
charts/*/dist/*
152155
chat/*/dist/*
156+
mcp-ui/*/dist/*
153157
packages/*/dist/*
154158
tools/*/dist/*
155159
key: ${{needs.build.outputs.cache-primary-key}}
@@ -201,6 +205,7 @@ jobs:
201205
path: |
202206
charts/*/dist/*
203207
chat/*/dist/*
208+
mcp-ui/*/dist/*
204209
packages/*/dist/*
205210
tools/*/dist/*
206211
key: ${{needs.build.outputs.cache-primary-key}}
@@ -246,6 +251,7 @@ jobs:
246251
path: |
247252
charts/*/dist/*
248253
chat/*/dist/*
254+
mcp-ui/*/dist/*
249255
packages/*/dist/*
250256
tools/*/dist/*
251257
key: ${{needs.build.outputs.cache-primary-key}}

.github/workflows/react17.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ jobs:
3232
path: |
3333
charts/*/dist/*
3434
chat/*/dist/*
35+
mcp-ui/*/dist/*
3536
packages/*/dist/*
3637
tools/*/dist/*
3738
key: ${{ runner.os }}-REACT17-build-cache-${{ hashFiles('package.json', 'pnpm-lock.yaml', '**/src/') }}
@@ -51,7 +52,7 @@ jobs:
5152
run: pnpm install --prefer-offline # Intentionally not using --frozen-lockfile to allow for pnpm-lock.yaml updates
5253

5354
- name: Build packages
54-
run: pnpm build
55+
run: pnpm build --filter=!'@lg-apps/*'
5556

5657
- uses: actions/cache/save@v4
5758
name: Save build cache
@@ -60,6 +61,7 @@ jobs:
6061
path: |
6162
charts/*/dist/*
6263
chat/*/dist/*
64+
mcp-ui/*/dist/*
6365
packages/*/dist/*
6466
tools/*/dist/*
6567
key: ${{ steps.build-cache.outputs.cache-primary-key }}
@@ -85,6 +87,7 @@ jobs:
8587
path: |
8688
charts/*/dist/*
8789
chat/*/dist/*
90+
mcp-ui/*/dist/*
8891
packages/*/dist/*
8992
tools/*/dist/*
9093
key: ${{needs.build.outputs.cache-primary-key}}

.github/workflows/release.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ jobs:
3535
chat/*/dist/*
3636
chat/*/tsdoc.json
3737
chat/*/stories.js
38+
mcp-ui/*/dist/*
3839
packages/*/dist/*
3940
packages/*/tsdoc.json
4041
packages/*/stories.js
@@ -58,7 +59,7 @@ jobs:
5859

5960
- name: Build
6061
if: ${{ steps.build-cache.outputs.cache-hit != 'true' }}
61-
run: pnpm build
62+
run: pnpm build:packages
6263

6364
- name: Generate docs
6465
if: ${{ steps.build-cache.outputs.cache-hit != 'true' }}
@@ -75,6 +76,7 @@ jobs:
7576
chat/*/dist/*
7677
chat/*/tsdoc.json
7778
chat/*/stories.js
79+
mcp-ui/*/dist/*
7880
packages/*/dist/*
7981
packages/*/tsdoc.json
8082
packages/*/stories.js
@@ -118,6 +120,7 @@ jobs:
118120
chat/*/dist/*
119121
chat/*/tsdoc.json
120122
chat/*/stories.js
123+
mcp-ui/*/dist/*
121124
packages/*/dist/*
122125
packages/*/tsdoc.json
123126
packages/*/stories.js
@@ -171,6 +174,7 @@ jobs:
171174
chat/*/dist/*
172175
chat/*/tsdoc.json
173176
chat/*/stories.js
177+
mcp-ui/*/dist/*
174178
packages/*/dist/*
175179
packages/*/tsdoc.json
176180
packages/*/stories.js
@@ -232,6 +236,7 @@ jobs:
232236
chat/*/dist/*
233237
chat/*/tsdoc.json
234238
chat/*/stories.js
239+
mcp-ui/*/dist/*
235240
packages/*/dist/*
236241
packages/*/tsdoc.json
237242
packages/*/stories.js
@@ -284,6 +289,7 @@ jobs:
284289
chat/*/dist/*
285290
chat/*/tsdoc.json
286291
chat/*/stories.js
292+
mcp-ui/*/dist/*
287293
packages/*/dist/*
288294
packages/*/tsdoc.json
289295
packages/*/stories.js

apps/mcp-ui-app/.gitignore

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# next.js
12+
/.next/
13+
/out/
14+
15+
# production
16+
/build
17+
18+
# misc
19+
.DS_Store
20+
*.pem
21+
22+
# debug
23+
npm-debug.log*
24+
yarn-debug.log*
25+
yarn-error.log*
26+
27+
# local env files
28+
.env*.local
29+
.env.local
30+
31+
# vercel
32+
.vercel
33+
34+
# typescript
35+
*.tsbuildinfo
36+
next-env.d.ts
37+

apps/mcp-ui-app/README.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# MCP UI App
2+
3+
A Next.js application for the MCP UI, configured for iframe embedding with CORS and CSP headers.
4+
5+
## Getting Started
6+
7+
### 1. Environment Setup
8+
9+
Create a `.env.local` file in the app root with the following variables:
10+
11+
```bash
12+
# Base URL for the application
13+
NEXT_PUBLIC_BASE_URL=http://localhost:3000
14+
15+
# Allowed parent origins for iframe embedding (comma-separated)
16+
ALLOWED_IFRAME_ORIGINS=http://localhost:3000,http://localhost:3001,https://your-app.com
17+
```
18+
19+
Configuration options:
20+
21+
- `NEXT_PUBLIC_BASE_URL`: The base URL of your application
22+
- `ALLOWED_IFRAME_ORIGINS`: Comma-separated list of allowed parent origins for iframe embedding
23+
24+
### 2. Install dependencies
25+
26+
```bash
27+
pnpm install
28+
```
29+
30+
### 3. Run the development server
31+
32+
```bash
33+
pnpm dev
34+
```
35+
36+
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
37+
38+
## Configuration
39+
40+
### Base URL
41+
42+
The base URL is configured via the `NEXT_PUBLIC_BASE_URL` environment variable and can be accessed in your code:
43+
44+
```typescript
45+
import config from '@/config';
46+
47+
console.log(config.baseUrl); // http://localhost:3000
48+
```
49+
50+
### CORS and Iframe Embedding
51+
52+
The app is configured with:
53+
54+
- **CORS headers**: Allow cross-origin requests from specified origins
55+
- **CSP headers**: Content Security Policy appropriate for iframe embedding
56+
- **Frame ancestors**: Controls which domains can embed this app in an iframe
57+
58+
To allow your app to be embedded in an iframe from specific domains, add them to the `ALLOWED_IFRAME_ORIGINS` environment variable.
59+
60+
## Build
61+
62+
This app is excluded from the default `pnpm build` command in the workspace. To build this app specifically, run:
63+
64+
```bash
65+
cd apps/mcp-ui-app
66+
pnpm build
67+
```
68+
69+
Or from the workspace root:
70+
71+
```bash
72+
pnpm build:apps
73+
```

apps/mcp-ui-app/next.config.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/** @type {import('next').NextConfig} */
2+
const nextConfig = {
3+
reactStrictMode: true,
4+
transpilePackages: [
5+
'@lg-mcp-ui/list-databases',
6+
'@leafygreen-ui/card',
7+
'@leafygreen-ui/typography',
8+
'@leafygreen-ui/emotion',
9+
'@leafygreen-ui/tokens',
10+
'@leafygreen-ui/lib',
11+
],
12+
13+
async headers() {
14+
// Get allowed origins from environment variable
15+
const allowedOrigins = process.env.ALLOWED_IFRAME_ORIGINS?.split(',') || [
16+
'*',
17+
];
18+
19+
return [
20+
{
21+
// Apply to all routes
22+
source: '/:path*',
23+
headers: [
24+
// CORS headers for iframe embedding
25+
{
26+
key: 'Access-Control-Allow-Origin',
27+
value: allowedOrigins[0] || '*', // Use first origin or wildcard
28+
},
29+
{
30+
key: 'Access-Control-Allow-Methods',
31+
value: 'GET, POST, PUT, DELETE, OPTIONS',
32+
},
33+
{
34+
key: 'Access-Control-Allow-Headers',
35+
value: 'Content-Type, Authorization',
36+
},
37+
{
38+
key: 'Access-Control-Allow-Credentials',
39+
value: 'true',
40+
},
41+
// Content Security Policy for iframe embedding
42+
{
43+
key: 'Content-Security-Policy',
44+
value: [
45+
"default-src 'self'",
46+
"script-src 'self' 'unsafe-eval' 'unsafe-inline'",
47+
"style-src 'self' 'unsafe-inline'",
48+
"img-src 'self' data: https:",
49+
"font-src 'self' data:",
50+
"connect-src 'self'",
51+
`frame-ancestors ${allowedOrigins.join(' ')}`, // Allows embedding in iframes from these origins
52+
].join('; '),
53+
},
54+
],
55+
},
56+
];
57+
},
58+
};
59+
60+
module.exports = nextConfig;

apps/mcp-ui-app/package.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "@lg-apps/mcp-ui-app",
3+
"version": "0.1.0",
4+
"private": true,
5+
"scripts": {
6+
"dev": "next dev",
7+
"build": "next build",
8+
"start": "next start",
9+
"lint": "next lint"
10+
},
11+
"dependencies": {
12+
"@lg-mcp-ui/list-databases": "workspace:*",
13+
"next": "^14.2.0",
14+
"react": "^18.2.0",
15+
"react-dom": "^18.2.0"
16+
},
17+
"devDependencies": {
18+
"@types/node": "^20.12.5",
19+
"@types/react": "18.2.23",
20+
"@types/react-dom": "18.2.8",
21+
"typescript": "~5.8.0"
22+
}
23+
}
24+

apps/mcp-ui-app/src/app/layout.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import React from 'react';
2+
import type { Metadata } from 'next';
3+
4+
export const metadata: Metadata = {
5+
title: 'MCP UI App',
6+
description: 'MCP UI Application',
7+
};
8+
9+
export default function RootLayout({
10+
children,
11+
}: {
12+
children: React.ReactNode;
13+
}) {
14+
return (
15+
<html lang="en">
16+
<body>{children}</body>
17+
</html>
18+
);
19+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
'use client';
2+
3+
import React from 'react';
4+
import { ListDatabases } from '@lg-mcp-ui/list-databases';
5+
6+
export default function ListDatabasesPage() {
7+
return <ListDatabases databases={[]} />;
8+
}

0 commit comments

Comments
 (0)