list_contacts
Retrieve saved providers from your contacts list, ordered by most recent activity. Combine with search filters for refined results.
Instructions
List providers saved in the active agent's .contacts.json, newest activity first. Use search_agents with contacts_only=true to combine this with online/capability filters.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No |
Implementation Reference
- Handler for the 'list_contacts' tool. Reads the .contacts.json file for the active agent, sorts contacts by lastJobAt (or addedAt), applies the limit from the schema, sanitizes fields via sanitizeField/sanitizeUntrusted, and returns a text result with the contact list.
defineTool({ name: 'list_contacts', description: "List providers saved in the active agent's .contacts.json, newest activity " + 'first. Use search_agents with contacts_only=true to combine this with online/' + 'capability filters.', schema: ListContactsSchema, async handler(ctx, input) { ctx.toolRateLimiter.check(); const agent = ctx.active(); if (!agent.agentDir) { return textResult( 'Active agent is ephemeral; no on-disk contacts. Create a persistent agent first.', ); } const data = await readContacts(agent.agentDir); const sorted = [...data.contacts].sort((left, right) => { const leftKey = left.lastJobAt ?? left.addedAt; const rightKey = right.lastJobAt ?? right.addedAt; return rightKey - leftKey; }); const limited = sorted.slice(0, input.limit).map((contact) => ({ npub: contact.npub, name: contact.name !== undefined ? sanitizeField(contact.name, 200) : undefined, note: contact.note !== undefined ? sanitizeField(contact.note, 500) : undefined, added_at: contact.addedAt, last_job_at: contact.lastJobAt, last_capability: contact.lastCapability !== undefined ? sanitizeField(contact.lastCapability, 200) : undefined, })); const { text: wrapped } = sanitizeUntrusted(JSON.stringify(limited, null, 2), 'structured'); return textResult(`${limited.length} contact(s):\n${wrapped}`); }, }), - Zod schema for list_contacts: accepts an optional 'limit' (1-200, default 50).
const ListContactsSchema = z.object({ limit: z.number().int().min(1).max(200).default(50), }); - packages/mcp/src/server.ts:32-40 (registration)All tools are aggregated in the allTools array. feedbackContactsTools (which contains list_contacts) is spread into the registry at line 38.
const allTools: ToolDefinition[] = [ ...discoveryTools, ...customerTools, ...walletTools, ...dashboardTools, ...agentTools, ...feedbackContactsTools, ...policiesTools, ]; - readContacts reads the .contacts.json file from the agent's directory. Returns an empty list if missing or corrupt.
/** Read .contacts.json. Returns an empty list if missing or corrupt. */ export async function readContacts(agentDir: string): Promise<Contacts> { return readRaw(pathFor(agentDir)); } - packages/mcp/src/sanitize.ts:305-311 (helper)sanitizeField strips dangerous Unicode and truncates to maxLen. Used by the list_contacts handler to sanitize contact name, note, and lastCapability before returning.
export function sanitizeField(input: string, maxLen: number): string { let text = stripDangerousUnicode(input); if (text.length > maxLen) { text = text.slice(0, maxLen) + '...'; } return text; }