Sign In

@linkedctl/mcp

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@linkedctl/mcp - npm Package Compare versions

Comparing version
0.0.0
to
0.1.0
+3
dist/index.d.ts
#!/usr/bin/env node
export {};
//# sourceMappingURL=index.d.ts.map
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
#!/usr/bin/env node
// SPDX-License-Identifier: AGPL-3.0-only
// Copyright (C) 2026 Oleksii PELYKH
import { startStdioServer } from "./stdio.js";
await startStdioServer();
//# sourceMappingURL=index.js.map
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,gBAAgB,EAAE,CAAC"}
# @linkedctl/mcp
MCP (Model Context Protocol) server for LinkedIn API integration -- the AI-tool interface used by [`linkedctl`](https://github.com/alexey-pelykh/linkedctl).
## Installation
```sh
npm install @linkedctl/mcp
```
Requires Node.js >= 24.
## Overview
This package provides an MCP server that exposes LinkedIn API operations as tools for AI assistants (Claude, Cursor, etc.). It registers tools for creating posts, checking authentication status, and revoking tokens.
For full MCP integration documentation and available tools, see the [main project](https://github.com/alexey-pelykh/linkedctl).
## License
[AGPL-3.0-only](https://www.gnu.org/licenses/agpl-3.0.txt)
+5
-1

@@ -1,2 +0,6 @@

export {};
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
/**
* Create and configure the LinkedCtl MCP server with all tools registered.
*/
export declare function createMcpServer(): McpServer;
//# sourceMappingURL=server.d.ts.map
+1
-1

@@ -1,1 +0,1 @@

{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC"}
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAcpE;;GAEG;AACH,wBAAgB,eAAe,IAAI,SAAS,CAqK3C"}
// SPDX-License-Identifier: AGPL-3.0-only
// Copyright (C) 2026 Oleksii PELYKH
export {};
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { resolveConfig, LinkedInClient, getCurrentPersonUrn, createTextPost, loadConfigFile, validateConfig, getTokenExpiry, clearOAuthTokens, revokeAccessToken, } from "@linkedctl/core";
/**
* Create and configure the LinkedCtl MCP server with all tools registered.
*/
export function createMcpServer() {
const server = new McpServer({
name: "linkedctl",
version: "0.0.0",
});
server.registerTool("post_create", {
title: "Create Post",
description: "Create a text post on LinkedIn",
inputSchema: {
text: z.string().describe("The text content of the post"),
visibility: z.enum(["PUBLIC", "CONNECTIONS"]).optional().describe("Post visibility (defaults to PUBLIC)"),
profile: z.string().optional().describe("Profile name to use from config file"),
},
}, async (args) => {
const { config } = await resolveConfig({
profile: args.profile,
requiredScopes: ["openid", "profile", "email", "w_member_social"],
});
// resolveConfig guarantees oauth.accessToken and apiVersion are defined
const accessToken = config.oauth?.accessToken ?? "";
const apiVersion = config.apiVersion ?? "";
const client = new LinkedInClient({ accessToken, apiVersion });
const authorUrn = await getCurrentPersonUrn(client);
const visibility = args.visibility ?? "PUBLIC";
const postUrn = await createTextPost(client, {
author: authorUrn,
text: args.text,
visibility,
});
return {
content: [{ type: "text", text: `Post created: ${postUrn}` }],
};
});
server.registerTool("auth_status", {
title: "Auth Status",
description: "Show authentication status for a profile",
inputSchema: {
profile: z.string().optional().describe("Profile name to check (uses default if not specified)"),
},
}, async (args) => {
const { raw } = await loadConfigFile({ profile: args.profile });
const { config } = validateConfig(raw);
const label = args.profile ?? "default";
if (config.oauth?.accessToken === undefined || config.oauth.accessToken === "") {
return {
content: [
{
type: "text",
text: `Profile: ${label}\nStatus: not configured\nRun "linkedctl auth login" to set up authentication.`,
},
],
};
}
const expiry = getTokenExpiry(config.oauth.accessToken);
if (expiry === undefined) {
return {
content: [
{
type: "text",
text: `Profile: ${label}\nStatus: authenticated\nExpiry: unknown (token is not a JWT)`,
},
],
};
}
if (expiry.isExpired) {
return {
content: [
{
type: "text",
text: `Profile: ${label}\nStatus: expired\nExpired: ${expiry.expiresAt.toISOString()}\nRun "linkedctl auth login" to re-authenticate.`,
},
],
};
}
return {
content: [
{
type: "text",
text: `Profile: ${label}\nStatus: authenticated\nExpires: ${expiry.expiresAt.toISOString()}`,
},
],
};
});
server.registerTool("auth_revoke", {
title: "Revoke Auth Token",
description: "Revoke the access token server-side and clear local credentials for a profile",
inputSchema: {
profile: z.string().optional().describe("Profile name to revoke (uses default if not specified)"),
},
}, async (args) => {
const { raw } = await loadConfigFile({ profile: args.profile });
const { config } = validateConfig(raw);
const label = args.profile ?? "default";
if (config.oauth === undefined) {
return {
content: [{ type: "text", text: `Profile "${label}" not found or has no OAuth config.` }],
isError: true,
};
}
const accessToken = config.oauth.accessToken;
const clientId = config.oauth.clientId;
const clientSecret = config.oauth.clientSecret;
if (accessToken === undefined || accessToken === "" || clientId === undefined || clientSecret === undefined) {
await clearOAuthTokens({ profile: args.profile });
return {
content: [
{
type: "text",
text: `No complete credentials for server-side revocation. Local credentials cleared for profile "${label}".`,
},
],
};
}
let serverRevoked = true;
let warning = "";
try {
await revokeAccessToken(clientId, clientSecret, accessToken);
}
catch (error) {
serverRevoked = false;
warning = error instanceof Error ? error.message : String(error);
}
await clearOAuthTokens({ profile: args.profile });
const lines = [];
if (serverRevoked) {
lines.push(`Access token revoked server-side for profile "${label}".`);
}
else {
lines.push(`Warning: Server-side revocation failed: ${warning}`);
}
lines.push(`Local credentials cleared for profile "${label}".`);
return {
content: [{ type: "text", text: lines.join("\n") }],
};
});
return server;
}
//# sourceMappingURL=server.js.map

@@ -1,1 +0,1 @@

{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,CAAC"}
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}

@@ -1,2 +0,5 @@

export {};
/**
* Start the MCP server using stdio transport.
*/
export declare function startStdioServer(): Promise<void>;
//# sourceMappingURL=stdio.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,CAAC"}
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"AAMA;;GAEG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAItD"}
// SPDX-License-Identifier: AGPL-3.0-only
// Copyright (C) 2026 Oleksii PELYKH
export {};
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { createMcpServer } from "./server.js";
/**
* Start the MCP server using stdio transport.
*/
export async function startStdioServer() {
const server = createMcpServer();
const transport = new StdioServerTransport();
await server.connect(transport);
}
//# sourceMappingURL=stdio.js.map

@@ -1,1 +0,1 @@

{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,CAAC"}
{"version":3,"file":"stdio.js","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC"}
{
"name": "@linkedctl/mcp",
"version": "0.0.0",
"version": "0.1.0",
"description": "MCP server for LinkedIn API integration",

@@ -50,5 +50,15 @@ "type": "module",

},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.26.0",
"zod": "^4.3.6",
"@linkedctl/core": "^0.1.0"
},
"devDependencies": {
"@types/node": "^24",
"eslint": "^9.39.2",
"typescript": "^5.9.3",
"vitest": "^4.0.18"
},
"scripts": {
"clean": "rm -rf dist tsconfig.tsbuildinfo",
"prepack": "cp ../../LICENSE .",
"build": "tsc",

@@ -59,14 +69,3 @@ "typecheck": "tsc --noEmit",

"dev": "tsc --watch"
},
"dependencies": {
"@linkedctl/core": "workspace:^",
"@modelcontextprotocol/sdk": "catalog:",
"zod": "catalog:"
},
"devDependencies": {
"@types/node": "catalog:",
"eslint": "catalog:",
"typescript": "catalog:",
"vitest": "catalog:"
}
}
}