@@ -1280,142 +1280,123 @@ const App = () => {
12801280 throw new Error ( "InspectorClient is not connected" ) ;
12811281 }
12821282
1283- try {
1284- // Find the tool schema to clean parameters properly
1285- const tool = inspectorTools . find ( ( t ) => t . name === name ) ;
1286- const cleanedParams = tool ?. inputSchema
1287- ? cleanParams ( params , tool . inputSchema as JsonSchemaType )
1288- : params ;
1289-
1290- // Merge general metadata with tool-specific metadata
1291- // Tool-specific metadata takes precedence over general metadata
1292- const generalMetadata = {
1293- ...metadata , // General metadata
1294- progressToken : String ( progressTokenRef . current ++ ) ,
1295- } ;
1296- const toolSpecificMetadata = toolMetadata
1297- ? Object . fromEntries (
1298- Object . entries ( toolMetadata ) . map ( ( [ k , v ] ) => [ k , String ( v ) ] ) ,
1299- )
1300- : undefined ;
1283+ const tool = inspectorTools . find ( ( t ) => t . name === name ) ;
1284+ const taskSupport = tool ?. execution ?. taskSupport ?? "forbidden" ;
1285+ const effectiveRunAsTask =
1286+ taskSupport === "required" ||
1287+ ( taskSupport === "optional" && runAsTask === true ) ;
1288+
1289+ const cleanedParams = tool ?. inputSchema
1290+ ? cleanParams ( params , tool . inputSchema as JsonSchemaType )
1291+ : params ;
1292+ const generalMetadata = {
1293+ ...metadata ,
1294+ progressToken : String ( progressTokenRef . current ++ ) ,
1295+ } ;
1296+ const toolSpecificMetadata = toolMetadata
1297+ ? Object . fromEntries (
1298+ Object . entries ( toolMetadata ) . map ( ( [ k , v ] ) => [ k , String ( v ) ] ) ,
1299+ )
1300+ : undefined ;
1301+ const taskOptions = effectiveRunAsTask
1302+ ? { ttl : getMCPTaskTtl ( config ) }
1303+ : undefined ;
13011304
1302- const taskOptions =
1303- runAsTask === true ? { ttl : getMCPTaskTtl ( config ) } : undefined ;
1305+ try {
1306+ if ( effectiveRunAsTask ) {
1307+ // Use callToolStream for task-augmented execution (required or optional+checked)
1308+ let currentTaskId : string | undefined ;
1309+
1310+ const onTaskCreated = (
1311+ e : CustomEvent < { taskId : string ; task : { taskId : string } } > ,
1312+ ) => {
1313+ const { taskId } = e . detail ;
1314+ currentTaskId = taskId ;
1315+ setToolResult ( {
1316+ content : [
1317+ {
1318+ type : "text" ,
1319+ text : `Task created: ${ taskId } . Polling for status...` ,
1320+ } ,
1321+ ] ,
1322+ _meta : {
1323+ "io.modelcontextprotocol/related-task" : { taskId } ,
1324+ } ,
1325+ } as CompatibilityCallToolResult ) ;
1326+ } ;
13041327
1305- const invocation = await inspectorClient . callTool (
1306- name ,
1307- cleanedParams as Record < string , JsonValue > ,
1308- generalMetadata ,
1309- toolSpecificMetadata ,
1310- taskOptions ,
1311- ) ;
1328+ const onTaskStatusChange = (
1329+ e : CustomEvent < {
1330+ taskId : string ;
1331+ task : { status : string ; statusMessage ?: string } ;
1332+ } > ,
1333+ ) => {
1334+ const { taskId, task } = e . detail ;
1335+ if ( currentTaskId !== taskId ) return ;
1336+ setToolResult ( {
1337+ content : [
1338+ {
1339+ type : "text" ,
1340+ text : `Task status: ${ task . status } ${ task . statusMessage ? ` - ${ task . statusMessage } ` : "" } . Polling...` ,
1341+ } ,
1342+ ] ,
1343+ _meta : {
1344+ "io.modelcontextprotocol/related-task" : { taskId } ,
1345+ } ,
1346+ } as CompatibilityCallToolResult ) ;
1347+ void inspectorClient . listRequestorTasks ( ) ;
1348+ } ;
13121349
1313- // Check if server returned a task reference (task-augmented execution)
1314- const rawResult = invocation . result as
1315- | ( Record < string , unknown > & {
1316- task ?: { taskId : string ; status : string ; pollInterval ?: number } ;
1317- } )
1318- | null
1319- | undefined ;
1320- const isTaskResult = (
1321- res : unknown ,
1322- ) : res is {
1323- task : { taskId : string ; status : string ; pollInterval ?: number } ;
1324- } =>
1325- ! ! res &&
1326- typeof res === "object" &&
1327- "task" in res &&
1328- ! ! ( res as Record < string , unknown > ) . task &&
1329- typeof ( res as Record < string , unknown > ) . task === "object" &&
1330- "taskId" in ( res as { task : Record < string , unknown > } ) . task ;
1331-
1332- if ( runAsTask && rawResult && isTaskResult ( rawResult ) ) {
1333- const taskId = rawResult . task . taskId ;
1334- const pollInterval = rawResult . task . pollInterval ?? 1000 ;
1350+ inspectorClient . addEventListener ( "taskCreated" , onTaskCreated ) ;
1351+ inspectorClient . addEventListener (
1352+ "taskStatusChange" ,
1353+ onTaskStatusChange ,
1354+ ) ;
13351355 setIsPollingTask ( true ) ;
1336- const initialResponseMeta =
1337- rawResult && typeof rawResult === "object" && "_meta" in rawResult
1338- ? ( ( rawResult as { _meta ?: Record < string , unknown > } ) . _meta ?? { } )
1339- : undefined ;
1340- setToolResult ( {
1341- content : [
1342- {
1343- type : "text" ,
1344- text : `Task created: ${ taskId } . Polling for status...` ,
1345- } ,
1346- ] ,
1347- _meta : {
1348- ...( initialResponseMeta || { } ) ,
1349- "io.modelcontextprotocol/related-task" : { taskId } ,
1350- } ,
1351- } as CompatibilityCallToolResult ) ;
1352-
1353- let taskCompleted = false ;
1354- while ( ! taskCompleted ) {
1355- try {
1356- await new Promise ( ( resolve ) => setTimeout ( resolve , pollInterval ) ) ;
1357- const taskStatus = await inspectorClient . getRequestorTask ( taskId ) ;
1358-
1359- if (
1360- taskStatus . status === "completed" ||
1361- taskStatus . status === "failed" ||
1362- taskStatus . status === "cancelled"
1363- ) {
1364- taskCompleted = true ;
1365- if ( taskStatus . status === "completed" ) {
1366- const result =
1367- await inspectorClient . getRequestorTaskResult ( taskId ) ;
1368- setToolResult ( result as CompatibilityCallToolResult ) ;
1369- } else {
1370- setToolResult ( {
1356+
1357+ try {
1358+ const invocation = await inspectorClient . callToolStream (
1359+ name ,
1360+ cleanedParams as Record < string , JsonValue > ,
1361+ generalMetadata ,
1362+ toolSpecificMetadata ,
1363+ taskOptions ,
1364+ ) ;
1365+
1366+ const compatibilityResult : CompatibilityCallToolResult =
1367+ invocation . result
1368+ ? {
1369+ content : invocation . result . content || [ ] ,
1370+ isError : false ,
1371+ }
1372+ : {
13711373 content : [
13721374 {
13731375 type : "text" ,
1374- text : `Task ${ taskStatus . status } : ${ taskStatus . statusMessage ?? "No additional information" } ` ,
1376+ text : invocation . error || "Tool call failed" ,
13751377 } ,
13761378 ] ,
13771379 isError : true ,
1378- } ) ;
1379- }
1380- void inspectorClient . listRequestorTasks ( ) ;
1381- } else {
1382- const pollingResponseMeta =
1383- rawResult &&
1384- typeof rawResult === "object" &&
1385- "_meta" in rawResult
1386- ? ( ( rawResult as { _meta ?: Record < string , unknown > } ) . _meta ??
1387- { } )
1388- : undefined ;
1389- setToolResult ( {
1390- content : [
1391- {
1392- type : "text" ,
1393- text : `Task status: ${ taskStatus . status } ${ taskStatus . statusMessage ? ` - ${ taskStatus . statusMessage } ` : "" } . Polling...` ,
1394- } ,
1395- ] ,
1396- _meta : {
1397- ...( pollingResponseMeta || { } ) ,
1398- "io.modelcontextprotocol/related-task" : { taskId } ,
1399- } ,
1400- } as CompatibilityCallToolResult ) ;
1401- void inspectorClient . listRequestorTasks ( ) ;
1402- }
1403- } catch ( pollingError ) {
1404- setToolResult ( {
1405- content : [
1406- {
1407- type : "text" ,
1408- text : `Error polling task status: ${ pollingError instanceof Error ? pollingError . message : String ( pollingError ) } ` ,
1409- } ,
1410- ] ,
1411- isError : true ,
1412- } ) ;
1413- taskCompleted = true ;
1414- }
1380+ } ;
1381+ setToolResult ( compatibilityResult ) ;
1382+ } finally {
1383+ inspectorClient . removeEventListener ( "taskCreated" , onTaskCreated ) ;
1384+ inspectorClient . removeEventListener (
1385+ "taskStatusChange" ,
1386+ onTaskStatusChange ,
1387+ ) ;
1388+ setIsPollingTask ( false ) ;
14151389 }
1416- setIsPollingTask ( false ) ;
14171390 } else {
1418- // Convert ToolCallInvocation to CompatibilityCallToolResult
1391+ // Use callTool for non-task execution
1392+ const invocation = await inspectorClient . callTool (
1393+ name ,
1394+ cleanedParams as Record < string , JsonValue > ,
1395+ generalMetadata ,
1396+ toolSpecificMetadata ,
1397+ undefined , // no task options
1398+ ) ;
1399+
14191400 const compatibilityResult : CompatibilityCallToolResult =
14201401 invocation . result
14211402 ? {
@@ -1433,21 +1414,18 @@ const App = () => {
14331414 } ;
14341415 setToolResult ( compatibilityResult ) ;
14351416 }
1436- // Clear any validation errors since tool execution completed
14371417 setErrors ( ( prev ) => ( { ...prev , tools : null } ) ) ;
14381418 } catch ( e ) {
14391419 setIsPollingTask ( false ) ;
1440- const toolResult : CompatibilityCallToolResult = {
1420+ setToolResult ( {
14411421 content : [
14421422 {
14431423 type : "text" ,
14441424 text : ( e as Error ) . message ?? String ( e ) ,
14451425 } ,
14461426 ] ,
14471427 isError : true ,
1448- } ;
1449- setToolResult ( toolResult ) ;
1450- // Clear validation errors - tool execution errors are shown in ToolResults
1428+ } ) ;
14511429 setErrors ( ( prev ) => ( { ...prev , tools : null } ) ) ;
14521430 }
14531431 } ;
0 commit comments