mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-21 12:51:17 -05:00
Add restart capability to servers
This commit is contained in:
@@ -498,9 +498,9 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case "retryMcpServer": {
|
case "restartMcpServer": {
|
||||||
try {
|
try {
|
||||||
await this.mcpHub?.retryConnection(message.text!)
|
await this.mcpHub?.restartConnection(message.text!)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(`Failed to retry connection for ${message.text}:`, error)
|
console.error(`Failed to retry connection for ${message.text}:`, error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
} from "../../shared/mcp"
|
} from "../../shared/mcp"
|
||||||
import { fileExistsAtPath } from "../../utils/fs"
|
import { fileExistsAtPath } from "../../utils/fs"
|
||||||
import { arePathsEqual } from "../../utils/path"
|
import { arePathsEqual } from "../../utils/path"
|
||||||
|
import delay from "delay"
|
||||||
|
|
||||||
export type McpConnection = {
|
export type McpConnection = {
|
||||||
server: McpServer
|
server: McpServer
|
||||||
@@ -121,7 +122,7 @@ export class McpHub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async connectToServer(name: string, config: StdioServerParameters): Promise<void> {
|
private async connectToServer(name: string, config: StdioServerParameters): Promise<void> {
|
||||||
// Remove existing connection if it exists
|
// Remove existing connection if it exists (should never happen, the connection should be deleted beforehand)
|
||||||
this.connections = this.connections.filter((conn) => conn.server.name !== name)
|
this.connections = this.connections.filter((conn) => conn.server.name !== name)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -176,7 +177,6 @@ export class McpHub {
|
|||||||
transport,
|
transport,
|
||||||
}
|
}
|
||||||
this.connections.push(connection)
|
this.connections.push(connection)
|
||||||
await this.notifyWebviewOfServerChanges()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,8 +219,6 @@ export class McpHub {
|
|||||||
connection.server.tools = await this.fetchToolsList(name)
|
connection.server.tools = await this.fetchToolsList(name)
|
||||||
connection.server.resources = await this.fetchResourcesList(name)
|
connection.server.resources = await this.fetchResourcesList(name)
|
||||||
connection.server.resourceTemplates = await this.fetchResourceTemplatesList(name)
|
connection.server.resourceTemplates = await this.fetchResourceTemplatesList(name)
|
||||||
|
|
||||||
await this.notifyWebviewOfServerChanges()
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Update status with error
|
// Update status with error
|
||||||
const connection = this.connections.find((conn) => conn.server.name === name)
|
const connection = this.connections.find((conn) => conn.server.name === name)
|
||||||
@@ -228,7 +226,6 @@ export class McpHub {
|
|||||||
connection.server.status = "disconnected"
|
connection.server.status = "disconnected"
|
||||||
connection.server.error = error instanceof Error ? error.message : String(error)
|
connection.server.error = error instanceof Error ? error.message : String(error)
|
||||||
}
|
}
|
||||||
await this.notifyWebviewOfServerChanges()
|
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,7 +278,6 @@ export class McpHub {
|
|||||||
console.error(`Failed to close transport for ${name}:`, error)
|
console.error(`Failed to close transport for ${name}:`, error)
|
||||||
}
|
}
|
||||||
this.connections = this.connections.filter((conn) => conn.server.name !== name)
|
this.connections = this.connections.filter((conn) => conn.server.name !== name)
|
||||||
await this.notifyWebviewOfServerChanges()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,10 +317,11 @@ export class McpHub {
|
|||||||
}
|
}
|
||||||
// If server exists with same config, do nothing
|
// If server exists with same config, do nothing
|
||||||
}
|
}
|
||||||
|
await this.notifyWebviewOfServerChanges()
|
||||||
this.isConnecting = false
|
this.isConnecting = false
|
||||||
}
|
}
|
||||||
|
|
||||||
async retryConnection(serverName: string): Promise<void> {
|
async restartConnection(serverName: string): Promise<void> {
|
||||||
this.isConnecting = true
|
this.isConnecting = true
|
||||||
const provider = this.providerRef.deref()
|
const provider = this.providerRef.deref()
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
@@ -335,6 +332,10 @@ export class McpHub {
|
|||||||
const connection = this.connections.find((conn) => conn.server.name === serverName)
|
const connection = this.connections.find((conn) => conn.server.name === serverName)
|
||||||
const config = connection?.server.config
|
const config = connection?.server.config
|
||||||
if (config) {
|
if (config) {
|
||||||
|
connection.server.status = "connecting"
|
||||||
|
await this.notifyWebviewOfServerChanges()
|
||||||
|
await delay(500) // artificial delay to show user that server is restarting
|
||||||
|
await this.deleteConnection(serverName)
|
||||||
// Try to connect again using existing config
|
// Try to connect again using existing config
|
||||||
await this.connectToServer(serverName, JSON.parse(config))
|
await this.connectToServer(serverName, JSON.parse(config))
|
||||||
}
|
}
|
||||||
@@ -344,9 +345,20 @@ export class McpHub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async notifyWebviewOfServerChanges(): Promise<void> {
|
private async notifyWebviewOfServerChanges(): Promise<void> {
|
||||||
|
// servers should always be sorted in the order they are defined in the settings file
|
||||||
|
const settingsPath = await this.getMcpSettingsFilePath()
|
||||||
|
const content = await fs.readFile(settingsPath, "utf-8")
|
||||||
|
const config = JSON.parse(content)
|
||||||
|
const serverOrder = Object.keys(config.mcpServers || {})
|
||||||
await this.providerRef.deref()?.postMessageToWebview({
|
await this.providerRef.deref()?.postMessageToWebview({
|
||||||
type: "mcpServers",
|
type: "mcpServers",
|
||||||
mcpServers: this.connections.map((connection) => connection.server),
|
mcpServers: [...this.connections]
|
||||||
|
.sort((a, b) => {
|
||||||
|
const indexA = serverOrder.indexOf(a.server.name)
|
||||||
|
const indexB = serverOrder.indexOf(b.server.name)
|
||||||
|
return indexA - indexB
|
||||||
|
})
|
||||||
|
.map((connection) => connection.server),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export interface WebviewMessage {
|
|||||||
| "cancelTask"
|
| "cancelTask"
|
||||||
| "refreshOpenRouterModels"
|
| "refreshOpenRouterModels"
|
||||||
| "openMcpSettings"
|
| "openMcpSettings"
|
||||||
| "retryMcpServer"
|
| "restartMcpServer"
|
||||||
text?: string
|
text?: string
|
||||||
askResponse?: ClineAskResponse
|
askResponse?: ClineAskResponse
|
||||||
apiConfiguration?: ApiConfiguration
|
apiConfiguration?: ApiConfiguration
|
||||||
|
|||||||
@@ -820,12 +820,12 @@ export const ChatRowContent = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{useMcpServer.arguments && (
|
{useMcpServer.arguments && (
|
||||||
<div style={{ marginTop: "6px" }}>
|
<div style={{ marginTop: "8px" }}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
marginBottom: "4px",
|
marginBottom: "4px",
|
||||||
opacity: 0.8,
|
opacity: 0.8,
|
||||||
fontSize: "11px",
|
fontSize: "12px",
|
||||||
textTransform: "uppercase",
|
textTransform: "uppercase",
|
||||||
}}>
|
}}>
|
||||||
Arguments
|
Arguments
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const McpResourceRow = ({ item }: McpResourceRowProps) => {
|
|||||||
<div
|
<div
|
||||||
key={uri}
|
key={uri}
|
||||||
style={{
|
style={{
|
||||||
padding: "3px 0 8px 0",
|
padding: "3px 0",
|
||||||
}}>
|
}}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ const McpToolRow = ({ tool }: McpToolRowProps) => {
|
|||||||
<div
|
<div
|
||||||
key={tool.name}
|
key={tool.name}
|
||||||
style={{
|
style={{
|
||||||
padding: "3px 0 8px 0",
|
padding: "3px 0",
|
||||||
}}>
|
}}>
|
||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex" }}>
|
||||||
<span className="codicon codicon-symbol-method" style={{ marginRight: "6px" }}></span>
|
<span className="codicon codicon-symbol-method" style={{ marginRight: "6px" }}></span>
|
||||||
|
|||||||
@@ -150,9 +150,9 @@ const ServerRow = ({ server }: { server: McpServer }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleRetry = () => {
|
const handleRestart = () => {
|
||||||
vscode.postMessage({
|
vscode.postMessage({
|
||||||
type: "retryMcpServer",
|
type: "restartMcpServer",
|
||||||
text: server.name,
|
text: server.name,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -196,9 +196,11 @@ const ServerRow = ({ server }: { server: McpServer }) => {
|
|||||||
borderRadius: "0 0 4px 4px",
|
borderRadius: "0 0 4px 4px",
|
||||||
}}>
|
}}>
|
||||||
<div style={{ color: "var(--vscode-testing-iconFailed)", marginBottom: "8px" }}>{server.error}</div>
|
<div style={{ color: "var(--vscode-testing-iconFailed)", marginBottom: "8px" }}>{server.error}</div>
|
||||||
<VSCodeButton appearance="secondary" onClick={handleRetry}>
|
<VSCodeButton
|
||||||
<span className="codicon codicon-debug-restart" style={{ marginRight: "6px" }}></span>
|
appearance="secondary"
|
||||||
Retry Connection
|
onClick={handleRestart}
|
||||||
|
disabled={server.status === "connecting"}>
|
||||||
|
{server.status === "connecting" ? "Retrying..." : "Retry Connection"}
|
||||||
</VSCodeButton>
|
</VSCodeButton>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -206,7 +208,7 @@ const ServerRow = ({ server }: { server: McpServer }) => {
|
|||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
background: "var(--vscode-textCodeBlock-background)",
|
background: "var(--vscode-textCodeBlock-background)",
|
||||||
padding: "0 12px 0 12px",
|
padding: "0 12px 12px 12px",
|
||||||
fontSize: "13px",
|
fontSize: "13px",
|
||||||
borderRadius: "0 0 4px 4px",
|
borderRadius: "0 0 4px 4px",
|
||||||
}}>
|
}}>
|
||||||
@@ -217,7 +219,7 @@ const ServerRow = ({ server }: { server: McpServer }) => {
|
|||||||
<VSCodePanelView id="tools-view">
|
<VSCodePanelView id="tools-view">
|
||||||
{server.tools && server.tools.length > 0 ? (
|
{server.tools && server.tools.length > 0 ? (
|
||||||
<div
|
<div
|
||||||
style={{ display: "flex", flexDirection: "column", gap: "6px", width: "100%" }}>
|
style={{ display: "flex", flexDirection: "column", gap: "8px", width: "100%" }}>
|
||||||
{server.tools.map((tool) => (
|
{server.tools.map((tool) => (
|
||||||
<McpToolRow key={tool.name} tool={tool} />
|
<McpToolRow key={tool.name} tool={tool} />
|
||||||
))}
|
))}
|
||||||
@@ -233,7 +235,7 @@ const ServerRow = ({ server }: { server: McpServer }) => {
|
|||||||
{(server.resources && server.resources.length > 0) ||
|
{(server.resources && server.resources.length > 0) ||
|
||||||
(server.resourceTemplates && server.resourceTemplates.length > 0) ? (
|
(server.resourceTemplates && server.resourceTemplates.length > 0) ? (
|
||||||
<div
|
<div
|
||||||
style={{ display: "flex", flexDirection: "column", gap: "3px", width: "100%" }}>
|
style={{ display: "flex", flexDirection: "column", gap: "8px", width: "100%" }}>
|
||||||
{[...(server.resourceTemplates || []), ...(server.resources || [])].map(
|
{[...(server.resourceTemplates || []), ...(server.resources || [])].map(
|
||||||
(item) => (
|
(item) => (
|
||||||
<McpResourceRow
|
<McpResourceRow
|
||||||
@@ -250,6 +252,14 @@ const ServerRow = ({ server }: { server: McpServer }) => {
|
|||||||
)}
|
)}
|
||||||
</VSCodePanelView>
|
</VSCodePanelView>
|
||||||
</VSCodePanels>
|
</VSCodePanels>
|
||||||
|
|
||||||
|
<VSCodeButton
|
||||||
|
appearance="secondary"
|
||||||
|
onClick={handleRestart}
|
||||||
|
disabled={server.status === "connecting"}
|
||||||
|
style={{ width: "calc(100% - 14px)", margin: "0 7px 3px 7px" }}>
|
||||||
|
{server.status === "connecting" ? "Restarting..." : "Restart Server"}
|
||||||
|
</VSCodeButton>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user