Always allow MCP for web (#6462)
* mcp and extension setting disabled + always allow mcp tools on web * fix tests
This commit is contained in:
parent
59b2755810
commit
311a451005
@ -104,7 +104,7 @@ const SettingsMenu = () => {
|
|||||||
title: 'common:mcp-servers',
|
title: 'common:mcp-servers',
|
||||||
route: route.settings.mcp_servers,
|
route: route.settings.mcp_servers,
|
||||||
hasSubMenu: false,
|
hasSubMenu: false,
|
||||||
isEnabled: PlatformFeatures[PlatformFeature.MCP_SERVERS],
|
isEnabled: PlatformFeatures[PlatformFeature.MCP_SERVERS_SETTINGS],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'common:local_api_server',
|
title: 'common:local_api_server',
|
||||||
@ -122,7 +122,7 @@ const SettingsMenu = () => {
|
|||||||
title: 'common:extensions',
|
title: 'common:extensions',
|
||||||
route: route.settings.extensions,
|
route: route.settings.extensions,
|
||||||
hasSubMenu: false,
|
hasSubMenu: false,
|
||||||
isEnabled: PlatformFeatures[PlatformFeature.EXTENSION_MANAGEMENT],
|
isEnabled: PlatformFeatures[PlatformFeature.EXTENSIONS_SETTINGS],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import { create } from 'zustand'
|
import { create } from 'zustand'
|
||||||
import { persist, createJSONStorage } from 'zustand/middleware'
|
import { persist, createJSONStorage } from 'zustand/middleware'
|
||||||
import { localStorageKey } from '@/constants/localStorage'
|
import { localStorageKey } from '@/constants/localStorage'
|
||||||
|
import { PlatformFeatures } from '@/lib/platform/const'
|
||||||
|
import { PlatformFeature } from '@/lib/platform/types'
|
||||||
|
|
||||||
export type ToolApprovalModalProps = {
|
export type ToolApprovalModalProps = {
|
||||||
toolName: string
|
toolName: string
|
||||||
@ -32,7 +34,7 @@ export const useToolApproval = create<ToolApprovalState>()(
|
|||||||
persist(
|
persist(
|
||||||
(set, get) => ({
|
(set, get) => ({
|
||||||
approvedTools: {},
|
approvedTools: {},
|
||||||
allowAllMCPPermissions: false,
|
allowAllMCPPermissions: PlatformFeatures[PlatformFeature.MCP_AUTO_APPROVE_TOOLS],
|
||||||
isModalOpen: false,
|
isModalOpen: false,
|
||||||
modalProps: null,
|
modalProps: null,
|
||||||
|
|
||||||
@ -55,6 +57,12 @@ export const useToolApproval = create<ToolApprovalState>()(
|
|||||||
|
|
||||||
showApprovalModal: (toolName: string, threadId: string, toolParameters?: object) => {
|
showApprovalModal: (toolName: string, threadId: string, toolParameters?: object) => {
|
||||||
return new Promise<boolean>((resolve) => {
|
return new Promise<boolean>((resolve) => {
|
||||||
|
// Auto-approve MCP tools when feature is enabled
|
||||||
|
if (PlatformFeatures[PlatformFeature.MCP_AUTO_APPROVE_TOOLS]) {
|
||||||
|
resolve(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Check if tool is already approved for this thread
|
// Check if tool is already approved for this thread
|
||||||
const state = get()
|
const state = get()
|
||||||
if (state.isToolApproved(threadId, toolName)) {
|
if (state.isToolApproved(threadId, toolName)) {
|
||||||
|
|||||||
@ -14,15 +14,9 @@ export const PlatformFeatures: Record<PlatformFeature, boolean> = {
|
|||||||
// Hardware monitoring and GPU usage
|
// Hardware monitoring and GPU usage
|
||||||
[PlatformFeature.HARDWARE_MONITORING]: isPlatformTauri(),
|
[PlatformFeature.HARDWARE_MONITORING]: isPlatformTauri(),
|
||||||
|
|
||||||
// Extension installation/management
|
|
||||||
[PlatformFeature.EXTENSION_MANAGEMENT]: true,
|
|
||||||
|
|
||||||
// Local model inference (llama.cpp)
|
// Local model inference (llama.cpp)
|
||||||
[PlatformFeature.LOCAL_INFERENCE]: isPlatformTauri(),
|
[PlatformFeature.LOCAL_INFERENCE]: isPlatformTauri(),
|
||||||
|
|
||||||
// MCP (Model Context Protocol) servers
|
|
||||||
[PlatformFeature.MCP_SERVERS]: true,
|
|
||||||
|
|
||||||
// Local API server
|
// Local API server
|
||||||
[PlatformFeature.LOCAL_API_SERVER]: isPlatformTauri(),
|
[PlatformFeature.LOCAL_API_SERVER]: isPlatformTauri(),
|
||||||
|
|
||||||
@ -46,4 +40,13 @@ export const PlatformFeatures: Record<PlatformFeature, boolean> = {
|
|||||||
|
|
||||||
// Model provider settings page management - disabled for web only
|
// Model provider settings page management - disabled for web only
|
||||||
[PlatformFeature.MODEL_PROVIDER_SETTINGS]: isPlatformTauri(),
|
[PlatformFeature.MODEL_PROVIDER_SETTINGS]: isPlatformTauri(),
|
||||||
|
|
||||||
|
// Auto-enable MCP tool permissions - enabled for web platform
|
||||||
|
[PlatformFeature.MCP_AUTO_APPROVE_TOOLS]: !isPlatformTauri(),
|
||||||
|
|
||||||
|
// MCP servers settings page - disabled for web
|
||||||
|
[PlatformFeature.MCP_SERVERS_SETTINGS]: isPlatformTauri(),
|
||||||
|
|
||||||
|
// Extensions settings page - disabled for web
|
||||||
|
[PlatformFeature.EXTENSIONS_SETTINGS]: isPlatformTauri(),
|
||||||
}
|
}
|
||||||
@ -16,15 +16,9 @@ export enum PlatformFeature {
|
|||||||
// Hardware monitoring and GPU usage
|
// Hardware monitoring and GPU usage
|
||||||
HARDWARE_MONITORING = 'hardwareMonitoring',
|
HARDWARE_MONITORING = 'hardwareMonitoring',
|
||||||
|
|
||||||
// Extension installation/management
|
|
||||||
EXTENSION_MANAGEMENT = 'extensionManagement',
|
|
||||||
|
|
||||||
// Local model inference (llama.cpp)
|
// Local model inference (llama.cpp)
|
||||||
LOCAL_INFERENCE = 'localInference',
|
LOCAL_INFERENCE = 'localInference',
|
||||||
|
|
||||||
// MCP (Model Context Protocol) servers
|
|
||||||
MCP_SERVERS = 'mcpServers',
|
|
||||||
|
|
||||||
// Local API server
|
// Local API server
|
||||||
LOCAL_API_SERVER = 'localApiServer',
|
LOCAL_API_SERVER = 'localApiServer',
|
||||||
|
|
||||||
@ -48,4 +42,13 @@ export enum PlatformFeature {
|
|||||||
|
|
||||||
// Model provider settings page management
|
// Model provider settings page management
|
||||||
MODEL_PROVIDER_SETTINGS = 'modelProviderSettings',
|
MODEL_PROVIDER_SETTINGS = 'modelProviderSettings',
|
||||||
|
|
||||||
|
// Auto-enable MCP tool permissions without approval
|
||||||
|
MCP_AUTO_APPROVE_TOOLS = 'mcpAutoApproveTools',
|
||||||
|
|
||||||
|
// MCP servers settings page management
|
||||||
|
MCP_SERVERS_SETTINGS = 'mcpServersSettings',
|
||||||
|
|
||||||
|
// Extensions settings page management
|
||||||
|
EXTENSIONS_SETTINGS = 'extensionsSettings',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,7 +18,7 @@ export const Route = createFileRoute(route.settings.extensions as any)({
|
|||||||
|
|
||||||
function Extensions() {
|
function Extensions() {
|
||||||
return (
|
return (
|
||||||
<PlatformGuard feature={PlatformFeature.EXTENSION_MANAGEMENT}>
|
<PlatformGuard feature={PlatformFeature.EXTENSIONS_SETTINGS}>
|
||||||
<ExtensionsContent />
|
<ExtensionsContent />
|
||||||
</PlatformGuard>
|
</PlatformGuard>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -23,8 +23,6 @@ import { useTranslation } from '@/i18n/react-i18next-compat'
|
|||||||
import { useAppState } from '@/hooks/useAppState'
|
import { useAppState } from '@/hooks/useAppState'
|
||||||
import { PlatformGuard } from '@/lib/platform/PlatformGuard'
|
import { PlatformGuard } from '@/lib/platform/PlatformGuard'
|
||||||
import { PlatformFeature } from '@/lib/platform'
|
import { PlatformFeature } from '@/lib/platform'
|
||||||
import { isPlatformTauri } from '@/lib/platform/utils'
|
|
||||||
import { MCPTool } from '@janhq/core'
|
|
||||||
|
|
||||||
// Function to mask sensitive values
|
// Function to mask sensitive values
|
||||||
const maskSensitiveValue = (value: string) => {
|
const maskSensitiveValue = (value: string) => {
|
||||||
@ -92,118 +90,12 @@ export const Route = createFileRoute(route.settings.mcp_servers as any)({
|
|||||||
|
|
||||||
function MCPServers() {
|
function MCPServers() {
|
||||||
return (
|
return (
|
||||||
<PlatformGuard feature={PlatformFeature.MCP_SERVERS}>
|
<PlatformGuard feature={PlatformFeature.MCP_SERVERS_SETTINGS}>
|
||||||
{isPlatformTauri() ? <MCPServersDesktop /> : <MCPServersWeb />}
|
<MCPServersDesktop />
|
||||||
</PlatformGuard>
|
</PlatformGuard>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Web version of MCP servers - simpler UI without server management
|
|
||||||
function MCPServersWeb() {
|
|
||||||
const { t } = useTranslation()
|
|
||||||
const serviceHub = useServiceHub()
|
|
||||||
const { allowAllMCPPermissions, setAllowAllMCPPermissions } = useToolApproval()
|
|
||||||
|
|
||||||
const [webMcpTools, setWebMcpTools] = useState<MCPTool[]>([])
|
|
||||||
const [webMcpServers, setWebMcpServers] = useState<string[]>([])
|
|
||||||
const [webMcpLoading, setWebMcpLoading] = useState(true)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
async function loadWebMcpData() {
|
|
||||||
setWebMcpLoading(true)
|
|
||||||
try {
|
|
||||||
const [tools, servers] = await Promise.all([
|
|
||||||
serviceHub.mcp().getTools(),
|
|
||||||
serviceHub.mcp().getConnectedServers(),
|
|
||||||
])
|
|
||||||
setWebMcpTools(tools)
|
|
||||||
setWebMcpServers(servers)
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to load web MCP data:', error)
|
|
||||||
setWebMcpTools([])
|
|
||||||
setWebMcpServers([])
|
|
||||||
} finally {
|
|
||||||
setWebMcpLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
loadWebMcpData()
|
|
||||||
}, [serviceHub])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col h-full">
|
|
||||||
<HeaderPage>
|
|
||||||
<h1 className="font-medium">{t('common:settings')}</h1>
|
|
||||||
</HeaderPage>
|
|
||||||
<div className="flex h-full w-full">
|
|
||||||
<SettingsMenu />
|
|
||||||
<div className="p-4 w-full h-[calc(100%-32px)] overflow-y-auto">
|
|
||||||
<div className="flex flex-col justify-between gap-4 gap-y-3 w-full">
|
|
||||||
<Card
|
|
||||||
header={
|
|
||||||
<div className="flex flex-col mb-4">
|
|
||||||
<h1 className="text-main-view-fg font-medium text-base">
|
|
||||||
{t('mcp-servers:title')}
|
|
||||||
</h1>
|
|
||||||
<p className="text-sm text-main-view-fg/70 mt-1">
|
|
||||||
MCP tools are automatically available in your chat sessions
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<CardItem
|
|
||||||
title={t('mcp-servers:allowPermissions')}
|
|
||||||
description={t('mcp-servers:allowPermissionsDesc')}
|
|
||||||
actions={
|
|
||||||
<div className="flex-shrink-0 ml-4">
|
|
||||||
<Switch
|
|
||||||
checked={allowAllMCPPermissions}
|
|
||||||
onCheckedChange={setAllowAllMCPPermissions}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Card>
|
|
||||||
|
|
||||||
<Card>
|
|
||||||
<CardItem
|
|
||||||
title="MCP Service Status"
|
|
||||||
description={
|
|
||||||
webMcpLoading
|
|
||||||
? "Loading MCP service status..."
|
|
||||||
: webMcpServers.length > 0
|
|
||||||
? `Connected to ${webMcpServers.join(', ')}. ${webMcpTools.length} tools available.`
|
|
||||||
: "MCP service not connected"
|
|
||||||
}
|
|
||||||
descriptionOutside={
|
|
||||||
webMcpTools.length > 0 && !webMcpLoading && (
|
|
||||||
<div className="mt-2">
|
|
||||||
<h4 className="text-sm font-medium text-main-view-fg/80 mb-2">Available Tools:</h4>
|
|
||||||
<div className="grid grid-cols-1 gap-2">
|
|
||||||
{webMcpTools.map((tool) => (
|
|
||||||
<div key={tool.name} className="flex items-start gap-2 p-2 bg-main-view-fg/5 rounded">
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="font-medium text-sm">{tool.name}</div>
|
|
||||||
<div className="text-xs text-main-view-fg/70">{tool.description}</div>
|
|
||||||
{tool.server && (
|
|
||||||
<div className="text-xs text-main-view-fg/50 mt-1">Server: {tool.server}</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Desktop version of MCP servers - full server management capabilities
|
|
||||||
function MCPServersDesktop() {
|
function MCPServersDesktop() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const serviceHub = useServiceHub()
|
const serviceHub = useServiceHub()
|
||||||
@ -351,10 +243,12 @@ function MCPServersDesktop() {
|
|||||||
setLoadingServers((prev) => ({ ...prev, [serverKey]: true }))
|
setLoadingServers((prev) => ({ ...prev, [serverKey]: true }))
|
||||||
const config = getServerConfig(serverKey)
|
const config = getServerConfig(serverKey)
|
||||||
if (active && config) {
|
if (active && config) {
|
||||||
serviceHub.mcp().activateMCPServer(serverKey, {
|
serviceHub
|
||||||
...(config ?? (mcpServers[serverKey] as MCPServerConfig)),
|
.mcp()
|
||||||
active,
|
.activateMCPServer(serverKey, {
|
||||||
})
|
...(config ?? (mcpServers[serverKey] as MCPServerConfig)),
|
||||||
|
active,
|
||||||
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// Save single server
|
// Save single server
|
||||||
editServer(serverKey, {
|
editServer(serverKey, {
|
||||||
@ -388,10 +282,13 @@ function MCPServersDesktop() {
|
|||||||
active,
|
active,
|
||||||
})
|
})
|
||||||
syncServers()
|
syncServers()
|
||||||
serviceHub.mcp().deactivateMCPServer(serverKey).finally(() => {
|
serviceHub
|
||||||
serviceHub.mcp().getConnectedServers().then(setConnectedServers)
|
.mcp()
|
||||||
setLoadingServers((prev) => ({ ...prev, [serverKey]: false }))
|
.deactivateMCPServer(serverKey)
|
||||||
})
|
.finally(() => {
|
||||||
|
serviceHub.mcp().getConnectedServers().then(setConnectedServers)
|
||||||
|
setLoadingServers((prev) => ({ ...prev, [serverKey]: false }))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,17 +11,18 @@ expect.extend(matchers)
|
|||||||
vi.mock('@/lib/platform/const', () => ({
|
vi.mock('@/lib/platform/const', () => ({
|
||||||
PlatformFeatures: {
|
PlatformFeatures: {
|
||||||
hardwareMonitoring: true,
|
hardwareMonitoring: true,
|
||||||
extensionManagement: true,
|
|
||||||
localInference: true,
|
localInference: true,
|
||||||
mcpServers: true,
|
|
||||||
localApiServer: true,
|
localApiServer: true,
|
||||||
modelHub: true,
|
modelHub: true,
|
||||||
systemIntegrations: true,
|
systemIntegrations: true,
|
||||||
httpsProxy: true,
|
httpsProxy: true,
|
||||||
defaultProviders: true,
|
defaultProviders: true,
|
||||||
analytics: true,
|
analytics: true,
|
||||||
webAutoModelSelection: true,
|
webAutoModelSelection: false,
|
||||||
modelProviderSettings: true,
|
modelProviderSettings: true,
|
||||||
|
mcpAutoApproveTools: false,
|
||||||
|
mcpServersSettings: true,
|
||||||
|
extensionsSettings: true,
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user