mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-25 00:36:31 +02:00
fix MCP OAuth for all 5 services, add MCP connector edit view
This commit is contained in:
parent
dde1948a5c
commit
dfa40b8801
4 changed files with 53 additions and 16 deletions
|
|
@ -128,7 +128,7 @@ async def connect_mcp_service(
|
||||||
status_code=502,
|
status_code=502,
|
||||||
detail=f"DCR for {svc.name} did not return a client_id.",
|
detail=f"DCR for {svc.name} did not return a client_id.",
|
||||||
)
|
)
|
||||||
elif not svc.supports_dcr and svc.client_id_env:
|
elif svc.client_id_env:
|
||||||
client_id = getattr(config, svc.client_id_env, None)
|
client_id = getattr(config, svc.client_id_env, None)
|
||||||
client_secret = getattr(config, svc.client_secret_env or "", None) or ""
|
client_secret = getattr(config, svc.client_secret_env or "", None) or ""
|
||||||
if not client_id:
|
if not client_id:
|
||||||
|
|
@ -446,7 +446,7 @@ async def reauth_mcp_service(
|
||||||
status_code=502,
|
status_code=502,
|
||||||
detail=f"DCR for {svc.name} did not return a client_id.",
|
detail=f"DCR for {svc.name} did not return a client_id.",
|
||||||
)
|
)
|
||||||
elif not svc.supports_dcr and svc.client_id_env:
|
elif svc.client_id_env:
|
||||||
client_id = getattr(config, svc.client_id_env, None)
|
client_id = getattr(config, svc.client_id_env, None)
|
||||||
client_secret = getattr(config, svc.client_secret_env or "", None) or ""
|
client_secret = getattr(config, svc.client_secret_env or "", None) or ""
|
||||||
if not client_id:
|
if not client_id:
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
"""Registry of MCP services with OAuth 2.1 support.
|
"""Registry of MCP services with OAuth support.
|
||||||
|
|
||||||
Each entry maps a URL-safe service key to its MCP server endpoint and
|
Each entry maps a URL-safe service key to its MCP server endpoint and
|
||||||
authentication strategy. Services with ``supports_dcr=True`` will use
|
authentication configuration. Services with ``supports_dcr=True`` use
|
||||||
RFC 7591 Dynamic Client Registration; the rest require pre-configured
|
RFC 7591 Dynamic Client Registration (the MCP server issues its own
|
||||||
credentials via environment variables.
|
credentials); the rest use pre-configured credentials via env vars.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
@ -65,8 +65,8 @@ MCP_SERVICES: dict[str, MCPServiceConfig] = {
|
||||||
name="Airtable",
|
name="Airtable",
|
||||||
mcp_url="https://mcp.airtable.com/mcp",
|
mcp_url="https://mcp.airtable.com/mcp",
|
||||||
connector_type="AIRTABLE_CONNECTOR",
|
connector_type="AIRTABLE_CONNECTOR",
|
||||||
oauth_discovery_origin="https://airtable.com",
|
|
||||||
supports_dcr=False,
|
supports_dcr=False,
|
||||||
|
oauth_discovery_origin="https://airtable.com",
|
||||||
client_id_env="AIRTABLE_CLIENT_ID",
|
client_id_env="AIRTABLE_CLIENT_ID",
|
||||||
client_secret_env="AIRTABLE_CLIENT_SECRET",
|
client_secret_env="AIRTABLE_CLIENT_SECRET",
|
||||||
scopes=["data.records:read", "data.records:write", "schema.bases:read", "schema.bases:write"],
|
scopes=["data.records:read", "data.records:write", "schema.bases:read", "schema.bases:write"],
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { CheckCircle2 } from "lucide-react";
|
||||||
|
import type { FC } from "react";
|
||||||
|
import type { ConnectorConfigProps } from "../index";
|
||||||
|
|
||||||
|
export const MCPServiceConfig: FC<ConnectorConfigProps> = ({ connector }) => {
|
||||||
|
const serviceName = connector.config?.mcp_service as string | undefined;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="rounded-xl border border-border bg-primary/5 p-4 flex items-start gap-3">
|
||||||
|
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-emerald-500/10 shrink-0 mt-0.5">
|
||||||
|
<CheckCircle2 className="size-4 text-emerald-500" />
|
||||||
|
</div>
|
||||||
|
<div className="text-xs sm:text-sm">
|
||||||
|
<p className="font-medium text-xs sm:text-sm">Connected via MCP</p>
|
||||||
|
<p className="text-muted-foreground mt-1 text-[10px] sm:text-sm">
|
||||||
|
Your agent can search, read, and take actions in{" "}
|
||||||
|
{serviceName
|
||||||
|
? serviceName.charAt(0).toUpperCase() + serviceName.slice(1)
|
||||||
|
: "this service"}{" "}
|
||||||
|
in real time. No background indexing needed.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -17,7 +17,7 @@ import { PeriodicSyncConfig } from "../../components/periodic-sync-config";
|
||||||
import { SummaryConfig } from "../../components/summary-config";
|
import { SummaryConfig } from "../../components/summary-config";
|
||||||
import { VisionLLMConfig } from "../../components/vision-llm-config";
|
import { VisionLLMConfig } from "../../components/vision-llm-config";
|
||||||
import { getConnectorDisplayName } from "../../tabs/all-connectors-tab";
|
import { getConnectorDisplayName } from "../../tabs/all-connectors-tab";
|
||||||
import { getConnectorConfigComponent } from "../index";
|
import { type ConnectorConfigProps, getConnectorConfigComponent } from "../index";
|
||||||
|
|
||||||
const REAUTH_ENDPOINTS: Partial<Record<string, string>> = {
|
const REAUTH_ENDPOINTS: Partial<Record<string, string>> = {
|
||||||
[EnumConnectorName.LINEAR_CONNECTOR]: "/api/v1/auth/linear/connector/reauth",
|
[EnumConnectorName.LINEAR_CONNECTOR]: "/api/v1/auth/linear/connector/reauth",
|
||||||
|
|
@ -118,11 +118,16 @@ export const ConnectorEditView: FC<ConnectorEditViewProps> = ({
|
||||||
}
|
}
|
||||||
}, [searchSpaceId, searchSpaceIdAtom, reauthEndpoint, connector.id]);
|
}, [searchSpaceId, searchSpaceIdAtom, reauthEndpoint, connector.id]);
|
||||||
|
|
||||||
// Get connector-specific config component
|
const isMCPBacked = Boolean(connector.config?.server_config);
|
||||||
const ConnectorConfigComponent = useMemo(
|
|
||||||
() => getConnectorConfigComponent(connector.connector_type),
|
// Get connector-specific config component (MCP-backed connectors use a generic view)
|
||||||
[connector.connector_type]
|
const ConnectorConfigComponent = useMemo(() => {
|
||||||
);
|
if (isMCPBacked) {
|
||||||
|
const { MCPServiceConfig } = require("../components/mcp-service-config");
|
||||||
|
return MCPServiceConfig as FC<ConnectorConfigProps>;
|
||||||
|
}
|
||||||
|
return getConnectorConfigComponent(connector.connector_type);
|
||||||
|
}, [connector.connector_type, isMCPBacked]);
|
||||||
const [isScrolled, setIsScrolled] = useState(false);
|
const [isScrolled, setIsScrolled] = useState(false);
|
||||||
const [hasMoreContent, setHasMoreContent] = useState(false);
|
const [hasMoreContent, setHasMoreContent] = useState(false);
|
||||||
const [showDisconnectConfirm, setShowDisconnectConfirm] = useState(false);
|
const [showDisconnectConfirm, setShowDisconnectConfirm] = useState(false);
|
||||||
|
|
@ -223,7 +228,9 @@ export const ConnectorEditView: FC<ConnectorEditViewProps> = ({
|
||||||
{getConnectorDisplayName(connector.name)}
|
{getConnectorDisplayName(connector.name)}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-xs sm:text-base text-muted-foreground mt-1">
|
<p className="text-xs sm:text-base text-muted-foreground mt-1">
|
||||||
Manage your connector settings and sync configuration
|
{isMCPBacked
|
||||||
|
? "Connected — your agent can interact with this service in real time"
|
||||||
|
: "Manage your connector settings and sync configuration"}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -421,7 +428,7 @@ export const ConnectorEditView: FC<ConnectorEditViewProps> = ({
|
||||||
<RefreshCw className={cn("size-3.5", reauthing && "animate-spin")} />
|
<RefreshCw className={cn("size-3.5", reauthing && "animate-spin")} />
|
||||||
Re-authenticate
|
Re-authenticate
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : !isMCPBacked ? (
|
||||||
<Button
|
<Button
|
||||||
onClick={onSave}
|
onClick={onSave}
|
||||||
disabled={isSaving || isDisconnecting}
|
disabled={isSaving || isDisconnecting}
|
||||||
|
|
@ -430,7 +437,7 @@ export const ConnectorEditView: FC<ConnectorEditViewProps> = ({
|
||||||
<span className={isSaving ? "opacity-0" : ""}>Save Changes</span>
|
<span className={isSaving ? "opacity-0" : ""}>Save Changes</span>
|
||||||
{isSaving && <Spinner size="sm" className="absolute" />}
|
{isSaving && <Spinner size="sm" className="absolute" />}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue