Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions examples/video-resource-server/mcp-app.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@
<div id="player" class="player" style="display: none;">
<video id="video" controls></video>
<p id="video-info" class="video-info"></p>
<button id="change-video-btn" class="change-btn">Change Video</button>
</div>

<div id="video-picker-container" class="picker-container" style="display: none;">
<h3>Available Videos</h3>
<select id="video-picker" class="video-picker">
<option value="">Select a video...</option>
</select>
<button id="load-video-btn" class="load-btn" disabled>Load Video</button>
</div>
</main>
<script type="module" src="/src/mcp-app.ts"></script>
Expand Down
11 changes: 10 additions & 1 deletion examples/video-resource-server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,16 @@ export function createServer(): McpServer {

server.registerResource(
"video",
new ResourceTemplate("videos://{id}", { list: undefined }),
new ResourceTemplate("videos://{id}", {
list: async () => ({
resources: Object.entries(VIDEO_LIBRARY).map(([id, video]) => ({
uri: `videos://${id}`,
name: `video-${id}`,
description: `Video: ${video.description}`,
mimeType: "video/mp4",
})),
}),
}),
{
description: "Video served via MCP resource (base64 blob)",
mimeType: "video/mp4",
Expand Down
88 changes: 86 additions & 2 deletions examples/video-resource-server/src/global.css
Original file line number Diff line number Diff line change
@@ -1,10 +1,94 @@
:root {
color-scheme: light dark;

/*
* Fallbacks for host style variables used by this app.
* The host may provide these (and many more) via the host context.
*/
--color-text-primary: light-dark(#1f2937, #f3f4f6);
--color-text-inverse: light-dark(#f3f4f6, #1f2937);
--color-text-info: light-dark(#1d4ed8, #60a5fa);
--color-background-primary: light-dark(#ffffff, #1a1a1a);
--color-background-inverse: light-dark(#1a1a1a, #ffffff);
--color-background-info: light-dark(#eff6ff, #1e3a5f);
--color-ring-primary: light-dark(#3b82f6, #60a5fa);
--border-radius-md: 6px;
--border-width-regular: 1px;
--font-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
--font-weight-normal: 400;
--font-weight-bold: 700;
--font-text-md-size: 1rem;
--font-text-md-line-height: 1.5;
--font-heading-3xl-size: 2.25rem;
--font-heading-3xl-line-height: 1.1;
--font-heading-2xl-size: 1.875rem;
--font-heading-2xl-line-height: 1.2;
--font-heading-xl-size: 1.5rem;
--font-heading-xl-line-height: 1.25;
--font-heading-lg-size: 1.25rem;
--font-heading-lg-line-height: 1.3;
--font-heading-md-size: 1rem;
--font-heading-md-line-height: 1.4;
--font-heading-sm-size: 0.875rem;
--font-heading-sm-line-height: 1.4;

/* Spacing derived from host typography */
--spacing-unit: var(--font-text-md-size);
--spacing-xs: calc(var(--spacing-unit) * 0.25);
--spacing-sm: calc(var(--spacing-unit) * 0.5);
--spacing-md: var(--spacing-unit);
--spacing-lg: calc(var(--spacing-unit) * 1.5);

/* App accent color (customize for your brand) */
--color-accent: #2563eb;
--color-text-on-accent: #ffffff;
}

* {
box-sizing: border-box;
}

html, body {
font-family: system-ui, -apple-system, sans-serif;
font-size: 1rem;
font-family: var(--font-sans);
font-size: var(--font-text-md-size);
font-weight: var(--font-weight-normal);
line-height: var(--font-text-md-line-height);
color: var(--color-text-primary);
margin: 0;
padding: 0;
}

h1 {
font-size: var(--font-heading-3xl-size);
line-height: var(--font-heading-3xl-line-height);
}
h2 {
font-size: var(--font-heading-2xl-size);
line-height: var(--font-heading-2xl-line-height);
}
h3 {
font-size: var(--font-heading-xl-size);
line-height: var(--font-heading-xl-line-height);
}
h4 {
font-size: var(--font-heading-lg-size);
line-height: var(--font-heading-lg-line-height);
}
h5 {
font-size: var(--font-heading-md-size);
line-height: var(--font-heading-md-line-height);
}
h6 {
font-size: var(--font-heading-sm-size);
line-height: var(--font-heading-sm-line-height);
}

code, pre, kbd {
font-family: var(--font-mono);
font-size: 1em;
}

b, strong {
font-weight: var(--font-weight-bold);
}
85 changes: 74 additions & 11 deletions examples/video-resource-server/src/mcp-app.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@
flex-direction: column;
align-items: center;
justify-content: center;
padding: 2rem;
gap: 1rem;
color: #6b7280;
padding: var(--spacing-lg);
gap: var(--spacing-md);
color: var(--color-text-info);
}

.spinner {
width: 48px;
height: 48px;
border: 4px solid #e5e7eb;
border-top-color: #3b82f6;
border: 4px solid color-mix(in srgb, var(--color-text-primary) 20%, transparent);
border-top-color: var(--color-accent);
border-radius: 50%;
animation: spin 1s linear infinite;
}
Expand All @@ -27,13 +27,13 @@
}

.error {
padding: 1rem;
padding: var(--spacing-md);
color: #dc2626;
}

.error-title {
font-weight: 600;
margin: 0 0 0.5rem 0;
font-weight: var(--font-weight-bold);
margin: 0 0 var(--spacing-sm) 0;
}

.error p {
Expand All @@ -43,12 +43,75 @@
.player video {
width: 100%;
max-height: 480px;
border-radius: 8px;
border-radius: var(--border-radius-md);
background-color: #000;
}

.video-info {
margin-top: 0.5rem;
margin-top: var(--spacing-sm);
font-size: 0.875rem;
color: #6b7280;
color: var(--color-text-info);
}

.picker-container {
padding: var(--spacing-md);
}

.picker-container h3 {
margin: 0 0 var(--spacing-md) 0;
font-size: var(--font-heading-lg-size);
font-weight: var(--font-weight-bold);
}

.video-picker {
width: 100%;
padding: var(--spacing-sm);
font-size: var(--font-text-md-size);
border: var(--border-width-regular) solid color-mix(in srgb, var(--color-text-primary) 20%, transparent);
border-radius: var(--border-radius-md);
margin-bottom: var(--spacing-md);
background-color: var(--color-background-primary);
color: var(--color-text-primary);
font-family: var(--font-sans);
}

@media (prefers-color-scheme: dark) {
.video-picker option {
background-color: var(--color-background-info);
color: var(--color-text-primary);
}
}

.load-btn,
.change-btn {
padding: var(--spacing-sm) var(--spacing-md);
font-size: var(--font-text-md-size);
font-weight: var(--font-weight-bold);
color: var(--color-text-on-accent);
background-color: var(--color-accent);
border: none;
border-radius: var(--border-radius-md);
cursor: pointer;
transition: background-color 0.2s;
}

.load-btn:hover:not(:disabled),
.change-btn:hover {
background-color: color-mix(in srgb, var(--color-accent) 85%, var(--color-background-inverse));
}

.load-btn:focus-visible,
.change-btn:focus-visible {
outline: calc(var(--border-width-regular) * 2) solid var(--color-ring-primary);
outline-offset: var(--border-width-regular);
}

.load-btn:disabled {
background-color: color-mix(in srgb, var(--color-text-primary) 40%, transparent);
cursor: not-allowed;
opacity: 0.6;
}

.change-btn {
margin-top: var(--spacing-md);
}
Loading
Loading