diff --git a/client/src/App.tsx b/client/src/App.tsx index 184f04d93..12e9a7bd0 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1526,6 +1526,9 @@ const App = () => { error={errors.prompts} /> { clearError("tools"); diff --git a/client/src/components/ToolsTab.tsx b/client/src/components/ToolsTab.tsx index 339ba7c61..febea1d8f 100644 --- a/client/src/components/ToolsTab.tsx +++ b/client/src/components/ToolsTab.tsx @@ -53,9 +53,38 @@ import { isReservedMetaKey, } from "@/utils/metaUtils"; +/** + * Extended Tool type that includes optional fields used by the inspector. + */ +export interface ExtendedTool extends Tool, WithIcons { + _meta?: Record; + execution?: { + taskSupport?: "forbidden" | "required" | "optional"; + }; +} + // Type guard to safely detect the optional _meta field without using `any` -const hasMeta = (tool: Tool): tool is Tool & { _meta: unknown } => - typeof (tool as { _meta?: unknown })._meta !== "undefined"; +const hasMeta = ( + tool: Tool, +): tool is ExtendedTool & { _meta: Record } => + typeof (tool as ExtendedTool)._meta !== "undefined"; + +// Returns the execution.taskSupport value for a tool, defaulting to "forbidden" per MCP spec +const getTaskSupport = ( + tool: Tool | null, +): "forbidden" | "required" | "optional" => { + if (!tool) return "forbidden"; + const extendedTool = tool as ExtendedTool; + const taskSupport = extendedTool.execution?.taskSupport; + if ( + taskSupport === "forbidden" || + taskSupport === "required" || + taskSupport === "optional" + ) { + return taskSupport; + } + return "forbidden"; +}; // Type guard to safely detect the optional annotations field const hasAnnotations = ( @@ -148,6 +177,7 @@ const ToolsTab = ({ error, resourceContent, onReadResource, + serverSupportsTaskRequests, }: { tools: Tool[]; listTools: () => void; @@ -166,6 +196,7 @@ const ToolsTab = ({ error: string | null; resourceContent: Record; onReadResource?: (uri: string) => void; + serverSupportsTaskRequests: boolean; }) => { const [params, setParams] = useState>({}); const [runAsTask, setRunAsTask] = useState(false); @@ -210,14 +241,17 @@ const ToolsTab = ({ ]; }); setParams(Object.fromEntries(params)); - setRunAsTask(false); + const toolTaskSupport = serverSupportsTaskRequests + ? getTaskSupport(selectedTool) + : "forbidden"; + setRunAsTask(toolTaskSupport === "required"); // Reset validation errors when switching tools setHasValidationErrors(false); // Clear form refs for the previous tool formRefs.current = {}; - }, [selectedTool]); + }, [selectedTool, serverSupportsTaskRequests]); const hasReservedMetadataEntry = metadataEntries.some(({ key }) => { const trimmedKey = key.trim(); @@ -234,6 +268,10 @@ const ToolsTab = ({ return trimmedKey !== "" && !hasValidMetaName(trimmedKey); }); + const taskSupport = serverSupportsTaskRequests + ? getTaskSupport(selectedTool) + : "forbidden"; + return (
@@ -249,7 +287,7 @@ const ToolsTab = ({ renderItem={(tool) => (
- +
{tool.title || tool.name} @@ -270,7 +308,7 @@ const ToolsTab = ({
{selectedTool && ( )} @@ -747,21 +785,24 @@ const ToolsTab = ({
)} -
- - setRunAsTask(checked) - } - /> - -
+ {taskSupport !== "forbidden" && ( +
+ + setRunAsTask(checked) + } + disabled={taskSupport === "required"} + /> + +
+ )}