Skip to main content

MCP Hooks

React hooks for interacting with MCP servers from within your App components. All hooks work within an AppProvider or GPTAppProvider context.

useTool

The primary hook for calling MCP tools with full state management, retries, and result transformation.

Basic Usage

function RefreshButton() {
  const { call, loading, result, error } = useTool('refresh-data');

  return (
    <button onClick={() => call()} disabled={loading}>
      {loading ? 'Refreshing...' : 'Refresh'}
    </button>
  );
}

With Arguments

function WeatherWidget({ city }: { city: string }) {
  const { call, result, loading } = useTool('get-weather');

  useEffect(() => {
    call({ city });
  }, [city]);

  if (loading) return <Skeleton />;
  return <div>{result?.temperature}°C</div>;
}

With Options

const { call, result, error, retry, reset } = useTool('create-item', {
  defaultArgs: { type: 'note' },
  transform: (result) => result.structuredContent?.item,
  retry: { count: 3, delay: 1000 },
  onStart: () => console.log('Starting...'),
  onSuccess: (item) => toast.success(`Created: ${item.name}`),
  onError: (error) => toast.error(error.message),
  onComplete: () => console.log('Done'),
});

Return Value

PropertyTypeDescription
call(args?) => Promise<T>Execute the tool
mutate(args) => Promise<T>Alias for call (semantic)
loadingbooleanWhether tool is executing
state'idle' | 'loading' | 'success' | 'error'Current state
resultT | nullLast successful result
errorError | nullLast error
reset() => voidReset to initial state
retry() => Promise<T>Retry last call
abort() => voidAbort current call

Options

OptionTypeDescription
defaultArgsRecord<string, unknown>Default arguments merged with call args
transform(result) => TTransform the raw tool result
retrynumber | { count, delay }Retry configuration
onStart() => voidCalled when tool starts
onSuccess(result) => voidCalled on success
onError(error) => voidCalled on error
onComplete() => voidCalled after success or error

useResource

Read MCP server resources with auto-refresh and subscription support.

Basic Usage

function UserProfile() {
  const { data, loading, error, refresh } = useResource<User>('user://profile');

  if (loading) return <Skeleton />;
  if (error) return <Alert>{error.message}</Alert>;

  return (
    <Card>
      <h2>{data?.name}</h2>
      <Button onClick={refresh}>Refresh</Button>
    </Card>
  );
}

With Auto-Refresh

const { data } = useResource('metrics://dashboard', {
  refreshInterval: 5000,  // Refresh every 5 seconds
  transform: (raw) => raw.metrics,
});

Return Value

PropertyTypeDescription
dataT | nullResource data
loadingbooleanWhether loading
errorError | nullError if any
refresh() => Promise<T>Manual refresh
lastUpdatedDate | nullLast update timestamp

Options

OptionTypeDescription
refreshIntervalnumberAuto-refresh interval in ms
subscribebooleanEnable subscription (when supported)
transform(data) => TTransform resource data
skipbooleanSkip initial fetch

useMessage

Send messages to the host chat interface.
function FeedbackButton() {
  const { sendMessage } = useMessage();

  const handleClick = async () => {
    await sendMessage('User requested help with the dashboard');
  };

  return <Button onClick={handleClick}>Ask for Help</Button>;
}

Return Value

PropertyTypeDescription
sendMessage(text: string) => Promise<void>Send message to host

useHostContext

Access host environment information like theme, viewport, and display mode.
function ThemedComponent() {
  const { theme, displayMode, viewport } = useHostContext();

  return (
    <div className={theme === 'dark' ? 'dark-mode' : 'light-mode'}>
      <p>Display mode: {displayMode}</p>
      <p>Viewport: {viewport?.width}x{viewport?.height}</p>
    </div>
  );
}

Return Value

PropertyTypeDescription
theme'light' | 'dark'Current theme
displayModestringCurrent display mode
viewport{ width, height }Viewport dimensions
stylesobjectHost style variables

useToolResult

Access the tool result passed from the host when rendering a tool-linked UI.
function WeatherCard() {
  const { result, loading, error } = useToolResult<WeatherData>();

  if (loading) return <Skeleton />;
  if (error) return <Alert>{error.message}</Alert>;
  if (!result) return null;

  return (
    <Card>
      <h2>{result.city}</h2>
      <p>{result.temperature}°C - {result.condition}</p>
    </Card>
  );
}

useToolInput

Access the tool input arguments when the host is streaming input to your app.
function LivePreview() {
  const { input } = useToolInput<{ query: string }>();

  return (
    <div>
      <p>Current query: {input?.query ?? 'None'}</p>
    </div>
  );
}

useToolStream

Handle streaming tool responses with partial updates.
function StreamingResponse() {
  const { partial, isStreaming } = useToolStream<{ text: string }>();

  return (
    <div>
      {isStreaming && <Spinner />}
      <ReactMarkdown>{partial?.text ?? ''}</ReactMarkdown>
    </div>
  );
}

useMcpApp

Low-level hook to access the full MCP App context. Most use cases are covered by the specialized hooks above.
function AdvancedComponent() {
  const { 
    app,           // Raw ext-apps App instance
    isConnected,   // Connection state
    error,         // Connection error
    callTool,      // Call any tool
    sendMessage,   // Send chat message
    sendLog,       // Send log to host
    openLink,      // Open URL in host
    requestDisplayMode,  // Request display mode change
  } = useMcpApp();

  const handleFullscreen = async () => {
    await requestDisplayMode('fullscreen');
  };

  return (
    <Button onClick={handleFullscreen}>
      Go Fullscreen
    </Button>
  );
}