examples: add MCP Apps arcade server (#346)
This commit is contained in:
parent
e93f8a0d8b
commit
2187bd4498
1 changed files with 1018 additions and 6 deletions
83
examples/arcade-server/README.md
Normal file
83
examples/arcade-server/README.md
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# Example: Arcade Server
|
||||
|
||||
An MCP Apps server that lets you browse and play classic arcade games from [archive.org](https://archive.org) directly in an MCP-enabled host.
|
||||
|
||||
## Overview
|
||||
|
||||
This example demonstrates serving **external HTML content** as an MCP App resource. The resource is a static loader that uses the MCP Apps protocol to receive tool arguments, then fetches the processed game HTML from a server endpoint. This pattern allows the same resource to display different games based on tool input.
|
||||
|
||||
Key techniques:
|
||||
|
||||
- MCP Apps protocol handshake (`ui/initialize` → `ui/notifications/tool-input`) to receive game ID dynamically
|
||||
- Server-side HTML fetching and processing per game ID
|
||||
- `<base href>` tag for resolving relative URLs against archive.org
|
||||
- `baseUriDomains` CSP metadata to allow the base tag
|
||||
- Rewriting ES module `import()` to classic `<script src>` loading (for srcdoc iframe compatibility)
|
||||
- Local script endpoint to bypass CORS restrictions in sandboxed iframes
|
||||
|
||||
## Key Files
|
||||
|
||||
- [`server.ts`](server.ts) - MCP server with tool and resource registration
|
||||
- [`index.ts`](index.ts) - HTTP transport and Express setup
|
||||
- [`game-processor.ts`](game-processor.ts) - Fetches and processes archive.org HTML
|
||||
- [`search.ts`](search.ts) - Archive.org search with smart fallbacks
|
||||
|
||||
## Getting Started
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
The server starts on `http://localhost:3002/mcp` by default. Set the `PORT` environment variable to change it.
|
||||
|
||||
### MCP Client Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"arcade": {
|
||||
"url": "http://localhost:3002/mcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Tools
|
||||
|
||||
| Tool | Description | UI |
|
||||
| ---------------- | ------------------------------------------- | --- |
|
||||
| `search_games` | Search archive.org for arcade games by name | No |
|
||||
| `get_game_by_id` | Load and play a specific game | Yes |
|
||||
|
||||
## How It Works
|
||||
|
||||
```
|
||||
1. Host calls search_games → Server queries archive.org API → Returns game list
|
||||
2. Host calls get_game_by_id → Tool validates gameId and returns success
|
||||
3. Host reads resource → Gets static loader with MCP Apps protocol handler
|
||||
4. View performs ui/initialize handshake with host
|
||||
5. Host sends tool-input with gameId → View fetches /game-html/:gameId
|
||||
6. Server fetches embed HTML from archive.org and processes it:
|
||||
- Removes archive.org's <base> tag
|
||||
- Injects <base href="https://archive.org/"> for URL resolution
|
||||
- Rewrites ES module import() to <script src> loading
|
||||
- Fetches emulation.min.js, patches it, serves from local endpoint
|
||||
- Injects layout CSS for full-viewport display
|
||||
7. Game runs: emulator loads ROM, initializes MAME, game is playable
|
||||
```
|
||||
|
||||
### Why the Processing?
|
||||
|
||||
Archive.org's game embed pages use ES module `import()` for loading the emulation engine. In `srcdoc` iframes (used by MCP hosts), `import()` fails because the iframe has a `null` origin. The server works around this by:
|
||||
|
||||
1. **Fetching `emulation.min.js` server-side** and replacing `import()` with `window.loadScript()`
|
||||
2. **Serving the patched script** from a local Express endpoint (`/scripts/emulation.js`)
|
||||
3. **Using `<script src>`** which is not subject to CORS restrictions, unlike `fetch()` or `import()`
|
||||
|
||||
## Example Game IDs
|
||||
|
||||
- `arcade_20pacgal` - Ms. Pac-Man / Galaga
|
||||
- `arcade_galaga` - Galaga
|
||||
- `arcade_sf2` - Street Fighter II
|
||||
- `doom-play` - The Ultimate DOOM
|
||||
Loading…
Reference in a new issue