Skip to content

added tools for posts and comments via the official api#339

Open
tronicum wants to merge 832 commits intostickerdaniel:mainfrom
tronicum:main
Open

added tools for posts and comments via the official api#339
tronicum wants to merge 832 commits intostickerdaniel:mainfrom
tronicum:main

Conversation

@tronicum
Copy link
Copy Markdown

@tronicum tronicum commented Apr 9, 2026

needs app and user tokens. you might need to have an small biz (freelance should work) and the api calls are rate limited (100-500 p.d.)

stickerdaniel and others added 30 commits March 8, 2026 20:08
…raping_add_compact_references

feat(scraping): add compact references
…r-all-major-dependencies

chore(deps): update all major dependencies (major)
…ependencies

chore(deps): update ci dependencies
Updated the prerequisites section to include a link for installing uv.
…-patch-1

docs(README): installation link for uv in README
<!-- greptile_comment -->

<h3>Greptile Summary</h3>

This PR introduces a `SequentialToolExecutionMiddleware` that wraps every MCP tool call in an `asyncio.Lock`, ensuring only one LinkedIn scraping operation runs at a time within a single server process. This protects the shared Patchright browser session from race conditions when the server is used in `streamable-http` mode with concurrent clients. The middleware is registered in `create_mcp_server()`, provides optional in-flight progress notifications to queued callers, and emits debug-level timing logs for lock wait/hold durations. Documentation is updated consistently across `README.md`, `AGENTS.md`, and `docs/docker-hub.md`.

- **New file `linkedin_mcp_server/sequential_tool_middleware.py`**: clean `asyncio.Lock`-based middleware with progress reporting and structured debug logging.
- **`server.py`**: one-line addition of `mcp.add_middleware(SequentialToolExecutionMiddleware())` at server creation.
- **`tests/test_server.py`**: four async tests covering middleware registration, serialization under concurrency (`asyncio.gather`), result preservation, and progress-reporting behaviour.
- **Docs**: `README.md`, `AGENTS.md`, `docs/docker-hub.md` all updated with notes about the serialization behaviour and how to observe it via debug logging.

<h3>Confidence Score: 5/5</h3>

- This PR is safe to merge — the change is well-scoped, correctly implemented, and backed by targeted tests.
- The core mechanism (`asyncio.Lock` held for the duration of each tool call) is the correct primitive for serializing work within a single asyncio event loop, which is exactly what uvicorn/FastMCP uses per worker. The lock is created inside the middleware instance (not at class level), so each server instance gets its own independent lock. Python 3.12+ is required, so there are no concerns about `asyncio.Lock` behaviour outside a running event loop. The finally block unconditionally releases the lock even on exceptions, and cancellation is handled correctly by the `async with` context manager. Tests cover all meaningful scenarios including concurrent execution, result integrity, and progress notifications.
- No files require special attention.

<h3>Important Files Changed</h3>

| Filename | Overview |
|----------|----------|
| linkedin_mcp_server/sequential_tool_middleware.py | New middleware that serializes MCP tool calls using asyncio.Lock; clean implementation with correct lock acquisition/release and optional progress reporting. |
| linkedin_mcp_server/server.py | Adds SequentialToolExecutionMiddleware to the server at creation time; one-line integration that is straightforward and correct. |
| tests/test_server.py | New test file covering middleware registration, serialization under concurrency, result preservation, and progress reporting; tests are correct and well-scoped but the concurrency test has a minor potential for improvement. |
| AGENTS.md | Adds a note about tool-call serialization under the Transport Modes section; accurate and consistent with the implementation. |
| README.md | Adds a paragraph about serialization behavior and how to observe it via debug logging; documentation is clear and correct. |
| docs/docker-hub.md | Appends a note about tool serialization to the Docker notes section; consistent with README and AGENTS.md changes. |

</details>

<h3>Sequence Diagram</h3>

```mermaid
sequenceDiagram
    participant C1 as Client 1
    participant C2 as Client 2
    participant MW as SequentialToolExecutionMiddleware
    participant Lock as asyncio.Lock
    participant Tool as LinkedIn Tool

    C1->>MW: on_call_tool(tool_name)
    MW-->>C1: report_progress("Queued waiting for scraper lock")
    C2->>MW: on_call_tool(tool_name)
    MW-->>C2: report_progress("Queued waiting for scraper lock")

    MW->>Lock: acquire() [Client 1 wins]
    Lock-->>MW: acquired
    MW-->>C1: report_progress("Scraper lock acquired, starting tool")
    MW->>Tool: call_next(context) [Client 1 executes]
    Note over Lock: Client 2 waits here

    Tool-->>MW: ToolResult
    MW->>Lock: release()
    MW-->>C1: return ToolResult

    Lock-->>MW: acquired [Client 2 unblocked]
    MW-->>C2: report_progress("Scraper lock acquired, starting tool")
    MW->>Tool: call_next(context) [Client 2 executes]
    Tool-->>MW: ToolResult
    MW->>Lock: release()
    MW-->>C2: return ToolResult
```

<sub>Last reviewed commit: 2df6e04</sub>

<!-- /greptile_comment -->
dannersm and others added 28 commits April 12, 2026 23:14
Cover the four targeted fixes from 280fcdc:

1. _resolve_message_compose_box returns locator.last when count() > 0,
   skipping the wait_for that stalls under patchright. Also tests the
   fallback path (count raises, all selectors miss).
2. Compose URL includes profileUrn, screenContext, and interop params
   for new-connection compatibility.
3. send_message focuses via page.evaluate() and types via
   page.keyboard.type() — asserts compose_interact_failed on focus
   failure.
4. Enter key fallback when JS cannot find a visible send button.

Also adds a clarifying comment on the wait_for fallback block in
_resolve_message_compose_box explaining it covers the count()-exception
path for non-patchright drivers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Update README.md

* fix(readme): Fix typo and grammar in FAQ section

- "bann" → "ban"
- "this mcp" → "this MCP"
- "no user was banned using" → "no users have been banned for using"
Removed usage examples from the README file.
…raping_add_skills_and_projects_sections_to_get_person_profile

feat(scraping): Add skills and projects sections to get_person_profile
…ump_version_to_4.9.0

chore: Bump version to 4.9.0
…i_simplify_release_download_link

style(ci): Simplify release download link
- Match on field name instead of Pydantic error code for stability
Detail pages (experience, certifications, skills, etc.) paginate with
a "Show more" button inside <main>, not scroll-to-bottom. Click it in
a loop (bounded by max_scrolls) until the button disappears.

Resolves: stickerdaniel#360
- Configure mock_locator.filter in fixture so Show more loop exits cleanly
  without hitting the exception handler in detail-page tests
…raping_add_max_scrolls_parameter_to_get_person_profile

feat(scraping): Add max_scrolls parameter to get_person_profile
…ump_version_to_4.9.1

chore: Bump version to 4.9.1
- Drop Spanish-only aria-label from compose focus selector; generic
  contenteditable fallback already covers all locales
- Patch asyncio.sleep in TestSendMessageComposerInteraction helper so
  tests no longer burn 1.4s of real wall time per run
- Set wait_for mocks before the call in test_returns_locator_when_count_positive
  and assert_not_called() after, so the early-return invariant is actually verified
…-compose-box-actionability

Fix/344 bypass patchright compose box actionability in send_message
@stickerdaniel
Copy link
Copy Markdown
Owner

Re your LinkedIn qs:

Flags: rename --linkedin-auth--api-login. Keep --login for the browser scrape session. Symmetrical, makes the two auth worlds obvious.

ugcPosts → /rest/posts: fold into this PR, don't want to ship the deprecated endpoint. Changes:

  • POST /rest/posts / DELETE /rest/posts/{urn}
  • Header LinkedIn-Version: 202604 (const, bumpable)
  • Flat body: commentary, visibility, distribution: {feedDistribution: "MAIN_FEED", targetEntities: [], thirdPartyDistributionChannels: []}, lifecycleState: "PUBLISHED", isReshareDisabledByAuthor: false — drop the specificContent.com.linkedin.ugc.ShareContent wrapper
  • Comments: /rest/socialactions/{postUrn}/comments with the same version header
  • Scope / author URN / returned x-restli-id unchanged → tool return shapes stay

Drop link share (url param on create_post). URLs inline in commentary already auto-render with a preview card, and the new API requires caller-supplied title/description/thumbnail-URN (no OG scrape). Not worth the extra machinery for an agent-facing tool. Text + comments is the MVP; articles/images/reshare can come later if asked for.

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.

8 participants