Skip to main content

Governed LinkedIn marketing over MCP — draft, review, publish, comment, and analytics via the official LinkedIn API

Project description

English | 简体中文

Octopus LinkedIn

License: AGPL-3.0-or-later Python MCP

Governed LinkedIn marketing over MCP. Draft, review, publish, comment, and read engagement on LinkedIn — from Claude Desktop, Claude Code, or any MCP-compatible agent — using the official LinkedIn API.

Most "LinkedIn AI" tooling stops at writing the post. The obvious next step is publishing it — and that's where you want governance, not a black box. Octopus LinkedIn makes the whole loop explicit:

draft → review → approve → publish → comment → analyze

Drafting and approving are local-only — they never touch the network. publish_draft is the single gate that sends anything out, and it refuses to publish a draft that hasn't been explicitly approved.

Tools

Tool Sends to LinkedIn? What it does
get_profile read Your identity + a connectivity check
create_post Publish a text post
share_link Publish a post with a URL preview card
share_image Publish a post with one local image
share_images Publish a post with up to 9 images
delete_post Delete one of your posts
list_comments read List comments on your post
reply_comment Comment on a post you control
get_post_stats read Likes + comments for a post
create_draft ⬜ local Save a draft (text / link / image)
list_drafts ⬜ local List drafts, optionally by status
get_draft ⬜ local Read one draft
update_draft ⬜ local Edit a draft (resets approval)
approve_draft ⬜ local The review gate
delete_draft ⬜ local Delete a draft
schedule_draft ⬜ local Schedule an approved draft for later
unschedule_draft ⬜ local Clear a draft's scheduled time
publish_draft Publish an approved draft now
publish_due Publish all approved drafts whose time has come

Content intelligence (LLM-backed)

Conditioned on your brand voice; everything stays behind the approval gate.

Tool What it does
llm_info Show the active LLM provider/model (config check)
generate_draft Write a post from a brief → saved as a draft
polish_text / polish_draft Tighten clarity and flow
optimize_text / optimize_draft Rework for hook + structure + CTA
ab_variants Generate N distinct A/B variants
repurpose_url Turn an article URL into an original draft (SSRF-guarded)
triage_comments Classify your post's comments + draft replies
get_voice / set_voice Read/update your brand-voice profile

Plus MCP prompts (draft_post, repurpose_article, reply_to_comments) and resources (voice://profile, drafts://list) so MCP clients get task templates and live context, not just raw tool calls.

Scope note: the official API only lets you comment on content you control (your own posts, or an org Page you admin). It cannot auto-comment on arbitrary third-party posts — by design. See docs/ARCHITECTURE.md.

LLM configuration

Set one provider and its key (see .env.example):

LLM_PROVIDER=anthropic       # anthropic | openai | gemini
ANTHROPIC_API_KEY=sk-ant-... # or OPENAI_API_KEY / GEMINI_API_KEY
# LLM_MODEL=claude-sonnet-4-6  # optional override

Quick start

1. Install

python -m venv .venv && source .venv/bin/activate
pip install -e .

2. Create a LinkedIn app

At linkedin.com/developers, create a Standalone app tied to a Company Page, then add these products:

  • Share on LinkedIn → grants w_member_social (posting)
  • Sign In with LinkedIn using OpenID Connect → grants openid profile email

In the app's Auth tab, add an authorized redirect URL:

http://localhost:8000/callback

3. Configure

cp .env.example .env

Edit .env and paste your Client ID and Client Secret (Auth tab).

4. Authorize (one time)

python -m linkedin.auth

This opens your browser; log in and approve. A token is cached to token.json (gitignored, 0600). Member tokens last ~60 days; re-run this when it expires.

5. Run

python server.py

Connect to Claude Code

claude mcp add octopus-linkedin -- python /absolute/path/to/octopus-linkedin/server.py

Or add it to your MCP client config:

{
  "mcpServers": {
    "octopus-linkedin": {
      "command": "python",
      "args": ["/absolute/path/to/octopus-linkedin/server.py"]
    }
  }
}

Then just ask: "Draft a LinkedIn post about X, let me review it, then publish."

Example workflow

  1. create_draft — "Save this post about our launch."
  2. list_drafts / get_draft — review the wording.
  3. approve_draft — sign off.
  4. publish_draft — it goes live (and only now).
  5. get_post_stats — check likes and comments later.

CLI

The same engine ships as a CLI for scripting and cron:

octopus-linkedin authorize
octopus-linkedin post "Hello, world" --visibility PUBLIC
octopus-linkedin draft "A post to review later"
octopus-linkedin drafts --status approved
octopus-linkedin approve drft_abc123 --note "lgtm"
octopus-linkedin schedule drft_abc123 2026-07-02T09:00:00Z
octopus-linkedin run-scheduler --interval 60     # loop: publish due drafts
octopus-linkedin stats urn:li:share:123

Scheduling

Scheduling is split so nothing publishes by surprise: you schedule_draft an approved draft for a future UTC time, then a runner actually sends it when due. Run the runner one of three ways:

  • octopus-linkedin run-scheduler — a simple foreground loop, or
  • octopus-linkedin publish-due from cron every few minutes, or
  • the publish_due MCP tool on demand.

Only drafts that are both approved and past their time are published.

Development

pip install -e ".[dev]"
ruff check . && ruff format --check . && pytest

See CONTRIBUTING.md.

Roadmap

Shipped:

  • Scheduled publishing (publish an approved draft at a future time)
  • Multi-image posts (up to 9)
  • A standalone CLI alongside the MCP server
  • Bilingual docs (English | 简体中文)

Content-intelligence layer (shipped):

  • LLM backend — Anthropic / OpenAI / Gemini (write / polish / optimize)
  • MCP prompts + resources surface
  • Draft-from-URL / article repurposing (SSRF-guarded)
  • Brand-voice memory (conditions every generation)
  • Comment triage on your own posts (classify → draft reply → approve)
  • A/B variant generation

Gated (need LinkedIn approval), tracked but not built:

  • Company Page posting & engagement (Community Management API)
  • Impressions / reach via memberCreatorPostAnalytics (partner-gated, 2025)
  • PDF/document posts (need the versioned /rest/posts + Documents API)

Contributions to any of these are welcome.

Security

.env and token.json hold credentials and are gitignored — never commit them. See SECURITY.md for reporting and credential handling.

License

AGPL-3.0-or-later.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

octopus_linkedin-0.1.0.tar.gz (58.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

octopus_linkedin-0.1.0-py3-none-any.whl (45.1 kB view details)

Uploaded Python 3

File details

Details for the file octopus_linkedin-0.1.0.tar.gz.

File metadata

  • Download URL: octopus_linkedin-0.1.0.tar.gz
  • Upload date:
  • Size: 58.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for octopus_linkedin-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1ac7710a97e620a30362feae7375146e17c782560cdbb592e52c7f3c6439f062
MD5 25bb3223731dbc0ecca132f9f1b19f83
BLAKE2b-256 499697c68308b7d24d0bb5288af462bb79cf3858eff96ea56f5d4e7428ea19d5

See more details on using hashes here.

Provenance

The following attestation bundles were made for octopus_linkedin-0.1.0.tar.gz:

Publisher: publish.yml on octoryn/octopus-linkedin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file octopus_linkedin-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for octopus_linkedin-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d7ea27fc28644ccbc85ccb7ff7dc462e5af5e8d4d07b2f00b45e607caff90e7a
MD5 97506fe5eaf924286e58ef82e1aef968
BLAKE2b-256 b80034e018d52e65c4fa81e9cdbaffeba9fdf577022f70f6b284fe9e4f4ae126

See more details on using hashes here.

Provenance

The following attestation bundles were made for octopus_linkedin-0.1.0-py3-none-any.whl:

Publisher: publish.yml on octoryn/octopus-linkedin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page