@linwheel/mcp-server 0.2.0 โ†’ 0.2.1

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
@@ -219,6 +219,29 @@ The MCP server is a thin client. All heavy lifting (LLM calls, image generation,
219
219
 
220
220
  ---
221
221
 
222
+ ## ๐Ÿšข Releasing (maintainers)
223
+
224
+ The package publishes to npm via **trusted publishing (OIDC)** โ€” there is **no `NPM_TOKEN`**. The workflow (`.github/workflows/publish-mcp.yml`) mints a short-lived token from the GitHub id-token at publish time, and provenance is attached automatically. The trusted publisher is configured on npmjs.com (package โ†’ Settings โ†’ Trusted Publisher โ†’ GitHub Actions โ†’ `Peleke/linwheel` โ†’ `publish-mcp.yml` โ†’ environment `npm`).
225
+
226
+ To cut a release:
227
+
228
+ 1. Bump the version in **`mcp/package.json`**, then sync the lockfile and the server version string:
229
+ ```bash
230
+ cd mcp
231
+ # edit package.json version, then:
232
+ npm install --package-lock-only # sync mcp/package-lock.json
233
+ # also bump the version in src/index.ts (McpServer { version })
234
+ ```
235
+ 2. Merge the bump to `main` (via PR).
236
+ 3. **Publish by pushing a tag** that points at the merged commit:
237
+ ```bash
238
+ git tag mcp-v<version> origin/main && git push origin mcp-v<version>
239
+ ```
240
+
241
+ > โš ๏ธ **Publish only via a `mcp-v*` tag โ€” not `workflow_dispatch`.** The `npm` GitHub Environment has a deployment-branch rule that permits **tags matching `mcp-v*`** only. A manual `workflow_dispatch` from `main` is rejected with *"Branch 'main' is not allowed to deploy to npm due to environment protection rules."* If you re-run after a workflow fix, move the tag to the fixed commit first (`git tag -d`, delete the remote tag, re-tag `origin/main`, push) so GitHub reads the corrected workflow from the tag's commit.
242
+
243
+ ---
244
+
222
245
  <div align="center">
223
246
 
224
247
  Built with [Model Context Protocol](https://modelcontextprotocol.io) ยท Powered by [Claude](https://claude.ai)
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Local credential storage for the device-login flow.
3
+ *
4
+ * After the user approves a device authorization in the browser, the MCP client
5
+ * captures the minted key and writes it to ~/.linwheel/credentials.json. On the
6
+ * next startup, the server reads it as a fallback when LINWHEEL_API_KEY is unset
7
+ * โ€” the same pattern as `vercel login` (~/.vercel).
8
+ */
9
+ export interface LinWheelCredentials {
10
+ apiKey: string;
11
+ signingSecret?: string | null;
12
+ }
13
+ export declare function credentialsPath(): string;
14
+ export declare function readCredentials(): Promise<LinWheelCredentials | null>;
15
+ export declare function writeCredentials(creds: LinWheelCredentials): Promise<string>;
@@ -0,0 +1,28 @@
1
+ import { promises as fs } from "fs";
2
+ import { homedir } from "os";
3
+ import { join } from "path";
4
+ const DIR = join(homedir(), ".linwheel");
5
+ const FILE = join(DIR, "credentials.json");
6
+ export function credentialsPath() {
7
+ return FILE;
8
+ }
9
+ export async function readCredentials() {
10
+ try {
11
+ const raw = await fs.readFile(FILE, "utf8");
12
+ const parsed = JSON.parse(raw);
13
+ if (parsed && typeof parsed.apiKey === "string" && parsed.apiKey.length > 0) {
14
+ return parsed;
15
+ }
16
+ return null;
17
+ }
18
+ catch {
19
+ return null;
20
+ }
21
+ }
22
+ export async function writeCredentials(creds) {
23
+ // 0700 dir / 0600 file โ€” the key is a secret; keep it owner-only.
24
+ await fs.mkdir(DIR, { recursive: true, mode: 0o700 });
25
+ await fs.writeFile(FILE, JSON.stringify(creds, null, 2) + "\n", { mode: 0o600 });
26
+ return FILE;
27
+ }
28
+ //# sourceMappingURL=credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAgB5B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;AACzC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;AAE3C,MAAM,UAAU,eAAe;IAC7B,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAwB,CAAC;QACtD,IAAI,MAAM,IAAI,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5E,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAA0B;IAC/D,kEAAkE;IAClE,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACtD,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACjF,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Device-login client โ€” the MCP side of the `vercel login`-style flow.
3
+ *
4
+ * `start` kicks off a device authorization and returns a URL for the user to
5
+ * approve in the browser; `poll` checks whether they've approved yet and, once
6
+ * they have, returns the minted key (once).
7
+ */
8
+ export interface DeviceStart {
9
+ deviceCode: string;
10
+ userCode: string;
11
+ verificationUri: string;
12
+ verificationUriComplete: string;
13
+ interval: number;
14
+ expiresIn: number;
15
+ }
16
+ export type DevicePoll = {
17
+ status: "pending";
18
+ } | {
19
+ status: "denied";
20
+ } | {
21
+ status: "expired";
22
+ } | {
23
+ status: "approved";
24
+ apiKey: string;
25
+ signingSecret: string | null;
26
+ };
27
+ export declare function startDeviceLogin(baseUrl: string): Promise<DeviceStart>;
28
+ export declare function pollDeviceLogin(baseUrl: string, deviceCode: string): Promise<DevicePoll>;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Device-login client โ€” the MCP side of the `vercel login`-style flow.
3
+ *
4
+ * `start` kicks off a device authorization and returns a URL for the user to
5
+ * approve in the browser; `poll` checks whether they've approved yet and, once
6
+ * they have, returns the minted key (once).
7
+ */
8
+ export async function startDeviceLogin(baseUrl) {
9
+ const res = await fetch(`${baseUrl.replace(/\/$/, "")}/api/auth/device/start`, {
10
+ method: "POST",
11
+ headers: { "Content-Type": "application/json" },
12
+ body: "{}",
13
+ });
14
+ if (!res.ok) {
15
+ throw new Error(`Could not start LinWheel login (HTTP ${res.status}).`);
16
+ }
17
+ return (await res.json());
18
+ }
19
+ export async function pollDeviceLogin(baseUrl, deviceCode) {
20
+ const res = await fetch(`${baseUrl.replace(/\/$/, "")}/api/auth/device/poll`, {
21
+ method: "POST",
22
+ headers: { "Content-Type": "application/json" },
23
+ body: JSON.stringify({ deviceCode }),
24
+ });
25
+ if (!res.ok) {
26
+ throw new Error(`Could not check LinWheel login status (HTTP ${res.status}).`);
27
+ }
28
+ return (await res.json());
29
+ }
30
+ //# sourceMappingURL=device-login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-login.js","sourceRoot":"","sources":["../src/device-login.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAiBH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAAe;IACpD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,wBAAwB,EAAE;QAC7E,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI;KACX,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,wCAAwC,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAgB,CAAC;AAC3C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,OAAe,EACf,UAAkB;IAElB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,uBAAuB,EAAE;QAC5E,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,CAAC;KACrC,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,+CAA+C,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAe,CAAC;AAC1C,CAAC"}
package/dist/index.js CHANGED
@@ -3,75 +3,96 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { LinWheelClient } from "./client.js";
5
5
  import { registerAllTools } from "./tools/index.js";
6
+ import { z } from "zod";
7
+ import { readCredentials, writeCredentials } from "./credentials.js";
8
+ import { startDeviceLogin, pollDeviceLogin } from "./device-login.js";
6
9
  const BASE_URL = process.env.LINWHEEL_BASE_URL ?? "https://www.linwheel.io";
7
- const API_KEY = process.env.LINWHEEL_API_KEY;
8
- const server = new McpServer({ name: "linwheel", version: "0.2.0" }, { capabilities: { tools: {} } });
10
+ // Key resolution: LINWHEEL_API_KEY env var first, then the saved credentials
11
+ // file written by the device-login flow (~/.linwheel/credentials.json).
12
+ const stored = process.env.LINWHEEL_API_KEY ? null : await readCredentials();
13
+ const API_KEY = process.env.LINWHEEL_API_KEY ?? stored?.apiKey;
14
+ const SIGNING_SECRET = process.env.LINWHEEL_SIGNING_SECRET ?? stored?.signingSecret ?? undefined;
15
+ const server = new McpServer({ name: "linwheel", version: "0.2.1" }, { capabilities: { tools: {} } });
9
16
  if (API_KEY) {
10
17
  const client = new LinWheelClient({
11
18
  baseUrl: BASE_URL,
12
19
  apiKey: API_KEY,
13
- signingSecret: process.env.LINWHEEL_SIGNING_SECRET,
20
+ signingSecret: SIGNING_SECRET,
14
21
  timeoutMs: parseInt(process.env.LINWHEEL_TIMEOUT_MS ?? "60000", 10),
15
22
  });
16
23
  registerAllTools(server, client);
17
24
  }
18
25
  else {
19
- // No API key โ€” register setup tool only
20
- server.tool("linwheel_setup", "Get started with LinWheel. Returns step-by-step instructions to create an account and configure your API key. Call this first.", {}, async () => {
21
- const configExample = JSON.stringify({
22
- mcpServers: {
23
- linwheel: {
24
- command: "npx",
25
- args: ["-y", "@linwheel/mcp-server"],
26
- env: {
27
- LINWHEEL_API_KEY: "lw_sk_paste_your_key_here",
26
+ // No key configured โ€” expose the guided device login. Call once to get an
27
+ // approval URL, then again with the deviceCode to capture and save the key.
28
+ server.tool("linwheel_setup", "Connect LinWheel by logging in from the browser โ€” no manual key copying. Call with no arguments to get an approval URL; after you approve in the browser, call it again with the deviceCode it gave you to finish. Your key is saved to ~/.linwheel/credentials.json automatically; then restart your MCP client to load the tools.", {
29
+ deviceCode: z
30
+ .string()
31
+ .optional()
32
+ .describe("The deviceCode returned by the first call. Pass it after approving in the browser to finish login."),
33
+ }, async ({ deviceCode }) => {
34
+ if (!deviceCode) {
35
+ const start = await startDeviceLogin(BASE_URL);
36
+ return {
37
+ content: [
38
+ {
39
+ type: "text",
40
+ text: [
41
+ "# Connect LinWheel",
42
+ "",
43
+ "1. Open this URL and approve the device:",
44
+ ` ${start.verificationUriComplete}`,
45
+ ` (verification code: ${start.userCode})`,
46
+ "",
47
+ "2. After approving in the browser, call `linwheel_setup` again with:",
48
+ ` deviceCode: "${start.deviceCode}"`,
49
+ "",
50
+ "I'll capture your key and save it automatically. The code expires in ~10 minutes.",
51
+ ].join("\n"),
28
52
  },
29
- },
30
- },
31
- }, null, 2);
53
+ ],
54
+ };
55
+ }
56
+ const poll = await pollDeviceLogin(BASE_URL, deviceCode);
57
+ if (poll.status === "approved") {
58
+ const path = await writeCredentials({
59
+ apiKey: poll.apiKey,
60
+ signingSecret: poll.signingSecret,
61
+ });
62
+ return {
63
+ content: [
64
+ {
65
+ type: "text",
66
+ text: [
67
+ "โœ… Connected to LinWheel.",
68
+ "",
69
+ `Saved your key to ${path}.`,
70
+ "Restart your MCP client (or Claude Code) to load the LinWheel tools, then run `linwheel_onboard` to get started.",
71
+ ].join("\n"),
72
+ },
73
+ ],
74
+ };
75
+ }
76
+ if (poll.status === "pending") {
77
+ return {
78
+ content: [
79
+ {
80
+ type: "text",
81
+ text: "Still waiting for approval. Approve in the browser, then call `linwheel_setup` again with the same deviceCode.",
82
+ },
83
+ ],
84
+ };
85
+ }
32
86
  return {
33
87
  content: [
34
88
  {
35
89
  type: "text",
36
- text: [
37
- "# LinWheel Setup",
38
- "",
39
- "No API key configured. Follow these steps:",
40
- "",
41
- "## 1. Create an account",
42
- `Sign up at: ${BASE_URL}/login`,
43
- "",
44
- "## 2. Generate an API key",
45
- `Go to: ${BASE_URL}/settings`,
46
- 'Click "Generate API Key" and copy the key (starts with lw_sk_).',
47
- "The key is shown only once โ€” save it somewhere safe.",
48
- "",
49
- "## 3. Add to your MCP config",
50
- "",
51
- "**Claude Code** โ€” run this in your terminal:",
52
- "```",
53
- 'claude mcp add linwheel -- npx -y @linwheel/mcp-server',
54
- "```",
55
- "Then set the env var in your `.mcp.json`:",
56
- "",
57
- "```json",
58
- configExample,
59
- "```",
60
- "",
61
- "## 4. Restart Claude Code",
62
- "After updating config, restart Claude Code to load LinWheel tools.",
63
- "",
64
- "## 5. Verify",
65
- 'Ask Claude: "List my LinWheel posts" โ€” if it works, you\'re all set.',
66
- "",
67
- `Dashboard: ${BASE_URL}/dashboard`,
68
- `Docs: https://github.com/Peleke/linwheel/tree/main/mcp#readme`,
69
- ].join("\n"),
90
+ text: `Login ${poll.status}. Start over: call \`linwheel_setup\` with no arguments.`,
70
91
  },
71
92
  ],
72
93
  };
73
94
  });
74
- console.error("LinWheel MCP: No LINWHEEL_API_KEY set. Only linwheel_setup tool available.");
95
+ console.error("LinWheel MCP: No key configured. Run the linwheel_setup tool to log in.");
75
96
  }
76
97
  const transport = new StdioServerTransport();
77
98
  await server.connect(transport);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGpD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,yBAAyB,CAAC;AAC5E,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;AAE7C,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,EACtC,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAChC,CAAC;AAEF,IAAI,OAAO,EAAE,CAAC;IACZ,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC;QAChC,OAAO,EAAE,QAAQ;QACjB,MAAM,EAAE,OAAO;QACf,aAAa,EAAE,OAAO,CAAC,GAAG,CAAC,uBAAuB;QAClD,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,OAAO,EAAE,EAAE,CAAC;KACpE,CAAC,CAAC;IAEH,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACnC,CAAC;KAAM,CAAC;IACN,wCAAwC;IACxC,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,gIAAgI,EAChI,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,aAAa,GAAG,IAAI,CAAC,SAAS,CAClC;YACE,UAAU,EAAE;gBACV,QAAQ,EAAE;oBACR,OAAO,EAAE,KAAK;oBACd,IAAI,EAAE,CAAC,IAAI,EAAE,sBAAsB,CAAC;oBACpC,GAAG,EAAE;wBACH,gBAAgB,EAAE,2BAA2B;qBAC9C;iBACF;aACF;SACF,EACD,IAAI,EACJ,CAAC,CACF,CAAC;QAEF,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE;wBACJ,kBAAkB;wBAClB,EAAE;wBACF,4CAA4C;wBAC5C,EAAE;wBACF,yBAAyB;wBACzB,eAAe,QAAQ,QAAQ;wBAC/B,EAAE;wBACF,2BAA2B;wBAC3B,UAAU,QAAQ,WAAW;wBAC7B,iEAAiE;wBACjE,sDAAsD;wBACtD,EAAE;wBACF,8BAA8B;wBAC9B,EAAE;wBACF,8CAA8C;wBAC9C,KAAK;wBACL,wDAAwD;wBACxD,KAAK;wBACL,2CAA2C;wBAC3C,EAAE;wBACF,SAAS;wBACT,aAAa;wBACb,KAAK;wBACL,EAAE;wBACF,2BAA2B;wBAC3B,oEAAoE;wBACpE,EAAE;wBACF,cAAc;wBACd,sEAAsE;wBACtE,EAAE;wBACF,cAAc,QAAQ,YAAY;wBAClC,+DAA+D;qBAChE,CAAC,IAAI,CAAC,IAAI,CAAC;iBACb;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,OAAO,CAAC,KAAK,CACX,4EAA4E,CAC7E,CAAC;AACJ,CAAC;AAED,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAEhC,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linwheel/mcp-server",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "MCP server for LinWheel โ€” AI-powered LinkedIn content engine. Draft, schedule, and publish posts from Claude Code.",
5
5
  "type": "module",
6
6
  "bin": {