mcp-server-value-picker 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +122 -374
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,320 +1,180 @@
1
1
  # Value Picker Server
2
2
 
3
- A **debug/test MCP server** for validating that values selected in an MCP App UI are correctly passed to the AI model via `ui/update-model-context`. This package tests the complete View ↔ Host ↔ Model communication flow defined in [SEP-1865](../../specification/2026-01-26/apps.mdx).
3
+ A debug tool for **platform developers** building MCP Apps hosts. Use this MCP server to verify that your platform correctly implements the `ui/update-model-context` and `ui/message` protocols defined in [SEP-1865](../../specification/2026-01-26/apps.mdx).
4
4
 
5
- The tool explicitly tells the AI model that this is a test — the model should simply confirm which value it received, not analyze or elaborate on the selection.
5
+ ## Why Use This?
6
6
 
7
- ## Purpose
7
+ When building an MCP Apps host, you need to verify that:
8
8
 
9
- This example validates MCP Apps protocol features across all three layers:
9
+ 1. **Context injection works** Values selected in the UI iframe reach the AI model via `ui/update-model-context`
10
+ 2. **Message sending works** — The UI can trigger follow-up messages via `ui/message`
11
+ 3. **The complete flow works** — View → Host → Model communication is functioning end-to-end
10
12
 
11
- - **Server**: Tool registration, UI resource serving, `structuredContent` data passing
12
- - **Host**: Context injection, message proxying, lifecycle notifications
13
- - **View**: Theme handling, safe areas, tool result rendering, model context updates
13
+ This tool provides a simple "blind selection" test: the user picks a value in the UI, and the AI must correctly identify what was selected. If the AI knows the value, your platform is working. If not, something is broken in your `ui/update-model-context` implementation.
14
14
 
15
15
  ---
16
16
 
17
- ## Server-Side Features Tested
18
-
19
- ### Tool Registration with UI Metadata
20
-
21
- Uses `registerAppTool()` to associate a tool with a UI resource via `_meta.ui.resourceUri`:
22
-
23
- ```typescript
24
- // From server.ts
25
- registerAppTool(server, "pick_value", {
26
- title: "Pick a Value",
27
- description: "DEBUG/TEST TOOL: Tests MCP Apps communication between UI and model. The user picks a value in the UI, and you must confirm whether you received it. This validates that ui/update-model-context is working correctly. Do not treat this as a real decision — just report what value you received.",
28
- inputSchema: {},
29
- outputSchema: z.object({
30
- values: z.array(z.object({
31
- id: z.string(),
32
- label: z.string(),
33
- description: z.string(),
34
- })),
35
- }),
36
- _meta: { ui: { resourceUri: "ui://pick-value/mcp-app.html" } },
37
- }, async () => { /* handler */ });
38
- ```
39
-
40
- **Spec Reference** ([Resource Discovery](../../specification/2026-01-26/apps.mdx#resource-discovery)):
41
- ```typescript
42
- interface Tool {
43
- _meta?: {
44
- ui?: {
45
- resourceUri?: string; // URI of UI resource for rendering
46
- visibility?: Array<"model" | "app">;
47
- };
48
- };
49
- }
50
- ```
51
-
52
- ### UI Resource Registration
53
-
54
- Uses `registerAppResource()` to serve HTML content with the required MIME type:
55
-
56
- ```typescript
57
- // From server.ts
58
- registerAppResource(server, resourceUri, resourceUri,
59
- { mimeType: RESOURCE_MIME_TYPE }, // "text/html;profile=mcp-app"
60
- async () => ({
61
- contents: [{ uri: resourceUri, mimeType: RESOURCE_MIME_TYPE, text: html }],
62
- })
63
- );
64
- ```
65
-
66
- **Spec Reference** ([UI Resource Format](../../specification/2026-01-26/apps.mdx#ui-resource-format)):
67
- > `mimeType` MUST be `text/html;profile=mcp-app`
68
-
69
- ### Dual Content Model (`content` + `structuredContent`)
70
-
71
- Tool returns both model-facing text and UI-facing structured data:
72
-
73
- ```typescript
74
- // From server.ts
75
- return {
76
- content: [{
77
- type: "text",
78
- text: `[MCP Apps Test] This is a debug tool for testing value communication...
79
- Your job: Simply report back the value you received. This tests whether the MCP Apps context injection is working. Do not provide detailed analysis of the values — just confirm what was selected.`,
80
- }],
81
- structuredContent: {
82
- values: VALUES, // Array of {id, label, description}
83
- instruction: "Wait for the user to select a value via the UI.",
84
- },
85
- };
86
- ```
87
-
88
- **Spec Reference** ([Data Passing](../../specification/2026-01-26/apps.mdx#data-passing)):
89
- > - `content`: Text representation for model context and text-only hosts
90
- > - `structuredContent`: Structured data optimized for UI rendering (not added to model context)
91
-
92
- ### Transport Modes
93
-
94
- Supports both STDIO and Streamable HTTP transports with auto-detection:
95
-
96
- ```typescript
97
- // From main.ts
98
- function resolveTransport(): "stdio" | "http" {
99
- if (process.argv.includes("--stdio")) return "stdio";
100
- if (process.argv.includes("--http")) return "http";
101
- return process.stdin.isTTY ? "http" : "stdio";
102
- }
103
- ```
104
-
105
- ---
106
-
107
- ## View-Side Features Tested
108
-
109
- ### App Initialization & Connection
17
+ ## Installation
110
18
 
111
- Uses the `App` class with `PostMessageTransport` to connect to the Host:
19
+ ### Via npm (Recommended)
112
20
 
113
- ```typescript
114
- // From src/mcp-app.ts
115
- const app = new App({ name: "Value Picker", version: "1.0.0" });
116
- await app.connect();
117
- ```
21
+ Install from [npmjs.com/package/mcp-server-value-picker](https://www.npmjs.com/package/mcp-server-value-picker):
118
22
 
119
- **Spec Reference** ([Transport Layer](../../specification/2026-01-26/apps.mdx#transport-layer)):
120
- ```typescript
121
- const transport = new MessageTransport(window.parent);
122
- const client = new Client({ name: "ui-view", version: "1.0.0" });
123
- await client.connect(transport);
23
+ ```bash
24
+ npm install -g mcp-server-value-picker
124
25
  ```
125
26
 
126
- ### Host Context Handling
127
-
128
- Retrieves and responds to host context after connection:
27
+ Run the server:
129
28
 
130
- ```typescript
131
- // From src/mcp-app.ts
132
- app.connect().then(() => {
133
- const ctx = app.getHostContext();
134
- if (ctx) handleHostContextChanged(ctx);
135
- });
29
+ ```bash
30
+ # Auto-detects transport mode
31
+ mcp-server-value-picker
136
32
 
137
- app.onhostcontextchanged = handleHostContextChanged;
138
- ```
33
+ # Force STDIO mode (for Claude Desktop)
34
+ mcp-server-value-picker --stdio
139
35
 
140
- **Spec Reference** ([Host Context in McpUiInitializeResult](../../specification/2026-01-26/apps.mdx#host-context-in-mcpuiinitializeresult)):
141
- ```typescript
142
- interface HostContext {
143
- theme?: "light" | "dark";
144
- styles?: { variables?: Record<string, string>; css?: { fonts?: string } };
145
- safeAreaInsets?: { top: number; right: number; bottom: number; left: number };
146
- // ... other fields
147
- }
36
+ # Force HTTP mode
37
+ mcp-server-value-picker --http
148
38
  ```
149
39
 
150
- ### Theme Application
151
-
152
- Applies the host's color scheme preference:
40
+ Or run directly with npx (no install required):
153
41
 
154
- ```typescript
155
- // From src/mcp-app.ts
156
- if (ctx.theme) {
157
- applyDocumentTheme(ctx.theme);
158
- }
42
+ ```bash
43
+ npx mcp-server-value-picker
159
44
  ```
160
45
 
161
- **Spec Reference** ([Theming](../../specification/2026-01-26/apps.mdx#theming)):
162
- > Views can use the `applyDocumentTheme` utility to easily respond to Host Context `theme` changes
163
-
164
- ### CSS Variable Injection
165
-
166
- Applies host-provided CSS custom properties for visual cohesion:
46
+ ### Local Development
167
47
 
168
- ```typescript
169
- // From src/mcp-app.ts
170
- if (ctx.styles?.variables) {
171
- applyHostStyleVariables(ctx.styles.variables);
172
- }
173
- ```
48
+ For modifying the example or contributing:
174
49
 
175
- **Spec Reference** ([Theming - Current Standardized Variables](../../specification/2026-01-26/apps.mdx#current-standardized-variables)):
176
- ```typescript
177
- type McpUiStyleVariableKey =
178
- | "--color-background-primary"
179
- | "--color-text-primary"
180
- | "--font-sans"
181
- // ... 80+ standardized variables
50
+ ```bash
51
+ npm install
52
+ npm run build
53
+ npm start
182
54
  ```
183
55
 
184
- ### Custom Font Loading
56
+ Default HTTP endpoint: `http://localhost:3456/mcp`
185
57
 
186
- Injects host-provided font CSS (e.g., `@font-face` or `@import`):
58
+ ---
187
59
 
188
- ```typescript
189
- // From src/mcp-app.ts
190
- if (ctx.styles?.css?.fonts) {
191
- applyHostFonts(ctx.styles.css.fonts);
192
- }
193
- ```
60
+ ## How the Test Works
194
61
 
195
- **Spec Reference** ([Custom Fonts](../../specification/2026-01-26/apps.mdx#custom-fonts)):
196
- > Hosts can provide custom fonts via `styles.css.fonts`
62
+ 1. Connect this MCP server to your platform
63
+ 2. The AI calls the `pick_value` tool, which displays 10 selectable values in the UI
64
+ 3. User clicks a value card
65
+ 4. The UI sends `ui/update-model-context` with the selection details
66
+ 5. The UI sends `ui/message` asking "I have picked a value, can you tell me what it is?"
67
+ 6. **If your platform works**: The AI responds with the correct value
68
+ 7. **If something is broken**: The AI won't know what was selected
197
69
 
198
- ### Safe Area Insets
70
+ ### Expected Model Response
199
71
 
200
- Respects host-provided padding for notches, toolbars, etc.:
72
+ The tool description explicitly tells the AI this is a debug test. A correct response looks like:
201
73
 
202
- ```typescript
203
- // From src/mcp-app.ts
204
- if (ctx.safeAreaInsets) {
205
- mainEl.style.paddingTop = `${ctx.safeAreaInsets.top}px`;
206
- mainEl.style.paddingRight = `${ctx.safeAreaInsets.right}px`;
207
- mainEl.style.paddingBottom = `${ctx.safeAreaInsets.bottom}px`;
208
- mainEl.style.paddingLeft = `${ctx.safeAreaInsets.left}px`;
209
- }
210
- ```
74
+ > "You selected **Alpha Protocol** (id: alpha)."
211
75
 
212
- ### Tool Result Handler
76
+ If the AI elaborates extensively on the value meanings, the test still passed (context injection worked), but the AI didn't follow the debug instructions.
213
77
 
214
- Receives structured data via `ui/notifications/tool-result`:
78
+ ---
215
79
 
216
- ```typescript
217
- // From src/mcp-app.ts
218
- app.ontoolresult = (result) => {
219
- const structured = result.structuredContent as { values?: Value[] } | undefined;
220
- if (structured?.values) {
221
- renderValues(structured.values);
222
- }
223
- };
224
- ```
80
+ ## What This Tests
81
+
82
+ ### Platform Requirements Verified
83
+
84
+ | Your Platform Must... | Protocol Message | Verified By |
85
+ | ----------------------------------- | -------------------------------- | ---------------------------- |
86
+ | Inject UI context into model | `ui/update-model-context` | AI knows selected value |
87
+ | Forward UI messages to conversation | `ui/message` | AI receives follow-up prompt |
88
+ | Deliver tool results to UI | `ui/notifications/tool-result` | UI renders value cards |
89
+ | Pass tool arguments to UI | `ui/notifications/tool-input` | UI receives empty args |
90
+ | Handle teardown gracefully | `ui/resource-teardown` | No errors on close |
91
+
92
+ ### Full Specification Coverage
93
+
94
+ [Full Specification](https://github.com/modelcontextprotocol/ext-apps/tree/main/specification)
95
+
96
+ | Feature | Spec Section |
97
+ | ---------------------------------------------------- | -------------------- |
98
+ | `text/html;profile=mcp-app` MIME type | UI Resource Format |
99
+ | `ui://` URI scheme | UI Resource Format |
100
+ | `_meta.ui.resourceUri` linkage | Resource Discovery |
101
+ | `ui/initialize` / `ui/notifications/initialized` | Lifecycle |
102
+ | `ui/notifications/tool-input` | Data Passing |
103
+ | `ui/notifications/tool-result` | Data Passing |
104
+ | `ui/notifications/tool-cancelled` | Notifications |
105
+ | `ui/resource-teardown` | Cleanup |
106
+ | `ui/update-model-context` | Requests |
107
+ | `ui/message` | Requests |
108
+ | `ui/notifications/host-context-changed` | Notifications |
109
+ | `HostContext.theme` | Theming |
110
+ | `HostContext.styles.variables` | Theming |
111
+ | `HostContext.styles.css.fonts` | Custom Fonts |
112
+ | `HostContext.safeAreaInsets` | Container Dimensions |
113
+ | `content` + `structuredContent` dual model | Data Passing |
225
114
 
226
- **Spec Reference** ([ui/notifications/tool-result](../../specification/2026-01-26/apps.mdx#notifications-host--view)):
227
- ```typescript
228
- {
229
- jsonrpc: "2.0",
230
- method: "ui/notifications/tool-result",
231
- params: CallToolResult // { content, structuredContent, _meta }
232
- }
233
- ```
115
+ ---
234
116
 
235
- ### Tool Input Handler
117
+ ## Files
236
118
 
237
- Receives tool call arguments (empty in this case):
119
+ | File | Purpose |
120
+ | ------------------- | ------------------------------------------------------ |
121
+ | `server.ts` | MCP server with `pick_value` tool and UI resource |
122
+ | `src/mcp-app.ts` | View implementation (`App` class, handlers, context) |
123
+ | `src/mcp-app.css` | View styling with CSS variable fallbacks |
124
+ | `mcp-app.html` | HTML template with color-scheme meta tag |
125
+ | `main.ts` | Entry point with STDIO/HTTP transport selection |
238
126
 
239
- ```typescript
240
- // From src/mcp-app.ts
241
- app.ontoolinput = (params) => {
242
- console.info("Received tool input:", params);
243
- };
244
- ```
127
+ ---
245
128
 
246
- **Spec Reference** ([ui/notifications/tool-input](../../specification/2026-01-26/apps.mdx#notifications-host--view)):
247
- ```typescript
248
- {
249
- jsonrpc: "2.0",
250
- method: "ui/notifications/tool-input",
251
- params: { arguments: Record<string, unknown> }
252
- }
253
- ```
129
+ ## Implementation Details
254
130
 
255
- ### Tool Cancellation Handler
131
+ <details>
132
+ <summary>Server-side implementation</summary>
256
133
 
257
- Handles cancelled tool execution:
134
+ ### Tool Registration with UI Metadata
258
135
 
259
136
  ```typescript
260
- // From src/mcp-app.ts
261
- app.ontoolcancelled = (params) => {
262
- statusEl.textContent = "Tool call was cancelled";
263
- };
137
+ registerAppTool(server, "pick_value", {
138
+ title: "Pick a Value",
139
+ description: "DEBUG/TEST TOOL: Tests MCP Apps communication between UI and model...",
140
+ inputSchema: {},
141
+ _meta: { ui: { resourceUri: "ui://pick-value/mcp-app.html" } },
142
+ }, async () => { /* handler */ });
264
143
  ```
265
144
 
266
- **Spec Reference** ([ui/notifications/tool-cancelled](../../specification/2026-01-26/apps.mdx#notifications-host--view)):
267
- > Host MUST send this notification if the tool execution was cancelled, for any reason
268
-
269
- ### Teardown Handler
270
-
271
- Gracefully handles resource teardown:
145
+ ### Dual Content Model
272
146
 
273
147
  ```typescript
274
- // From src/mcp-app.ts
275
- app.onteardown = async () => {
276
- console.info("Value Picker app is being torn down");
277
- return {};
148
+ return {
149
+ content: [{
150
+ type: "text",
151
+ text: `[MCP Apps Test] This is a debug tool...`,
152
+ }],
153
+ structuredContent: {
154
+ values: VALUES, // UI-only, not sent to model
155
+ },
278
156
  };
279
157
  ```
280
158
 
281
- **Spec Reference** ([ui/resource-teardown](../../specification/2026-01-26/apps.mdx#notifications-host--view)):
282
- > Host MUST send this notification before tearing down the UI resource
159
+ </details>
283
160
 
284
- ### Update Model Context
161
+ <details>
162
+ <summary>View-side implementation</summary>
285
163
 
286
- Injects the user's selection into the model's context:
164
+ ### Context Update
287
165
 
288
166
  ```typescript
289
- // From src/mcp-app.ts
290
167
  await app.updateModelContext({
291
168
  content: [{
292
169
  type: "text",
293
- text: `The user selected "${value.label}" (id: ${value.id}). Description: ${value.description}.`,
170
+ text: `The user selected "${value.label}" (id: ${value.id}).`,
294
171
  }],
295
172
  });
296
173
  ```
297
174
 
298
- **Spec Reference** ([ui/update-model-context](../../specification/2026-01-26/apps.mdx#requests-view--host)):
299
- ```typescript
300
- {
301
- jsonrpc: "2.0",
302
- method: "ui/update-model-context",
303
- params: {
304
- content?: ContentBlock[],
305
- structuredContent?: Record<string, unknown>
306
- }
307
- }
308
- ```
309
-
310
- > The View MAY send this request to update the Host's model context. This context will be used in future turns.
311
-
312
- ### Send User Message
313
-
314
- Triggers an AI response after selection:
175
+ ### Message Sending
315
176
 
316
177
  ```typescript
317
- // From src/mcp-app.ts
318
178
  await app.sendMessage({
319
179
  role: "user",
320
180
  content: [{
@@ -324,127 +184,15 @@ await app.sendMessage({
324
184
  });
325
185
  ```
326
186
 
327
- **Spec Reference** ([ui/message](../../specification/2026-01-26/apps.mdx#requests-view--host)):
328
- ```typescript
329
- {
330
- jsonrpc: "2.0",
331
- method: "ui/message",
332
- params: {
333
- role: "user",
334
- content: { type: "text", text: string }
335
- }
336
- }
337
- ```
338
-
339
- > Host SHOULD add the message to the conversation context, preserving the specified role.
340
-
341
- ---
342
-
343
- ## Test Pattern: "Blind Selection"
344
-
345
- This example implements a "blind selection" test pattern to validate context injection:
346
-
347
- 1. User clicks a value card in the UI
348
- 2. View sends `ui/update-model-context` with the selection details
349
- 3. View sends `ui/message` with "I have picked a value, can you tell me what it is?"
350
- 4. The AI must read the context to respond with the correct value
351
-
352
- This proves that `updateModelContext` successfully injects data that the model can access, without the user message containing the answer.
353
-
354
- ### Expected Model Behavior
355
-
356
- The tool description explicitly tells the model this is a debug/test tool. The model should:
357
-
358
- - **Do**: Simply confirm which value it received (e.g., "You selected Alpha Protocol")
359
- - **Don't**: Provide detailed analysis, recommendations, or elaborate on the value meanings
360
-
361
- If the model goes into detail about the values, the test still passes (context injection worked), but the model didn't follow the debug instructions.
362
-
363
- ---
364
-
365
- ## Installation
366
-
367
- ### Via npm (Recommended)
368
-
369
- Install the published package from [npmjs.com/package/mcp-server-value-picker](https://www.npmjs.com/package/mcp-server-value-picker):
370
-
371
- ```bash
372
- npm install -g mcp-server-value-picker
373
- ```
374
-
375
- Run the server:
376
-
377
- ```bash
378
- # Run (auto-detects transport mode)
379
- mcp-server-value-picker
380
-
381
- # Force STDIO mode (for Claude Desktop)
382
- mcp-server-value-picker --stdio
383
-
384
- # Force HTTP mode
385
- mcp-server-value-picker --http
386
- ```
387
-
388
- Or run directly with npx (no install required):
389
-
390
- ```bash
391
- npx mcp-server-value-picker
392
- ```
393
-
394
- ### Local Development
395
-
396
- For modifying the example or contributing:
397
-
398
- ```bash
399
- # Install dependencies
400
- npm install
401
-
402
- # Build UI and server
403
- npm run build
404
-
405
- # Run (auto-detects transport mode)
406
- npm start
407
-
408
- # Force STDIO mode
409
- npm start -- --stdio
187
+ ### Host Context Handling
410
188
 
411
- # Force HTTP mode
412
- npm start -- --http
189
+ ```typescript
190
+ app.onhostcontextchanged = (ctx) => {
191
+ if (ctx.theme) applyDocumentTheme(ctx.theme);
192
+ if (ctx.styles?.variables) applyHostStyleVariables(ctx.styles.variables);
193
+ if (ctx.styles?.css?.fonts) applyHostFonts(ctx.styles.css.fonts);
194
+ if (ctx.safeAreaInsets) { /* apply padding */ }
195
+ };
413
196
  ```
414
197
 
415
- Default HTTP endpoint: `http://localhost:3456/mcp`
416
-
417
- ---
418
-
419
- ## Files
420
-
421
- | File | Purpose |
422
- |------|---------|
423
- | `server.ts` | MCP server with `pick_value` tool and UI resource |
424
- | `src/mcp-app.ts` | View implementation (`App` class, handlers, context) |
425
- | `src/mcp-app.css` | View styling with CSS variable fallbacks |
426
- | `mcp-app.html` | HTML template with color-scheme meta tag |
427
- | `main.ts` | Entry point with STDIO/HTTP transport selection |
428
-
429
- ---
430
-
431
- ## Specification Coverage
432
-
433
- | Feature | Spec Section | Tested |
434
- |---------|--------------|--------|
435
- | `text/html;profile=mcp-app` MIME type | UI Resource Format | ✓ |
436
- | `ui://` URI scheme | UI Resource Format | ✓ |
437
- | `_meta.ui.resourceUri` linkage | Resource Discovery | ✓ |
438
- | `ui/initialize` / `ui/notifications/initialized` | Lifecycle | ✓ |
439
- | `ui/notifications/tool-input` | Data Passing | ✓ |
440
- | `ui/notifications/tool-result` | Data Passing | ✓ |
441
- | `ui/notifications/tool-cancelled` | Notifications | ✓ |
442
- | `ui/resource-teardown` | Cleanup | ✓ |
443
- | `ui/update-model-context` | Requests | ✓ |
444
- | `ui/message` | Requests | ✓ |
445
- | `ui/notifications/host-context-changed` | Notifications | ✓ |
446
- | `HostContext.theme` | Theming | ✓ |
447
- | `HostContext.styles.variables` | Theming | ✓ |
448
- | `HostContext.styles.css.fonts` | Custom Fonts | ✓ |
449
- | `HostContext.safeAreaInsets` | Container Dimensions | ✓ |
450
- | `content` + `structuredContent` dual model | Data Passing | ✓ |
198
+ </details>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-server-value-picker",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "type": "module",
5
5
  "description": "Debug/test MCP App: Validates that values selected in UI are correctly passed to the AI model via ui/update-model-context",
6
6
  "main": "dist/server.js",