Skip to content

Commit

Permalink
Allow to auto-start MCP servers on frontend start-up
Browse files Browse the repository at this point in the history
fixed #14692
  • Loading branch information
JonasHelming committed Jan 16, 2025
1 parent 7e73dda commit 7440e30
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************

import { FrontendApplicationContribution, PreferenceProvider, PreferenceService } from '@theia/core/lib/browser';
import { inject, injectable } from '@theia/core/shared/inversify';
import { MCPServerDescription, MCPServerManager } from '../common';
Expand All @@ -24,6 +25,7 @@ interface MCPServersPreferenceValue {
command: string;
args?: string[];
env?: { [key: string]: string };
autostart?: boolean; // Add autostart property
};

interface MCPServersPreference {
Expand All @@ -35,7 +37,8 @@ namespace MCPServersPreference {
return !!obj && typeof obj === 'object' &&
'command' in obj && typeof obj.command === 'string' &&
(!('args' in obj) || Array.isArray(obj.args) && obj.args.every(arg => typeof arg === 'string')) &&
(!('env' in obj) || !!obj.env && typeof obj.env === 'object' && Object.values(obj.env).every(value => typeof value === 'string'));
(!('env' in obj) || !!obj.env && typeof obj.env === 'object' && Object.values(obj.env).every(value => typeof value === 'string')) &&
(!('autostart' in obj) || typeof obj.autostart === 'boolean');
}
}

Expand Down Expand Up @@ -72,8 +75,9 @@ export class McpFrontendApplicationContribution implements FrontendApplicationCo
MCP_SERVERS_PREF,
{}
));
this.syncServers(servers);
this.prevServers = this.convertToMap(servers);
this.syncServers(this.prevServers);
this.autoStartServers(this.prevServers);

this.preferenceService.onPreferenceChanged(event => {
if (event.preferenceName === MCP_SERVERS_PREF) {
Expand All @@ -83,6 +87,18 @@ export class McpFrontendApplicationContribution implements FrontendApplicationCo
});
this.frontendMCPService.registerToolsForAllStartedServers();
}
protected async autoStartServers(servers: Map<string, MCPServerDescription>): Promise<void> {
const serverNames = servers.keys();
const startedServers = await this.frontendMCPService.getStartedServers();
for (const name of serverNames) {
const serverDesc = servers.get(name);
if (serverDesc && serverDesc.autostart) {
if (!startedServers.includes(name)) {
await this.frontendMCPService.startServer(name);
}
}
}
}

protected handleServerChanges(newServers: MCPServersPreference): void {
const oldServers = this.prevServers;
Expand Down Expand Up @@ -116,20 +132,17 @@ export class McpFrontendApplicationContribution implements FrontendApplicationCo
this.prevServers = updatedServers;
}

protected syncServers(servers: MCPServersPreference): void {
const updatedServers = this.convertToMap(servers);
protected syncServers(servers: Map<string, MCPServerDescription>): void {

for (const [, description] of updatedServers) {
for (const [, description] of servers) {
this.manager.addOrUpdateServer(description);
}

for (const [name] of this.prevServers) {
if (!updatedServers.has(name)) {
if (!servers.has(name)) {
this.manager.removeServer(name);
}
}

this.prevServers = updatedServers;
}

protected convertToMap(servers: MCPServersPreference): Map<string, MCPServerDescription> {
Expand Down
19 changes: 13 additions & 6 deletions packages/ai-mcp/src/browser/mcp-preferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ export const McpServersPreferenceSchema: PreferenceSchema = {
[MCP_SERVERS_PREF]: {
type: 'object',
title: 'MCP Servers Configuration',
markdownDescription: 'Configure MCP servers with command, arguments and optionally environment variables. Each server is identified by a unique key, such as\
"brave-search" or "filesystem".\
markdownDescription: 'Configure MCP servers with command, arguments, optionally environment variables, and autostart.\
Each server is identified by a unique key, such as "brave-search" or "filesystem".\
To start a server, use the "MCP: Start MCP Server" command, which enables you to select the desired server.\
To stop a server, use the "MCP: Stop MCP Server" command.\
\n\
Expand All @@ -40,17 +40,18 @@ export const McpServersPreferenceSchema: PreferenceSchema = {
],\n\
"env": {\n\
"BRAVE_API_KEY": "YOUR_API_KEY"\n\
}\n\
},\n\
"autostart": true\n\
},\n\
"filesystem": {\n\
"command": "npx",\n\
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/YOUR_USERNAME/Desktop"],\n\
"env": {\n\
"CUSTOM_ENV_VAR": "custom-value"\n\
}\n\
},\n\
"autostart": false\n\
}\n\
}\
```',
}\n ```',
additionalProperties: {
type: 'object',
properties: {
Expand All @@ -74,6 +75,12 @@ export const McpServersPreferenceSchema: PreferenceSchema = {
additionalProperties: {
type: 'string'
}
},
autostart: {
type: 'boolean',
title: 'Autostart',
markdownDescription: 'Automatically start this server when the frontend starts. Newly added servers are not immediatly auto stated.',
default: false
}
},
required: ['command', 'args']
Expand Down
5 changes: 5 additions & 0 deletions packages/ai-mcp/src/common/mcp-server-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ export interface MCPServerDescription {
* Optional environment variables to set when starting the server.
*/
env?: { [key: string]: string };

/**
* Flag indicating whether the server should automatically start when the application starts.
*/
autostart?: boolean;
}

export const MCPServerManager = Symbol('MCPServerManager');
Expand Down

0 comments on commit 7440e30

Please sign in to comment.