From 1c287d95e023e490b752c9ebeb4548393602919b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20Biro=C5=A1?= Date: Mon, 22 Dec 2025 11:33:32 +0100 Subject: [PATCH 1/5] feat: Add Cursor & VSCode integration --- .../src/theme/LLMButtons/index.jsx | 128 +++++++++++++++++- 1 file changed, 125 insertions(+), 3 deletions(-) diff --git a/apify-docs-theme/src/theme/LLMButtons/index.jsx b/apify-docs-theme/src/theme/LLMButtons/index.jsx index 63c7c28a26..064527c321 100644 --- a/apify-docs-theme/src/theme/LLMButtons/index.jsx +++ b/apify-docs-theme/src/theme/LLMButtons/index.jsx @@ -31,6 +31,27 @@ const DROPDOWN_OPTIONS = [ Icon: MarkdownIcon, value: 'viewAsMarkdown', }, + { + label: 'Copy MCP server', + description: 'Copy Apify MCP configuration', + showExternalIcon: false, + Icon: CopyIcon, + value: 'copyMcpServer', + }, + { + label: 'Connect to Cursor', + description: 'Open MCP configurator for Cursor', + showExternalIcon: true, + Icon: ExternalLinkIcon, + value: 'connectCursor', + }, + { + label: 'Connect to VS Code', + description: 'Open MCP configurator for VS Code', + showExternalIcon: true, + Icon: ExternalLinkIcon, + value: 'connectVsCode', + }, { label: 'Open in ChatGPT', description: 'Ask questions about this page', @@ -54,6 +75,14 @@ const DROPDOWN_OPTIONS = [ }, ]; +const MCP_CONFIG_JSON = `{ + "mcpServers": { + "apify": { + "url": "https://mcp.apify.com/?tools=docs" + } + } +}`; + const getPrompt = (currentUrl) => `Read from ${currentUrl} so I can ask questions about it.`; const getMarkdownUrl = (currentUrl) => { const url = new URL(currentUrl); @@ -161,6 +190,90 @@ const onCopyAsMarkdownClick = async ({ setCopyingStatus }) => { } }; +const onCopyMcpServerClick = async () => { + if (window.analytics) { + window.analytics.track('Clicked', { + app: 'docs', + button_text: 'Copy MCP server', + element: 'llm-buttons.copyMcpServer', + }); + } + + try { + await navigator.clipboard.writeText(MCP_CONFIG_JSON); + } catch (error) { + console.error('Failed to copy MCP configuration:', error); + } +}; + +const openApifyMcpConfigurator = (integration) => { + try { + window.open(`https://mcp.apify.com/?integration=${integration}`, '_blank'); + } catch (error) { + console.error('Error opening fallback URL:', error); + } +}; + +const openMcpIntegration = async (integration, mcpUrl) => { + // Try to open the app directly using URL scheme + let appUrl; + if (integration === 'cursor') { + // Cursor deeplink format: + // cursor://anysphere.cursor-deeplink/mcp/install?name=$NAME&config=$BASE64_JSON + const cursorConfig = { + url: mcpUrl, + }; + const encodedConfig = btoa(JSON.stringify(cursorConfig)); + appUrl = `cursor://anysphere.cursor-deeplink/mcp/install?name=apify&config=${encodeURIComponent(encodedConfig)}`; + } else if (integration === 'vscode') { + // VS Code deeplink format: vscode:mcp/install? + // JSON structure: {"name":"Apify","type":"http","url":""} + const mcpConfig = { + name: 'Apify', + type: 'http', + url: mcpUrl, + }; + const encodedConfig = encodeURIComponent(JSON.stringify(mcpConfig)); + appUrl = `vscode:mcp/install?${encodedConfig}`; + } + + if (appUrl) { + try { + window.open(appUrl, '_blank'); + } catch { + // If deeplink fails, fallback to web configurator + openApifyMcpConfigurator(integration); + } + } else { + // Fallback to web configurator + openApifyMcpConfigurator(integration); + } +}; + +const onConnectCursorClick = () => { + if (window.analytics) { + window.analytics.track('Clicked', { + app: 'docs', + button_text: 'Connect to Cursor', + element: 'llm-buttons.connectCursor', + }); + } + + openMcpIntegration('cursor', 'https://mcp.apify.com/?tools=docs'); +}; + +const onConnectVsCodeClick = () => { + if (window.analytics) { + window.analytics.track('Clicked', { + app: 'docs', + button_text: 'Connect to VS Code', + element: 'llm-buttons.connectVsCode', + }); + } + + openMcpIntegration('vscode', 'https://mcp.apify.com/?tools=docs'); +}; + const onViewAsMarkdownClick = () => { if (window.analytics) { window.analytics.track('Clicked', { @@ -257,6 +370,15 @@ export default function LLMButtons({ isApiReferencePage = false }) { case 'viewAsMarkdown': onViewAsMarkdownClick(); break; + case 'copyMcpServer': + onCopyMcpServerClick(); + break; + case 'connectCursor': + onConnectCursorClick(); + break; + case 'connectVsCode': + onConnectVsCodeClick(); + break; case 'openInChatGPT': onOpenInChatGPTClick(); break; @@ -277,9 +399,9 @@ export default function LLMButtons({ isApiReferencePage = false }) { [styles.llmMenuApiReferencePage]: isApiReferencePage, })} onMenuOpen={(isOpen) => chevronIconRef.current?.classList.toggle( - styles.chevronIconOpen, - isOpen, - ) + styles.chevronIconOpen, + isOpen, + ) } components={{ MenuBase: (props) => ( From 0eab3e5b2443ac9062beb46d262aae01753f92ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20Biro=C5=A1?= Date: Mon, 22 Dec 2025 13:21:46 +0100 Subject: [PATCH 2/5] fix: code optimisation --- apify-docs-theme/src/theme/LLMButtons/index.jsx | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/apify-docs-theme/src/theme/LLMButtons/index.jsx b/apify-docs-theme/src/theme/LLMButtons/index.jsx index 064527c321..1ea2cbeb33 100644 --- a/apify-docs-theme/src/theme/LLMButtons/index.jsx +++ b/apify-docs-theme/src/theme/LLMButtons/index.jsx @@ -227,7 +227,6 @@ const openMcpIntegration = async (integration, mcpUrl) => { appUrl = `cursor://anysphere.cursor-deeplink/mcp/install?name=apify&config=${encodeURIComponent(encodedConfig)}`; } else if (integration === 'vscode') { // VS Code deeplink format: vscode:mcp/install? - // JSON structure: {"name":"Apify","type":"http","url":""} const mcpConfig = { name: 'Apify', type: 'http', @@ -238,16 +237,11 @@ const openMcpIntegration = async (integration, mcpUrl) => { } if (appUrl) { - try { - window.open(appUrl, '_blank'); - } catch { - // If deeplink fails, fallback to web configurator - openApifyMcpConfigurator(integration); - } - } else { - // Fallback to web configurator - openApifyMcpConfigurator(integration); + window.open(appUrl, '_blank'); + return; } + // Fallback to web configurator + openApifyMcpConfigurator(integration); }; const onConnectCursorClick = () => { From a90f31d9ef648eb8dcb93a8a7c27da6e31c3306f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20Biro=C5=A1?= Date: Mon, 22 Dec 2025 13:29:28 +0100 Subject: [PATCH 3/5] fix: code cleanup --- .../src/theme/LLMButtons/index.jsx | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/apify-docs-theme/src/theme/LLMButtons/index.jsx b/apify-docs-theme/src/theme/LLMButtons/index.jsx index 1ea2cbeb33..212a6e8e08 100644 --- a/apify-docs-theme/src/theme/LLMButtons/index.jsx +++ b/apify-docs-theme/src/theme/LLMButtons/index.jsx @@ -75,10 +75,12 @@ const DROPDOWN_OPTIONS = [ }, ]; +const MCP_SERVER_URL = 'https://mcp.apify.com/?tools=docs'; + const MCP_CONFIG_JSON = `{ "mcpServers": { "apify": { - "url": "https://mcp.apify.com/?tools=docs" + "url": "${MCP_SERVER_URL}" } } }`; @@ -214,14 +216,14 @@ const openApifyMcpConfigurator = (integration) => { } }; -const openMcpIntegration = async (integration, mcpUrl) => { +const openMcpIntegration = async (integration) => { // Try to open the app directly using URL scheme let appUrl; if (integration === 'cursor') { // Cursor deeplink format: // cursor://anysphere.cursor-deeplink/mcp/install?name=$NAME&config=$BASE64_JSON const cursorConfig = { - url: mcpUrl, + url: MCP_SERVER_URL, }; const encodedConfig = btoa(JSON.stringify(cursorConfig)); appUrl = `cursor://anysphere.cursor-deeplink/mcp/install?name=apify&config=${encodeURIComponent(encodedConfig)}`; @@ -230,17 +232,20 @@ const openMcpIntegration = async (integration, mcpUrl) => { const mcpConfig = { name: 'Apify', type: 'http', - url: mcpUrl, + url: MCP_SERVER_URL, }; const encodedConfig = encodeURIComponent(JSON.stringify(mcpConfig)); appUrl = `vscode:mcp/install?${encodedConfig}`; } if (appUrl) { - window.open(appUrl, '_blank'); - return; + const openedWindow = window.open(appUrl, '_blank'); + + if (openedWindow) { + return; + } } - // Fallback to web configurator + // Fallback to web configurator if appUrl doesn't exist or window.open failed openApifyMcpConfigurator(integration); }; @@ -253,7 +258,7 @@ const onConnectCursorClick = () => { }); } - openMcpIntegration('cursor', 'https://mcp.apify.com/?tools=docs'); + openMcpIntegration('cursor'); }; const onConnectVsCodeClick = () => { @@ -265,7 +270,7 @@ const onConnectVsCodeClick = () => { }); } - openMcpIntegration('vscode', 'https://mcp.apify.com/?tools=docs'); + openMcpIntegration('vscode'); }; const onViewAsMarkdownClick = () => { From 6dd473253d923336b160fb0eba921371aaea0fe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20Biro=C5=A1?= Date: Mon, 22 Dec 2025 13:41:24 +0100 Subject: [PATCH 4/5] feat: Add correct MCP icon --- apify-docs-theme/src/theme/LLMButtons/index.jsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apify-docs-theme/src/theme/LLMButtons/index.jsx b/apify-docs-theme/src/theme/LLMButtons/index.jsx index 212a6e8e08..6dd037b2f0 100644 --- a/apify-docs-theme/src/theme/LLMButtons/index.jsx +++ b/apify-docs-theme/src/theme/LLMButtons/index.jsx @@ -10,6 +10,7 @@ import { ExternalLinkIcon, LoaderIcon, MarkdownIcon, + McpIcon, PerplexityIcon, } from '@apify/ui-icons'; import { Menu, Text, theme } from '@apify/ui-library'; @@ -35,13 +36,14 @@ const DROPDOWN_OPTIONS = [ label: 'Copy MCP server', description: 'Copy Apify MCP configuration', showExternalIcon: false, - Icon: CopyIcon, + Icon: McpIcon, value: 'copyMcpServer', }, { label: 'Connect to Cursor', description: 'Open MCP configurator for Cursor', showExternalIcon: true, + // TODO: Replace with CursorIcon - we don't have one yet Icon: ExternalLinkIcon, value: 'connectCursor', }, @@ -49,6 +51,7 @@ const DROPDOWN_OPTIONS = [ label: 'Connect to VS Code', description: 'Open MCP configurator for VS Code', showExternalIcon: true, + // TODO: Replace with VS Code Icon - we don't have one yet Icon: ExternalLinkIcon, value: 'connectVsCode', }, From ea8caf56008580f9205cc7e4930a1af7e3af36e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20Biro=C5=A1?= Date: Tue, 6 Jan 2026 11:10:22 +0100 Subject: [PATCH 5/5] feat(docs): Add VSCode & Cursor icons --- apify-docs-theme/src/theme/LLMButtons/index.jsx | 12 +++++++----- package-lock.json | 9 +++++---- package.json | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/apify-docs-theme/src/theme/LLMButtons/index.jsx b/apify-docs-theme/src/theme/LLMButtons/index.jsx index 6dd037b2f0..688cee078d 100644 --- a/apify-docs-theme/src/theme/LLMButtons/index.jsx +++ b/apify-docs-theme/src/theme/LLMButtons/index.jsx @@ -7,11 +7,13 @@ import { CheckIcon, ChevronDownIcon, CopyIcon, + CursorIcon, ExternalLinkIcon, LoaderIcon, MarkdownIcon, McpIcon, PerplexityIcon, + VscodeIcon, } from '@apify/ui-icons'; import { Menu, Text, theme } from '@apify/ui-library'; @@ -34,25 +36,25 @@ const DROPDOWN_OPTIONS = [ }, { label: 'Copy MCP server', - description: 'Copy Apify MCP configuration', + description: 'Copy MCP Server URL to clipboard', showExternalIcon: false, Icon: McpIcon, value: 'copyMcpServer', }, { label: 'Connect to Cursor', - description: 'Open MCP configurator for Cursor', + description: 'Install MCP Server on Cursor', showExternalIcon: true, // TODO: Replace with CursorIcon - we don't have one yet - Icon: ExternalLinkIcon, + Icon: CursorIcon, value: 'connectCursor', }, { label: 'Connect to VS Code', - description: 'Open MCP configurator for VS Code', + description: 'Install MCP server on VS Code', showExternalIcon: true, // TODO: Replace with VS Code Icon - we don't have one yet - Icon: ExternalLinkIcon, + Icon: VscodeIcon, value: 'connectVsCode', }, { diff --git a/package-lock.json b/package-lock.json index f5f8a1943c..0a4d24bb00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "apify-docs-theme" ], "dependencies": { - "@apify/ui-icons": "^1.19.0", + "@apify/ui-icons": "^1.25.0", "@apify/ui-library": "^1.97.2", "@docusaurus/core": "^3.8.1", "@docusaurus/faster": "^3.8.1", @@ -750,10 +750,11 @@ "dev": true }, "node_modules/@apify/ui-icons": { - "version": "1.24.1", - "resolved": "https://registry.npmjs.org/@apify/ui-icons/-/ui-icons-1.24.1.tgz", - "integrity": "sha512-lnf3D189VjFFAe2/7a2zm04a7NKm6Dd5Fk6oHncLVDkEVph5R0ImvD4NPY08YzvrfZ7s5ewY0WPOOF3rFoMzhw==", + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/@apify/ui-icons/-/ui-icons-1.25.0.tgz", + "integrity": "sha512-kD5ggDePMVz8H7wx5NSuwcP3E/mAy7oBN4ivC9Tuk9S20+LNy0jea7IPEnjLg16rjjfCPynZ2w/2CO/k5aJN0w==", "hasInstallScript": true, + "license": "Apache-2.0", "dependencies": { "clsx": "^2.0.0" }, diff --git a/package.json b/package.json index 771cbc9122..ea0ab83cdf 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ }, "dependencies": { "@apify/ui-library": "^1.97.2", - "@apify/ui-icons": "^1.19.0", + "@apify/ui-icons": "^1.25.0", "@docusaurus/core": "^3.8.1", "@docusaurus/faster": "^3.8.1", "@docusaurus/plugin-client-redirects": "^3.8.1",