Skip to content

feat: reply to existing messaging threads - #673

Open
golatam wants to merge 3 commits into
stickerdaniel:mainfrom
golatam:feat/thread-targeted-replies
Open

feat: reply to existing messaging threads#673
golatam wants to merge 3 commits into
stickerdaniel:mainfrom
golatam:feat/thread-targeted-replies

Conversation

@golatam

@golatam golatam commented Aug 5, 2026

Copy link
Copy Markdown

Summary

Adds a thread-targeted reply tool for LinkedIn messaging:

  • reply_to_thread(thread_id, message, confirm_send) accepts a raw thread ID or canonical LinkedIn thread URL.
  • Refuses redirects or final URLs that do not match the requested thread before typing.
  • Scopes composer and send controls to the active messaging main region.
  • A dry run (confirm_send=false) never focuses, types, or sends.
  • After a confirmed send, re-reads the exact requested thread and only returns sent when the outgoing message is visible there; otherwise returns sent_unverified.

This avoids the profile-compose path used by send_message, which can be unavailable for Premium/Open Profile and can create a separate DM instead of replying to an existing InMail/thread.

Validation

  • uv run pytest tests/test_tools.py tests/test_scraping.py -q — 299 passed
  • uv run ruff check … — passed
  • uv run ty check … — passed
  • Live controlled validation used an existing thread and verified the outgoing reply by read-back from the exact thread ID.

Synthetic prompt

Add a confirmation-gated reply_to_thread MCP tool that sends only within a validated existing LinkedIn messaging thread, rejects mismatched redirects, scopes DOM actions to the active thread, and verifies success by reading back the exact thread.

Generated with GPT-5.6 Terra.

@github-actions github-actions Bot added the enhancement New feature or request label Aug 5, 2026
@greptile-apps

greptile-apps Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds a confirmation-gated MCP tool for replying inside a validated LinkedIn messaging thread, with scoped composer interaction and post-send read-back.

  • Normalizes raw thread IDs and canonical LinkedIn thread URLs.
  • Rejects URL drift before typing and keeps dry runs free of input events.
  • Attempts to verify a new matching message after reopening the requested thread.

Confidence Score: 4/5

The PR is not yet safe to merge because send verification can still report an unsent reply as successful, and confirmed repeated replies remain blocked.

The fallback verification identity changes with DOM position and rendered content across a full re-navigation, so an unchanged existing message can appear new after a failed send; independently, the pre-send snapshot branch still returns before typing whenever matching text is already present.

Files Needing Attention: linkedin_mcp_server/scraping/extractor.py, tests/test_scraping.py

Important Files Changed

Filename Overview
linkedin_mcp_server/scraping/extractor.py Adds thread validation, scoped interaction, and read-back verification, but fallback message identities can change across re-navigation and yield false send confirmation.
linkedin_mcp_server/tools/messaging.py Registers the destructive reply tool and delegates its confirmation flag and inputs to the extractor consistently.
tests/test_scraping.py Covers confirmation, URL pinning, empty input, and mocked snapshot transitions, but does not exercise fallback identity across a real DOM re-render.
tests/test_tools.py Verifies tool-level delegation and preservation of the confirmation gate.
tests/test_daemon_election.py Updates the registered-tool inventory to include reply_to_thread.

Sequence Diagram

sequenceDiagram
  participant Client as MCP Client
  participant Tool as reply_to_thread tool
  participant Extractor as LinkedInExtractor
  participant LinkedIn as LinkedIn thread
  Client->>Tool: thread_id, message, confirm_send
  Tool->>Extractor: reply_to_thread(...)
  Extractor->>LinkedIn: Open canonical thread URL
  Extractor->>Extractor: Validate active thread ID
  Extractor->>LinkedIn: Capture pre-send message signatures
  alt confirm_send is false
    Extractor-->>Client: confirmation_required
  else confirmed
    Extractor->>LinkedIn: Focus composer, type, submit
    Extractor->>LinkedIn: Reopen canonical thread URL
    Extractor->>LinkedIn: Capture post-send signatures
    Extractor-->>Client: sent or sent_unverified
  end
Loading
Prompt To Fix All With AI
### Issue 1
linkedin_mcp_server/scraping/extractor.py:2856
**DOM fallback misidentifies stale messages**

If LinkedIn re-renders a pre-existing matching message at a different DOM index or path after the canonical thread is reopened, the fallback signature changes and the snapshot subtraction treats that unchanged row as newly sent, causing a failed send to return `status="sent"` and `sent=true`.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (3): Last reviewed commit: "test: include thread reply tool in proxy..." | Re-trigger Greptile

Comment thread linkedin_mcp_server/scraping/extractor.py Outdated
Comment thread linkedin_mcp_server/scraping/extractor.py Outdated
Comment on lines +2901 to +2908
if before_snapshot:
return {
"url": self._page.url,
"thread_id": normalized_thread_id,
"status": "message_already_present",
"message": "This reply text is already visible in the requested thread; no send was attempted.",
"sent": False,
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Repeated replies are rejected

When a confirmed reply has the same normalized text as an existing message, this early return prevents any composer interaction, causing a legitimate repeated reply to remain unsent. Existing matching rows should be excluded during post-send identity comparison rather than used to prohibit the send.

Knowledge Base Used:

Prompt To Fix With AI
This is a comment left during a code review.
Path: linkedin_mcp_server/scraping/extractor.py
Line: 2901-2908

Comment:
**Repeated replies are rejected**

When a confirmed reply has the same normalized text as an existing message, this early return prevents any composer interaction, causing a legitimate repeated reply to remain unsent. Existing matching rows should be excluded during post-send identity comparison rather than used to prohibit the send.

**Knowledge Base Used:**
- [Scraping Engine](https://app.greptile.com/daniel-sticker/-/custom-context/knowledge-base/stickerdaniel/linkedin-mcp-server/-/docs/scraping.md)
- [MCP Tools](https://app.greptile.com/daniel-sticker/-/custom-context/knowledge-base/stickerdaniel/linkedin-mcp-server/-/docs/tools.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

path.unshift(Array.prototype.indexOf.call(parent.children, node));
node = parent;
}
return [stableId || `${index}:${path.join('.')}:${text}`];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 DOM fallback misidentifies stale messages

If LinkedIn re-renders a pre-existing matching message at a different DOM index or path after the canonical thread is reopened, the fallback signature changes and the snapshot subtraction treats that unchanged row as newly sent, causing a failed send to return status="sent" and sent=true.

Knowledge Base Used: Scraping Engine

Prompt To Fix With AI
This is a comment left during a code review.
Path: linkedin_mcp_server/scraping/extractor.py
Line: 2856

Comment:
**DOM fallback misidentifies stale messages**

If LinkedIn re-renders a pre-existing matching message at a different DOM index or path after the canonical thread is reopened, the fallback signature changes and the snapshot subtraction treats that unchanged row as newly sent, causing a failed send to return `status="sent"` and `sent=true`.

**Knowledge Base Used:** [Scraping Engine](https://app.greptile.com/daniel-sticker/-/custom-context/knowledge-base/stickerdaniel/linkedin-mcp-server/-/docs/scraping.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant