diff --git a/examples/sheet-music-server/README.md b/examples/sheet-music-server/README.md
new file mode 100644
index 00000000..0eba9ff8
--- /dev/null
+++ b/examples/sheet-music-server/README.md
@@ -0,0 +1,84 @@
+# Example: Sheet Music Server
+
+A demo MCP App that renders [ABC notation](https://en.wikipedia.org/wiki/ABC_notation) as sheet music with interactive audio playback using the [abcjs](https://www.abcjs.net/) library.
+
+
+
+  |
+  |
+
+
+
+## Features
+
+- **Audio Playback**: Built-in audio player with play/pause and loop controls
+- **Sheet Music Rendering**: Displays ABC notation as properly formatted sheet music
+
+## Running
+
+1. Install dependencies:
+
+ ```bash
+ npm install
+ ```
+
+2. Build and start the server:
+
+ ```bash
+ npm run start:http # for Streamable HTTP transport
+ # OR
+ npm run start:stdio # for stdio transport
+ ```
+
+3. View using the [`basic-host`](https://github.com/modelcontextprotocol/ext-apps/tree/main/examples/basic-host) example or another MCP Apps-compatible host.
+
+### Tool Input
+
+When calling the `play-sheet-music` tool, provide ABC notation:
+
+```json
+{
+ "abcNotation": "X:1\nT:C Major Scale\nM:4/4\nL:1/4\nK:C\nC D E F | G A B c |"
+}
+```
+
+#### ABC Notation Examples
+
+**C Major Scale:**
+
+```abc
+X:1
+T:C Major Scale
+M:4/4
+L:1/4
+K:C
+C D E F | G A B c |
+```
+
+**Twinkle, Twinkle Little Star:**
+
+```abc
+X:1
+T:Twinkle, Twinkle Little Star
+M:4/4
+L:1/4
+K:C
+C C G G | A A G2 | F F E E | D D C2 |
+G G F F | E E D2 | G G F F | E E D2 |
+C C G G | A A G2 | F F E E | D D C2 |
+```
+
+## Architecture
+
+### Server (`server.ts`)
+
+Exposes a single `play-sheet-music` tool that accepts:
+
+- `abcNotation`: ABC notation string to render
+
+The tool validates the ABC notation server-side using the abcjs parser and returns any parse errors. The actual rendering happens client-side when the UI receives the tool input.
+
+### App (`src/mcp-app.ts`)
+
+- Receives ABC notation via `ontoolinput` handler
+- Uses abcjs for audio playback controls and sheet music rendering (in `renderAbc()`)
diff --git a/examples/sheet-music-server/mcp-app.html b/examples/sheet-music-server/mcp-app.html
new file mode 100644
index 00000000..f9b53022
--- /dev/null
+++ b/examples/sheet-music-server/mcp-app.html
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+ Sheet Music Viewer
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/sheet-music-server/package.json b/examples/sheet-music-server/package.json
new file mode 100644
index 00000000..a2cd1ca0
--- /dev/null
+++ b/examples/sheet-music-server/package.json
@@ -0,0 +1,34 @@
+{
+ "name": "sheet-music-server",
+ "version": "1.0.0",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "build": "tsc --noEmit && cross-env INPUT=mcp-app.html vite build",
+ "watch": "cross-env INPUT=mcp-app.html vite build --watch",
+ "serve:http": "bun server.ts",
+ "serve:stdio": "bun server.ts --stdio",
+ "start": "npm run start:http",
+ "start:http": "cross-env NODE_ENV=development npm run build && npm run serve:http",
+ "start:stdio": "cross-env NODE_ENV=development npm run build && npm run serve:stdio",
+ "dev": "cross-env NODE_ENV=development concurrently 'npm run watch' 'npm run serve:http'"
+ },
+ "dependencies": {
+ "@modelcontextprotocol/ext-apps": "../..",
+ "@modelcontextprotocol/sdk": "^1.24.0",
+ "abcjs": "^6.4.4",
+ "zod": "^4.1.13"
+ },
+ "devDependencies": {
+ "@types/cors": "^2.8.19",
+ "@types/express": "^5.0.0",
+ "@types/node": "^22.0.0",
+ "concurrently": "^9.2.1",
+ "cors": "^2.8.5",
+ "cross-env": "^7.0.3",
+ "express": "^5.1.0",
+ "typescript": "^5.9.3",
+ "vite": "^6.0.0",
+ "vite-plugin-singlefile": "^2.3.0"
+ }
+}
diff --git a/examples/sheet-music-server/server.ts b/examples/sheet-music-server/server.ts
new file mode 100644
index 00000000..d6da53f2
--- /dev/null
+++ b/examples/sheet-music-server/server.ts
@@ -0,0 +1,119 @@
+import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+import type {
+ CallToolResult,
+ ReadResourceResult,
+} from "@modelcontextprotocol/sdk/types.js";
+import fs from "node:fs/promises";
+import path from "node:path";
+import { z } from "zod";
+import ABCJS from "abcjs";
+import {
+ RESOURCE_MIME_TYPE,
+ RESOURCE_URI_META_KEY,
+ registerAppResource,
+ registerAppTool,
+} from "@modelcontextprotocol/ext-apps/server";
+import { startServer } from "./src/server-utils.js";
+
+const DIST_DIR = path.join(import.meta.dirname, "dist");
+
+const DEFAULT_ABC_NOTATION_INPUT = `X:1
+T:Twinkle, Twinkle Little Star
+M:4/4
+L:1/4
+K:C
+C C G G | A A G2 | F F E E | D D C2 |
+G G F F | E E D2 | G G F F | E E D2 |
+C C G G | A A G2 | F F E E | D D C2 |`;
+
+/**
+ * Creates a new MCP server instance with the sheet music tool and resource.
+ */
+function createServer(): McpServer {
+ const server = new McpServer({
+ name: "Sheet Music Server",
+ version: "1.0.0",
+ });
+
+ const resourceUri = "ui://sheet-music/mcp-app.html";
+
+ // Register the play-sheet-music tool.
+ // Validates ABC notation server-side, then the client renders via ontoolinput.
+ registerAppTool(
+ server,
+ "play-sheet-music",
+ {
+ title: "Play Sheet Music",
+ description:
+ "Plays music from ABC notation with audio playback and visual sheet music. " +
+ "Use this to compose original songs (for birthdays, holidays, or any occasion) " +
+ "or perform well-known tunes (folk songs, nursery rhymes, hymns, classical melodies). " +
+ "For accurate renditions of well-known tunes, look up the ABC notation from " +
+ "abcnotation.com or thesession.org rather than recalling from memory.",
+ inputSchema: z.object({
+ abcNotation: z
+ .string()
+ .default(DEFAULT_ABC_NOTATION_INPUT)
+ .describe(
+ "ABC notation string to render as sheet music with audio playback",
+ ),
+ }),
+ _meta: { [RESOURCE_URI_META_KEY]: resourceUri },
+ },
+ async ({ abcNotation }): Promise => {
+ // Validate ABC notation using abcjs parser
+ const [{ warnings }] = ABCJS.parseOnly(abcNotation);
+
+ // Check for parse warnings (abcjs reports errors as warnings)
+ if (warnings && warnings.length > 0) {
+ // Strip HTML markup from warning messages
+ const messages = warnings.map((w) => w.replace(/<[^>]*>/g, ""));
+ const error = `Invalid ABC notation:\n${messages.join("\n")}`;
+ return {
+ isError: true,
+ content: [{ type: "text", text: error }],
+ };
+ }
+
+ return {
+ content: [{ type: "text", text: "Input parsed successfully." }],
+ };
+ },
+ );
+
+ // Register the UI resource that serves the bundled HTML/JS/CSS.
+ registerAppResource(
+ server,
+ resourceUri,
+ resourceUri,
+ { mimeType: RESOURCE_MIME_TYPE, description: "Sheet Music Viewer UI" },
+ async (): Promise => {
+ const html = await fs.readFile(
+ path.join(DIST_DIR, "mcp-app.html"),
+ "utf-8",
+ );
+
+ return {
+ contents: [
+ {
+ uri: resourceUri,
+ mimeType: RESOURCE_MIME_TYPE,
+ text: html,
+ _meta: {
+ ui: {
+ csp: {
+ // Allow loading soundfonts for audio playback
+ connectDomains: ["https://paulrosen.github.io"],
+ },
+ },
+ },
+ },
+ ],
+ };
+ },
+ );
+
+ return server;
+}
+
+startServer(createServer);
diff --git a/examples/sheet-music-server/src/global.css b/examples/sheet-music-server/src/global.css
new file mode 100644
index 00000000..97cda440
--- /dev/null
+++ b/examples/sheet-music-server/src/global.css
@@ -0,0 +1,12 @@
+* {
+ box-sizing: border-box;
+}
+
+html, body {
+ font-family: system-ui, -apple-system, sans-serif;
+ font-size: 1rem;
+}
+
+code {
+ font-size: 1em;
+}
diff --git a/examples/sheet-music-server/src/mcp-app.css b/examples/sheet-music-server/src/mcp-app.css
new file mode 100644
index 00000000..48435e34
--- /dev/null
+++ b/examples/sheet-music-server/src/mcp-app.css
@@ -0,0 +1,87 @@
+:root {
+ --color-bg: #ffffff;
+ --color-text: #1f2937;
+ --color-text-muted: #6b7280;
+ --color-primary: #2563eb;
+ --color-success: #10b981;
+ --color-danger: #ef4444;
+ --color-card-bg: #f9fafb;
+ --color-border: #e5e7eb;
+}
+
+@media (prefers-color-scheme: dark) {
+ :root {
+ --color-bg: #111827;
+ --color-text: #f9fafb;
+ --color-text-muted: #9ca3af;
+ --color-primary: #3b82f6;
+ --color-success: #34d399;
+ --color-danger: #f87171;
+ --color-card-bg: #1f2937;
+ --color-border: #374151;
+ }
+}
+
+html,
+body {
+ margin: 0;
+ padding: 0;
+ background: var(--color-bg);
+ color: var(--color-text);
+}
+
+.main {
+ width: 100%;
+ margin: 0 auto;
+ padding: 8px;
+ display: flex;
+ flex-direction: column;
+ gap: 8px;
+}
+
+/* Header */
+#audio-controls:empty {
+ display: none;
+}
+
+#audio-controls:not(:empty) ~ #status {
+ display: none;
+}
+
+.audio-controls {
+ width: 100%;
+
+ .abcjs-inline-audio {
+ border-radius: 8px;
+
+ /* Make loop button active state more visible */
+ .abcjs-midi-loop.abcjs-pushed {
+ background-color: var(--color-success) !important;
+ border-color: var(--color-success) !important;
+ }
+ }
+}
+
+.status {
+ font-size: 0.875rem;
+ color: var(--color-text-muted);
+}
+
+.status.error {
+ color: var(--color-danger);
+}
+
+
+/* Sheet Music Section */
+.sheet-section {
+ background: var(--color-card-bg);
+ border-radius: 8px;
+ padding: 16px;
+ border: 1px solid var(--color-border);
+ min-height: 500px;
+
+ .sheet-music-container {
+ width: 100%;
+ overflow-x: auto;
+ }
+}
diff --git a/examples/sheet-music-server/src/mcp-app.ts b/examples/sheet-music-server/src/mcp-app.ts
new file mode 100644
index 00000000..a6efadeb
--- /dev/null
+++ b/examples/sheet-music-server/src/mcp-app.ts
@@ -0,0 +1,120 @@
+/**
+ * @file Sheet Music App - renders ABC notation with abcjs and provides audio playback
+ */
+import { App } from "@modelcontextprotocol/ext-apps";
+import ABCJS from "abcjs";
+import "abcjs/abcjs-audio.css";
+import "./global.css";
+import "./mcp-app.css";
+
+const log = {
+ info: console.log.bind(console, "[APP]"),
+ error: console.error.bind(console, "[APP]"),
+};
+
+// State management
+interface AppState {
+ visualObj: ABCJS.TuneObject[] | null;
+ synthControl: ABCJS.SynthObjectController | null;
+}
+
+const state: AppState = {
+ visualObj: null,
+ synthControl: null,
+};
+
+// DOM element references
+const mainEl = document.querySelector(".main") as HTMLElement;
+const statusEl = document.getElementById("status")!;
+const sheetMusicEl = document.getElementById("sheet-music")!;
+const audioControlsEl = document.getElementById("audio-controls")!;
+
+/**
+ * Updates the status display.
+ */
+function setStatus(text: string, isError = false): void {
+ statusEl.textContent = text;
+ statusEl.classList.toggle("error", isError);
+}
+
+/**
+ * Renders ABC notation to sheet music and sets up audio playback
+ */
+async function renderAbc(abcNotation: string): Promise {
+ try {
+ setStatus("Rendering...");
+
+ // Clear previous content
+ sheetMusicEl.innerHTML = "";
+ audioControlsEl.innerHTML = "";
+
+ // Render the sheet music visually
+ state.visualObj = ABCJS.renderAbc(sheetMusicEl, abcNotation, {
+ responsive: "resize",
+ add_classes: true,
+ });
+
+ if (!state.visualObj || state.visualObj.length === 0) {
+ throw new Error("Failed to parse music notation");
+ }
+
+ if (!ABCJS.synth.supportsAudio()) {
+ throw new Error("Audio not supported in this browser");
+ }
+
+ // Create synth controller with UI controls
+ state.synthControl = new ABCJS.synth.SynthController();
+ state.synthControl.load(audioControlsEl, null, {
+ displayLoop: true,
+ // displayRestart: true,
+ displayPlay: true,
+ displayProgress: true,
+ // displayWarp: true,
+ });
+
+ // Connect synth to the rendered tune
+ await state.synthControl.setTune(state.visualObj[0], false, {});
+
+ setStatus("Ready to play!");
+ } catch (error) {
+ log.error("Render error:", error);
+ setStatus(`Error: ${(error as Error).message}`, true);
+ audioControlsEl.innerHTML = "";
+ }
+}
+
+// Create app instance
+const app = new App({ name: "Sheet Music App", version: "1.0.0" });
+
+// Handle tool input - receives ABC notation from the host
+app.ontoolinput = (params) => {
+ log.info("Received tool input:", params);
+
+ const abcNotation = params.arguments?.abcNotation as string | undefined;
+
+ if (abcNotation) {
+ renderAbc(abcNotation);
+ } else {
+ setStatus("No ABC notation provided", true);
+ }
+};
+
+// Error handler
+app.onerror = log.error;
+
+app.onhostcontextchanged = (params) => {
+ if (params.safeAreaInsets) {
+ mainEl.style.paddingTop = `${params.safeAreaInsets.top}px`;
+ mainEl.style.paddingRight = `${params.safeAreaInsets.right}px`;
+ mainEl.style.paddingBottom = `${params.safeAreaInsets.bottom}px`;
+ mainEl.style.paddingLeft = `${params.safeAreaInsets.left}px`;
+ }
+};
+
+// Connect to host
+app.connect().then(() => {
+ const ctx = app.getHostContext();
+ if (ctx) {
+ app.onhostcontextchanged(ctx);
+ }
+});
diff --git a/examples/sheet-music-server/src/server-utils.ts b/examples/sheet-music-server/src/server-utils.ts
new file mode 100644
index 00000000..40524237
--- /dev/null
+++ b/examples/sheet-music-server/src/server-utils.ts
@@ -0,0 +1,110 @@
+/**
+ * Shared utilities for running MCP servers with various transports.
+ */
+
+import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
+import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
+import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
+import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
+import cors from "cors";
+import type { Request, Response } from "express";
+
+/**
+ * Starts an MCP server using the appropriate transport based on command-line arguments.
+ *
+ * If `--stdio` is passed, uses stdio transport. Otherwise, uses Streamable HTTP transport.
+ *
+ * @param createServer - Factory function that creates a new McpServer instance.
+ */
+export async function startServer(
+ createServer: () => McpServer,
+): Promise {
+ try {
+ if (process.argv.includes("--stdio")) {
+ await startStdioServer(createServer);
+ } else {
+ await startStreamableHttpServer(createServer);
+ }
+ } catch (e) {
+ console.error(e);
+ process.exit(1);
+ }
+}
+
+/**
+ * Starts an MCP server with stdio transport.
+ *
+ * @param createServer - Factory function that creates a new McpServer instance.
+ */
+export async function startStdioServer(
+ createServer: () => McpServer,
+): Promise {
+ await createServer().connect(new StdioServerTransport());
+}
+
+/**
+ * Starts an MCP server with Streamable HTTP transport in stateless mode.
+ *
+ * Each request creates a fresh server and transport instance, which are
+ * closed when the response ends (no session tracking).
+ *
+ * The server listens on the port specified by the PORT environment variable,
+ * defaulting to 3001 if not set.
+ *
+ * @param createServer - Factory function that creates a new McpServer instance per request.
+ */
+export async function startStreamableHttpServer(
+ createServer: () => McpServer,
+): Promise {
+ const port = parseInt(process.env.PORT ?? "3001", 10);
+
+ // Express app - bind to all interfaces for development/testing
+ const expressApp = createMcpExpressApp({ host: "0.0.0.0" });
+ expressApp.use(cors());
+
+ expressApp.all("/mcp", async (req: Request, res: Response) => {
+ // Create fresh server and transport for each request (stateless mode)
+ const server = createServer();
+ const transport = new StreamableHTTPServerTransport({
+ sessionIdGenerator: undefined,
+ });
+
+ // Clean up when response ends
+ res.on("close", () => {
+ transport.close().catch(() => {});
+ server.close().catch(() => {});
+ });
+
+ try {
+ await server.connect(transport);
+ await transport.handleRequest(req, res, req.body);
+ } catch (error) {
+ console.error("MCP error:", error);
+ if (!res.headersSent) {
+ res.status(500).json({
+ jsonrpc: "2.0",
+ error: { code: -32603, message: "Internal server error" },
+ id: null,
+ });
+ }
+ }
+ });
+
+ const { promise, resolve, reject } = Promise.withResolvers();
+
+ const httpServer = expressApp.listen(port, (err?: Error) => {
+ if (err) return reject(err);
+ console.log(`Server listening on http://localhost:${port}/mcp`);
+ resolve();
+ });
+
+ const shutdown = () => {
+ console.log("\nShutting down...");
+ httpServer.close(() => process.exit(0));
+ };
+
+ process.on("SIGINT", shutdown);
+ process.on("SIGTERM", shutdown);
+
+ return promise;
+}
diff --git a/examples/sheet-music-server/tsconfig.json b/examples/sheet-music-server/tsconfig.json
new file mode 100644
index 00000000..535267b2
--- /dev/null
+++ b/examples/sheet-music-server/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "lib": ["ESNext", "DOM", "DOM.Iterable"],
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": true,
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "verbatimModuleSyntax": true,
+ "noEmit": true,
+ "strict": true,
+ "skipLibCheck": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true
+ },
+ "include": ["src", "server.ts"]
+}
diff --git a/examples/sheet-music-server/vite.config.ts b/examples/sheet-music-server/vite.config.ts
new file mode 100644
index 00000000..6ff6d997
--- /dev/null
+++ b/examples/sheet-music-server/vite.config.ts
@@ -0,0 +1,24 @@
+import { defineConfig } from "vite";
+import { viteSingleFile } from "vite-plugin-singlefile";
+
+const INPUT = process.env.INPUT;
+if (!INPUT) {
+ throw new Error("INPUT environment variable is not set");
+}
+
+const isDevelopment = process.env.NODE_ENV === "development";
+
+export default defineConfig({
+ plugins: [viteSingleFile()],
+ build: {
+ sourcemap: isDevelopment ? "inline" : undefined,
+ cssMinify: !isDevelopment,
+ minify: !isDevelopment,
+
+ rollupOptions: {
+ input: INPUT,
+ },
+ outDir: "dist",
+ emptyOutDir: false,
+ },
+});
diff --git a/package-lock.json b/package-lock.json
index 00ad1e77..93d25950 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -306,7 +306,7 @@
"version": "1.0.0",
"dependencies": {
"@modelcontextprotocol/ext-apps": "../..",
- "@modelcontextprotocol/sdk": "^1.22.0",
+ "@modelcontextprotocol/sdk": "^1.24.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"zod": "^4.1.13"
@@ -318,7 +318,6 @@
"@types/react": "^19.2.2",
"@types/react-dom": "^19.2.2",
"@vitejs/plugin-react": "^4.3.4",
- "bun": "^1.3.2",
"concurrently": "^9.2.1",
"cors": "^2.8.5",
"express": "^5.1.0",
@@ -386,6 +385,63 @@
"dev": true,
"license": "MIT"
},
+ "examples/sheet-music-server": {
+ "version": "1.0.0",
+ "dependencies": {
+ "@modelcontextprotocol/ext-apps": "../..",
+ "@modelcontextprotocol/sdk": "^1.24.0",
+ "abcjs": "^6.4.4",
+ "zod": "^4.1.13"
+ },
+ "devDependencies": {
+ "@types/cors": "^2.8.19",
+ "@types/express": "^5.0.0",
+ "@types/node": "^22.0.0",
+ "concurrently": "^9.2.1",
+ "cors": "^2.8.5",
+ "cross-env": "^7.0.3",
+ "express": "^5.1.0",
+ "typescript": "^5.9.3",
+ "vite": "^6.0.0",
+ "vite-plugin-singlefile": "^2.3.0"
+ }
+ },
+ "examples/sheet-music-server/node_modules/@types/node": {
+ "version": "22.19.3",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.3.tgz",
+ "integrity": "sha512-1N9SBnWYOJTrNZCdh/yJE+t910Y128BoyY+zBLWhL3r0TYzlTmFdXrPwHL9DyFZmlEXNQQolTZh3KHV31QDhyA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "examples/sheet-music-server/node_modules/cross-env": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
+ "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cross-spawn": "^7.0.1"
+ },
+ "bin": {
+ "cross-env": "src/bin/cross-env.js",
+ "cross-env-shell": "src/bin/cross-env-shell.js"
+ },
+ "engines": {
+ "node": ">=10.14",
+ "npm": ">=6",
+ "yarn": ">=1"
+ }
+ },
+ "examples/sheet-music-server/node_modules/undici-types": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"examples/system-monitor-server": {
"version": "1.0.0",
"dependencies": {
@@ -2394,6 +2450,16 @@
"dev": true,
"license": "BSD-3-Clause"
},
+ "node_modules/abcjs": {
+ "version": "6.5.2",
+ "resolved": "https://registry.npmjs.org/abcjs/-/abcjs-6.5.2.tgz",
+ "integrity": "sha512-XLDZPy/4TZbOqPsLwuu0Umsl79NTAcObEkboPxdYZXI8/fU6PNh59SAnkZOnEPVbyT8EXfBUjgNoe/uKd3T0xQ==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/paulrosen"
+ }
+ },
"node_modules/accepts": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
@@ -2685,40 +2751,6 @@
"resolved": "examples/budget-allocator-server",
"link": true
},
- "node_modules/bun": {
- "version": "1.3.5",
- "resolved": "https://registry.npmjs.org/bun/-/bun-1.3.5.tgz",
- "integrity": "sha512-c1YHIGUfgvYPJmLug5QiLzNWlX2Dg7X/67JWu1Va+AmMXNXzC/KQn2lgQ7rD+n1u1UqDpJMowVGGxTNpbPydNw==",
- "cpu": [
- "arm64",
- "x64"
- ],
- "dev": true,
- "hasInstallScript": true,
- "license": "MIT",
- "os": [
- "darwin",
- "linux",
- "win32"
- ],
- "bin": {
- "bun": "bin/bun.exe",
- "bunx": "bin/bunx.exe"
- },
- "optionalDependencies": {
- "@oven/bun-darwin-aarch64": "1.3.5",
- "@oven/bun-darwin-x64": "1.3.5",
- "@oven/bun-darwin-x64-baseline": "1.3.5",
- "@oven/bun-linux-aarch64": "1.3.5",
- "@oven/bun-linux-aarch64-musl": "1.3.5",
- "@oven/bun-linux-x64": "1.3.5",
- "@oven/bun-linux-x64-baseline": "1.3.5",
- "@oven/bun-linux-x64-musl": "1.3.5",
- "@oven/bun-linux-x64-musl-baseline": "1.3.5",
- "@oven/bun-windows-x64": "1.3.5",
- "@oven/bun-windows-x64-baseline": "1.3.5"
- }
- },
"node_modules/bun-types": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/bun-types/-/bun-types-1.3.3.tgz",
@@ -5656,6 +5688,10 @@
"node": ">=8"
}
},
+ "node_modules/sheet-music-server": {
+ "resolved": "examples/sheet-music-server",
+ "link": true
+ },
"node_modules/shell-quote": {
"version": "1.8.3",
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz",
diff --git a/tests/e2e/servers.spec.ts b/tests/e2e/servers.spec.ts
index eaf83da7..e4b1bb52 100644
--- a/tests/e2e/servers.spec.ts
+++ b/tests/e2e/servers.spec.ts
@@ -30,6 +30,7 @@ const SERVERS = [
{ key: "cohort-heatmap", name: "Cohort Heatmap Server" },
{ key: "customer-segmentation", name: "Customer Segmentation Server" },
{ key: "scenario-modeler", name: "SaaS Scenario Modeler" },
+ { key: "sheet-music", name: "Sheet Music Server" },
{ key: "system-monitor", name: "System Monitor Server" },
{ key: "threejs", name: "Three.js Server" },
{ key: "wiki-explorer", name: "Wiki Explorer" },
diff --git a/tests/e2e/servers.spec.ts-snapshots/sheet-music.png b/tests/e2e/servers.spec.ts-snapshots/sheet-music.png
new file mode 100644
index 00000000..54d0a96f
Binary files /dev/null and b/tests/e2e/servers.spec.ts-snapshots/sheet-music.png differ