6
6
import './media/mcpServersView.css' ;
7
7
import * as dom from '../../../../base/browser/dom.js' ;
8
8
import { ActionBar } from '../../../../base/browser/ui/actionbar/actionbar.js' ;
9
- import { Button } from '../../../../base/browser/ui/button/button.js' ;
10
9
import { IListContextMenuEvent , IListRenderer } from '../../../../base/browser/ui/list/list.js' ;
11
10
import { Event } from '../../../../base/common/event.js' ;
12
11
import { combinedDisposable , Disposable , DisposableStore , dispose , IDisposable , isDisposable } from '../../../../base/common/lifecycle.js' ;
@@ -21,7 +20,6 @@ import { IKeybindingService } from '../../../../platform/keybinding/common/keybi
21
20
import { WorkbenchPagedList } from '../../../../platform/list/browser/listService.js' ;
22
21
import { INotificationService } from '../../../../platform/notification/common/notification.js' ;
23
22
import { IOpenerService } from '../../../../platform/opener/common/opener.js' ;
24
- import { defaultButtonStyles } from '../../../../platform/theme/browser/defaultStyles.js' ;
25
23
import { IThemeService } from '../../../../platform/theme/common/themeService.js' ;
26
24
import { getLocationBasedViewColors , ViewPane } from '../../../browser/parts/views/viewPane.js' ;
27
25
import { IViewletViewOptions } from '../../../browser/parts/views/viewsViewlet.js' ;
@@ -40,17 +38,25 @@ import { IWorkbenchContribution } from '../../../common/contributions.js';
40
38
import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js' ;
41
39
import { DefaultViewsContext , SearchMcpServersContext } from '../../extensions/common/extensions.js' ;
42
40
import { VIEW_CONTAINER } from '../../extensions/browser/extensions.contribution.js' ;
41
+ import { renderMarkdown } from '../../../../base/browser/markdownRenderer.js' ;
42
+ import { MarkdownString } from '../../../../base/common/htmlContent.js' ;
43
43
44
44
export interface McpServerListViewOptions {
45
45
showWelcomeOnEmpty ?: boolean ;
46
46
}
47
47
48
+ interface IQueryResult {
49
+ showWelcomeContent : boolean ;
50
+ model : IPagedModel < IWorkbenchMcpServer > ;
51
+ }
52
+
48
53
export class McpServersListView extends ViewPane {
49
54
50
55
private list : WorkbenchPagedList < IWorkbenchMcpServer > | null = null ;
51
56
private listContainer : HTMLElement | null = null ;
52
57
private welcomeContainer : HTMLElement | null = null ;
53
58
private readonly contextMenuActionRunner = this . _register ( new ActionRunner ( ) ) ;
59
+ private input : IQueryResult | undefined ;
54
60
55
61
constructor (
56
62
private readonly mpcViewOptions : McpServerListViewOptions ,
@@ -106,6 +112,10 @@ export class McpServersListView extends ViewPane {
106
112
this . mcpWorkbenchService . open ( options . element ! , options . editorOptions ) ;
107
113
} ) ) ;
108
114
this . _register ( this . list . onContextMenu ( e => this . onContextMenu ( e ) , this ) ) ;
115
+
116
+ if ( this . input ) {
117
+ this . renderInput ( ) ;
118
+ }
109
119
}
110
120
111
121
private async onContextMenu ( e : IListContextMenuEvent < IWorkbenchMcpServer > ) : Promise < void > {
@@ -145,16 +155,29 @@ export class McpServersListView extends ViewPane {
145
155
}
146
156
147
157
async show ( query : string ) : Promise < IPagedModel < IWorkbenchMcpServer > > {
148
- if ( ! this . list ) {
149
- return new PagedModel ( [ ] ) ;
158
+ if ( this . input ) {
159
+ this . input = undefined ;
150
160
}
151
161
152
162
query = query . trim ( ) ;
153
163
const servers = query ? await this . mcpWorkbenchService . queryGallery ( { text : query . replace ( '@mcp' , '' ) } ) : await this . mcpWorkbenchService . queryLocal ( ) ;
154
- this . list . model = new DelayedPagedModel ( new PagedModel ( servers ) ) ;
164
+ const showWelcomeContent = ! this . mcpGalleryService . isEnabled ( ) && servers . length === 0 && ! ! this . mpcViewOptions . showWelcomeOnEmpty ;
155
165
156
- this . showWelcomeContent ( ! this . mcpGalleryService . isEnabled ( ) && servers . length === 0 && ! ! this . mpcViewOptions . showWelcomeOnEmpty ) ;
157
- return this . list . model ;
166
+ const model = new PagedModel ( servers ) ;
167
+ this . input = { model, showWelcomeContent } ;
168
+ this . renderInput ( ) ;
169
+
170
+ return model ;
171
+ }
172
+
173
+ private renderInput ( ) {
174
+ if ( ! this . input ) {
175
+ return ;
176
+ }
177
+ if ( this . list ) {
178
+ this . list . model = new DelayedPagedModel ( this . input . model ) ;
179
+ }
180
+ this . showWelcomeContent ( this . input . showWelcomeContent ) ;
158
181
}
159
182
160
183
private showWelcomeContent ( show : boolean ) : void {
@@ -173,17 +196,19 @@ export class McpServersListView extends ViewPane {
173
196
title . textContent = localize ( 'mcp.welcome.title' , "MCP Servers" ) ;
174
197
175
198
const description = dom . append ( welcomeContent , dom . $ ( '.mcp-welcome-description' ) ) ;
176
- description . textContent = localize ( 'mcp.welcome.description' , "Extend agent mode by installing MCP servers to bring extra tools for connecting to databases, invoking APIs, performing specialized tasks, etc." ) ;
177
-
178
- // Browse button
179
- const buttonContainer = dom . append ( welcomeContent , dom . $ ( '.mcp-welcome-button-container' ) ) ;
180
- const button = this . _register ( new Button ( buttonContainer , {
181
- title : localize ( 'mcp.welcome.browseButton' , "Browse MCP Servers" ) ,
182
- ...defaultButtonStyles
199
+ const browseUrl = this . productService . quality === 'insider' ? 'https://code.visualstudio.com/insider/mcp' : 'https://code.visualstudio.com/mcp' ;
200
+ const markdownResult = this . _register ( renderMarkdown ( new MarkdownString (
201
+ localize ( 'mcp.welcome.descriptionWithLink' , "Extend agent mode by installing [MCP servers]({0}) to bring extra tools for connecting to databases, invoking APIs, performing specialized tasks, etc." , browseUrl ) ,
202
+ { isTrusted : true }
203
+ ) , {
204
+ actionHandler : {
205
+ callback : ( content : string ) => {
206
+ this . openerService . open ( URI . parse ( content ) ) ;
207
+ } ,
208
+ disposables : this . _store
209
+ }
183
210
} ) ) ;
184
- button . label = localize ( 'mcp.welcome.browseButton' , "Browse MCP Servers" ) ;
185
-
186
- this . _register ( button . onDidClick ( ( ) => this . openerService . open ( URI . parse ( this . productService . quality === 'insider' ? 'https://code.visualstudio.com/insider/mcp' : 'https://code.visualstudio.com/mcp' ) ) ) ) ;
211
+ description . appendChild ( markdownResult . element ) ;
187
212
}
188
213
189
214
}
0 commit comments