Skip to main content
Glama

monica_list_contacts

Retrieve paginated contacts from Monica CRM with customizable detail levels and optional filters for gender, tags, and communication details.

Instructions

Retrieve a paginated list of contacts without requiring a search query. Choose the detail level (minimal/basic/expanded/full) and optional filters (gender, tags, communication details).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
detailLevelNominimal
filtersNo
limitNo
pageNo

Implementation Reference

  • The main execution handler for the 'monica_list_contacts' tool. Parses input with Zod schema, determines required data inclusions based on detail level and filters, resolves gender name if needed, fetches contacts via client.listContacts API, applies post-fetch filtering (gender, tags, emails, phones, partial status), maps contacts to requested detail level using helper functions, generates summary, and returns structured paginated list response.
    async (rawInput) => {
      const input = listContactsInputSchema.parse(rawInput);
      const filters = input.filters ?? {};
      const includePartial = filters.includePartial ?? false;
      const requiresContactFields =
        input.detailLevel !== 'minimal' || filters.hasEmail === true || filters.hasPhone === true;
      const hasTagFilters = Boolean(
        (filters.tagIds && filters.tagIds.length > 0) || (filters.tagNames && filters.tagNames.length > 0)
      );
      const requiresTags = input.detailLevel !== 'minimal' && (input.detailLevel !== 'basic' || hasTagFilters);
      const requiresAddresses = input.detailLevel === 'expanded' || input.detailLevel === 'full';
    
      const genderNameFromId = filters.genderId
        ? await resolveGenderNameById(client, filters.genderId)
        : undefined;
      const normalizedGender = (filters.genderName ?? genderNameFromId)?.trim().toLowerCase();
      const normalizedTagNames = (filters.tagNames ?? []).map((name) => name.trim().toLowerCase());
    
      const response = await client.listContacts({
        limit: input.limit,
        page: input.page,
        includePartial,
        includeContactFields: requiresContactFields || input.detailLevel === 'full',
        includeTags: requiresTags || input.detailLevel !== 'minimal',
        includeAddresses: requiresAddresses || input.detailLevel === 'full'
      });
    
      const contacts = response.data.filter((contact) =>
        matchesFilters({
          contact,
          includePartial,
          normalizedGender,
          normalizedTagNames,
          requiredTagIds: filters.tagIds,
          requireEmail: filters.hasEmail,
          requirePhone: filters.hasPhone
        })
      );
    
      const mapped = contacts.map((contact) =>
        buildContactRepresentation(contact, input.detailLevel as DetailLevel)
      );
    
      const summary = generateListSummary({
        count: mapped.length,
        itemName: 'contact',
        contextInfo: `detail level ${input.detailLevel}`
      });
    
      return buildListResponse({
        items: mapped,
        itemName: 'contact',
        summaryText: summary,
        structuredData: {
          action: 'list',
          detailLevel: input.detailLevel,
          filters: {
            ...filters,
            genderName: normalizedGender ? genderNameFromId ?? filters.genderName : filters.genderName
          },
          contacts: mapped
        },
        pagination: extractPagination(response)
      });
    }
  • Direct registration of the 'monica_list_contacts' tool via server.registerTool, specifying title, description, and inline inputSchema (Zod-based with detailLevel, filters, pagination). The handler is provided inline.
    server.registerTool(
      'monica_list_contacts',
      {
        title: 'List Monica contacts',
        description:
          'Retrieve a paginated list of contacts without requiring a search query. Choose the detail level (minimal/basic/expanded/full) and optional filters (gender, tags, communication details).',
        inputSchema: {
          detailLevel: z.enum(detailLevels).default('minimal'),
          filters: filtersSchema,
          limit: z.number().int().min(1).max(100).optional(),
          page: z.number().int().min(1).optional()
        }
      },
      async (rawInput) => {
        const input = listContactsInputSchema.parse(rawInput);
        const filters = input.filters ?? {};
        const includePartial = filters.includePartial ?? false;
        const requiresContactFields =
          input.detailLevel !== 'minimal' || filters.hasEmail === true || filters.hasPhone === true;
        const hasTagFilters = Boolean(
          (filters.tagIds && filters.tagIds.length > 0) || (filters.tagNames && filters.tagNames.length > 0)
        );
        const requiresTags = input.detailLevel !== 'minimal' && (input.detailLevel !== 'basic' || hasTagFilters);
        const requiresAddresses = input.detailLevel === 'expanded' || input.detailLevel === 'full';
    
        const genderNameFromId = filters.genderId
          ? await resolveGenderNameById(client, filters.genderId)
          : undefined;
        const normalizedGender = (filters.genderName ?? genderNameFromId)?.trim().toLowerCase();
        const normalizedTagNames = (filters.tagNames ?? []).map((name) => name.trim().toLowerCase());
    
        const response = await client.listContacts({
          limit: input.limit,
          page: input.page,
          includePartial,
          includeContactFields: requiresContactFields || input.detailLevel === 'full',
          includeTags: requiresTags || input.detailLevel !== 'minimal',
          includeAddresses: requiresAddresses || input.detailLevel === 'full'
        });
    
        const contacts = response.data.filter((contact) =>
          matchesFilters({
            contact,
            includePartial,
            normalizedGender,
            normalizedTagNames,
            requiredTagIds: filters.tagIds,
            requireEmail: filters.hasEmail,
            requirePhone: filters.hasPhone
          })
        );
    
        const mapped = contacts.map((contact) =>
          buildContactRepresentation(contact, input.detailLevel as DetailLevel)
        );
    
        const summary = generateListSummary({
          count: mapped.length,
          itemName: 'contact',
          contextInfo: `detail level ${input.detailLevel}`
        });
    
        return buildListResponse({
          items: mapped,
          itemName: 'contact',
          summaryText: summary,
          structuredData: {
            action: 'list',
            detailLevel: input.detailLevel,
            filters: {
              ...filters,
              genderName: normalizedGender ? genderNameFromId ?? filters.genderName : filters.genderName
            },
            contacts: mapped
          },
          pagination: extractPagination(response)
        });
      }
    );
  • listContactsInputSchema: Zod object schema defining validated input structure - detailLevel enum (minimal/basic/expanded/full), optional filters object, limit (1-100), page.
    const listContactsInputSchema = z.object({
      detailLevel: z.enum(detailLevels).default('minimal'),
      filters: filtersSchema,
      limit: z.number().int().min(1).max(100).optional(),
      page: z.number().int().min(1).optional()
    });
  • filtersSchema: Zod schema for optional filters including genderId/name, tagIds/names, hasEmail/hasPhone booleans, includePartial.
    const filtersSchema = z
      .object({
        genderId: z.number().int().positive().optional(),
        genderName: z.string().min(1).max(50).optional(),
        tagIds: z.array(z.number().int().positive()).max(25).optional(),
        tagNames: z.array(z.string().min(1).max(255)).max(25).optional(),
        hasEmail: z.boolean().optional(),
        hasPhone: z.boolean().optional(),
        includePartial: z.boolean().optional()
      })
      .optional();
  • Invocation of registerContactListTools(context) within the top-level registerTools function, which orchestrates registration of all MCP tools.
    registerContactListTools(context);

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/Jacob-Stokes/monica-mcp'

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