• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mongodb-js / mongodb-mcp-server / 20349165663

18 Dec 2025 07:40PM UTC coverage: 79.757% (+0.3%) from 79.435%
20349165663

Pull #812

github

web-flow
Merge eb4138d29 into 0abd1dc20
Pull Request #812: feat(mcp-ui): add hook for posting data back to MCP clien

1480 of 1937 branches covered (76.41%)

Branch coverage included in aggregate %.

101 of 103 new or added lines in 3 files covered. (98.06%)

6849 of 8506 relevant lines covered (80.52%)

82.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

33.33
/src/ui/hooks/useRenderData.ts
1
import { useEffect, useState } from "react";
1!
2

3
/** Expected structure of the postMessage data from parent window */
4
interface RenderDataMessage {
5
    type: string;
6
    payload?: {
7
        renderData?: unknown;
8
    };
9
}
10

11
/** Return type for the useRenderData hook */
12
interface UseRenderDataResult<T> {
13
    data: T | null;
14
    isLoading: boolean;
15
    error: string | null;
16
    /** The origin of the parent window, captured from the first valid message */
17
    parentOrigin: string | null;
18
}
19

20
/**
21
 * Hook for receiving render data from parent window via postMessage
22
 * This is used by iframe-based UI components that receive data from an MCP client
23
 *
24
 * @template T - The type of data expected in the renderData payload
25
 * @returns An object containing:
26
 *   - data: The received render data (or null if not yet received)
27
 *   - isLoading: Whether data is still being loaded
28
 *   - error: Error message if message validation failed
29
 *   - parentOrigin: The origin of the parent window (for secure postMessage calls)
30
 *
31
 * @example
32
 * ```tsx
33
 * interface MyData {
34
 *   items: string[];
35
 * }
36
 *
37
 * function MyComponent() {
38
 *   const { data, isLoading, error, parentOrigin } = useRenderData<MyData>();
39
 *   const { intent } = useHostCommunication({ targetOrigin: parentOrigin ?? undefined });
40
 *   return <button onClick={() => intent("my-action")}>Click</button>;
41
 * }
42
 * ```
43
 */
44
export function useRenderData<T = unknown>(): UseRenderDataResult<T> {
1✔
45
    const [data, setData] = useState<T | null>(null);
4✔
46
    const [isLoading, setIsLoading] = useState(true);
4✔
47
    const [error, setError] = useState<string | null>(null);
4✔
48
    const [parentOrigin, setParentOrigin] = useState<string | null>(null);
4✔
49

50
    useEffect(() => {
4✔
51
        const handleMessage = (event: MessageEvent<RenderDataMessage>): void => {
×
52
            if (event.data?.type !== "ui-lifecycle-iframe-render-data") {
×
53
                // Silently ignore messages that aren't for us
54
                return;
×
55
            }
×
56

NEW
57
            setParentOrigin((current) => current ?? event.origin);
×
58

59
            if (!event.data.payload || typeof event.data.payload !== "object") {
×
60
                const errorMsg = "Invalid payload structure received";
×
61
                setError(errorMsg);
×
62
                setIsLoading(false);
×
63
                return;
×
64
            }
×
65

66
            const renderData = event.data.payload.renderData;
×
67

68
            if (renderData === undefined || renderData === null) {
×
69
                setIsLoading(false);
×
70
                // Not an error - parent may intentionally send null
71
                return;
×
72
            }
×
73

74
            if (typeof renderData !== "object") {
×
75
                const errorMsg = `Expected object but received ${typeof renderData}`;
×
76
                setError(errorMsg);
×
77
                setIsLoading(false);
×
78
                return;
×
79
            }
×
80

81
            setData(renderData as T);
×
82
            setIsLoading(false);
×
83
            setError(null);
×
84
        };
×
85

86
        window.addEventListener("message", handleMessage);
×
87
        window.parent.postMessage({ type: "ui-lifecycle-iframe-ready" }, "*");
×
88

89
        return (): void => {
×
90
            window.removeEventListener("message", handleMessage);
×
91
        };
×
92
    }, []);
4✔
93

94
    return {
4✔
95
        data,
4✔
96
        isLoading,
4✔
97
        error,
4✔
98
        parentOrigin,
4✔
99
    };
4✔
100
}
4✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc