linkedin-toolkit-mcp 2.0.2 → 2.1.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/dist/bridge.d.ts +1 -1
- package/dist/bridge.js +1 -1
- package/dist/cli.d.ts +44 -0
- package/dist/cli.js +300 -7
- package/dist/cli.js.map +1 -1
- package/dist/contract.d.ts +38 -9
- package/dist/contract.js +53 -8
- package/dist/contract.js.map +1 -1
- package/dist/endpoints.d.ts +49 -0
- package/dist/endpoints.js +160 -0
- package/dist/endpoints.js.map +1 -0
- package/dist/fake-data.d.ts +8 -0
- package/dist/fake-data.js +37 -2
- package/dist/fake-data.js.map +1 -1
- package/dist/prompts.js +1 -1
- package/dist/prompts.js.map +1 -1
- package/dist/server.d.ts +11 -0
- package/dist/server.js +18 -1
- package/dist/server.js.map +1 -1
- package/dist/setup.d.ts +248 -0
- package/dist/setup.js +584 -0
- package/dist/setup.js.map +1 -0
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +1 -1
- package/openapi.json +290 -8
- package/package.json +1 -1
- package/tools.json +5 -4
package/dist/setup.d.ts
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `lit setup` — everything between "I found this repo" and "my agent can use
|
|
3
|
+
* it", minus the three clicks Chrome will not let anybody automate.
|
|
4
|
+
*
|
|
5
|
+
* The old path was: find the Releases page, download a zip, unzip it somewhere
|
|
6
|
+
* you will not delete, turn on Developer mode, Load unpacked, run a server,
|
|
7
|
+
* find the pairing token, paste it, then hand-write a JSON config block for
|
|
8
|
+
* whichever agent you use. Seven steps, six of which a computer can do.
|
|
9
|
+
*
|
|
10
|
+
* This module does the six. Everything here is a small function with its
|
|
11
|
+
* dependencies passed in — `fetch`, the filesystem, the clock, the
|
|
12
|
+
* environment — so the whole flow is testable without a network, a Chrome, or
|
|
13
|
+
* a home directory.
|
|
14
|
+
*
|
|
15
|
+
* What it deliberately does not do:
|
|
16
|
+
* - claim Chrome opened a page it may have ignored (see `chromeLaunch`);
|
|
17
|
+
* - write a client config file it cannot parse (a malformed file is refused,
|
|
18
|
+
* never rewritten);
|
|
19
|
+
* - install anything outside `~/.linkedin-toolkit` unless asked.
|
|
20
|
+
*/
|
|
21
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, writeFileSync, copyFileSync } from 'node:fs';
|
|
22
|
+
export declare const REPO = "OpenRecruiterTools/linkedin-toolkit";
|
|
23
|
+
export declare const RELEASES_URL = "https://github.com/OpenRecruiterTools/linkedin-toolkit/releases";
|
|
24
|
+
/** A setup step that failed for a reason the user can act on. */
|
|
25
|
+
export declare class SetupError extends Error {
|
|
26
|
+
readonly howToFix?: string | undefined;
|
|
27
|
+
constructor(message: string, howToFix?: string | undefined);
|
|
28
|
+
}
|
|
29
|
+
/** The slice of `node:fs` this module uses, so tests can pass their own. */
|
|
30
|
+
export type FsLike = {
|
|
31
|
+
existsSync: typeof existsSync;
|
|
32
|
+
mkdirSync: typeof mkdirSync;
|
|
33
|
+
readFileSync: typeof readFileSync;
|
|
34
|
+
readdirSync: typeof readdirSync;
|
|
35
|
+
renameSync: typeof renameSync;
|
|
36
|
+
rmSync: typeof rmSync;
|
|
37
|
+
writeFileSync: typeof writeFileSync;
|
|
38
|
+
copyFileSync: typeof copyFileSync;
|
|
39
|
+
};
|
|
40
|
+
export declare const realFs: FsLike;
|
|
41
|
+
/**
|
|
42
|
+
* The release asset for one version.
|
|
43
|
+
*
|
|
44
|
+
* The release workflow names the zip from the tag, so `linkedin-toolkit-mcp`
|
|
45
|
+
* 2.1.0 and `linkedin-toolkit-extension-v2.1.0.zip` are the same release by
|
|
46
|
+
* construction. A version the user passed by hand may carry a leading `v`.
|
|
47
|
+
*/
|
|
48
|
+
export declare function extensionZipUrl(version: string): string;
|
|
49
|
+
/** The API read that answers "what is the newest release, and what is in it?" */
|
|
50
|
+
export declare function latestReleaseApiUrl(): string;
|
|
51
|
+
export type Download = {
|
|
52
|
+
url: string;
|
|
53
|
+
version: string;
|
|
54
|
+
/** `version` when the exact release existed, `latest` when we fell back. */
|
|
55
|
+
source: 'version' | 'latest';
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Resolve the newest release's extension asset.
|
|
59
|
+
*
|
|
60
|
+
* `releases/latest/download/<name>` cannot be used directly because the asset
|
|
61
|
+
* name carries the version, which is the thing we do not know — so the release
|
|
62
|
+
* is read through the API and its asset list is matched.
|
|
63
|
+
*/
|
|
64
|
+
export declare function resolveLatestRelease(fetchImpl: typeof fetch): Promise<Download>;
|
|
65
|
+
/**
|
|
66
|
+
* Download the extension zip for `version`, falling back to the latest release.
|
|
67
|
+
*
|
|
68
|
+
* The fallback is the normal case on a fork, on a pre-release npm install, or
|
|
69
|
+
* any time the npm package is published slightly ahead of the GitHub release —
|
|
70
|
+
* and it is reported, because installing a different version than you asked
|
|
71
|
+
* for should never be silent.
|
|
72
|
+
*/
|
|
73
|
+
export declare function downloadExtension(options: {
|
|
74
|
+
version: string;
|
|
75
|
+
fetchImpl?: typeof fetch;
|
|
76
|
+
}): Promise<Download & {
|
|
77
|
+
buffer: Buffer;
|
|
78
|
+
}>;
|
|
79
|
+
export type ZipEntry = {
|
|
80
|
+
name: string;
|
|
81
|
+
data: Buffer;
|
|
82
|
+
};
|
|
83
|
+
/** Every file in the archive, decompressed. Directory entries are dropped. */
|
|
84
|
+
export declare function readZip(buffer: Buffer): ZipEntry[];
|
|
85
|
+
/**
|
|
86
|
+
* Is this a LinkedIn Toolkit extension zip?
|
|
87
|
+
*
|
|
88
|
+
* The failure this catches is mundane and common: GitHub served an HTML error
|
|
89
|
+
* page, a proxy served a login page, or the release has no asset — and the
|
|
90
|
+
* bytes get unpacked into a folder Chrome then refuses. Checking the magic
|
|
91
|
+
* number and the manifest turns that into one sentence.
|
|
92
|
+
*/
|
|
93
|
+
export declare function validateExtensionZip(buffer: Buffer): {
|
|
94
|
+
entries: ZipEntry[];
|
|
95
|
+
manifestVersion: string;
|
|
96
|
+
name: string;
|
|
97
|
+
};
|
|
98
|
+
/** Reject anything that would write outside the target folder. */
|
|
99
|
+
export declare function safeEntryName(name: string): string;
|
|
100
|
+
/** Write every entry under `dir`, creating the folders it needs. */
|
|
101
|
+
export declare function unpackZipTo(entries: ZipEntry[], dir: string, fs?: FsLike): number;
|
|
102
|
+
/**
|
|
103
|
+
* Replace `target` with `staged`, keeping a working folder at all times.
|
|
104
|
+
*
|
|
105
|
+
* Chrome loads the extension from this folder on every start, so a half-
|
|
106
|
+
* written folder is a broken extension until the user notices. The new copy is
|
|
107
|
+
* unpacked beside it and only then swapped in; if the swap fails, the previous
|
|
108
|
+
* copy goes back.
|
|
109
|
+
*/
|
|
110
|
+
export declare function swapIn(options: {
|
|
111
|
+
target: string;
|
|
112
|
+
staged: string;
|
|
113
|
+
fs?: FsLike;
|
|
114
|
+
now?: () => number;
|
|
115
|
+
}): {
|
|
116
|
+
replaced: boolean;
|
|
117
|
+
};
|
|
118
|
+
export type InstallResult = Download & {
|
|
119
|
+
dir: string;
|
|
120
|
+
files: number;
|
|
121
|
+
replaced: boolean;
|
|
122
|
+
manifestVersion: string;
|
|
123
|
+
};
|
|
124
|
+
/** Download, check, unpack, swap. The whole of step (a) in one call. */
|
|
125
|
+
export declare function installExtension(options: {
|
|
126
|
+
version: string;
|
|
127
|
+
dir: string;
|
|
128
|
+
fetchImpl?: typeof fetch;
|
|
129
|
+
fs?: FsLike;
|
|
130
|
+
now?: () => number;
|
|
131
|
+
}): Promise<InstallResult>;
|
|
132
|
+
/**
|
|
133
|
+
* The version of `linkedin-toolkit-mcp` that is actually running.
|
|
134
|
+
*
|
|
135
|
+
* The extension and the server are released together from one tag, so the
|
|
136
|
+
* installed package version is the right default for which zip to fetch. This
|
|
137
|
+
* reads the package's own manifest rather than a constant, so a published
|
|
138
|
+
* build can never disagree with itself about what it is.
|
|
139
|
+
*/
|
|
140
|
+
export declare function packageVersion(read?: (path: string) => string): string | null;
|
|
141
|
+
/** Where the extension lives unless `--dir` says otherwise. */
|
|
142
|
+
export declare function defaultExtensionDir(home?: string | undefined): string;
|
|
143
|
+
export type Platform = 'win32' | 'darwin' | 'linux' | string;
|
|
144
|
+
export type ChromeLaunch = {
|
|
145
|
+
kind: 'spawn';
|
|
146
|
+
command: string;
|
|
147
|
+
args: string[];
|
|
148
|
+
} | {
|
|
149
|
+
kind: 'none';
|
|
150
|
+
reason: string;
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* How to ask Chrome to show `chrome://extensions`, if we can ask at all.
|
|
154
|
+
*
|
|
155
|
+
* Chrome ignores `chrome://` URLs handed to it on the command line in most
|
|
156
|
+
* builds — it opens a new tab page instead and says nothing. So this never
|
|
157
|
+
* reports success: it either asks and tells the user to type the URL if
|
|
158
|
+
* nothing appeared, or it does not ask and says why. Claiming a page opened
|
|
159
|
+
* when it did not is worse than not trying.
|
|
160
|
+
*/
|
|
161
|
+
export declare function chromeLaunch(platform: Platform, env?: NodeJS.ProcessEnv, exists?: (path: string) => boolean): ChromeLaunch;
|
|
162
|
+
export declare const CLIENTS: readonly ["claude-desktop", "claude-code", "cursor", "windsurf", "vscode", "n8n", "print"];
|
|
163
|
+
export type ClientId = (typeof CLIENTS)[number];
|
|
164
|
+
export declare const SERVER_KEY = "linkedin-toolkit";
|
|
165
|
+
/** The stdio entry every MCP client gets, in that client's spelling. */
|
|
166
|
+
export declare function serverEntry(client: ClientId): Record<string, unknown>;
|
|
167
|
+
export type ClientTarget = {
|
|
168
|
+
id: ClientId;
|
|
169
|
+
label: string;
|
|
170
|
+
/** `write`: we can merge into a real file. `print`: we can only show it. */
|
|
171
|
+
mode: 'write' | 'print';
|
|
172
|
+
/** The config file, when there is one. */
|
|
173
|
+
path?: string;
|
|
174
|
+
/** The object key servers hang off: `mcpServers` everywhere but VS Code. */
|
|
175
|
+
key: 'mcpServers' | 'servers';
|
|
176
|
+
/** Why this one is printed rather than written, or what to do after writing. */
|
|
177
|
+
note: string;
|
|
178
|
+
};
|
|
179
|
+
export type Env = {
|
|
180
|
+
platform: Platform;
|
|
181
|
+
env?: NodeJS.ProcessEnv;
|
|
182
|
+
home?: string;
|
|
183
|
+
cwd?: string;
|
|
184
|
+
};
|
|
185
|
+
/**
|
|
186
|
+
* Where each client keeps its MCP config, per OS.
|
|
187
|
+
*
|
|
188
|
+
* Two are project-scoped by design (`.mcp.json`, `.vscode/mcp.json`) because
|
|
189
|
+
* that is where those clients look first and where a user can see them; two
|
|
190
|
+
* are user-scoped because the client has no project scope. n8n is printed, not
|
|
191
|
+
* written: its MCP client is configured inside a workflow in the n8n UI — and
|
|
192
|
+
* on the usual Docker install the config is not even on this machine — so
|
|
193
|
+
* there is no file here to merge into.
|
|
194
|
+
*/
|
|
195
|
+
export declare function clientTarget(id: ClientId, context: Env): ClientTarget;
|
|
196
|
+
/** The snippet a print-only client gets. */
|
|
197
|
+
export declare function configSnippet(client: ClientId): string;
|
|
198
|
+
export type MergeResult = {
|
|
199
|
+
/** The file to write, already serialised. */
|
|
200
|
+
contents: string;
|
|
201
|
+
/** False when the file already said exactly this. */
|
|
202
|
+
changed: boolean;
|
|
203
|
+
/** Other servers that were in the file and are still in it. */
|
|
204
|
+
kept: string[];
|
|
205
|
+
};
|
|
206
|
+
/**
|
|
207
|
+
* Merge our entry into an existing client config without touching anything else.
|
|
208
|
+
*
|
|
209
|
+
* A config file people have edited by hand is not ours to rewrite. Anything we
|
|
210
|
+
* cannot parse — malformed JSON, a top level that is not an object, a
|
|
211
|
+
* `mcpServers` that is not an object — is refused with the path, so the user
|
|
212
|
+
* fixes their file rather than losing it to us.
|
|
213
|
+
*/
|
|
214
|
+
export declare function mergeMcpConfig(options: {
|
|
215
|
+
existing: string | null;
|
|
216
|
+
key: 'mcpServers' | 'servers';
|
|
217
|
+
name?: string;
|
|
218
|
+
entry: Record<string, unknown>;
|
|
219
|
+
path?: string;
|
|
220
|
+
}): MergeResult;
|
|
221
|
+
/** `2026-09-18T14-22-05Z`, so backups sort and never collide on a retry. */
|
|
222
|
+
export declare function backupStamp(at: number): string;
|
|
223
|
+
export type WriteOutcome = {
|
|
224
|
+
path: string;
|
|
225
|
+
/** What happened: nothing needed, written, or would have been written. */
|
|
226
|
+
action: 'unchanged' | 'written' | 'dry-run';
|
|
227
|
+
backup?: string;
|
|
228
|
+
kept: string[];
|
|
229
|
+
created: boolean;
|
|
230
|
+
};
|
|
231
|
+
/**
|
|
232
|
+
* Write (or pretend to write) one client's config.
|
|
233
|
+
*
|
|
234
|
+
* The original is copied to `<file>.bak-<timestamp>` before it is replaced —
|
|
235
|
+
* this is somebody's editor config, and a merge bug should cost them a rename,
|
|
236
|
+
* not their other MCP servers.
|
|
237
|
+
*/
|
|
238
|
+
export declare function writeClientConfig(options: {
|
|
239
|
+
target: ClientTarget;
|
|
240
|
+
entry: Record<string, unknown>;
|
|
241
|
+
dryRun?: boolean;
|
|
242
|
+
fs?: FsLike;
|
|
243
|
+
now?: () => number;
|
|
244
|
+
}): WriteOutcome;
|
|
245
|
+
/** The three things Chrome will not let any installer do for you. */
|
|
246
|
+
export declare function chromeSteps(dir: string): string[];
|
|
247
|
+
/** What `lit setup` says when the extension never paired. */
|
|
248
|
+
export declare function pairingTimeoutMessage(seconds: number): string;
|