From 611468b97232d1332b528bfda0af7f6034101446 Mon Sep 17 00:00:00 2001
From: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
Date: Wed, 10 Jun 2026 14:58:33 +0100
Subject: [PATCH] Add SaaS MCP usage tab (#6590)
---
.../public/locales/en-GB/translation.toml | 54 ++--
.../config/configSections/McpSection.tsx | 262 ++++++++++++++++++
.../shared/config/saasConfigNavSections.tsx | 40 +++
.../saas/components/shared/config/types.ts | 9 +-
.../src/saas/services/apiClient.test.ts | 9 +
5 files changed, 348 insertions(+), 26 deletions(-)
create mode 100644 frontend/editor/src/saas/components/shared/config/configSections/McpSection.tsx
diff --git a/frontend/editor/public/locales/en-GB/translation.toml b/frontend/editor/public/locales/en-GB/translation.toml
index e907cba19..b3f5109ce 100644
--- a/frontend/editor/public/locales/en-GB/translation.toml
+++ b/frontend/editor/public/locales/en-GB/translation.toml
@@ -3049,6 +3049,37 @@ impact = "Any applications or services currently using these keys will stop work
title = "Refresh API Keys"
warning = "⚠️ Warning: This action will generate new API keys and make your previous keys invalid."
+[config.mcp]
+description = "Model Context Protocol (MCP) lets AI assistants like Claude use your Stirling PDF tools directly. Connect a client once and your assistant can convert, edit, secure and process documents on your behalf."
+navLabel = "MCP Server"
+tip = "Every action your assistant runs is performed as your account and counts towards your usage, just like using Stirling PDF directly."
+title = "MCP Server"
+viewApiKeys = "View API keys"
+
+[config.mcp.copy]
+configLabel = "Config"
+copied = "Copied"
+copy = "Copy"
+endpointLabel = "Endpoint URL"
+tooltip = "Copy {{label}}"
+tooltipCopied = "{{label}} copied"
+
+[config.mcp.endpoint]
+label = "Your MCP endpoint"
+
+[config.mcp.setup]
+addTo = "Add to"
+hint = "Pick your client, paste the snippet into the file shown, then restart it. You'll sign in with your Stirling account on first use - no keys to copy."
+title = "Connect your AI assistant"
+
+[config.mcp.tools]
+ai = "AI"
+convert = "Convert"
+misc = "Misc"
+pages = "Pages"
+security = "Security"
+title = "What your assistant can do"
+
[config.overview]
description = "Current application settings and configuration details."
error = "Error"
@@ -3210,7 +3241,6 @@ creditsRemaining = "{{current}} of {{total}} remaining"
creditsThisMonth = "Monthly credits"
current = "Current Plan"
customPricing = "Custom"
-customWatchedFolders = "Custom Watched Folders"
dedicatedSupportSlas = "Dedicated support & SLAs"
enterpriseSubscription = "Enterprise"
everythingInCredits = "Everything in Credits, plus:"
@@ -3518,7 +3548,6 @@ addFiles = "Add Files"
[fileManager]
active = "Active"
-addToWatchedFolder = "Add to Watched Folder"
addToUpload = "Add to Upload"
changesNotUploaded = "Changes not uploaded"
clearAll = "Clear All"
@@ -4563,10 +4592,8 @@ sendResetLink = "Send reset link"
sessionExpired = "Your session has expired. Please sign in again."
createAccount = "Create an account"
signin = "Sign in"
-signInAnonymously = "Sign Up as a Guest"
signingIn = "Signing in..."
signInWith = "Sign in with"
-subtitle = "Sign back in to Stirling PDF"
title = "Sign in"
unexpectedError = "Unexpected error: {{message}}"
updatePassword = "Update password"
@@ -5782,7 +5809,6 @@ label = "SMTP Username"
[quickAccess]
access = "Access"
-watchedFolders = "Watched Folders"
accessAddPerson = "Add another person"
accessBack = "Back"
accessCopyLink = "Copy link"
@@ -6873,6 +6899,7 @@ createFailed = "Failed to create signing request"
[signup]
accountCreatedSuccessfully = "Account created successfully! You can now sign in."
+alreadyHaveAccount = "I already have an account"
checkEmailConfirmation = "Check your email for a confirmation link to complete your registration."
confirmPassword = "Confirm password"
confirmPasswordPlaceholder = "Confirm password"
@@ -6898,7 +6925,6 @@ skip = "Skip"
subtitle = "Join Stirling PDF to get started"
title = "Create an account"
unexpectedError = "Unexpected error: {{message}}"
-useEmailInstead = "Use Email Instead"
[sizes]
large = "Large"
@@ -8172,20 +8198,14 @@ newFolder = "New folder"
noFolders = "No watched folders yet"
sidebarTitle = "Watched Folders"
title = "Watched Folders"
-sidebarFiles = "My Files"
[watchedFolders.modal]
automation = "Automation"
-automationSaved = "Automation saved"
createFolder = "Create Folder"
-stepsSaved = "Steps saved — click Create Folder to finish"
automationRequired = "Add at least one configured step before saving."
color = "Accent color"
createTitle = "New Watched Folder"
-description = "Description"
-descriptionPlaceholder = "What does this folder do?"
editTitle = "Edit Watched Folder"
-icon = "Icon"
name = "Folder name"
namePlaceholder = "My Watched Folder"
nameRequired = "Folder name is required"
@@ -8193,17 +8213,13 @@ nameTooLong = "Folder name must be 50 characters or less"
saveChanges = "Save Changes"
saveFailed = "Failed to save folder. Please try again."
automationNameFallback = "Watched Folder automation"
-retryLabel = "Auto-retry"
maxRetries = "Max retries"
-maxRetriesDesc = "0 to disable"
retryDelay = "Delay (minutes)"
-outputLabel = "Output"
outputModeVersion = "Replace original?"
outputModeVersionDesc = "Output becomes a new version of the input file rather than a separate file"
outputModeNewDesc = "Output is saved as a new separate file"
outputName = "Output filename prefix"
outputNameSuffix = "Suffix"
-outputNamePlaceholderVersion = "Same as original"
sectionFolder = "Folder"
sectionSourceOutput = "Source & Output"
sectionSteps = "Steps"
@@ -8230,14 +8246,10 @@ positionSuffix = "Suffix"
[watchedFolders.home]
create = "Create your first Watched Folder"
-dropHere = "Drop to process"
editFolder = "Edit folder"
empty = "No watched folders yet"
file = "file"
files = "files"
-openFolder = "Open folder"
-title = "Watched Folders"
-subtitle = "Folders that automatically process PDFs with your configured pipeline"
emptyTitle = "Automate your PDF workflows"
emptyDesc = "Set up a Watched Folder once. Drop PDFs in and they're automatically compressed, OCR'd, split, merged — whatever your pipeline does."
addAnother = "Add another Watched Folder"
@@ -8245,7 +8257,6 @@ addAnotherDesc = "Automatically process files with a new pipeline"
resume = "Resume"
pause = "Pause"
deleteFolder = "Delete folder"
-noSteps = "No automation steps configured"
[watchedFolders.card]
edit = "Edit folder"
@@ -8328,7 +8339,6 @@ previewLoadFailed = "Could not load file preview."
back = "Back"
dismiss = "Dismiss"
retry = "Retry"
-view = "View"
download = "Download"
downloadInput = "Download input"
downloadOutput = "Download output"
diff --git a/frontend/editor/src/saas/components/shared/config/configSections/McpSection.tsx b/frontend/editor/src/saas/components/shared/config/configSections/McpSection.tsx
new file mode 100644
index 000000000..8313fdd12
--- /dev/null
+++ b/frontend/editor/src/saas/components/shared/config/configSections/McpSection.tsx
@@ -0,0 +1,262 @@
+import { useMemo } from "react";
+import { useTranslation } from "react-i18next";
+import {
+ Stack,
+ Paper,
+ Text,
+ Group,
+ Alert,
+ Code,
+ Badge,
+ Button,
+ CopyButton,
+ Tabs,
+ Tooltip,
+ ThemeIcon,
+} from "@mantine/core";
+import LocalIcon from "@app/components/shared/LocalIcon";
+import { useAppConfig } from "@app/contexts/AppConfigContext";
+import { openAppSettings } from "@app/utils/appSettings";
+
+/** Strip a single trailing slash so we can safely append paths. */
+function trimTrailingSlash(url: string): string {
+ return url.endsWith("/") ? url.slice(0, -1) : url;
+}
+
+/** A small copy-to-clipboard button that sits inline next to a URL/snippet. */
+function CopyInline({ value, label }: { value: string; label: string }) {
+ const { t } = useTranslation();
+ return (
+
{mcpUrl}
+ {c.file}
+ {c.config}
+