@@ -1363,6 +1363,7 @@ const mcpUrlForActiveLocalServer = (input: {
13631363 readonly elicitationMode : "browser" | "model" ;
13641364 readonly artifacts : boolean ;
13651365 readonly searchTools : boolean ;
1366+ readonly toolMode : "codemode" | "passthrough" ;
13661367} ) : URL => {
13671368 const url = new URL ( "/mcp" , input . connection . origin ) ;
13681369 if ( input . elicitationMode === "browser" ) {
@@ -1378,6 +1379,10 @@ const mcpUrlForActiveLocalServer = (input: {
13781379 if ( input . searchTools ) {
13791380 url . searchParams . set ( "search_tools" , "true" ) ;
13801381 }
1382+ // Passthrough is the non-default surface; only it is spelled out.
1383+ if ( input . toolMode === "passthrough" ) {
1384+ url . searchParams . set ( "mode" , "passthrough" ) ;
1385+ }
13811386 return url ;
13821387} ;
13831388
@@ -1394,6 +1399,7 @@ const runMcpHttpBridge = async (input: {
13941399 readonly elicitationMode : "browser" | "model" ;
13951400 readonly artifacts : boolean ;
13961401 readonly searchTools : boolean ;
1402+ readonly toolMode : "codemode" | "passthrough" ;
13971403} ) : Promise < void > => {
13981404 const stdio = new StdioServerTransport ( ) ;
13991405 const authorization = getExecutorServerAuthorizationHeader ( input . manifest . connection ) ;
@@ -1403,6 +1409,7 @@ const runMcpHttpBridge = async (input: {
14031409 elicitationMode : input . elicitationMode ,
14041410 artifacts : input . artifacts ,
14051411 searchTools : input . searchTools ,
1412+ toolMode : input . toolMode ,
14061413 } ) ,
14071414 authorization ? { requestInit : { headers : { Authorization : authorization } } } : undefined ,
14081415 ) ;
@@ -1482,6 +1489,7 @@ const runStdioMcpSession = (input: {
14821489 readonly elicitationMode : "browser" | "model" ;
14831490 readonly artifacts : boolean ;
14841491 readonly searchTools : boolean ;
1492+ readonly toolMode : "codemode" | "passthrough" ;
14851493} ) =>
14861494 Effect . gen ( function * ( ) {
14871495 // `executor mcp` never owns the local database. If a local server is already
@@ -1499,6 +1507,7 @@ const runStdioMcpSession = (input: {
14991507 elicitationMode : input . elicitationMode ,
15001508 artifacts : input . artifacts ,
15011509 searchTools : input . searchTools ,
1510+ toolMode : input . toolMode ,
15021511 } ) ,
15031512 ) ;
15041513 return ;
@@ -1526,6 +1535,7 @@ const runStdioMcpSession = (input: {
15261535 elicitationMode : input . elicitationMode ,
15271536 artifacts : input . artifacts ,
15281537 searchTools : input . searchTools ,
1538+ toolMode : input . toolMode ,
15291539 } ) ,
15301540 ) ;
15311541 } ) ;
@@ -2898,11 +2908,30 @@ const mcpCommand = Command.make(
28982908 "Serve one search_<integration> tool per connected integration. Off by default; each routes through the same flow as tools.search inside execute." ,
28992909 ) ,
29002910 ) ,
2911+ toolMode : Options . choice ( "mode" , [ "codemode" , "passthrough" ] as const )
2912+ . pipe ( Options . withDefault ( "codemode" ) )
2913+ . pipe (
2914+ Options . withDescription (
2915+ "codemode (default) serves the execute tool; passthrough serves search and invoke, with input schemas in search results and client approval for invoke." ,
2916+ ) ,
2917+ ) ,
29012918 } ,
2902- ( { scope, elicitationMode, noArtifacts, searchTools } ) =>
2919+ ( { scope, elicitationMode, noArtifacts, searchTools, toolMode } ) =>
29032920 Effect . gen ( function * ( ) {
29042921 applyScope ( scope ) ;
2905- yield * runStdioMcpSession ( { elicitationMode, artifacts : ! noArtifacts , searchTools } ) ;
2922+ if ( toolMode === "passthrough" && searchTools ) {
2923+ return yield * Effect . fail (
2924+ new Error (
2925+ "--search-tools is a codemode option; passthrough already provides search. Drop --search-tools or --mode passthrough." ,
2926+ ) ,
2927+ ) ;
2928+ }
2929+ yield * runStdioMcpSession ( {
2930+ elicitationMode,
2931+ artifacts : ! noArtifacts ,
2932+ searchTools,
2933+ toolMode,
2934+ } ) ;
29062935 } ) ,
29072936) . pipe ( Command . withDescription ( "Start an MCP server over stdio" ) ) ;
29082937
0 commit comments