Tools reference
Inputs, results, and behavior for every tool the Homie MCP server exposes.
The Homie MCP server exposes fifteen read-only tools to every token. Tokens with the mcp:write scope also receive four write tools, for nineteen in total. Write tools are not registered at all for a read-only token, so they never appear in its tool list.
- Organization-scoped tools search the whole network of the organization that owns the token. They work with user MCP tokens and organization API keys.
- User-scoped tools act on the authenticated user personally: their own connections, prioritized list, target lists, and re-score runs. They need a user MCP token, and organization API keys are rejected.
- Company tools query Homie's shared company directory.
| Tool | Scope | Access | Use it to |
|---|---|---|---|
get_icp | Organization | Read | Read the Ideal Customer Profile before prospecting. |
search_ghost_opportunities | Organization | Read | Look up prospects the agent has already surfaced, by keyword. |
list_ghost_opportunities | Organization | Read | Page through all surfaced prospects, with filters and sorting. |
list_person_network | Organization | Read | See who a given person knows, warmest first. |
search_warm_paths | Organization | Read | Find intro routes to one person or company. |
check_warmness_rescore | User | Read | Wait for AI re-scoring of cold connections and read the refined scores. |
search_network | Organization | Read | Run a natural-language search across the network. |
search_people | Organization | Read | Find people by name, email, role, or company. |
get_person | Organization | Read | Fetch one person by id. |
list_first_degree_connections | User | Read | Page through your own direct connections. |
list_second_degree_connections | User | Read | See who your contacts could introduce you to. |
search_companies | Directory | Read | Find companies by name, industry, or location. |
get_company | Directory | Read | Fetch one company by id. |
list_target_lists | User | Read | List your target lists. |
get_target_list | User | Read | Read one target list and its companies. |
add_prioritized_connection | User | Write | Mark a direct connection as a key relationship. |
remove_prioritized_connection | User | Write | Undo a prioritization. |
create_target_list | User | Write | Create an empty target list. |
modify_target_list | User | Write | Rename a target list, or add or remove a company. |
Every tool returns structured content. The result carries a typed structuredContent payload, validated against the tool's declared outputSchema, alongside a JSON text fallback. MCP clients that support structured output get typed results instead of parsing JSON out of a text blob.
Start with get_icp when prospecting. Warmness ranks reachability, not fit, so results ordered by warmness alone put colleagues ahead of prospects.
Already-requested people. Candidate lists (company-mode search_warm_paths, list_person_network) exclude anyone the organization has already requested an intro to, reporting the count as excludedIntroRequested; includeIntroRequested: true brings them back. Lookup tools (person-mode search_warm_paths, search_people, get_person) never filter, but annotate results with introRequested, introStatus, introRequestedBy, and introRequestedAt. Every status counts as already asked, including LOST — the status travels with the annotation so you can judge whether a stale request is worth retrying.
get_icp
Read the organization's Ideal Customer Profile. Takes no arguments.
Returns { configured, icp? }. When configured is false the organization has not set one up; ask the user who they are targeting rather than guessing. Otherwise icp carries name, description, positions, industries, locations, companySize, companyType, additionalContext, skipWarmConnections, isAutoGenerated, sourceWebsite, and updatedAt.
The ICP is stored text, not a scorer: read it and filter the people other tools return against it yourself. Nothing is scored server-side, so there is no added latency or model cost per query.
list_person_network
List the people a given person is connected to, warmest first. This answers "who does Kalle know", "warm paths from Kalle's network", and "who could Kalle introduce us to".
This is the raw-network fallback. Call search_ghost_opportunities first with the person's name and company. Prefer any opportunities it returns, because they are already scored against the ICP.
| Field | Type | Notes |
|---|---|---|
name | string | Person's name, fuzzy-matched. Usually what you have. On a tie the best-connected match wins. |
linkedinId | string | LinkedIn handle. |
personId | string | Homie person id. A user id is also accepted here, since warm paths return fromUserId. |
limit | number | 1-50, default 20. |
offset | number | 0-based offset. Use the previous response's nextOffset. |
includeIntroRequested | boolean | Default false. Set true to include people already asked about, annotated. |
Returns { person, connections, totalCount, returnedCount, limit, offset, nextOffset, hasMore, excludedIntroRequested, coverage }. Each connection carries position, currentCompany, city, country, warmness, and warmnessSignals, which is what you need to qualify them against the ICP.
Check coverage before describing the result
coverage says how complete the network is, which is a different question from how big it is. Most people in the graph are derived or none, so an empty list is usually not evidence that someone has no connections.
| Value | Meaning |
|---|---|
synced | The person is a Homie user and their own connections were imported. The list is their network. |
derived | Their connections are known indirectly, through the people around them. This is the slice of their network Homie has observed, not all of it. Say so rather than implying completeness. |
none | Homie has no outbound edges for them. An empty connections means "not mapped", never "they know nobody". |
The subject must be in the organization's network: either an org member, or someone an org member is directly connected to. Anyone else returns a scope error rather than turning this into a directory lookup over every person in Homie.
Do not reach for alternatives that look similar. Enumerating list_ghost_opportunities and filtering for a connector is slow and misses anyone the agent has not surfaced. search_network's asUserId only accepts org members who hold a Homie account, so it cannot express "as this person in our network".
Cold connections are re-scored
When the top of the list includes people with warmness below 25, Homie queues the subject's edges to them for background AI re-scoring. Up to ten people are queued per call. This needs a user MCP token, because the run is tracked against the requesting user. Call check_warmness_rescore next, and answer with its refined scores rather than the cold ones.
search_warm_paths
Find warm intro paths from anyone in the organization to a target person OR to anyone at a target company.
| Field | Type | Notes |
|---|---|---|
prospectPersonId | string | Homie person id. Pass exactly one target: this, prospectLinkedinId, prospectName, or prospectCompany. |
prospectLinkedinId | string | LinkedIn handle. |
prospectName | string | Fuzzy name match. Add prospectCompany alongside it to disambiguate; it then narrows the person rather than switching modes. |
prospectCompany | string | Company name. On its own, returns paths to anyone working there. Each path's target field identifies the specific employee. |
prospectRoles | string[] | Company-only filter: 1–20 literal role phrases, OR-ed against current profile titles before finding paths. For example ["head of security", "security", "ciso"]. Titles are not independent verification of seniority. |
maxHops | number | 1-3. Keep only routes with at most this many relationship edges. 3 also opts in to three-hop third_degree routes. |
includePossiblePaths | boolean | Default false. Set true to include complete routes with weak or unscored hops. These are possible routes, not warm intros. |
limit | number | 1-50, default 20. Maximum paths requested; the response size budget may return fewer. Always continue with nextOffset. |
offset | number | 0-based offset for pagination. Use the previous response's nextOffset to fetch the next page. |
includeIntroRequested | boolean | Company mode only. Default false. Set true to include employees the org already asked for an intro to. |
scope | string | organization (default) searches from everyone here; me restricts to the authenticated user and requires a user-scoped token. |
fromUserIds | string[] | Search only from these org members. Accepts user ids or person ids. Mutually exclusive with a non-default scope. |
connectionTypes | string[] | Keep only these path types: direct, second_degree, third_degree, advocate, advocate_second_degree. |
Returns { outcome, message, fallbackConnections, prospect, company, paths[], totalCount, returnedCount, limit, offset, nextOffset, hasMore, excludedIntroRequested, coverage }. For person mode company is null; for company mode prospect is null and each path entry has a target field with the employee being reached.
Compact connector responses
Both the structured result and JSON text fallback contain the same compact page,
limited to 12,000 UTF-8 bytes per payload. Raw scoring-factor breakdowns and image
URLs are omitted. Person identities, positions, companies, ordered hops, scores,
signal labels and intro-request annotations remain available. An unscored hop
stays null; it is not evidence of a warm relationship.
limit is an upper bound, not a guaranteed page length. If the page is shortened,
returnedCount reflects the paths actually included, hasMore is true, and
nextOffset points to the first undisplayed path. Keep the same filters and pass
that value as offset; do not add limit yourself. totalCount and graph
coverage retain their original meaning. Use get_person for additional profile
details instead of requesting larger path pages.
Read outcome before calling anything a warm intro
outcome | Meaning |
|---|---|
found | At least one genuinely warm route, with warmness above 0, was returned. |
no_paths | The target exists but no route is warm. paths may still hold cold routes whose connector-to-target hop scores 0. Those are reachable in name only. |
target_not_found | No such person or company is in the organization's network. prospect and company are both null. |
incomplete | A bounded scan hit its cap, so a warm route may have been missed. This takes precedence over no_paths. |
A list of paths alone is not proof of a warm route, so gate on outcome === "found" or on a path's own warmness. On no_paths and target_not_found the result carries a human-readable message. When the organization has any warm contacts, it also carries fallbackConnections: the organization's warmest reachable people, warmest first. Relay the message and offer those people as the closest existing contacts. Never present them as a path to the requested target, and never report an empty result as "they know no one".
coverage reports capped, candidatePeople, candidatePeopleCap, secondDegreeEdgesCapped, and thirdDegreeEdgesCapped. capped is true when the employee candidate cap or a second- or third-degree edge cap was reached. Check it before implying the list is complete.
Scoping the search
By default this searches from every member of the organization, which answers "can we reach them". Narrowing the source answers the everyday variants:
| Question | Arguments |
|---|---|
| Can anyone here reach them? | (default) |
| Can I reach them? | scope: "me" |
| Who in my first-degree network bridges to them? | scope: "me", connectionTypes: ["second_degree"] |
| Do I already know them? | scope: "me", connectionTypes: ["direct"] |
| Can a specific colleague reach them? | fromUserIds: ["<user or person id>"] |
| Only routes through advocates | connectionTypes: ["advocate", "advocate_second_degree"] |
scope: "me" needs a user-scoped MCP token; an organization API key has no personal network and gets a scope error telling it to use fromUserIds instead. fromUserIds accepts either id kind because warm paths return fromUserId while every other tool returns person ids. People in the network who have no Homie account cannot be a source at all — use list_person_network for them.
excludedIntroRequested counts employees withheld in company mode because an intro was already requested. It is always 0 in person mode, which annotates the prospect with introRequested instead of filtering: you named one person, so answering "no paths" because an intro is already in flight would hide more than it helps.
Each path includes:
fromUserId/fromUserName: the org member whose perspective enables the path.connector: the intermediary person.viaAdvocate: for anadvocate_second_degreepath, the accepted advocate the org member can ask first. In that path type,connectoris the advocate's connection to the target.connectionType: one of:direct: the org member knows the target.second_degree: the org member knows someone who knows the target.third_degree: a three-hop route, returned only whenmaxHopsis3.advocate: an advocate of the org member knows the target.advocate_second_degree: an advocate of the org member knows someone who knows the target.
hops: the route as an ordered list of edges. Each hop hasfrom,to,warmness, andsignals.warmness: overall score for ranking (0-100).userToConnectorWarmness+userToConnectorSignals: score and human-readable signal labels for the source-side relationship. For a route via an advocate, use the orderedhopsto identify each relationship precisely.connectorToProspectWarmness+connectorToProspectSignals: score and labels for the connector to target hop (set for non-direct paths).
The *Signals arrays and each hop's signals contain human-readable evidence
(e.g. "Working together at Acme", "3 mutual connections", "Both reacted to each other's posts").
Raw *Breakdown objects remain optional in the output schema for compatibility,
but compact MCP responses omit them. REST responses and native Homie cards are
unaffected.
Results are ranked in this order: direct, advocate, 2nd-degree, advocate 2nd-degree, 3rd-degree. Within each tier, warmer paths appear first. When the target is found but has no paths, the matched prospect or company is still returned, with outcome: "no_paths".
Cold connections are re-scored
When the result surfaces cold connections from the authenticated user's own network, Homie queues them for background AI re-scoring. This needs a user MCP token. The message then tells you scoring is running. Call check_warmness_rescore and answer with the refined scores.
check_warmness_rescore
Wait for the background AI re-scoring that search_warm_paths or list_person_network just queued for cold connections, then return the refined scores. User-scoped: organization API keys have no re-score runs, so they always get status: "none".
| Field | Type | Notes |
|---|---|---|
runId | string | Optional. A specific re-score run. Omit it to use your latest one. |
Call it right after a tool says scoring is running. It blocks until the run finishes, checking every few seconds for up to about 35 seconds. Without runId, it only considers runs started in the last 15 minutes. You can then answer once with the improved scores instead of asking the user to try again.
Returns { status, completed, failed, total, results }.
status | Meaning |
|---|---|
completed | The run finished and results are final. |
running | The wait timed out before the run finished. Call again to get the rest. |
failed | The run errored. |
none | There is no recent re-score to report. |
completed and total count re-scored pairs. Each entry in results has name, previousScore (the formula score before re-scoring), newScore (the AI-refined score, now saved on the connection), and a short summary. It lists up to 20 successfully re-scored people, highest newScore first.
list_first_degree_connections
List the authenticated user's own first-degree LinkedIn connections. Unlike the search tools, this one is scoped to the token's user personally — organization API keys are rejected.
| Field | Type | Notes |
|---|---|---|
limit | number | 1-50, default 20. |
offset | number | 0-based offset for pagination. Use the previous response's nextOffset to fetch the next page. |
Returns { connections, totalCount, returnedCount, limit, offset, nextOffset, hasMore }. Each connection has person fields only: id, name, linkedinId, position, currentCompany. Ordered by name. Connections whose warmness hasn't been computed yet are included — warmness is enrichment, not a membership filter.
list_second_degree_connections
People connected to one of your own first-degree contacts, but whom you don't know directly. Each entry names the bridging connector, so you can see who could introduce you. User-scoped: organization API keys are rejected.
| Field | Type | Notes |
|---|---|---|
limit | number | 1-50, default 20. |
offset | number | 0-based offset for pagination. Use the previous response's nextOffset. |
viaConnectorId | string | Only list people reachable through this first-degree contact (a person id). |
Returns { connections, totalCount, returnedCount, limit, offset, nextOffset, hasMore, scannedBridges, capped }, ordered warmest first. Each connection carries viaConnector (the bridging contact) and warmness for the connector→person edge.
Coverage is bounded. Second-degree networks can be very large, so results cover a bounded number of warm edges per connector. Without viaConnectorId, the bridge set is bounded too. totalCount counts people within that window, scannedBridges says how many contacts were considered, and capped: true means a bridge or per-connector edge cap was reached. This signal applies with or without viaConnectorId.
add_prioritized_connection
Add one of your own first-degree connections to your prioritized list, meaning the people you consider key relationships. This tool writes. User-scoped: organization API keys are rejected.
| Field | Type | Notes |
|---|---|---|
personId | string | Homie person id, as returned by list_first_degree_connections, search_people, or get_person. Pass one of these two fields. |
connectionId | string | Connection id, as an alternative. Useful for an id taken from a ghost opportunity's bestPath.connectionId. |
Prioritizing has three effects:
- The person moves to the top of your priority list.
- A strong priority signal enters that connection's warmness score, which is recalculated immediately.
- If the person also has a Homie account, they are promoted to an accepted advocate, so they appear as an available connector.
Returns { id, connectionId, priority, alreadyPrioritized, person, warmness }. alreadyPrioritized is true when the person was already on the list. A retry after the person reaches the top is a no-op: it does not increment priority or rerun side effects. warmness is the score after the initial recalc, or the stored score on a no-op; it is omitted if scoring failed, which does not undo the write.
Only your own first-degree connections can be prioritized. Passing a second-degree person, or someone else's connection, returns a validation error.
remove_prioritized_connection
Remove one of your first-degree connections from your prioritized list. This tool writes. User-scoped: organization API keys are rejected.
| Field | Type | Notes |
|---|---|---|
personId | string | Homie person id. Pass one of these two fields. |
connectionId | string | Connection id, as an alternative, exactly as for the add tool. |
Removing withdraws the priority signal from that connection's warmness score, which is recalculated immediately. It does not revoke advocate status that was granted when the person was prioritized.
Returns { connectionId, removed, person, warmness }. removed is false when the person was not on your list, in which case nothing changes and warmness is the stored score. Only call it when the user explicitly asks to unprioritize someone.
get_person
Fetch one person by their Homie person id (as returned by search_people, search_warm_paths, or list_first_degree_connections).
| Field | Type | Notes |
|---|---|---|
id | string | Required. Homie person id. |
Returns { found, person? }. person includes profile fields, current company, network size, a degree field ("first" or "second"), and — on first-degree connections — the org's warmness, warmnessBreakdown, and human-readable warmnessSignals. found is false when the person isn't in the organization's network (1st or 2nd degree), so the tool never reveals that someone exists outside your graph.
list_ghost_opportunities
List the organization's ghost opportunities — prospects the agent discovered, each with an ICP evaluation, buying-intent signals, key insights, and the best warm intro path. Org-scoped: works with both user MCP tokens and organization API keys.
| Field | Type | Notes |
|---|---|---|
status | string | visible, saved, accepted, intro_requested, or dismissed. Default: the active set. |
sort | string | newest (default), oldest, or relevancy. |
search | string | Substring match on prospect name, company, or position. |
limit | number | 1-50, default 20. |
offset | number | 0-based offset for pagination. Use the previous response's nextOffset. |
Returns { opportunities, totalCount, returnedCount, limit, offset, nextOffset, hasMore }. Prospects working at your own company are excluded. A path whose connector is one of your own org members is not surfaced as bestPath (it would just echo back what the org already knows); when every path for an opportunity is internal, the opportunity is still returned with bestPath omitted.
search_ghost_opportunities
Search the ghost opportunities the agent has already discovered, by keyword. Use it for questions like "any opportunities at fintechs?" or "opportunities matching Acme", and before list_person_network when someone asks who a person could introduce. Org-scoped: works with both user MCP tokens and organization API keys.
It does not scan the network or create new opportunities. For open-ended prospecting use search_network, and for a route to one specific person or company use search_warm_paths.
| Field | Type | Notes |
|---|---|---|
query | string | Required. Substring matched against prospect name, company, and position. |
status | string | visible, saved, accepted, intro_requested, or dismissed. Default: the active set. |
sort | string | relevancy (default, highest overallScore first), newest, or oldest. |
limit | number | 1-50, default 20. |
offset | number | 0-based offset for pagination. Use the previous response's nextOffset. |
Returns the same payload as list_ghost_opportunities, with the same exclusions. The only differences are that query is required and results sort by relevancy by default.
search_network
Natural-language search across the organization's combined network. Best for queries like "VPs of Eng at Series C startups in NYC".
The response includes totalCount and returnedCount.
| Field | Type | Notes |
|---|---|---|
query | string | Required. |
networks | ("user" | "advocate" | "organization")[] | Default: all three. |
strictness | 1-3 | 1=relaxed (default), 2=normal, 3=strict. |
asUserId | string | Org member to use as perspective for user/advocate networks. Accepts their user id or their person id. Defaults to the authenticated MCP user when available, otherwise the oldest admin. People in the network without a Homie account cannot be a perspective; use list_person_network for them. |
limit | number | 1-50, default 20. |
The search uses the same semantic engine as the Homie app's own search page and falls back to a simpler keyword search when that is unavailable or returns nothing. The response carries a fallback object explaining any downgrade, so read it rather than assuming which search ran.
search_people
Substring search across people in the network (1st-degree direct connections + 2nd-degree by default).
| Field | Type | Notes |
|---|---|---|
query | string | Required. Matches name, email, position, company. |
limit | number | 1-50, default 20. |
includeSecondDegree | boolean | Default true. |
Returns { results: [...] }. Each result includes a degree field ("first" or "second"), a warmness score, and a warmnessBreakdown object with the factors behind the score.
search_companies
Search Homie's company directory by name, industry, or HQ location. This is a directory lookup, not a warm-path search.
| Field | Type | Notes |
|---|---|---|
query | string | Required. |
page | number | 1-based, default 1. |
limit | number | 1-50, default 20. |
get_company
Fetch one company from Homie's directory. This is a directory lookup, not a warm-path search; use search_warm_paths with prospectCompany to reach people there.
| Field | Type | Notes |
|---|---|---|
id | string | Required. Either the Homie id or the LinkedIn companyId, as returned by search_companies, get_target_list, or a person's company. |
Returns { found, company? }. The company carries id, companyId, name, industry, headquartersLocation, minSize, maxSize, and logoUrl when available. Unknown ids return found: false rather than an error.
list_target_lists
List your own target lists, most recently updated first. User-scoped: organization API keys are rejected.
Takes no arguments. Returns { targetLists }; each summary contains id, name, companyCount, unmatchedCompanyCount, createdAt, and updatedAt. Use the list's id as targetListId with get_target_list or modify_target_list.
companyCount counts companies linked to Homie's company directory. unmatchedCompanyCount counts imported company names that have not yet matched a directory record.
get_target_list
Read one of your own target lists and page through its matched companies. User-scoped: organization API keys are rejected.
| Field | Type | Notes |
|---|---|---|
targetListId | string | Target-list id from list_target_lists. |
limit | number | 1-50, default 20. |
offset | number | 0-based company offset. Use the previous response's nextOffset. |
Returns { found, targetList? }. The target list includes its summary fields plus companies, totalCount, returnedCount, limit, offset, nextOffset, and hasMore. Each company carries its Homie id, LinkedIn companyId, name, industry, and headquarters when available. Lists that do not belong to the authenticated user return found:false.
create_target_list
Create a new, empty target list that you own. This tool writes. User-scoped: organization API keys are rejected.
| Field | Type | Notes |
|---|---|---|
name | string | Required. 255 characters maximum, trimmed. |
If you already own a list with exactly this name, no duplicate is created and that list is returned instead, so a retry is safe. Follow up with modify_target_list to add companies. Only call it when the user asks for a new list, or asks to add companies to a list that list_target_lists shows does not exist.
Returns { created, targetList }. created is false when the existing list was returned.
modify_target_list
Rename one of your own target lists, add a company, or remove a company. This tool writes and only the list's owner can use it. Organization API keys are rejected.
| Field | Type | Notes |
|---|---|---|
targetListId | string | Target-list id from list_target_lists. |
action | string | rename, add_company, or remove_company. |
name | string | Required only for rename; 255 characters maximum. |
companyId | string | Required for add/remove. Accepts either the id or companyId returned by search_companies. |
Resolve the list first with list_target_lists. For company changes, use search_companies to resolve the company and get_target_list when you need to inspect current membership. Only call the write after the user explicitly asks for the change.
Returns { action, changed, targetList }. changed:false means the requested end state was already true: the list already had that name or company, or the company was already absent. This makes repeat calls safe.
Resources
Every tool hands back ids. Rather than re-running a search to turn an id back into a record, read it directly:
| URI | Returns |
|---|---|
homie://person/{id} | Same payload as get_person. |
homie://company/{id} | Same payload as get_company. Accepts the Homie company id or the LinkedIn companyId. |
homie://icp | Same { configured, icp? } payload as get_icp. |
homie://ghost-opportunity/{id} | One opportunity, same shape as an entry from list_ghost_opportunities. |
All four return application/json. Person and opportunity resources outside your organization's reach return a found:false payload rather than erroring, so they do not confirm the existence of records you cannot access. Company lookup uses the shared company directory.
These are addressable lookups rather than enumerable collections, so the templates don't support listing. Enumerate with the paginated tools instead.
Prompts
warm-intro-brief
The workflow the server exists for. Give it a prospect (LinkedIn handle, full name, or company) and it drives search_warm_paths + get_person, then briefs you on:
- who to ask — the connector and the org member who owns that relationship,
- why the path works — quoting the warmness signal labels verbatim rather than paraphrasing them,
- how to ask — a short message grounded in the actual shared context,
- alternatives — the next-best path, when it's a genuinely different route.
It instructs the model never to invent a connector, signal, or score, and to say so plainly when no path exists.