Skip to main content
Glama
dragonkhoi

mixpanel

query_profiles

Retrieve and filter Mixpanel user profiles by specific properties or identifiers. Analyze user behavior and extract detailed profile data for targeted insights.

Instructions

Query Mixpanel user profiles with filtering options. Useful for retrieving detailed user profiles, filtering by specific properties, and analyzing user behavior across different dimensions.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
as_of_timestampNoThis parameter is only useful when also using 'behaviors'
behaviorsNoIf you are exporting user profiles using an event selector, you use a 'behaviors' parameter in your request
data_group_idNoThe ID of the group key, used when querying group profiles
distinct_idNoA unique identifier used to distinguish an individual profile
distinct_idsNoA JSON array of distinct_ids to retrieve profiles for. Example: '["id1", "id2"]'
filter_by_cohortNoTakes a JSON object with a single key called 'id' whose value is the cohort ID. Example: '{"id":12345}'
include_all_usersNoOnly applicable with 'filter_by_cohort' parameter. Default is true
output_propertiesNoA JSON array of names of properties you want returned. Example: '["$last_name", "$email", "Total Spent"]'
pageNoWhich page of the results to retrieve. Pages start at zero. If the 'page' parameter is provided, the session_id parameter must also be provided
project_idNoThe Mixpanel project ID. Optional since it has a default.. Optional since it has a default.
session_idNoA string id provided in the results of a previous query. Using a session_id speeds up api response, and allows paging through results
whereNoAn expression to filter users (or groups) by. Using the following grammar: <expression> ::= 'properties["' <property> '"]' | <expression> <binary op> <expression> | <unary op> <expression> | <math op> '(' <expression> ')' | <typecast op> '(' <expression> ')' | '(' <expression> ')' | <boolean literal> | <numeric literal> | <string literal> <binary op> ::= '+' | '-' | '*' | '/' | '%' | '==' | '!=' | '>' | '>=' | '<' | '<=' | 'in' | 'and' | 'or' <unary op> ::= '-' | 'not' <math op> ::= 'floor' | 'round' | 'ceil' <typecast op> ::= 'boolean' | 'number' | 'string' <property> ::= 'properties["' <property name> '"]'
workspace_idNoThe ID of the workspace if applicable

Implementation Reference

  • src/index.ts:935-1051 (registration)
    Registration of the 'query_profiles' tool using server.tool(), including name, description, input schema, and handler function reference.
      "query_profiles",
      "Query Mixpanel user profiles with filtering options. Useful for retrieving detailed user profiles, filtering by specific properties, and analyzing user behavior across different dimensions.",
      {
        project_id: z.string().describe("The Mixpanel project ID. Optional since it has a default.. Optional since it has a default.").optional(),
        workspace_id: z.string().describe("The ID of the workspace if applicable").optional(),
        distinct_id: z.string().describe("A unique identifier used to distinguish an individual profile").optional(),
        distinct_ids: z.string().describe("A JSON array of distinct_ids to retrieve profiles for. Example: '[\"id1\", \"id2\"]'").optional(),
        data_group_id: z.string().describe("The ID of the group key, used when querying group profiles").optional(),
        where: z.string().describe(`An expression to filter users (or groups) by. Using the following grammar: <expression> ::= 'properties["' <property> '"]'
                    | <expression> <binary op> <expression>
                    | <unary op> <expression>
                    | <math op> '(' <expression> ')'
                    | <typecast op> '(' <expression> ')'
                    | '(' <expression> ')'
                    | <boolean literal>
                    | <numeric literal>
                    | <string literal>
      <binary op> ::= '+' | '-' | '*' | '/' | '%' | '==' | '!=' |
                      '>' | '>=' | '<' | '<=' | 'in' | 'and' | 'or'
       <unary op> ::= '-' | 'not'
        <math op> ::= 'floor' | 'round' | 'ceil'
    <typecast op> ::= 'boolean' | 'number' | 'string'
       <property> ::= 'properties["' <property name> '"]'`).optional(),
        output_properties: z.string().describe("A JSON array of names of properties you want returned. Example: '[\"$last_name\", \"$email\", \"Total Spent\"]'").optional(),
        session_id: z.string().describe("A string id provided in the results of a previous query. Using a session_id speeds up api response, and allows paging through results").optional(),
        page: z.number().describe("Which page of the results to retrieve. Pages start at zero. If the 'page' parameter is provided, the session_id parameter must also be provided").optional(),
        behaviors: z.number().describe("If you are exporting user profiles using an event selector, you use a 'behaviors' parameter in your request").optional(),
        as_of_timestamp: z.number().describe("This parameter is only useful when also using 'behaviors'").optional(),
        filter_by_cohort: z.string().describe("Takes a JSON object with a single key called 'id' whose value is the cohort ID. Example: '{\"id\":12345}'").optional(),
        include_all_users: z.boolean().describe("Only applicable with 'filter_by_cohort' parameter. Default is true").optional(),
      },
      async ({ 
        project_id = DEFAULT_PROJECT_ID, 
        workspace_id, 
        distinct_id, 
        distinct_ids, 
        data_group_id, 
        where, 
        output_properties, 
        session_id, 
        page, 
        behaviors, 
        as_of_timestamp, 
        filter_by_cohort, 
        include_all_users 
      }) => {
        try {
          // Create authorization header using base64 encoding of credentials
          const credentials = `${SERVICE_ACCOUNT_USER_NAME}:${SERVICE_ACCOUNT_PASSWORD}`;
          const encodedCredentials = Buffer.from(credentials).toString('base64');
          
          // Construct base URL with project_id
          let url = `https://mixpanel.com/api/query/engage?project_id=${project_id}`;
          
          // Add optional workspace_id if provided
          if (workspace_id) {
            url += `&workspace_id=${workspace_id}`;
          }
          
          // Create form data for POST request
          const formData = new URLSearchParams();
          
          // Add optional parameters to form data if they exist
          if (distinct_id) formData.append('distinct_id', distinct_id);
          if (distinct_ids) formData.append('distinct_ids', distinct_ids);
          if (data_group_id) formData.append('data_group_id', data_group_id);
          if (where) formData.append('where', where);
          if (output_properties) formData.append('output_properties', output_properties);
          if (session_id) formData.append('session_id', session_id);
          if (page !== undefined) formData.append('page', page.toString());
          if (behaviors !== undefined) formData.append('behaviors', behaviors.toString());
          if (as_of_timestamp !== undefined) formData.append('as_of_timestamp', as_of_timestamp.toString());
          if (filter_by_cohort) formData.append('filter_by_cohort', filter_by_cohort);
          if (include_all_users !== undefined) formData.append('include_all_users', include_all_users.toString());
          
          // Set up request options
          const options = {
            method: 'POST',
            headers: {
              'accept': 'application/json',
              'authorization': `Basic ${encodedCredentials}`,
              'content-type': 'application/x-www-form-urlencoded'
            },
            body: formData
          };
          
          // Make the API request
          const response = await fetch(url, options);
          
          if (!response.ok) {
            const errorText = await response.text();
            throw new Error(`API request failed with status ${response.status}: ${errorText}`);
          }
          
          const data = await response.json();
          return {
            content: [
              {
                type: "text",
                text: JSON.stringify(data)
              }
            ]
          };
        } catch (error) {
          console.error('Error querying profiles:', error);
          return {
            content: [
              {
                type: "text",
                text: `Error querying profiles: ${error}`
              }
            ],
            isError: true
          };
        }
      }
    );
  • Zod input schema for the 'query_profiles' tool, defining parameters like project_id, distinct_ids, where filter expression, output_properties, pagination (session_id, page), and cohort filtering.
      {
        project_id: z.string().describe("The Mixpanel project ID. Optional since it has a default.. Optional since it has a default.").optional(),
        workspace_id: z.string().describe("The ID of the workspace if applicable").optional(),
        distinct_id: z.string().describe("A unique identifier used to distinguish an individual profile").optional(),
        distinct_ids: z.string().describe("A JSON array of distinct_ids to retrieve profiles for. Example: '[\"id1\", \"id2\"]'").optional(),
        data_group_id: z.string().describe("The ID of the group key, used when querying group profiles").optional(),
        where: z.string().describe(`An expression to filter users (or groups) by. Using the following grammar: <expression> ::= 'properties["' <property> '"]'
                    | <expression> <binary op> <expression>
                    | <unary op> <expression>
                    | <math op> '(' <expression> ')'
                    | <typecast op> '(' <expression> ')'
                    | '(' <expression> ')'
                    | <boolean literal>
                    | <numeric literal>
                    | <string literal>
      <binary op> ::= '+' | '-' | '*' | '/' | '%' | '==' | '!=' |
                      '>' | '>=' | '<' | '<=' | 'in' | 'and' | 'or'
       <unary op> ::= '-' | 'not'
        <math op> ::= 'floor' | 'round' | 'ceil'
    <typecast op> ::= 'boolean' | 'number' | 'string'
       <property> ::= 'properties["' <property name> '"]'`).optional(),
        output_properties: z.string().describe("A JSON array of names of properties you want returned. Example: '[\"$last_name\", \"$email\", \"Total Spent\"]'").optional(),
        session_id: z.string().describe("A string id provided in the results of a previous query. Using a session_id speeds up api response, and allows paging through results").optional(),
        page: z.number().describe("Which page of the results to retrieve. Pages start at zero. If the 'page' parameter is provided, the session_id parameter must also be provided").optional(),
        behaviors: z.number().describe("If you are exporting user profiles using an event selector, you use a 'behaviors' parameter in your request").optional(),
        as_of_timestamp: z.number().describe("This parameter is only useful when also using 'behaviors'").optional(),
        filter_by_cohort: z.string().describe("Takes a JSON object with a single key called 'id' whose value is the cohort ID. Example: '{\"id\":12345}'").optional(),
        include_all_users: z.boolean().describe("Only applicable with 'filter_by_cohort' parameter. Default is true").optional(),
      },
  • The handler function implements the tool logic: authenticates with Mixpanel service account, builds POST request to /api/query/engage with form-encoded parameters, fetches user profiles data, and returns JSON response or error message.
    async ({ 
      project_id = DEFAULT_PROJECT_ID, 
      workspace_id, 
      distinct_id, 
      distinct_ids, 
      data_group_id, 
      where, 
      output_properties, 
      session_id, 
      page, 
      behaviors, 
      as_of_timestamp, 
      filter_by_cohort, 
      include_all_users 
    }) => {
      try {
        // Create authorization header using base64 encoding of credentials
        const credentials = `${SERVICE_ACCOUNT_USER_NAME}:${SERVICE_ACCOUNT_PASSWORD}`;
        const encodedCredentials = Buffer.from(credentials).toString('base64');
        
        // Construct base URL with project_id
        let url = `https://mixpanel.com/api/query/engage?project_id=${project_id}`;
        
        // Add optional workspace_id if provided
        if (workspace_id) {
          url += `&workspace_id=${workspace_id}`;
        }
        
        // Create form data for POST request
        const formData = new URLSearchParams();
        
        // Add optional parameters to form data if they exist
        if (distinct_id) formData.append('distinct_id', distinct_id);
        if (distinct_ids) formData.append('distinct_ids', distinct_ids);
        if (data_group_id) formData.append('data_group_id', data_group_id);
        if (where) formData.append('where', where);
        if (output_properties) formData.append('output_properties', output_properties);
        if (session_id) formData.append('session_id', session_id);
        if (page !== undefined) formData.append('page', page.toString());
        if (behaviors !== undefined) formData.append('behaviors', behaviors.toString());
        if (as_of_timestamp !== undefined) formData.append('as_of_timestamp', as_of_timestamp.toString());
        if (filter_by_cohort) formData.append('filter_by_cohort', filter_by_cohort);
        if (include_all_users !== undefined) formData.append('include_all_users', include_all_users.toString());
        
        // Set up request options
        const options = {
          method: 'POST',
          headers: {
            'accept': 'application/json',
            'authorization': `Basic ${encodedCredentials}`,
            'content-type': 'application/x-www-form-urlencoded'
          },
          body: formData
        };
        
        // Make the API request
        const response = await fetch(url, options);
        
        if (!response.ok) {
          const errorText = await response.text();
          throw new Error(`API request failed with status ${response.status}: ${errorText}`);
        }
        
        const data = await response.json();
        return {
          content: [
            {
              type: "text",
              text: JSON.stringify(data)
            }
          ]
        };
      } catch (error) {
        console.error('Error querying profiles:', error);
        return {
          content: [
            {
              type: "text",
              text: `Error querying profiles: ${error}`
            }
          ],
          isError: true
        };
      }
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It mentions the tool is for 'querying' and 'retrieving,' which implies read-only behavior, but doesn't explicitly state whether it's safe, requires authentication, has rate limits, or what format the results return. For a tool with 13 parameters and no output schema, this leaves significant behavioral gaps unaddressed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and front-loaded, stating the core purpose in the first sentence. The second sentence elaborates on use cases without redundancy. Both sentences earn their place by clarifying intent and utility, making it efficient and well-structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the complexity (13 parameters, no annotations, no output schema), the description is incomplete. It doesn't explain what the tool returns, how results are structured, or any behavioral constraints like pagination or error handling. For a query tool with many options and no structured output documentation, this leaves the agent with insufficient context to use it effectively.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema description coverage is 100%, meaning all 13 parameters are documented in the input schema itself. The description adds no specific parameter information beyond the generic mention of 'filtering options.' Since the schema does the heavy lifting, the baseline score of 3 is appropriate—the description doesn't add value here but doesn't need to compensate for gaps.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Query Mixpanel user profiles with filtering options.' It specifies the resource (user profiles) and action (query with filtering). However, it doesn't explicitly differentiate this from sibling tools like 'profile_event_activity' or 'list_saved_cohorts', which likely work with similar Mixpanel data but serve different purposes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides some implied usage context by mentioning it's 'useful for retrieving detailed user profiles, filtering by specific properties, and analyzing user behavior across different dimensions.' This suggests when to use it, but it doesn't explicitly state when NOT to use it or name alternatives among the sibling tools. For example, it doesn't clarify when to use this versus 'profile_event_activity' for user behavior analysis.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Related Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/dragonkhoi/mixpanel-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server