@clickonsearch/linkedin-mcp-server 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,78 +1,105 @@
1
1
  # @clickonsearch/linkedin-mcp-server
2
2
 
3
- MCP server for a **personal** LinkedIn account via LinkedIn's OAuth 2.0 API.
4
- Exposes exactly two tools: `get_profile` and `create_post`.
3
+ Connects a personal LinkedIn account to this repo's agents: read your
4
+ profile, publish posts. Usually you won't run this directly —
5
+ [`linkedin-agent`](../../agents/linkedin-agent)'s README tells you when to.
5
6
 
6
- ## Why only two tools
7
-
8
- LinkedIn's public API is far more restricted than GitHub's or Gmail's. A
9
- standard, self-serve developer app can only:
10
-
11
- - Read the authenticated member's own basic profile (OpenID Connect).
12
- - Publish a post to their own feed (`w_member_social`).
13
-
14
- **Sending LinkedIn messages is not available via any public API** — it only
15
- exists under partner programs (Talent Solutions, Sales Navigator) that
16
- require a formal application and LinkedIn's manual approval; there is no
17
- self-serve path to it at all.
18
-
19
- **Replying/commenting on posts** has a documented endpoint
20
- (`/v2/socialActions/{urn}/comments`), but creating comments requires a
21
- separate LinkedIn Developer Program product ("Community Management API" or
22
- similar) that also needs LinkedIn's case-by-case approval — it is not
23
- included in standard "Sign In with LinkedIn" / "Share on LinkedIn" access.
24
- This server doesn't implement it; if you get that access approved, adding
25
- a `create_comment` tool following the same pattern as `create_post` would
26
- be straightforward.
7
+ ```
8
+ linkedin-agent (or any MCP client)
9
+ │
10
+ ▼
11
+ ┌─────────────────────────────┐
12
+ │ linkedin-mcp-server │ Streamable HTTP MCP
13
+ └──────────────┬──────────────┘
14
+ │
15
+ ▼
16
+ ┌─────────────────────────────┐
17
+ │ LinkedIn OAuth API │ get_profile / create_post
18
+ └──────────────┬──────────────┘
19
+ │
20
+ ▼
21
+ your LinkedIn account
22
+ ```
27
23
 
28
24
  ## Setup
29
25
 
30
- 1. Create an app at [linkedin.com/developers/apps](https://www.linkedin.com/developers/apps).
31
- 2. Under **Products**, add **"Sign In with LinkedIn using OpenID Connect"**
32
- and **"Share on LinkedIn"** — both are self-serve, no approval wait.
33
- 3. Under **Auth**, add an **Authorized redirect URL** matching
34
- `LINKEDIN_REDIRECT_URI` below exactly (default `http://localhost:3300/callback`).
26
+ **1. Create a LinkedIn app** (free, a few minutes):
27
+
28
+ 1. Go to [linkedin.com/developers/apps](https://www.linkedin.com/developers/apps) → Create app.
29
+ 2. Under **Products**, add **"Sign In with LinkedIn using OpenID Connect"** and **"Share on LinkedIn"**.
30
+ 3. Under **Auth**, add an **Authorized redirect URL**: `http://localhost:3300/callback`.
35
31
  4. Copy the app's **Client ID** and **Client Secret**.
36
32
 
33
+ **2. Authorize it** (one time — run from a folder you'll reuse in step 3):
34
+
37
35
  ```bash
38
- cd mcp-servers/linkedin-mcp-server
39
- npm install
40
- cp .env.example .env
41
- # fill in LINKEDIN_CLIENT_ID / LINKEDIN_CLIENT_SECRET
36
+ LINKEDIN_CLIENT_ID=<id> LINKEDIN_CLIENT_SECRET=<secret> \
37
+ npx -p @clickonsearch/linkedin-mcp-server linkedin-authorize
42
38
  ```
43
39
 
44
- ## Authorize (one-time)
40
+ This opens a link — sign in, approve, done. It saves a token to
41
+ `linkedin-token.json` in the current folder, so step 3 needs to run from
42
+ this same folder.
43
+
44
+ > LinkedIn's access tokens last ~60 days and (for a standard app) don't
45
+ > auto-renew. When yours expires, just re-run the authorize command above —
46
+ > you'll get a clear error telling you to when that happens.
47
+
48
+ ## Run
45
49
 
46
50
  ```bash
47
- npm run dev:authorize
51
+ LINKEDIN_CLIENT_ID=<id> LINKEDIN_CLIENT_SECRET=<secret> \
52
+ npx @clickonsearch/linkedin-mcp-server
48
53
  ```
49
54
 
50
- This prints a URL — open it, sign in, approve — and it saves a token to
51
- `LINKEDIN_TOKEN_PATH` (default `./linkedin-token.json`, gitignored).
55
+ It's now listening on `http://127.0.0.1:4300` for whatever agent you point
56
+ at it.
52
57
 
53
- **Important:** LinkedIn only issues a refresh token to apps it has approved
54
- for offline access. For a standard app, the access token this saves is
55
- valid for **~60 days** and there is no automatic renewal — re-run this
56
- command once it expires (tools will fail with a clear "access token has
57
- expired" error when that happens).
58
+ ### Letting another machine connect
58
59
 
59
- ## Run
60
+ By default only programs on the same computer can reach this server. To
61
+ allow others (an agent in a container, or on another machine), pick a
62
+ secret and set both:
60
63
 
61
64
  ```bash
62
- npm run dev
65
+ export LINKEDIN_MCP_TOKEN=$(openssl rand -hex 32)
66
+ BIND_HOST=0.0.0.0 npx @clickonsearch/linkedin-mcp-server
63
67
  ```
64
68
 
65
- - `POST http://localhost:4300/mcp` — the MCP endpoint (Streamable HTTP, stateless).
66
- - `GET http://localhost:4300/health` — liveness check.
69
+ Give `linkedin-agent` the same `LINKEDIN_MCP_TOKEN` and it sends it
70
+ automatically. The server refuses to start on any other address without a
71
+ token. Anyone holding the token can post to your LinkedIn feed as you, so
72
+ treat it like a password — and since it travels over plain HTTP, only use
73
+ this on a network you trust or behind TLS (for example a reverse proxy).
74
+
75
+ ## What it exposes
76
+
77
+ | Tool | What it does |
78
+ | -------------- | -------------------------------------------------------- |
79
+ | `get_profile` | Your name, email, and picture |
80
+ | `create_post` | Publishes a text post to your own feed |
81
+
82
+ ## Good to know
83
+
84
+ LinkedIn's public API only allows reading your own profile and posting to
85
+ your own feed — that's genuinely everything a standard app can do. It
86
+ **can't** send messages (no public API for that at all) or comment on
87
+ other people's posts (needs special LinkedIn approval). This server
88
+ doesn't pretend otherwise.
67
89
 
68
- ## Tools
90
+ ---
69
91
 
70
- | Tool | Args | Notes |
71
- | -------------- | ------ | ----------------------------------------------------- |
72
- | `get_profile` | — | Name, email, picture — from the OpenID Connect userinfo endpoint |
73
- | `create_post` | `text` | Publishes to the authenticated member's own feed, `visibility: PUBLIC` |
92
+ ## For developers
74
93
 
75
- ## Using it as a library
94
+ **Running from source:**
95
+
96
+ ```bash
97
+ cd mcp-servers/linkedin-mcp-server
98
+ npm install
99
+ cp .env.example .env # fill in LINKEDIN_CLIENT_ID / LINKEDIN_CLIENT_SECRET
100
+ npm run dev:authorize # opens a consent link in your browser, one time
101
+ npm run dev
102
+ ```
76
103
 
77
104
  ```ts
78
105
  import { TokenManager, LinkedInClient, createServer } from "./src/index.js";
@@ -0,0 +1,16 @@
1
+ import type { RequestHandler } from "express";
2
+ export interface ListenConfig {
3
+ host: string;
4
+ /** Bearer token every caller must present. Always set when `host` isn't loopback. */
5
+ authToken?: string;
6
+ }
7
+ export declare function isLoopbackHost(host: string): boolean;
8
+ /**
9
+ * Listens on loopback only unless BIND_HOST says otherwise, and refuses to
10
+ * listen on anything else without a token — the MCP tools can publish
11
+ * posts to your LinkedIn feed as you, so a network-reachable server with no
12
+ * caller authentication is never acceptable.
13
+ */
14
+ export declare function resolveListenConfig(env?: NodeJS.ProcessEnv): ListenConfig;
15
+ /** Rejects any request without `Authorization: Bearer <token>`. Compared in constant time. */
16
+ export declare function requireBearerToken(token: string): RequestHandler;
package/dist/access.js ADDED
@@ -0,0 +1,40 @@
1
+ import { createHash, timingSafeEqual } from "node:crypto";
2
+ const LOOPBACK_HOSTS = ["127.0.0.1", "localhost", "::1"];
3
+ const MIN_TOKEN_LENGTH = 16;
4
+ export function isLoopbackHost(host) {
5
+ return LOOPBACK_HOSTS.includes(host);
6
+ }
7
+ /**
8
+ * Listens on loopback only unless BIND_HOST says otherwise, and refuses to
9
+ * listen on anything else without a token — the MCP tools can publish
10
+ * posts to your LinkedIn feed as you, so a network-reachable server with no
11
+ * caller authentication is never acceptable.
12
+ */
13
+ export function resolveListenConfig(env = process.env) {
14
+ const host = env.BIND_HOST || "127.0.0.1";
15
+ const authToken = env.LINKEDIN_MCP_TOKEN || undefined;
16
+ if (authToken && authToken.length < MIN_TOKEN_LENGTH) {
17
+ throw new Error(`LINKEDIN_MCP_TOKEN must be at least ${MIN_TOKEN_LENGTH} characters (try: openssl rand -hex 32)`);
18
+ }
19
+ if (!isLoopbackHost(host) && !authToken) {
20
+ throw new Error(`Refusing to listen on ${host} without authentication. Set LINKEDIN_MCP_TOKEN ` +
21
+ `(try: openssl rand -hex 32), or unset BIND_HOST to listen on 127.0.0.1 only.`);
22
+ }
23
+ return { host, authToken };
24
+ }
25
+ function sha256(value) {
26
+ return createHash("sha256").update(value).digest();
27
+ }
28
+ /** Rejects any request without `Authorization: Bearer <token>`. Compared in constant time. */
29
+ export function requireBearerToken(token) {
30
+ const expected = sha256(token);
31
+ return (req, res, next) => {
32
+ const match = /^Bearer\s+(.+)$/i.exec(req.headers.authorization ?? "");
33
+ if (match && timingSafeEqual(sha256(match[1]), expected)) {
34
+ next();
35
+ return;
36
+ }
37
+ res.status(401).set("WWW-Authenticate", "Bearer").json({ error: "unauthorized" });
38
+ };
39
+ }
40
+ //# sourceMappingURL=access.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access.js","sourceRoot":"","sources":["../src/access.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG1D,MAAM,cAAc,GAAG,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;AACzD,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAQ5B,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;AACvC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACtE,MAAM,IAAI,GAAG,GAAG,CAAC,SAAS,IAAI,WAAW,CAAC;IAC1C,MAAM,SAAS,GAAG,GAAG,CAAC,kBAAkB,IAAI,SAAS,CAAC;IAEtD,IAAI,SAAS,IAAI,SAAS,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,uCAAuC,gBAAgB,yCAAyC,CAAC,CAAC;IACpH,CAAC;IACD,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CACb,yBAAyB,IAAI,kDAAkD;YAC7E,8EAA8E,CACjF,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AAC7B,CAAC;AAED,SAAS,MAAM,CAAC,KAAa;IAC3B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;AACrD,CAAC;AAED,8FAA8F;AAC9F,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC9C,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAE/B,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;QACxB,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,IAAI,EAAE,CAAC,CAAC;QACvE,IAAI,KAAK,IAAI,eAAe,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC;YACzD,IAAI,EAAE,CAAC;YACP,OAAO;QACT,CAAC;QACD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,kBAAkB,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;IACpF,CAAC,CAAC;AACJ,CAAC"}
package/dist/auth.js CHANGED
@@ -85,6 +85,10 @@ export class TokenManager {
85
85
  throw new Error("LinkedIn access token has expired. LinkedIn only issues refresh tokens to apps approved for " +
86
86
  'offline access; without one, re-run "npm run authorize" to get a new token.');
87
87
  }
88
+ if (!this.config.clientId || !this.config.clientSecret) {
89
+ throw new Error("LinkedIn access token needs refreshing, but LINKEDIN_CLIENT_ID/LINKEDIN_CLIENT_SECRET aren't " +
90
+ 'set. Add them to your .env, or re-run "npm run authorize" to get a fresh token.');
91
+ }
88
92
  this.token = await refreshAccessToken(this.config, this.token.refreshToken);
89
93
  await saveToken(this.tokenPath, this.token);
90
94
  }
package/dist/auth.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -3,40 +3,42 @@ import "dotenv/config";
3
3
  import { TokenManager } from "./auth.js";
4
4
  import { LinkedInClient } from "./linkedin.js";
5
5
  import { createServer } from "./server.js";
6
- function requireEnv(name) {
7
- const value = process.env[name];
8
- if (!value) {
9
- throw new Error(`Missing ${name} environment variable`);
10
- }
11
- return value;
12
- }
6
+ import { resolveListenConfig } from "./access.js";
7
+ /**
8
+ * clientId/clientSecret are only needed to refresh an expiring token (see
9
+ * TokenManager.getValidAccessToken) — a still-valid saved token needs
10
+ * neither, so this intentionally doesn't require them at startup.
11
+ */
13
12
  function loadConfig() {
14
13
  return {
15
- clientId: requireEnv("LINKEDIN_CLIENT_ID"),
16
- clientSecret: requireEnv("LINKEDIN_CLIENT_SECRET"),
14
+ clientId: process.env.LINKEDIN_CLIENT_ID ?? "",
15
+ clientSecret: process.env.LINKEDIN_CLIENT_SECRET ?? "",
17
16
  redirectUri: process.env.LINKEDIN_REDIRECT_URI ?? "http://localhost:3300/callback",
18
17
  scopes: (process.env.LINKEDIN_SCOPES ?? "openid profile email w_member_social").split(" "),
19
18
  };
20
19
  }
21
20
  async function main() {
22
- let config;
21
+ let listen;
23
22
  try {
24
- config = loadConfig();
23
+ listen = resolveListenConfig();
25
24
  }
26
25
  catch (error) {
27
26
  console.error(error instanceof Error ? error.message : String(error));
28
27
  process.exitCode = 1;
29
28
  return;
30
29
  }
30
+ const config = loadConfig();
31
31
  const tokenPath = process.env.LINKEDIN_TOKEN_PATH ?? "./linkedin-token.json";
32
32
  const port = Number(process.env.PORT ?? 4300);
33
33
  const tokens = new TokenManager(config, tokenPath);
34
34
  const linkedin = new LinkedInClient(tokens);
35
- const app = createServer(linkedin);
36
- app.listen(port, () => {
37
- console.error(`linkedin-mcp-server listening on http://localhost:${port}`);
38
- console.error(` MCP endpoint: POST http://localhost:${port}/mcp`);
39
- console.error(` Health: GET http://localhost:${port}/health`);
35
+ const app = createServer(linkedin, listen);
36
+ app.listen(port, listen.host, () => {
37
+ const origin = `http://${listen.host.includes(":") ? `[${listen.host}]` : listen.host}:${port}`;
38
+ console.error(`linkedin-mcp-server listening on ${origin}`);
39
+ console.error(` MCP endpoint: POST ${origin}/mcp`);
40
+ console.error(` Health: GET ${origin}/health`);
41
+ console.error(listen.authToken ? " Auth: bearer token required (LINKEDIN_MCP_TOKEN)" : " Auth: none (loopback only)");
40
42
  console.error(` If tools fail with "Not authorized yet", run: npm run authorize`);
41
43
  });
42
44
  }
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAA4B,MAAM,WAAW,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,WAAW,IAAI,uBAAuB,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,UAAU;IACjB,OAAO;QACL,QAAQ,EAAE,UAAU,CAAC,oBAAoB,CAAC;QAC1C,YAAY,EAAE,UAAU,CAAC,wBAAwB,CAAC;QAClD,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,gCAAgC;QAClF,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,sCAAsC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;KAC3F,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,IAAI,MAA2B,CAAC;IAChC,IAAI,CAAC;QACH,MAAM,GAAG,UAAU,EAAE,CAAC;IACxB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACtE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,uBAAuB,CAAC;IAC7E,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;IAE9C,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IAEnC,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;QACpB,OAAO,CAAC,KAAK,CAAC,qDAAqD,IAAI,EAAE,CAAC,CAAC;QAC3E,OAAO,CAAC,KAAK,CAAC,yCAAyC,IAAI,MAAM,CAAC,CAAC;QACnE,OAAO,CAAC,KAAK,CAAC,yCAAyC,IAAI,SAAS,CAAC,CAAC;QACtE,OAAO,CAAC,KAAK,CAAC,mEAAmE,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;AACL,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAA4B,MAAM,WAAW,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAqB,MAAM,aAAa,CAAC;AAErE;;;;GAIG;AACH,SAAS,UAAU;IACjB,OAAO;QACL,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,EAAE;QAC9C,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB,IAAI,EAAE;QACtD,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,gCAAgC;QAClF,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,sCAAsC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;KAC3F,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,IAAI,MAAoB,CAAC;IACzB,IAAI,CAAC;QACH,MAAM,GAAG,mBAAmB,EAAE,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACtE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,uBAAuB,CAAC;IAC7E,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;IAE9C,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACnD,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAE3C,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;QACjC,MAAM,MAAM,GAAG,UAAU,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;QAChG,OAAO,CAAC,KAAK,CAAC,oCAAoC,MAAM,EAAE,CAAC,CAAC;QAC5D,OAAO,CAAC,KAAK,CAAC,wBAAwB,MAAM,MAAM,CAAC,CAAC;QACpD,OAAO,CAAC,KAAK,CAAC,wBAAwB,MAAM,SAAS,CAAC,CAAC;QACvD,OAAO,CAAC,KAAK,CACX,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,4DAA4D,CAAC,CAAC,CAAC,sCAAsC,CACzH,CAAC;QACF,OAAO,CAAC,KAAK,CAAC,mEAAmE,CAAC,CAAC;IACrF,CAAC,CAAC,CAAC;AACL,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrB,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -3,3 +3,5 @@ export type { LinkedInOAuthConfig, StoredToken } from "./auth.js";
3
3
  export { LinkedInClient } from "./linkedin.js";
4
4
  export type { LinkedInProfile } from "./linkedin.js";
5
5
  export { createServer } from "./server.js";
6
+ export { resolveListenConfig, requireBearerToken, isLoopbackHost } from "./access.js";
7
+ export type { ListenConfig } from "./access.js";
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { TokenManager, buildAuthorizationUrl, exchangeCodeForToken, refreshAccessToken, loadToken, saveToken } from "./auth.js";
2
2
  export { LinkedInClient } from "./linkedin.js";
3
3
  export { createServer } from "./server.js";
4
+ export { resolveListenConfig, requireBearerToken, isLoopbackHost } from "./access.js";
4
5
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEhI,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEhI,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
package/dist/server.d.ts CHANGED
@@ -1,10 +1,16 @@
1
1
  import type { Express } from "express";
2
2
  import type { LinkedInClient } from "./linkedin.js";
3
+ import { type ListenConfig } from "./access.js";
3
4
  /**
4
5
  * Builds the Express app: `POST /mcp` is the stateless MCP endpoint (a
5
6
  * fresh McpServer per request, matching the SDK's own reference server),
6
7
  * `GET /health` is a liveness check. Unlike whatsapp-mcp-server, there's no
7
8
  * push/events stream here — LinkedIn's API is pure request/response, there's
8
9
  * nothing to watch for.
10
+ *
11
+ * `listen` must match what the caller passes to `app.listen`. The SDK's Host
12
+ * header check only guards browser-origin (DNS rebinding) attacks and is
13
+ * trivially bypassed by a network client sending `Host: localhost`, so it
14
+ * is not authentication: `authToken`, when set, gates every route.
9
15
  */
10
- export declare function createServer(linkedin: LinkedInClient): Express;
16
+ export declare function createServer(linkedin: LinkedInClient, listen?: ListenConfig): Express;
package/dist/server.js CHANGED
@@ -2,6 +2,7 @@ import * as z from "zod/v4";
2
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
4
4
  import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
5
+ import { requireBearerToken } from "./access.js";
5
6
  function buildMcpServer(linkedin) {
6
7
  const server = new McpServer({ name: "linkedin-mcp-server", version: "0.1.0" }, { capabilities: {} });
7
8
  server.registerTool("get_profile", { description: "Get the authenticated LinkedIn member's basic profile (name, email, picture)", inputSchema: {} }, async () => {
@@ -23,9 +24,17 @@ function buildMcpServer(linkedin) {
23
24
  * `GET /health` is a liveness check. Unlike whatsapp-mcp-server, there's no
24
25
  * push/events stream here — LinkedIn's API is pure request/response, there's
25
26
  * nothing to watch for.
27
+ *
28
+ * `listen` must match what the caller passes to `app.listen`. The SDK's Host
29
+ * header check only guards browser-origin (DNS rebinding) attacks and is
30
+ * trivially bypassed by a network client sending `Host: localhost`, so it
31
+ * is not authentication: `authToken`, when set, gates every route.
26
32
  */
27
- export function createServer(linkedin) {
28
- const app = createMcpExpressApp();
33
+ export function createServer(linkedin, listen = { host: "127.0.0.1" }) {
34
+ const app = createMcpExpressApp({ host: listen.host });
35
+ if (listen.authToken) {
36
+ app.use(requireBearerToken(listen.authToken));
37
+ }
29
38
  app.post("/mcp", async (req, res) => {
30
39
  try {
31
40
  const server = buildMcpServer(linkedin);
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clickonsearch/linkedin-mcp-server",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "MCP server for a personal LinkedIn account via LinkedIn's OAuth 2.0 API: read your own profile and publish posts to your feed.",
5
5
  "type": "module",
6
6
  "license": "MIT",