Skip to main content
Glama

Replies Needing An Answer

li_replies_to_answer
Read-only

Contacts who REPLIED and are awaiting a human/Claude answer (auto follow-ups already stopped). DB-backed and instant.

WORK THE WHOLE QUEUE IN THREE CALLS: ask for it with includeThread=true and each row arrives with the end of its stored conversation already attached, so there is no per-person read at all; draft every answer; send them together with li_send_reply's replies array. Without includeThread this is the queue alone and each person costs a second call to li_conversation_history.

THE QUEUE IS DERIVED FROM THE CONVERSATION, so a person leaves it by being answered — not by being marked. It drops anyone whose newest message from us is newer than their last word, which means a reply sent with li_send_reply clears the row BY ITSELF, but only once the send actually lands (it is queued, so that is minutes, not seconds) and only when it went out from the account on the row's own accountId — which li_send_reply now routes to for you, so you can hand this queue straight to it without grouping. Until then they are still here: read li_job_result, never re-send.

⚠️ THE ROW LEAVING THIS QUEUE IS NOT THE SAME AS THE CONVERSATION BEING CLOSED. Answering writes no status anywhere, so the contact still reads "needs reply" on their dossier and on the campaign, and the reply rate still counts them. li_mark_reply_handled is what records that a person dealt with it — call it after you answer, and call it for a conversation you are simply not going to answer.

⚠️ DO NOT use it to put somebody down for a while — it closes the conversation with no date to come back on. li_snooze_reply is that. Either way, a NEW message from them after the close or the snooze reopens it: the row comes back here carrying reopened (with what it had been marked, which is kept).

An answer somebody typed BY HAND in LinkedIn needs none of that: the inbox sweep (about hourly) notices a thread we already owed that now ends on our own message, stores it, and the row leaves this queue by itself. It runs only about hourly, so it can lag — force it with li_sweep_inbox (no selector sweeps every account) rather than reading threads one by one to check.

Each row carries WHO THEY ARE — name, headline, role, company and location, filled from research already bought for that person, so drafting needs no li_contact_dossier call. Plus campaignName (which sequence they are in, so you answer in the right offer's voice) and the two ends of the stored thread, theirLastAt and ourLastAt — their last word four days ago with nothing from us since is somebody genuinely waiting. Both null means this thread has never been read; theirLastAt alone can be the moment their reply was DETECTED when the thread itself was never stored. A row never shows our last message newer than theirs.

⚠️ An attached thread is the STORED one, so it can lag and it can be empty — empty means nobody has read that thread yet, NEVER that they did not write. For those, li_read_conversation fetches it live (a browser session, minutes) and stores it for next time. Record how it went afterwards with li_mark_outcome.

A row flagged bookingPending: true is somebody the booking link went to or who agreed to a call, and who has WRITTEN BACK since — answer what they said; they are deliberately NOT in li_booking_due, and a booking nudge on top of their message is refused. 🚨 Rows with bookingCheckRequired: true (our link is out, or a call is booked) need a CALENDAR SEARCH for that person before you write anything: people book within minutes of saying yes, and this server reads no calendar. Booked → send nothing, li_mark_booked. Not booked → answer, and li_send_reply with calendarChecked: true (refused without it). bookingHint says which. booking carries the state when one is tracked, and companyDomain their employer's web domain.

Input Schema

NameRequiredDescriptionDefault
limitNoMost rows to return (default 100); `truncated` says when there are more
sessionIdNoLimit to one account by id (li_list_accounts). Needed (or sessionLabel) when you have more than one account.
sessionLabelNoLimit to one account by label, LinkedIn name, profile slug or member id. Needed (or sessionId) when you have more than one account.
includeThreadNoAttach the end of each stored conversation to its row, so drafting needs no second call per person. Off by default because it is the difference between a queue and a queue plus every thread in it; threads are attached to at most the first 25 rows and the reply says when it stopped.
sessionLabelsNoSeveral accounts in ONE call, by label. Leaving every selector off already spans all your accounts, which is usually what you want; this is for "these three of my six". Each label must match exactly one of your accounts — a name shared by two is refused rather than guessed.
threadMessagesNoHow many of the most recent messages to attach per thread (default 6). Still returned oldest-first. Message text is never cut — a truncated question is the one thing that would make the answer wrong.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed3 schema fields changed
    • addedInput schema / properties / limit / description
      Added value: +"Most rows to return (default 100); `truncated` says when there are more"
    • changedInput schema / properties / sessionId / description
      Previous value: -"Scope to one account id"New value: +"Limit to one account by id (li_list_accounts). Needed (or sessionLabel) when you have more than one account."
    • changedInput schema / properties / sessionLabel / description
      Previous value: -"Scope to one account label (omit for all accounts)"New value: +"Limit to one account by label, LinkedIn name, profile slug or member id. Needed (or sessionId) when you have more than one account."
  2. First observed

TDQS

A4.8/5.0
Behavior5/5

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

Annotations only declare readOnly/non-destructive, but the description discloses much more: the queue is derived from the conversation, rows clear only once a queued send actually lands (minutes, not seconds) and only when sent from the row's own accountId, and a `reopened` flag returns with prior marker state. It also covers the booking edge cases (bookingPending, bookingCheckRequired, calendarChecked requirement) and thread-staleness caveats. This is unusually rich behavioral context beyond the structured fields.

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?

It is long, but the first sentence front-loads the core identity and the three-call workflow follows immediately, so structure is sound. Every paragraph carries actionable instruction rather than filler, though the density of repeated ⚠️ warnings means a reader must parse carefully to extract the ordered steps.

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

Completeness5/5

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

There is no output schema, so the description must carry the return contract, and it does: it enumerates row fields (name, headline, role, company, location, campaignName, theirLastAt/ourLastAt, bookingPending, bookingCheckRequired, bookingHint, booking, companyDomain, reopened). Combined with the workflow guidance, an agent has everything needed to call and consume the result correctly.

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

Parameters4/5

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

Schema coverage is 100%, so the baseline is 3, but the description adds real meaning: it explains why includeThread trades cost for eliminating per-person calls (and the 25-row thread cap), what threadMessages attaches, and how sessionLabels selects a subset of accounts with an exact-match rule. It stops short of fully documenting every selector's default behavior, but goes well past the schema's own text.

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

Purpose5/5

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

The opening line states a precise verb+resource and scope: contacts who REPLIED and are awaiting a human answer, with the clarifying parenthetical that auto follow-ups already stopped. It cleanly distinguishes itself from the nearest siblings (li_booking_due, li_due_messages, li_marked_conversations) by explaining what membership in the queue means. An agent can identify the tool's output without opening the schema.

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

Usage Guidelines5/5

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

Gives explicit operational routing: use includeThread to avoid per-person reads, send via li_send_reply's `replies` array, never use this to park someone (use li_snooze_reply), and force refresh with li_sweep_inbox instead of reading threads one by one. It also names the follow-up call li_mark_reply_handled and the pre-write calendar search for bookingCheckRequired rows. Alternatives and exclusions are spelled out rather than inferred.

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

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources