diff --git a/examples/simple-host/package.json b/examples/simple-host/package.json index d207c34..9f192c5 100644 --- a/examples/simple-host/package.json +++ b/examples/simple-host/package.json @@ -4,7 +4,7 @@ "version": "1.0.0", "type": "module", "scripts": { - "start:server": "python3 serve.py", + "start:server": "tsx server.ts", "start:mcp-server": "cd ../simple-server && npm install && npm run start", "build": "concurrently 'INPUT=example-host.html vite build' 'INPUT=example-host-react.html vite build' 'INPUT=sandbox.html vite build'", "server": "bun server.ts", diff --git a/examples/simple-host/serve.py b/examples/simple-host/serve.py deleted file mode 100644 index d32ed29..0000000 --- a/examples/simple-host/serve.py +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python3 -""" -Simple HTTP server to serve the MCP-UI proxy on port 8765 -""" - -import http.server -import os -import socketserver -import sys -from pathlib import Path - -PORT = int(os.environ.get('PORT', '8080')) -DIRECTORY = Path(__file__).parent / 'dist' - -class CustomHTTPRequestHandler(http.server.SimpleHTTPRequestHandler): - def __init__(self, *args, **kwargs): - super().__init__(*args, directory=DIRECTORY.as_posix(), **kwargs) - - def end_headers(self): - # Apply custom headers only to sandbox.html - if self.path == "/sandbox.html" or self.path == "/": - # Add CORS headers to allow cross-origin requests - self.send_header("Access-Control-Allow-Origin", "*") - self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS") - self.send_header("Access-Control-Allow-Headers", "*") - - # Add permissive CSP to allow external resources (images, styles, scripts) - csp = "; ".join( - [ - "default-src 'self'", - "img-src * data: blob: 'unsafe-inline'", - "style-src * blob: data: 'unsafe-inline'", - "script-src * blob: data: 'unsafe-inline' 'unsafe-eval'", - "connect-src *", - "font-src * blob: data:", - "media-src * blob: data:", - "frame-src * blob: data:", - ] - ) - self.send_header("Content-Security-Policy", csp) - - # Disable caching to ensure fresh content on every request - self.send_header("Cache-Control", "no-cache, no-store, must-revalidate") - self.send_header("Pragma", "no-cache") - self.send_header("Expires", "0") - - super().end_headers() - - -def main(): - print(f"Server running on: http://localhost:{PORT}") - print(f"Press Ctrl+C to stop the server\n") - - with socketserver.TCPServer(("", PORT), CustomHTTPRequestHandler) as httpd: - try: - httpd.serve_forever() - except KeyboardInterrupt: - print("\n\nServer stopped.") - sys.exit(0) - - -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/examples/simple-host/server.ts b/examples/simple-host/server.ts new file mode 100644 index 0000000..b601982 --- /dev/null +++ b/examples/simple-host/server.ts @@ -0,0 +1,58 @@ +#!/usr/bin/env npx tsx +/** + * Simple HTTP server to serve the host and sandbox html files with appropriate + * Content Security Policy (CSP) headers. + */ + +import express from "express"; +import cors from "cors"; +import { fileURLToPath } from "url"; +import { dirname, join } from "path"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const PORT = parseInt(process.env.PORT || "8080", 10); +const DIRECTORY = join(__dirname, "dist"); + +const app = express(); + +// CORS middleware for all routes +app.use(cors()); + +// Custom middleware for sandbox.html and root +app.use((req, res, next) => { + if (req.path === "/sandbox.html" || req.path === "/") { + // Permissive CSP to allow external resources (images, styles, scripts) + const csp = [ + "default-src 'self'", + "img-src * data: blob: 'unsafe-inline'", + "style-src * blob: data: 'unsafe-inline'", + "script-src * blob: data: 'unsafe-inline' 'unsafe-eval'", + "connect-src *", + "font-src * blob: data:", + "media-src * blob: data:", + "frame-src * blob: data:", + ].join("; "); + res.setHeader("Content-Security-Policy", csp); + + // Disable caching to ensure fresh content on every request + res.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); + res.setHeader("Pragma", "no-cache"); + res.setHeader("Expires", "0"); + } + next(); +}); + +// Serve static files from dist directory +app.use(express.static(DIRECTORY)); + +// Redirect root to example-host.html +app.get("/", (_req, res) => { + res.redirect("/example-host-react.html"); +}); + +app.listen(PORT, () => { + console.log(`Server running on: http://localhost:${PORT}`); + console.log("Press Ctrl+C to stop the server\n"); +}); diff --git a/package.json b/package.json index cadebfc..39647cd 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "homepage": "https://gist.github.com/a9603ba2d6757d6038ce066eded4c354", "name": "@modelcontextprotocol/ext-apps", - "version": "1.0.0", + "version": "0.0.1", "description": "Hey", "type": "module", "main": "./dist/src/app.js",