linkedinmcp
by vielhuber
README.md
# 💼linkedinmcp💼
one small php helper and mcp server for linkedin posting and your own member data. two apps, separate tokens, one tool set.
## php
```sh
composer require vielhuber/linkedinmcp
```
```php
use vielhuber\linkedinmcp\linkedinmcp;
$linkedin = new linkedinmcp();
$linkedin->profile();
$linkedin->snapshot(domain: 'PROFILE', start: 0);
$linkedin->posts(start: 0);
$linkedin->activity(startTime: $processedAt, count: 10);
$linkedin->memberAuthorization();
$linkedin->createPost(text: 'your approved text');
$linkedin->updatePost(postUrn: $postUrn, text: 'your approved replacement');
$linkedin->deletePost(postUrn: $postUrn);
$linkedin->uploadImage(filePath: '/absolute/path/to/image.png');
$linkedin->uploadVideo(filePath: '/absolute/path/to/video.mp4');
$linkedin->videoStatus(videoUrn: $mediaUrn);
```
two separate apps and tokens:
| app | token environment variable | scopes |
| ------------------------------------------- | ------------------------------- | -------------------------------- |
| posting: openid connect + share on linkedin | `LINKEDIN_POSTING_ACCESS_TOKEN` | `openid profile w_member_social` |
| member data portability api (member) | `LINKEDIN_MEMBER_ACCESS_TOKEN` | `r_dma_portability_self_serve` |
member access is region-dependent and limited to the app administrator's own data. keep both apps' identities separate. api versions: posting `202610`, member `202312`; override with `LINKEDIN_POSTING_VERSION` / `LINKEDIN_MEMBER_VERSION`.
php oauth: one `Authorization(clientId: ..., clientSecret: ..., redirectUri: ...)` per app; `url($state, $scopes)`, verify state, `exchangeCode($code)`. refresh only with an issued refresh token. oauth helpers are not mcp tools.
- snapshots: page index `start`; no-data response is http 404. no home feed.
- activity: 28 days after consent; cursor `processedAt`, deduplicate `activityId`, poll at most hourly.
- uploads return `id`, not a post; videos must be `AVAILABLE`. image processing checks may require extra permissions.
- approve writes first. edits change commentary only; use exact share/ugcpost urns. never blindly retry uncertain writes.
## mcp
```json
{
"mcpServers": {
"linkedin": {
"command": "php",
"args": ["/absolute/path/to/vendor/bin/mcp-server.php"],
"env": {
"LINKEDIN_POSTING_ACCESS_TOKEN": "your-posting-access-token",
"LINKEDIN_MEMBER_ACCESS_TOKEN": "your-member-access-token"
}
}
}
}
```
11 tools; php methods become snake_case tool names. stdio is private. http requires https and `MCP_TOKEN`.
[posting api](https://learn.microsoft.com/en-us/linkedin/marketing/community-management/shares/posts-api) · [member portability api](https://learn.microsoft.com/en-us/linkedin/dma/member-data-portability/member-data-portability-member/) · [oauth](https://learn.microsoft.com/en-us/linkedin/shared/authentication/authorization-code-flow)
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues