Support deep linking MCP (#1550)

<!-- CURSOR_SUMMARY -->
> [!NOTE]
> Adds support for `dyad://add-mcp-server` deep links that prefill MCP
server settings, and updates deep link context/consumers to use
timestamp-based effects and clearing to avoid repeat handling.
> 
> - **Deep Link Infrastructure**:
> - Introduce `src/ipc/deep_link_data.ts` with zod schema
(`AddMcpServerConfigSchema`) and typed `DeepLinkData`.
> - Extend `DeepLinkContext` with `clearLastDeepLink`, timestamped
events, and auto-navigate to `/settings#tools-mcp` on `add-mcp-server`.
> - **Main Process**:
>   - Handle `dyad://add-mcp-server?name=...&config=...`:
> - Base64-decode and validate `config`; send `deep-link-received` with
typed payload or show error.
> - **Settings UI (MCP)**:
> - In `ToolsMcpSettings`, prefill form from `add-mcp-server` payload
(supports `stdio` command/args and `http` url) and show info toast;
clear deep link after handling.
> - **Connectors/UI**:
>   - Update `TitleBar`, `NeonConnector`, `SupabaseConnector` to:
> - Depend on `lastDeepLink?.timestamp` and call `clearLastDeepLink()`
after handling (`dyad-pro-return`, `neon-oauth-return`,
`supabase-oauth-return`).
> - **IPC Renderer**:
>   - Use centralized `DeepLinkData` types in `ipc_client.ts`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
294a9c6f38442241b54e9bcbe19a7a772d338ee0. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
This commit is contained in:
Will Chen
2025-10-16 10:20:16 -07:00
committed by GitHub
parent d76f428447
commit 744e413e71
8 changed files with 117 additions and 15 deletions

View File

@@ -1,31 +1,47 @@
import React, { createContext, useContext, useEffect, useState } from "react";
import { IpcClient, DeepLinkData } from "../ipc/ipc_client";
import { IpcClient } from "../ipc/ipc_client";
import { DeepLinkData } from "../ipc/deep_link_data";
import { useScrollAndNavigateTo } from "@/hooks/useScrollAndNavigateTo";
type DeepLinkContextType = {
lastDeepLink: (DeepLinkData & { timestamp: number }) | null;
clearLastDeepLink: () => void;
};
const DeepLinkContext = createContext<DeepLinkContextType>({
lastDeepLink: null,
clearLastDeepLink: () => {},
});
export function DeepLinkProvider({ children }: { children: React.ReactNode }) {
const [lastDeepLink, setLastDeepLink] = useState<
(DeepLinkData & { timestamp: number }) | null
>(null);
const scrollAndNavigateTo = useScrollAndNavigateTo("/settings", {
behavior: "smooth",
block: "start",
});
useEffect(() => {
const ipcClient = IpcClient.getInstance();
const unsubscribe = ipcClient.onDeepLinkReceived((data) => {
// Update with timestamp to ensure state change even if same type comes twice
setLastDeepLink({ ...data, timestamp: Date.now() });
if (data.type === "add-mcp-server") {
// Navigate to tools-mcp section
scrollAndNavigateTo("tools-mcp");
}
});
return unsubscribe;
}, []);
return (
<DeepLinkContext.Provider value={{ lastDeepLink }}>
<DeepLinkContext.Provider
value={{
lastDeepLink,
clearLastDeepLink: () => setLastDeepLink(null),
}}
>
{children}
</DeepLinkContext.Provider>
);