> ## Documentation Index
> Fetch the complete documentation index at: https://docs.atxp.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# X Live Search

> Search X (formerly Twitter) for posts and conversations

## Overview

Use the X Live Search MCP server from your ATXP-powered agent to search X (formerly Twitter) for posts and conversations using xAI's Grok models. Powered by xAI's Agentic Search Tools API, the server uses AI agents that autonomously explore and make follow-up queries to provide comprehensive search results with citations.

## Example prompts

* "What are the latest updates from Stripe?"
* "Find popular tweets about AI from the last week with at least 100 likes"
* "Search for posts from @elonmusk about SpaceX"

## Tools

<AccordionGroup>
  <Accordion title="x_live_search">
    Searches X (formerly Twitter) for posts matching the query and optional filters using xAI's Agentic Search Tools API. The AI agent autonomously explores and makes follow-up queries to provide comprehensive results with citations to source posts.

    ### Arguments

    Accepts a JSON object with the following properties:

    <ParamField body="query" type="string" required>
      The search query to execute on X (formerly Twitter). Natural language queries work best with the agentic search API.
    </ParamField>

    <ParamField body="allowed_x_handles" type="string[]">
      List of X handles to include in search (up to 10). Format without @ symbol, e.g., \["elonmusk", "OpenAI"].
    </ParamField>

    <ParamField body="excluded_x_handles" type="string[]">
      List of X handles to exclude from search (up to 10). Format without @ symbol.
    </ParamField>

    <ParamField body="from_date" type="string">
      Start date for posts in ISO8601 format (YYYY-MM-DD).
    </ParamField>

    <ParamField body="to_date" type="string">
      End date for posts in ISO8601 format (YYYY-MM-DD).
    </ParamField>

    <ParamField body="enable_image_understanding" type="boolean">
      Enable AI analysis of images in posts. Increases token usage.
    </ParamField>

    <ParamField body="enable_video_understanding" type="boolean">
      Enable AI analysis of videos in X posts. Increases token usage.
    </ParamField>

    <ParamField body="enable_web_search" type="boolean">
      Enable web search beyond X to find additional context and information.
    </ParamField>

    <ParamField body="allowed_domains" type="string[]">
      When web search is enabled, limit results to these domains (e.g., \["arxiv.org", "openai.com"]).
    </ParamField>

    <ParamField body="min_likes" type="number">
      Minimum number of likes/favorites. Only returns posts with at least this many likes.
    </ParamField>

    <ParamField body="min_retweets" type="number">
      Minimum number of retweets. Only returns posts with at least this many retweets.
    </ParamField>

    <ParamField body="min_replies" type="number">
      Minimum number of replies. Only returns posts with at least this many replies.
    </ParamField>

    ### Response

    Returns a JSON object with the following properties:

    <ResponseField name="status" type="string">
      The status of the search operation. Returns "success" when the search completes successfully, or "error" on failure.
    </ResponseField>

    <ResponseField name="query" type="string">
      The original search query that was executed.
    </ResponseField>

    <ResponseField name="message" type="string">
      AI-generated summary of the search findings. Only present when status is "success".
    </ResponseField>

    <ResponseField name="citations" type="string[]">
      Array of X post URLs used as sources for the summary. Only present when status is "success".
    </ResponseField>

    <ResponseField name="toolCalls" type="object[]">
      Array of tool calls made by the AI agent during search, showing what searches were performed. Each object contains function name and arguments. Only present when status is "success".
    </ResponseField>

    <ResponseField name="errorMessage" type="string">
      Error details if the search failed. Only present when status is "error".
    </ResponseField>
  </Accordion>

  <Accordion title="x_live_search_async">
    Starts an asynchronous search of X (formerly Twitter) for posts matching the query and optional filters using xAI's Agentic Search Tools API. Returns a task ID immediately that can be used to check status and retrieve results. This is useful for avoiding timeouts on long-running searches.

    ### Arguments

    Accepts a JSON object with the following properties:

    <ParamField body="query" type="string" required>
      The search query to execute on X (formerly Twitter). Natural language queries work best with the agentic search API.
    </ParamField>

    <ParamField body="allowed_x_handles" type="string[]">
      List of X handles to include in search (up to 10). Format without @ symbol, e.g., \["elonmusk", "OpenAI"].
    </ParamField>

    <ParamField body="excluded_x_handles" type="string[]">
      List of X handles to exclude from search (up to 10). Format without @ symbol.
    </ParamField>

    <ParamField body="from_date" type="string">
      Start date for posts in ISO8601 format (YYYY-MM-DD).
    </ParamField>

    <ParamField body="to_date" type="string">
      End date for posts in ISO8601 format (YYYY-MM-DD).
    </ParamField>

    <ParamField body="enable_image_understanding" type="boolean">
      Enable AI analysis of images in posts. Increases token usage.
    </ParamField>

    <ParamField body="enable_video_understanding" type="boolean">
      Enable AI analysis of videos in X posts. Increases token usage.
    </ParamField>

    <ParamField body="enable_web_search" type="boolean">
      Enable web search beyond X to find additional context and information.
    </ParamField>

    <ParamField body="allowed_domains" type="string[]">
      When web search is enabled, limit results to these domains (e.g., \["arxiv.org", "openai.com"]).
    </ParamField>

    <ParamField body="min_likes" type="number">
      Minimum number of likes/favorites. Only returns posts with at least this many likes.
    </ParamField>

    <ParamField body="min_retweets" type="number">
      Minimum number of retweets. Only returns posts with at least this many retweets.
    </ParamField>

    <ParamField body="min_replies" type="number">
      Minimum number of replies. Only returns posts with at least this many replies.
    </ParamField>

    ### Response

    Returns a JSON object with the following properties:

    <ResponseField name="taskId" type="string">
      A unique task identifier that can be used with `x_get_search_async` to check the status and retrieve the result.
    </ResponseField>
  </Accordion>

  <Accordion title="x_get_search_async">
    Retrieves the status and result of an asynchronous X search task using the task ID. Tasks expire after 12 hours.

    ### Arguments

    Accepts a JSON object with the following properties:

    <ParamField body="taskId" type="string" required>
      The task ID returned from `x_live_search_async`.
    </ParamField>

    ### Response

    Returns a JSON object with the following properties:

    <ResponseField name="status" type="string">
      The current status of the task. Can be "pending", "in\_progress", "completed", or "error".
    </ResponseField>

    <ResponseField name="result" type="object">
      The search result object. Only present when status is "completed". Contains the same fields as the `x_live_search` response (status, query, message, citations, toolCalls).
    </ResponseField>

    <ResponseField name="error" type="string">
      Error details if the search failed. Only present when status is "error".
    </ResponseField>

    <ResponseField name="createdAt" type="number">
      Unix timestamp (in milliseconds) when the task was created.
    </ResponseField>

    <ResponseField name="completedAt" type="number">
      Unix timestamp (in milliseconds) when the task completed. Only present when status is "completed" or "error".
    </ResponseField>
  </Accordion>
</AccordionGroup>

## Usage

<Steps>
  <Step title="Define the X Live Search service">
    Create a reusable service configuration that points to the MCP server and standardizes how you pass arguments and read results. This lets your agent easily interact with the X Live Search tool in a consistent manner.

    ```typescript theme={null}
    const xLiveSearchService = {
        mcpServer: 'https://x-live-search.mcp.atxp.ai/',
        toolName: 'x_live_search',
        asyncSearchToolName: 'x_live_search_async',
        getSearchAsyncToolName: 'x_get_search_async',
        description: 'ATXP X Live Search MCP server',
        getArguments: (params: {
          query: string,
          allowed_x_handles?: string[],
          excluded_x_handles?: string[],
          from_date?: string,
          to_date?: string,
          enable_image_understanding?: boolean,
          enable_video_understanding?: boolean,
          enable_web_search?: boolean,
          allowed_domains?: string[],
          min_likes?: number,
          min_retweets?: number,
          min_replies?: number
        }) => params,
        getResult: (result: any) => {
          const jsonResult = result.content[0].text;
          const parsed = JSON.parse(jsonResult);
          return {
            status: parsed.status,
            query: parsed.query,
            message: parsed.message,
            citations: parsed.citations,
            toolCalls: parsed.toolCalls,
            errorMessage: parsed.errorMessage
          };
        },
        getAsyncCreateResult: (result: any) => {
          const jsonResult = result.content[0].text;
          const parsed = JSON.parse(jsonResult);
          return { taskId: parsed.taskId };
        },
        getAsyncStatusResult: (result: any) => {
          const jsonResult = result.content[0].text;
          const parsed = JSON.parse(jsonResult);
          return {
            status: parsed.status,
            result: parsed.result,
            error: parsed.error,
            createdAt: parsed.createdAt,
            completedAt: parsed.completedAt
          };
        }
      };
    ```
  </Step>

  <Step title="Create an ATXP client">
    <Tabs>
      <Tab title="Using an ATXP account">
        Create a client using an <a href="/developers/build-agents/create-account" target="_blank">ATXP account</a> by importing the ATXP client SDK and other dependencies.

        ```typescript theme={null}
        // Import the ATXP client SDK
        import { atxpClient, ATXPAccount } from '@atxp/client';

        // Read the ATXP account details from environment variables
        const atxpConnectionString = process.env.ATXP_CONNECTION;

        // Create a client using the `atxpClient` function
        const client = await atxpClient({
          mcpServer: xLiveSearchService.mcpServer,
          account: new ATXPAccount(atxpConnectionString),
        });
        ```
      </Tab>

      <Tab title="Using a Base account">
        Create a client using a Base account by importing the ATXP client SDK and other dependencies.

        ```typescript theme={null}
        // Import the ATXP client SDK and Base account
        import { atxpClient } from '@atxp/client';
        import { BaseAccount } from '@atxp/base';

        // Read the Base account details from the environment variables
        const baseRpcUrl = process.env.BASE_RPC_URL;
        const basePrivateKey = process.env.BASE_PRIVATE_KEY;

        // Create a client using the `atxpClient` function
        const client = await atxpClient({
          mcpServer: xLiveSearchService.mcpServer,
          account: new BaseAccount(baseRpcUrl, basePrivateKey),
        });
        ```
      </Tab>

      <Tab title="Using a Solana account">
        Create a client using a Solana account by importing the ATXP client SDK and other dependencies.

        ```typescript theme={null}
        // Import the ATXP client SDK and Solana account
        import { atxpClient } from '@atxp/client';
        import { SolanaAccount } from '@atxp/solana';

        // Read the Solana account details from the environment variables
        const solanaRpcUrl = process.env.SOLANA_RPC_URL;
        const solanaPrivateKey = process.env.SOLANA_PRIVATE_KEY;

        // Create a client using the `atxpClient` function
        const client = await atxpClient({
          mcpServer: xLiveSearchService.mcpServer,
          account: new SolanaAccount(solanaRpcUrl, solanaPrivateKey),
        });
        ```
      </Tab>

      <Tab title="Using a Worldchain account">
        Create a client using a Worldchain account with MiniKit integration.

        ```typescript theme={null}
        // Import the ATXP client SDK and Worldchain account creator
        import { atxpClient } from '@atxp/client';
        import { createMiniKitWorldchainAccount } from '@atxp/worldchain';
        import { MiniKit } from '@worldcoin/minikit-js';

        // Create a Worldchain account using MiniKit
        const account = await createMiniKitWorldchainAccount({
          walletAddress: '0x1234...', // User's wallet address
          miniKit: MiniKit
        });

        // Create a client using the `atxpClient` function
        const client = await atxpClient({
          mcpServer: xLiveSearchService.mcpServer,
          account,
        });
        ```
      </Tab>

      <Tab title="Using a Polygon account">
        **Browser applications:**

        ```typescript theme={null}
        // Import the ATXP client SDK and Polygon browser account
        import { atxpClient } from '@atxp/client';
        import { PolygonBrowserAccount } from '@atxp/polygon';

        // Initialize the Polygon browser account with wallet provider
        const account = await PolygonBrowserAccount.initialize({
          provider: window.ethereum, // or any EIP-1193 provider
          walletAddress: '0x1234...', // User's wallet address
        });

        // Create a client using the `atxpClient` function
        const client = await atxpClient({
          mcpServer: xLiveSearchService.mcpServer,
          account,
        });
        ```

        **Server/CLI applications:**

        ```typescript theme={null}
        // Import the ATXP client SDK and Polygon server account
        import { atxpClient } from '@atxp/client';
        import { PolygonServerAccount } from '@atxp/polygon';

        // Read the Polygon account details from the environment variables
        const polygonRpcUrl = process.env.POLYGON_RPC_URL;
        const polygonPrivateKey = process.env.POLYGON_PRIVATE_KEY;

        // Create a Polygon server account
        const account = new PolygonServerAccount(
          polygonRpcUrl,
          polygonPrivateKey,
          137 // Chain ID: 137 = Polygon mainnet, 80002 = Amoy testnet
        );

        // Create a client using the `atxpClient` function
        const client = await atxpClient({
          mcpServer: xLiveSearchService.mcpServer,
          account,
        });
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Use the X Live Search service in your agent">
    <Tabs>
      <Tab title="Synchronous Search">
        Call the X Live Search tool by passing your search query and optional filters as arguments.

        Read the response using the `getResult` method.

        ```typescript theme={null}
        const searchParams = {
          query: "What are the latest updates from Stripe?",
          allowed_x_handles: ["stripe"],
          from_date: "2024-01-01",
          min_likes: 100  // Only show posts with at least 100 likes
        };

        try {
          const result = await client.callTool({
              name: xLiveSearchService.toolName,
              arguments: xLiveSearchService.getArguments(searchParams),
          });
          const { status, query, message, citations, toolCalls, errorMessage } = xLiveSearchService.getResult(result);

          if (status === 'success') {
            console.log('Query:', query);
            console.log('Summary:', message);
            console.log('Citations:', citations);
            console.log('Tool Calls:', toolCalls); // See what the agent did
          } else {
            console.error('Search failed:', errorMessage);
          }
        } catch (error) {
          console.error(`Error with ${xLiveSearchService.description}:`, error);
          process.exit(1);
        }
        ```

        <Check>
          You should see the search summary and citations printed in your console.
        </Check>
      </Tab>

      <Tab title="Asynchronous Search">
        For longer search tasks or to avoid timeouts, use the async tools to start the search and poll for completion.

        ```typescript theme={null}
        const searchParams = {
          query: "What are the latest updates from Stripe?",
          allowed_x_handles: ["stripe"],
          from_date: "2024-01-01",
          min_likes: 100  // Only show posts with at least 100 likes
        };

        try {
          // Start async search
          const asyncResult = await client.callTool({
              name: xLiveSearchService.asyncSearchToolName,
              arguments: xLiveSearchService.getArguments(searchParams),
          });
          const { taskId } = xLiveSearchService.getAsyncCreateResult(asyncResult);
          console.log('Search started with task ID:', taskId);

          // Poll for completion
          let completed = false;
          while (!completed) {
            await new Promise(resolve => setTimeout(resolve, 5000)); // Wait 5 seconds

            const statusResult = await client.callTool({
                name: xLiveSearchService.getSearchAsyncToolName,
                arguments: { taskId },
            });
            const { status, result, error } = xLiveSearchService.getAsyncStatusResult(statusResult);

            console.log('Status:', status);

            if (status === 'completed') {
              console.log('Query:', result.query);
              console.log('Summary:', result.message);
              console.log('Citations:', result.citations);
              console.log('Tool Calls:', result.toolCalls); // See what the agent did
              completed = true;
            } else if (status === 'error') {
              console.error('Search failed:', error);
              completed = true;
            }
          }
        } catch (error) {
          console.error(`Error with ${xLiveSearchService.description}:`, error);
          process.exit(1);
        }
        ```

        <Check>
          You should see the task ID printed first, followed by status updates, and finally the search summary and citations when the search completes.
        </Check>
      </Tab>
    </Tabs>
  </Step>
</Steps>
