Skip to content

README: add Used-by section#452

Open
till-hohmann wants to merge 7 commits into
stickerdaniel:mainfrom
till-hohmann:readme-add-used-by
Open

README: add Used-by section#452
till-hohmann wants to merge 7 commits into
stickerdaniel:mainfrom
till-hohmann:readme-add-used-by

Conversation

@till-hohmann
Copy link
Copy Markdown

Adding a link to a project built on top of this MCP server.

till-hohmann/tinkering - linkedin-engagement-console is a daily LinkedIn engagement console with grounded drafting. It uses this MCP server as the LinkedIn data layer.

Happy to adjust the wording or move it elsewhere in the README if you'd prefer a different spot. Thanks for shipping this, the Patchright stealth approach made it possible.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 17, 2026

Greptile Summary

This PR adds LinkedIn posting actions and surfaces company post permalinks for downstream use. It changes:

  • Adds post_comment, react_to_post, and create_post MCP tools.
  • Registers the posting tools in the server startup path.
  • Adds extractor methods for comment, reaction, and post publishing flows.
  • Adds a company-post DOM probe to promote visible post permalinks into references.
  • Adds a README “Used by” section.

Confidence Score: 3/5

This should wait until the posting URL contract is fixed.

  • The new posting tools do not accept the relative post URLs returned by existing feed and company reference flows.
  • The company permalink probe can drop the absolute href form it is meant to recover.
  • These issues break the main handoff from scraping posts to commenting or reacting.

linkedin_mcp_server/scraping/extractor.py

Important Files Changed

Filename Overview
linkedin_mcp_server/scraping/extractor.py Adds permalink probing and posting/reaction/comment automation; this file contains the navigation and href-normalization issues.
linkedin_mcp_server/tools/posting.py Registers MCP wrappers for the new posting actions with confirmation gating.
linkedin_mcp_server/tools/company.py Augments company post results with probed post permalink references.
Prompt To Fix All With AI
Fix the following 3 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 3
linkedin_mcp_server/scraping/extractor.py:418-428
**Normalize probed hrefs**

This probe only accepts paths that already start with `/posts/` or `/feed/update/`. If LinkedIn exposes the same anchors as absolute URLs, such as `https://www.linkedin.com/posts/...`, this filter drops them and `get_company_posts` still returns no per-post references. The rest of the extractor already canonicalizes anchors through `anchor.href`, so this path should parse the href against the current origin before matching the pathname.

### Issue 2 of 3
linkedin_mcp_server/scraping/extractor.py:3545
**Accept relative permalinks**

`get_feed` and the new company-post reference path return LinkedIn post references as relative URLs like `/posts/...` and `/feed/update/...`, but this method passes `post_url` straight to `page.goto`. A caller that uses the returned reference with `post_comment` will fail navigation before reaching the post. Normalize relative LinkedIn paths to `https://www.linkedin.com...` before calling `_navigate_to_page`.

### Issue 3 of 3
linkedin_mcp_server/scraping/extractor.py:3890
**Accept relative permalinks**

The post references produced by `get_feed` and `get_company_posts` are relative LinkedIn paths, but `react_to_post` sends `post_url` directly into navigation. When a client passes `/posts/...` or `/feed/update/...` from those references, Playwright receives a URL with no scheme and the reaction flow never reaches the post. Normalize relative LinkedIn paths before navigating.

Reviews (3): Last reviewed commit: "feat(company): promote per-post permalin..." | Re-trigger Greptile

…gate

Mirrors messaging.send_message pattern: FastMCP destructive write,
JS-based composer focus + keyboard.type + JS submit click to bypass
Patchright actionability. Falls back to clicking the Comment action
button if the inline composer isn't visible. Verifies success by
polling for the typed comment text in the DOM.
…rm, dispatch input event

LinkedIn's comment submit button is labeled 'Comment' not 'Post';
the original selector aria-label*='Post' never matched. Also Quill
editor needed an explicit input event after keyboard.type to mark
the comment non-empty. Submit selector now scopes to the composer's
parent form/container to avoid hitting the feed-level Comment action
button. Returns diagnostic info on failure (candidate count + disabled
states) for the next failure mode.
…in response

Search all Comment/Post-labeled buttons globally and pick the one
closest to the input by vertical position, so we handle composers
whose parent form doesn't wrap the submit. Add Ctrl+Enter fallback
in case the click path is blocked. Surface the JS-side diagnostic
(candidate count, disabled states, text, classes) in the tool
response so the caller sees what's on the page without grepping
server logs.
…scan

LinkedIn empties the contenteditable on successful submit, which is a
more reliable signal than scraping the comment thread for the typed
text (comment-item class names drift across UI revisions). Primary
signal is now composerEmpty; secondary is text-visible in any
comment-container class, excluding the composer itself to avoid
false-positives when the composer didn't clear.
Comment on lines +3902 to +3909
if already_pressed and norm_reaction == "like":
return self._react_result(
self._page.url,
"already_reacted",
"Post already has the Like reaction applied. No change made.",
reaction=norm_reaction,
applied=True,
)
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 Check reaction type

This branch treats any active reaction as an existing Like. LinkedIn marks the reaction button active for Love, Celebrate, Support, and other reactions too, so calling react_to_post(..., reaction="like") on a post that currently has Love returns already_reacted with applied=True without changing it to Like. The short-circuit needs to verify the current reaction is actually Like before skipping the click.

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

Comment:
**Check reaction type**

This branch treats any active reaction as an existing Like. LinkedIn marks the reaction button active for Love, Celebrate, Support, and other reactions too, so calling `react_to_post(..., reaction="like")` on a post that currently has Love returns `already_reacted` with `applied=True` without changing it to Like. The short-circuit needs to verify the current reaction is actually Like before skipping the click.

How can I resolve this? If you propose a fix, please make it concise.

…ost_comment/react_to_post can target peer posts from get_company_posts results
Comment on lines +418 to +428
// /posts/<slug>-<digits>-<suffix>
// /feed/update/urn:li:activity:<digits>/
const anchors = Array.from(main.querySelectorAll('a[href]'));
const out = [];
const seen = new Set();
for (const a of anchors) {
const href = a.getAttribute('href') || '';
if (!href) continue;
// Strip query string and trailing slash for dedup parity
const noQuery = href.split('?')[0];
const isPostPath =
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 Normalize probed hrefs

This probe only accepts paths that already start with /posts/ or /feed/update/. If LinkedIn exposes the same anchors as absolute URLs, such as https://www.linkedin.com/posts/..., this filter drops them and get_company_posts still returns no per-post references. The rest of the extractor already canonicalizes anchors through anchor.href, so this path should parse the href against the current origin before matching the pathname.

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

Comment:
**Normalize probed hrefs**

This probe only accepts paths that already start with `/posts/` or `/feed/update/`. If LinkedIn exposes the same anchors as absolute URLs, such as `https://www.linkedin.com/posts/...`, this filter drops them and `get_company_posts` still returns no per-post references. The rest of the extractor already canonicalizes anchors through `anchor.href`, so this path should parse the href against the current origin before matching the pathname.

How can I resolve this? If you propose a fix, please make it concise.

comment_text: Body of the comment to post.
confirm_send: Must be True to actually submit the comment.
"""
await self._navigate_to_page(post_url)
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 Accept relative permalinks

get_feed and the new company-post reference path return LinkedIn post references as relative URLs like /posts/... and /feed/update/..., but this method passes post_url straight to page.goto. A caller that uses the returned reference with post_comment will fail navigation before reaching the post. Normalize relative LinkedIn paths to https://www.linkedin.com... before calling _navigate_to_page.

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

Comment:
**Accept relative permalinks**

`get_feed` and the new company-post reference path return LinkedIn post references as relative URLs like `/posts/...` and `/feed/update/...`, but this method passes `post_url` straight to `page.goto`. A caller that uses the returned reference with `post_comment` will fail navigation before reaching the post. Normalize relative LinkedIn paths to `https://www.linkedin.com...` before calling `_navigate_to_page`.

How can I resolve this? If you propose a fix, please make it concise.

reaction=norm_reaction,
)

await self._navigate_to_page(post_url)
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 Accept relative permalinks

The post references produced by get_feed and get_company_posts are relative LinkedIn paths, but react_to_post sends post_url directly into navigation. When a client passes /posts/... or /feed/update/... from those references, Playwright receives a URL with no scheme and the reaction flow never reaches the post. Normalize relative LinkedIn paths before navigating.

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

Comment:
**Accept relative permalinks**

The post references produced by `get_feed` and `get_company_posts` are relative LinkedIn paths, but `react_to_post` sends `post_url` directly into navigation. When a client passes `/posts/...` or `/feed/update/...` from those references, Playwright receives a URL with no scheme and the reaction flow never reaches the post. Normalize relative LinkedIn paths before navigating.

How can I resolve this? If you propose a fix, please make it concise.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant