mirror of
https://github.com/voideditor/void
synced 2026-05-23 17:38:23 +00:00
move MCP to settings
This commit is contained in:
parent
72143608a1
commit
18d1f2e6b9
2 changed files with 125 additions and 123 deletions
|
|
@ -1,113 +0,0 @@
|
|||
import { VoidSwitch, VoidButtonBgDarken } from '../util/inputs.js';
|
||||
import { MCPConfigFileParseErrorResponse, MCPServerEventType, MCPServerEventResponse, MCPServerObject, MCPServerOfName } from '../../../../common/mcpServiceTypes.js';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useAccessor, useMCPServiceState } from '../util/services.js';
|
||||
|
||||
|
||||
// MCP Server component
|
||||
const MCPServer = ({ name, server }: { name: string, server: MCPServerObject }) => {
|
||||
|
||||
const accessor = useAccessor();
|
||||
const mcpService = accessor.get('IMCPService');
|
||||
|
||||
const handleChangeEvent = (e: boolean) => {
|
||||
// Handle the change event
|
||||
mcpService.toggleMCPServer(name, e);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="border-b border-gray-800 bg-gray-300/10 py-4 rounded-lg ">
|
||||
<div className="flex items-center mx-4">
|
||||
{/* Status indicator */}
|
||||
<div className={`w-2 h-2 rounded-full mr-2
|
||||
${server.status === 'success' ? 'green-500'
|
||||
: server.status === 'error' ? 'red-500'
|
||||
: server.status === 'loading' ? 'yellow-500'
|
||||
: server.status === 'offline' ? 'gray-500'
|
||||
: ''}
|
||||
|
||||
`}></div>
|
||||
|
||||
{/* Server name */}
|
||||
<div className="text-sm font-medium mr-2">{name}</div>
|
||||
|
||||
{/* Power toggle switch */}
|
||||
<div className="ml-auto">
|
||||
<VoidSwitch
|
||||
value={server.isOn ?? false}
|
||||
disabled={server.status === 'error'}
|
||||
onChange={handleChangeEvent}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tools section */}
|
||||
<div className="mt-1 mx-4">
|
||||
<div className="flex flex-wrap gap-2 max-h-32 overflow-y-auto pb-1">
|
||||
{server.isOn && server.tools.length > 0 ? (
|
||||
server.tools.map((tool) => (
|
||||
<span
|
||||
key={tool.name}
|
||||
className="px-2 py-0.5 bg-black/5 dark:bg-white/5 rounded text-xs"
|
||||
title={tool.description || ''}
|
||||
>
|
||||
{tool.name}
|
||||
</span>
|
||||
))
|
||||
) : (
|
||||
<span className="text-xs text-gray-500">No tools available</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Command badge */}
|
||||
{server.isOn && server.command && (
|
||||
<div className="mt-2 mx-4">
|
||||
<div className="text-xs text-gray-400">Command:</div>
|
||||
<div className="px-2 py-1 bg-void-bg-3 text-xs font-mono overflow-x-auto whitespace-nowrap">
|
||||
{server.command}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Error message if present */}
|
||||
{server.error && (
|
||||
<div className="mt-2 ml-4 text-red-500 flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="mr-1">
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<line x1="12" y1="8" x2="12" y2="12"></line>
|
||||
<line x1="12" y1="16" x2="12.01" y2="16"></line>
|
||||
</svg>
|
||||
{server.error}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Main component that renders the list of servers
|
||||
const MCPServersList = () => {
|
||||
|
||||
const mcpServiceState = useMCPServiceState()
|
||||
const accessor = useAccessor();
|
||||
const mcpService = accessor.get('IMCPService');
|
||||
|
||||
return (
|
||||
<div className="text-white rounded-md py-4">
|
||||
<div>
|
||||
{!mcpServiceState.error && Object.entries(mcpServiceState.mcpServerOfName).map(([name, server]) => (
|
||||
<div className="py-2" key={name}>
|
||||
<MCPServer name={name} server={server} />
|
||||
</div>
|
||||
))}
|
||||
{mcpServiceState.error && (
|
||||
<div className="text-red-500 text-sm font-medium">
|
||||
{mcpServiceState.error}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MCPServersList;
|
||||
|
|
@ -19,7 +19,8 @@ import { ToolApprovalType, toolApprovalTypes } from '../../../../common/toolsSer
|
|||
import Severity from '../../../../../../../base/common/severity.js'
|
||||
import { getModelCapabilities, modelOverrideKeys, ModelOverrides } from '../../../../common/modelCapabilities.js';
|
||||
import { TransferEditorType, TransferFilesInfo } from '../../../extensionTransferTypes.js';
|
||||
import MCPServersList from './MCPServersList.js';
|
||||
import { MCPServerObject } from '../../../../common/mcpServiceTypes.js';
|
||||
import { useMCPServiceState } from '../util/services.js';
|
||||
|
||||
const ButtonLeftTextRightOption = ({ text, leftButton }: { text: string, leftButton?: React.ReactNode }) => {
|
||||
|
||||
|
|
@ -899,6 +900,118 @@ export const OneClickSwitchButton = ({ fromEditor = 'VS Code', className = '' }:
|
|||
|
||||
// full settings
|
||||
|
||||
// MCP Server component
|
||||
const MCPServer = ({ name, server }: { name: string, server: MCPServerObject }) => {
|
||||
const accessor = useAccessor();
|
||||
const mcpService = accessor.get('IMCPService');
|
||||
|
||||
const handleChangeEvent = (e: boolean) => {
|
||||
// Handle the change event
|
||||
mcpService.toggleMCPServer(name, e);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="border-b border-gray-800 bg-gray-300/10 py-4 rounded-lg ">
|
||||
<div className="flex items-center mx-4">
|
||||
{/* Status indicator */}
|
||||
<div className={`w-2 h-2 rounded-full mr-2
|
||||
${server.status === 'success' ? 'green-500'
|
||||
: server.status === 'error' ? 'red-500'
|
||||
: server.status === 'loading' ? 'yellow-500'
|
||||
: server.status === 'offline' ? 'gray-500'
|
||||
: ''}
|
||||
|
||||
`}></div>
|
||||
|
||||
{/* Server name */}
|
||||
<div className="text-sm font-medium mr-2">{name}</div>
|
||||
|
||||
{/* Power toggle switch */}
|
||||
<div className="ml-auto">
|
||||
<VoidSwitch
|
||||
value={server.isOn ?? false}
|
||||
disabled={server.status === 'error'}
|
||||
onChange={handleChangeEvent}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tools section */}
|
||||
<div className="mt-1 mx-4">
|
||||
<div className="flex flex-wrap gap-2 max-h-32 overflow-y-auto pb-1">
|
||||
{server.isOn && server.tools.length > 0 ? (
|
||||
server.tools.map((tool: { name: string; description?: string }) => (
|
||||
<span
|
||||
key={tool.name}
|
||||
className="px-2 py-0.5 bg-black/5 dark:bg-white/5 rounded text-xs"
|
||||
title={tool.description || ''}
|
||||
>
|
||||
{tool.name}
|
||||
</span>
|
||||
))
|
||||
) : (
|
||||
<span className="text-xs text-gray-500">No tools available</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Command badge */}
|
||||
{server.isOn && server.command && (
|
||||
<div className="mt-2 mx-4">
|
||||
<div className="text-xs text-gray-400">Command:</div>
|
||||
<div className="px-2 py-1 bg-void-bg-3 text-xs font-mono overflow-x-auto whitespace-nowrap">
|
||||
{server.command}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Error message if present */}
|
||||
{server.error && (
|
||||
<div className="mt-2 ml-4 text-red-500 flex items-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="mr-1">
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<line x1="12" y1="8" x2="12" y2="12"></line>
|
||||
<line x1="12" y1="16" x2="12.01" y2="16"></line>
|
||||
</svg>
|
||||
{server.error}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Main component that renders the list of servers
|
||||
const MCPServersList = () => {
|
||||
const mcpServiceState = useMCPServiceState()
|
||||
const accessor = useAccessor();
|
||||
const mcpService = accessor.get('IMCPService');
|
||||
|
||||
|
||||
let content: React.ReactNode
|
||||
if (mcpServiceState.error) {
|
||||
content = <div className="text-red-500 text-sm font-medium">
|
||||
{mcpServiceState.error}
|
||||
</div>
|
||||
}
|
||||
else {
|
||||
const entries = Object.entries(mcpServiceState.mcpServerOfName)
|
||||
if (entries.length === 0) {
|
||||
content = <div className="text-red-500 text-sm font-medium">
|
||||
No servers found
|
||||
</div>
|
||||
}
|
||||
else {
|
||||
content = entries.map(([name, server]) => (
|
||||
<div className="py-2" key={name}>
|
||||
<MCPServer name={name} server={server} />
|
||||
</div>
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
return content
|
||||
};
|
||||
|
||||
export const Settings = () => {
|
||||
const isDark = useIsDark()
|
||||
const accessor = useAccessor()
|
||||
|
|
@ -1235,6 +1348,7 @@ export const Settings = () => {
|
|||
|
||||
<div className='mt-12 max-w-[600px]'>
|
||||
<h2 className={`text-3xl mb-2`}>AI Instructions</h2>
|
||||
|
||||
<h4 className={`text-void-fg-3 mb-4`}>
|
||||
<ChatMarkdownRender inPTag={true} string={`
|
||||
System instructions to include with all AI requests.
|
||||
|
|
@ -1247,21 +1361,22 @@ Alternatively, place a \`.voidrules\` file in the root of your workspace.
|
|||
</div>
|
||||
|
||||
<div className='mt-12 max-w-[600px]'>
|
||||
<div className='flex items-center justify-between mb-2'>
|
||||
<h2 className={`text-3xl`}>MCP</h2>
|
||||
<VoidButtonBgDarken className='px-4 py-1' onClick={async () => { await mcpService.revealMCPConfigFile() }}>
|
||||
Add MCP Server
|
||||
</VoidButtonBgDarken>
|
||||
</div>
|
||||
<h2 className='text-3xl mb-2'>MCP</h2>
|
||||
<h4 className={`text-void-fg-3 mb-4`}>
|
||||
<ChatMarkdownRender inPTag={true} string={`
|
||||
Use Model Context Protocol to provide Agent mode with more tools.
|
||||
`} chatMessageLocation={undefined} />
|
||||
</h4>
|
||||
<ErrorBoundary>
|
||||
<MCPServersList />
|
||||
</ErrorBoundary>
|
||||
<div>
|
||||
<VoidButtonBgDarken className='px-4 py-1 mb-2' onClick={async () => { await mcpService.revealMCPConfigFile() }}>
|
||||
Add MCP Server
|
||||
</VoidButtonBgDarken>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ErrorBoundary>
|
||||
<MCPServersList />
|
||||
</ErrorBoundary>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue