mirror of
https://github.com/czlonkowski/n8n-mcp.git
synced 2026-02-09 06:43:08 +00:00
fix: align MCP Apps with official ext-apps spec (#574)
* feat: add MCP Apps with rich HTML UIs for tool results Add MCP Apps infrastructure that allows MCP hosts like Claude Desktop to render rich HTML UIs alongside tool results via `_meta.ui` and the MCP resources protocol. - Server-side UI module (src/mcp/ui/) with UIAppRegistry, tool-to-UI mapping, and _meta.ui injection into tool responses - React + Vite build pipeline (ui-apps/) producing self-contained HTML per app using vite-plugin-singlefile - Operation Result UI for workflow CRUD tools (create, update, delete, test, autofix, deploy) - Validation Summary UI for validation tools (validate_node, validate_workflow, n8n_validate_workflow) - Shared component library (Card, Badge, Expandable) with n8n dark theme - MCP resources protocol support (ListResources, ReadResource handlers) - Graceful degradation when ui-apps/dist/ is not built - 22 unit tests across 3 test files Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: improve MCP Apps test coverage and add security hardening - Expand test suite from 22 to 57 tests across 3 test files - Add UIAppRegistry.reset() for proper test isolation between tests - Replace some fs mocks with real temp directory tests in registry - Add edge case coverage: empty strings, pre-load state, double load, malformed URIs, duplicate tool patterns, empty HTML files - Add regression tests for specific tool-to-UI mappings - Add URI format consistency validation across all configs - Improve _meta.ui injection tests with structuredContent coexistence - Coverage: statements 79.4% -> 80%, lines 79.4% -> 80% Conceived by Romuald Członkowski - https://www.aiadvisors.pl/en Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: align MCP Apps with official ext-apps spec Update URI scheme from n8n-mcp://ui/ to ui://n8n-mcp/ per MCP spec. Move _meta.ui.resourceUri to tool definitions (tools/list) instead of tool call responses. Rewrite UI apps hook to use @modelcontextprotocol/ext-apps App class instead of window.__MCP_DATA__. Conceived by Romuald Czlonkowski - https://www.aiadvisors.pl/en Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
committed by
GitHub
parent
1f45cc6dcc
commit
23b90d01a6
@@ -1,30 +1,34 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__MCP_DATA__?: unknown;
|
||||
}
|
||||
}
|
||||
import { App } from '@modelcontextprotocol/ext-apps';
|
||||
|
||||
export function useToolData<T>(): T | null {
|
||||
const [data, setData] = useState<T | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// Try window.__MCP_DATA__ first (injected by host)
|
||||
if (window.__MCP_DATA__) {
|
||||
setData(window.__MCP_DATA__ as T);
|
||||
return;
|
||||
}
|
||||
const app = new App();
|
||||
|
||||
// Try embedded script tag
|
||||
const scriptEl = document.getElementById('mcp-data');
|
||||
if (scriptEl?.textContent) {
|
||||
try {
|
||||
setData(JSON.parse(scriptEl.textContent) as T);
|
||||
} catch {
|
||||
// Ignore parse errors
|
||||
app.ontoolresult = (result: any) => {
|
||||
// The host pushes tool result content; parse the first text item as JSON
|
||||
if (result?.content) {
|
||||
const textItem = Array.isArray(result.content)
|
||||
? result.content.find((c: any) => c.type === 'text')
|
||||
: null;
|
||||
if (textItem?.text) {
|
||||
try {
|
||||
setData(JSON.parse(textItem.text) as T);
|
||||
} catch {
|
||||
// Not JSON — use raw text as-is
|
||||
setData(textItem.text as unknown as T);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
app.connect();
|
||||
|
||||
return () => {
|
||||
app.close();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return data;
|
||||
|
||||
Reference in New Issue
Block a user