@@ -6,18 +6,24 @@ import {
6
6
ConfigValidationError ,
7
7
ModelRole ,
8
8
} from "@continuedev/config-yaml" ;
9
+
9
10
import {
10
11
ContinueConfig ,
11
12
ContinueRcJson ,
12
13
IDE ,
13
14
IdeSettings ,
14
15
SerializedContinueConfig ,
16
+ Tool ,
15
17
} from "../../" ;
18
+ import { constructMcpSlashCommand } from "../../commands/slash/mcp" ;
19
+ import { MCPManagerSingleton } from "../../context/mcp" ;
20
+ import MCPContextProvider from "../../context/providers/MCPContextProvider" ;
16
21
import { ControlPlaneProxyInfo } from "../../control-plane/analytics/IAnalyticsProvider.js" ;
17
22
import { ControlPlaneClient } from "../../control-plane/client.js" ;
18
23
import { getControlPlaneEnv } from "../../control-plane/env.js" ;
19
24
import { TeamAnalytics } from "../../control-plane/TeamAnalytics.js" ;
20
25
import ContinueProxy from "../../llm/llms/stubs/ContinueProxy" ;
26
+ import { encodeMCPToolUri } from "../../tools/callTool" ;
21
27
import { getConfigJsonPath , getConfigYamlPath } from "../../util/paths" ;
22
28
import { localPathOrUriToPath } from "../../util/pathToUri" ;
23
29
import { Telemetry } from "../../util/posthog" ;
@@ -26,6 +32,7 @@ import { loadContinueConfigFromJson } from "../load";
26
32
import { migrateJsonSharedConfig } from "../migrateSharedConfig" ;
27
33
import { rectifySelectedModelsFromGlobalContext } from "../selectedModels" ;
28
34
import { loadContinueConfigFromYaml } from "../yaml/loadYaml" ;
35
+
29
36
import { PlatformConfigMetadata } from "./PlatformProfileLoader" ;
30
37
31
38
export default async function doLoadConfig (
@@ -93,15 +100,90 @@ export default async function doLoadConfig(
93
100
configLoadInterrupted = result . configLoadInterrupted ;
94
101
}
95
102
96
- // Rectify model selections for each role
97
- if ( newConfig ) {
98
- newConfig = rectifySelectedModelsFromGlobalContext ( newConfig , profileId ) ;
99
- }
100
-
101
103
if ( configLoadInterrupted || ! newConfig ) {
102
104
return { errors, config : newConfig , configLoadInterrupted : true } ;
103
105
}
104
106
107
+ // TODO using config result but result with non-fatal errors is an antipattern?
108
+ // Remove ability have undefined errors, just have an array
109
+ errors = [ ...( errors ?? [ ] ) ] ;
110
+
111
+ // Rectify model selections for each role
112
+ newConfig = rectifySelectedModelsFromGlobalContext ( newConfig , profileId ) ;
113
+
114
+ // Add things from MCP servers
115
+ const mcpManager = MCPManagerSingleton . getInstance ( ) ;
116
+ const mcpServerStatuses = mcpManager . getStatuses ( ) ;
117
+
118
+ // Slightly hacky just need connection's client to make slash command for now
119
+ const serializableStatuses = mcpServerStatuses . map ( ( server ) => {
120
+ const { client, ...rest } = server ;
121
+ return rest ;
122
+ } ) ;
123
+ newConfig . mcpServerStatuses = serializableStatuses ;
124
+
125
+ for ( const server of mcpServerStatuses ) {
126
+ if ( server . status === "connected" ) {
127
+ const serverTools : Tool [ ] = server . tools . map ( ( tool ) => ( {
128
+ displayTitle : server . name + " " + tool . name ,
129
+ function : {
130
+ description : tool . description ,
131
+ name : tool . name ,
132
+ parameters : tool . inputSchema ,
133
+ } ,
134
+ faviconUrl : server . faviconUrl ,
135
+ readonly : false ,
136
+ type : "function" as const ,
137
+ wouldLikeTo : "" ,
138
+ uri : encodeMCPToolUri ( server . id , tool . name ) ,
139
+ group : server . name ,
140
+ } ) ) ;
141
+ newConfig . tools . push ( ...serverTools ) ;
142
+
143
+ const serverSlashCommands = server . prompts . map ( ( prompt ) =>
144
+ constructMcpSlashCommand (
145
+ server . client ,
146
+ prompt . name ,
147
+ prompt . description ,
148
+ prompt . arguments ?. map ( ( a : any ) => a . name ) ,
149
+ ) ,
150
+ ) ;
151
+ newConfig . slashCommands . push ( ...serverSlashCommands ) ;
152
+
153
+ const submenuItems = server . resources . map ( ( resource ) => ( {
154
+ title : resource . name ,
155
+ description : resource . description ?? resource . name ,
156
+ id : resource . uri ,
157
+ icon : server . faviconUrl ,
158
+ } ) ) ;
159
+ if ( submenuItems . length > 0 ) {
160
+ const serverContextProvider = new MCPContextProvider ( {
161
+ submenuItems,
162
+ mcpId : server . id ,
163
+ } ) ;
164
+ newConfig . contextProviders . push ( serverContextProvider ) ;
165
+ }
166
+ }
167
+ }
168
+
169
+ // Detect duplicate tool names
170
+ const counts : Record < string , number > = { } ;
171
+ newConfig . tools . forEach ( ( tool ) => {
172
+ if ( counts [ tool . function . name ] ) {
173
+ counts [ tool . function . name ] = counts [ tool . function . name ] + 1 ;
174
+ } else {
175
+ counts [ tool . function . name ] = 1 ;
176
+ }
177
+ } ) ;
178
+ Object . entries ( counts ) . forEach ( ( [ toolName , count ] ) => {
179
+ if ( count > 1 ) {
180
+ errors ! . push ( {
181
+ fatal : false ,
182
+ message : `Duplicate (${ count } ) tools named "${ toolName } " detected. Permissions will conflict and usage may be unpredictable` ,
183
+ } ) ;
184
+ }
185
+ } ) ;
186
+
105
187
newConfig . allowAnonymousTelemetry =
106
188
newConfig . allowAnonymousTelemetry && ( await ide . isTelemetryEnabled ( ) ) ;
107
189
0 commit comments