1- import { Effect , Layer , Option , Predicate , Result , Schema } from "effect" ;
1+ import { Cause , Effect , Layer , Option , Predicate , Result , Schema } from "effect" ;
22import type { HttpClient } from "effect/unstable/http" ;
33
44import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js" ;
@@ -1106,8 +1106,25 @@ export const mcpPlugin = definePlugin((options?: McpPluginOptions) => {
11061106
11071107 const refreshStdioConnections = ( integration : IntegrationSlug ) =>
11081108 Effect . gen ( function * ( ) {
1109+ const record = yield * ctx . core . integrations . get ( integration ) ;
1110+ const config = record ? parseMcpIntegrationConfig ( record . config ) : null ;
1111+ if ( ! config || config . transport !== "stdio" ) {
1112+ return yield * new McpConnectionError ( {
1113+ transport : "stdio" ,
1114+ message : `Cannot refresh tools for MCP integration ${ integration } : stdio config not found.` ,
1115+ } ) ;
1116+ }
1117+
11091118 const connections = yield * ctx . connections . list ( { integration } ) ;
11101119 if ( connections . length === 0 ) {
1120+ const requiredVars = requiredStdioEnvVars ( config ) ;
1121+ if ( requiredVars . length > 0 ) {
1122+ return yield * new McpConnectionError ( {
1123+ transport : "stdio" ,
1124+ message : `Cannot refresh tools because no visible connection has values for required environment variables: ${ requiredVars . join ( ", " ) } .` ,
1125+ } ) ;
1126+ }
1127+
11111128 yield * ctx . connections
11121129 . create ( {
11131130 owner : "org" ,
@@ -1136,7 +1153,18 @@ export const mcpPlugin = definePlugin((options?: McpPluginOptions) => {
11361153 }
11371154
11381155 const failedNames = yield * Effect . forEach ( connections , ( connection ) =>
1139- ctx . connections . refresh ( connection ) . pipe (
1156+ Effect . gen ( function * ( ) {
1157+ const values = yield * ctx . connections . resolveValues ( connection ) ;
1158+ const connectorInput = yield * buildConnectorInput (
1159+ config ,
1160+ values ,
1161+ String ( connection . template ) ,
1162+ allowStdio ,
1163+ httpClientLayer ,
1164+ ) ;
1165+ yield * discoverTools ( createMcpConnector ( connectorInput ) ) ;
1166+ yield * ctx . connections . refresh ( connection ) ;
1167+ } ) . pipe (
11401168 Effect . as ( null ) ,
11411169 Effect . catch ( ( ) => Effect . succeed ( String ( connection . name ) ) ) ,
11421170 ) ,
@@ -1150,6 +1178,17 @@ export const mcpPlugin = definePlugin((options?: McpPluginOptions) => {
11501178 }
11511179 } ) ;
11521180
1181+ const refreshStdioToolsBestEffort = ( integration : IntegrationSlug ) =>
1182+ refreshStdioConnections ( integration ) . pipe (
1183+ Effect . as ( false ) ,
1184+ Effect . catchCause ( ( cause ) =>
1185+ Effect . logWarning ( "stdio tools refresh failed after config commit" ) . pipe (
1186+ Effect . annotateLogs ( "cause" , Cause . pretty ( cause ) ) ,
1187+ Effect . as ( true ) ,
1188+ ) ,
1189+ ) ,
1190+ ) ;
1191+
11531192 const configureServer = ( slug : string , config : McpIntegrationConfigType ) =>
11541193 Effect . gen ( function * ( ) {
11551194 const integration = slugFrom ( slug ) ;
@@ -1167,7 +1206,7 @@ export const mcpPlugin = definePlugin((options?: McpPluginOptions) => {
11671206
11681207 if ( current . transport !== "stdio" ) {
11691208 yield * ctx . core . integrations . update ( integration , { config } ) ;
1170- return ;
1209+ return { config , toolsRefreshFailed : false } satisfies McpConfigureServerResult ;
11711210 }
11721211
11731212 if ( config . transport !== "stdio" ) {
@@ -1183,7 +1222,7 @@ export const mcpPlugin = definePlugin((options?: McpPluginOptions) => {
11831222 ) ;
11841223 if ( ! processConfigChanged ) {
11851224 yield * ctx . core . integrations . update ( integration , { config } ) ;
1186- return ;
1225+ return { config , toolsRefreshFailed : false } satisfies McpConfigureServerResult ;
11871226 }
11881227
11891228 yield * preflightStdioConfig ( integration , config ) ;
@@ -1193,13 +1232,37 @@ export const mcpPlugin = definePlugin((options?: McpPluginOptions) => {
11931232 yield * ctx . core . integrations . update ( integration , { config } ) ;
11941233 } ) ,
11951234 ) ;
1196- yield * refreshStdioConnections ( integration ) ;
1235+ const toolsRefreshFailed = yield * refreshStdioToolsBestEffort ( integration ) ;
1236+ return { config, toolsRefreshFailed } satisfies McpConfigureServerResult ;
11971237 } ) . pipe (
11981238 Effect . withSpan ( "mcp.plugin.configure_server" , {
11991239 attributes : { "mcp.integration.slug" : slug } ,
12001240 } ) ,
12011241 ) ;
12021242
1243+ const refreshServerTools = ( slug : string ) =>
1244+ Effect . gen ( function * ( ) {
1245+ const integration = slugFrom ( slug ) ;
1246+ const record = yield * ctx . core . integrations . get ( integration ) ;
1247+ const current = record ? parseMcpIntegrationConfig ( record . config ) : null ;
1248+ if ( record === null || current === null ) {
1249+ return yield * new IntegrationNotFoundError ( { slug : integration } ) ;
1250+ }
1251+ if ( current . transport !== "stdio" ) {
1252+ return yield * new McpConnectionError ( {
1253+ transport : "auto" ,
1254+ message :
1255+ "MCP tool refresh through the MCP server API is only supported for stdio servers." ,
1256+ } ) ;
1257+ }
1258+ const toolsRefreshFailed = yield * refreshStdioToolsBestEffort ( integration ) ;
1259+ return { toolsRefreshFailed } satisfies McpRefreshServerToolsResult ;
1260+ } ) . pipe (
1261+ Effect . withSpan ( "mcp.plugin.refresh_server_tools" , {
1262+ attributes : { "mcp.integration.slug" : slug } ,
1263+ } ) ,
1264+ ) ;
1265+
12031266 /** Merge-append auth methods onto the integration's existing
12041267 * `authenticationTemplate` (custom-method-create flow), mirroring the
12051268 * OpenAPI/GraphQL `configureAuth`. Returns the merged array. A no-op
@@ -1245,6 +1308,7 @@ export const mcpPlugin = definePlugin((options?: McpPluginOptions) => {
12451308 reconcileStdioConnections,
12461309 getServer,
12471310 configureServer,
1311+ refreshServerTools,
12481312 configureAuth,
12491313 } ;
12501314 } ,
@@ -1575,6 +1639,15 @@ export const mcpPlugin = definePlugin((options?: McpPluginOptions) => {
15751639
15761640export type McpExtensionFailure = McpConnectionError | McpToolDiscoveryError | StorageFailure ;
15771641
1642+ export interface McpConfigureServerResult {
1643+ readonly config : McpIntegrationConfigType ;
1644+ readonly toolsRefreshFailed : boolean ;
1645+ }
1646+
1647+ export interface McpRefreshServerToolsResult {
1648+ readonly toolsRefreshFailed : boolean ;
1649+ }
1650+
15781651export interface McpPluginExtension {
15791652 readonly probeEndpoint : (
15801653 input : string | McpProbeEndpointInput ,
@@ -1598,7 +1671,10 @@ export interface McpPluginExtension {
15981671 readonly configureServer : (
15991672 slug : string ,
16001673 config : McpIntegrationConfigType ,
1601- ) => Effect . Effect < void , McpExtensionFailure | IntegrationNotFoundError > ;
1674+ ) => Effect . Effect < McpConfigureServerResult , McpExtensionFailure | IntegrationNotFoundError > ;
1675+ readonly refreshServerTools : (
1676+ slug : string ,
1677+ ) => Effect . Effect < McpRefreshServerToolsResult , McpExtensionFailure | IntegrationNotFoundError > ;
16021678 readonly configureAuth : (
16031679 slug : string ,
16041680 input : McpConfigureAuthInput ,
0 commit comments