@mjquinlan2000/lawmatics-mcp 0.1.4 → 0.1.6
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 +5 -3
- package/dist/auth.js +1 -1
- package/dist/{chunk-MNDMZQAW.js → chunk-226LPP43.js} +83 -25
- package/dist/chunk-226LPP43.js.map +1 -0
- package/dist/{chunk-YU4TVN5Z.js → chunk-VBNUJ5ZR.js} +2 -2
- package/dist/lm.js +2 -2
- package/dist/server.js +119 -85
- package/dist/server.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-MNDMZQAW.js.map +0 -1
- /package/dist/{chunk-YU4TVN5Z.js.map → chunk-VBNUJ5ZR.js.map} +0 -0
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ export LM_REDIRECT_URI=http://127.0.0.1:8081/callback
|
|
|
31
31
|
npx @mjquinlan2000/lawmatics-mcp auth
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
Tokens are saved to `~/.config/lawmatics-mcp/tokens.
|
|
34
|
+
Tokens are saved to `~/.config/lawmatics-mcp/tokens` (encrypted). See [Token Encryption](../README.md#token-encryption) for setup.
|
|
35
35
|
|
|
36
36
|
> **Note:** Lawmatics does not support refresh tokens. When a token expires, you must re-run the `auth` command.
|
|
37
37
|
|
|
@@ -46,7 +46,8 @@ Add to your MCP client config (e.g. Claude Desktop `claude_desktop_config.json`)
|
|
|
46
46
|
"command": "npx",
|
|
47
47
|
"args": ["@mjquinlan2000/lawmatics-mcp"],
|
|
48
48
|
"env": {
|
|
49
|
-
"LM_ACCESS_TOKEN": "your_token"
|
|
49
|
+
"LM_ACCESS_TOKEN": "your_token",
|
|
50
|
+
"NODE_MCP_SECRET_KEY": "your_64_char_hex_key"
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
}
|
|
@@ -123,7 +124,8 @@ For local dev with an MCP client, use `tsx` directly:
|
|
|
123
124
|
"command": "tsx",
|
|
124
125
|
"args": ["/path/to/node-mcps/lawmatics-mcp/src/server.ts"],
|
|
125
126
|
"env": {
|
|
126
|
-
"LM_ACCESS_TOKEN": "your_token"
|
|
127
|
+
"LM_ACCESS_TOKEN": "your_token",
|
|
128
|
+
"NODE_MCP_SECRET_KEY": "your_64_char_hex_key"
|
|
127
129
|
}
|
|
128
130
|
}
|
|
129
131
|
}
|
package/dist/auth.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// ../shared/dist/oauth.js
|
|
2
2
|
import { execSync } from "child_process";
|
|
3
|
-
import { randomBytes } from "crypto";
|
|
4
|
-
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
3
|
+
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
4
|
+
import { mkdir, readFile, unlink, writeFile } from "fs/promises";
|
|
5
5
|
import { createServer } from "http";
|
|
6
6
|
import { homedir } from "os";
|
|
7
7
|
import { join } from "path";
|
|
@@ -10,18 +10,58 @@ function isRefreshable(tokens) {
|
|
|
10
10
|
}
|
|
11
11
|
function createAuth(config) {
|
|
12
12
|
const configDir = join(process.env.MCP_CONFIG_DIR ?? join(homedir(), ".config"), config.name);
|
|
13
|
-
const
|
|
13
|
+
const legacyTokensPath = join(configDir, "tokens.json");
|
|
14
|
+
const encryptedTokensPath = join(configDir, "tokens");
|
|
15
|
+
function getEncryptionKey() {
|
|
16
|
+
const key = process.env.NODE_MCP_SECRET_KEY;
|
|
17
|
+
if (!key) {
|
|
18
|
+
throw new Error("NODE_MCP_SECRET_KEY environment variable is required. Generate one with: openssl rand -hex 32");
|
|
19
|
+
}
|
|
20
|
+
const buf = Buffer.from(key, "hex");
|
|
21
|
+
if (buf.length !== 32) {
|
|
22
|
+
throw new Error("NODE_MCP_SECRET_KEY must be a 64-character hex string (32 bytes). Generate one with: openssl rand -hex 32");
|
|
23
|
+
}
|
|
24
|
+
return buf;
|
|
25
|
+
}
|
|
26
|
+
function encrypt(plaintext) {
|
|
27
|
+
const key = getEncryptionKey();
|
|
28
|
+
const iv = randomBytes(12);
|
|
29
|
+
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
30
|
+
const encrypted = Buffer.concat([
|
|
31
|
+
cipher.update(plaintext, "utf-8"),
|
|
32
|
+
cipher.final()
|
|
33
|
+
]);
|
|
34
|
+
const authTag = cipher.getAuthTag();
|
|
35
|
+
return Buffer.concat([iv, authTag, encrypted]);
|
|
36
|
+
}
|
|
37
|
+
function decrypt(data) {
|
|
38
|
+
const key = getEncryptionKey();
|
|
39
|
+
const iv = data.subarray(0, 12);
|
|
40
|
+
const authTag = data.subarray(12, 28);
|
|
41
|
+
const ciphertext = data.subarray(28);
|
|
42
|
+
const decipher = createDecipheriv("aes-256-gcm", key, iv);
|
|
43
|
+
decipher.setAuthTag(authTag);
|
|
44
|
+
return decipher.update(ciphertext, void 0, "utf-8") + decipher.final("utf-8");
|
|
45
|
+
}
|
|
14
46
|
async function readTokens() {
|
|
15
47
|
try {
|
|
16
|
-
const data = await readFile(
|
|
17
|
-
return JSON.parse(data);
|
|
48
|
+
const data = await readFile(encryptedTokensPath);
|
|
49
|
+
return JSON.parse(decrypt(data));
|
|
18
50
|
} catch {
|
|
19
|
-
|
|
51
|
+
try {
|
|
52
|
+
const data = await readFile(legacyTokensPath, "utf-8");
|
|
53
|
+
const tokens = JSON.parse(data);
|
|
54
|
+
await writeTokens(tokens);
|
|
55
|
+
await unlink(legacyTokensPath);
|
|
56
|
+
return tokens;
|
|
57
|
+
} catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
20
60
|
}
|
|
21
61
|
}
|
|
22
62
|
async function writeTokens(tokens) {
|
|
23
63
|
await mkdir(configDir, { recursive: true });
|
|
24
|
-
await writeFile(
|
|
64
|
+
await writeFile(encryptedTokensPath, encrypt(JSON.stringify(tokens)), {
|
|
25
65
|
mode: 384
|
|
26
66
|
});
|
|
27
67
|
}
|
|
@@ -33,16 +73,25 @@ function createAuth(config) {
|
|
|
33
73
|
}
|
|
34
74
|
}
|
|
35
75
|
async function exchangeCode(code, redirectUri, clientId, clientSecret) {
|
|
76
|
+
const useBasic = config.tokenAuthMethod === "basic";
|
|
77
|
+
const headers = {
|
|
78
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
79
|
+
};
|
|
80
|
+
const bodyParams = {
|
|
81
|
+
grant_type: "authorization_code",
|
|
82
|
+
code,
|
|
83
|
+
redirect_uri: redirectUri
|
|
84
|
+
};
|
|
85
|
+
if (useBasic) {
|
|
86
|
+
headers.Authorization = `Basic ${btoa(`${clientId}:${clientSecret}`)}`;
|
|
87
|
+
} else {
|
|
88
|
+
bodyParams.client_id = clientId;
|
|
89
|
+
bodyParams.client_secret = clientSecret;
|
|
90
|
+
}
|
|
36
91
|
const res = await fetch(config.tokenUrl, {
|
|
37
92
|
method: "POST",
|
|
38
|
-
headers
|
|
39
|
-
body: new URLSearchParams(
|
|
40
|
-
grant_type: "authorization_code",
|
|
41
|
-
code,
|
|
42
|
-
redirect_uri: redirectUri,
|
|
43
|
-
client_id: clientId,
|
|
44
|
-
client_secret: clientSecret
|
|
45
|
-
})
|
|
93
|
+
headers,
|
|
94
|
+
body: new URLSearchParams(bodyParams)
|
|
46
95
|
});
|
|
47
96
|
if (!res.ok) {
|
|
48
97
|
const text = await res.text();
|
|
@@ -60,15 +109,24 @@ function createAuth(config) {
|
|
|
60
109
|
return { access_token: data.access_token };
|
|
61
110
|
}
|
|
62
111
|
async function refreshAccessToken(refreshToken, clientId, clientSecret) {
|
|
112
|
+
const useBasic = config.tokenAuthMethod === "basic";
|
|
113
|
+
const headers = {
|
|
114
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
115
|
+
};
|
|
116
|
+
const bodyParams = {
|
|
117
|
+
grant_type: "refresh_token",
|
|
118
|
+
refresh_token: refreshToken
|
|
119
|
+
};
|
|
120
|
+
if (useBasic) {
|
|
121
|
+
headers.Authorization = `Basic ${btoa(`${clientId}:${clientSecret}`)}`;
|
|
122
|
+
} else {
|
|
123
|
+
bodyParams.client_id = clientId;
|
|
124
|
+
bodyParams.client_secret = clientSecret;
|
|
125
|
+
}
|
|
63
126
|
const res = await fetch(config.tokenUrl, {
|
|
64
127
|
method: "POST",
|
|
65
|
-
headers
|
|
66
|
-
body: new URLSearchParams(
|
|
67
|
-
grant_type: "refresh_token",
|
|
68
|
-
refresh_token: refreshToken,
|
|
69
|
-
client_id: clientId,
|
|
70
|
-
client_secret: clientSecret
|
|
71
|
-
})
|
|
128
|
+
headers,
|
|
129
|
+
body: new URLSearchParams(bodyParams)
|
|
72
130
|
});
|
|
73
131
|
if (!res.ok) {
|
|
74
132
|
throw new Error("Run 'yarn auth' to re-authenticate.");
|
|
@@ -184,7 +242,7 @@ ${authorizeUrl}
|
|
|
184
242
|
});
|
|
185
243
|
});
|
|
186
244
|
await writeTokens(tokens);
|
|
187
|
-
console.log(`Tokens saved to ${
|
|
245
|
+
console.log(`Tokens saved to ${encryptedTokensPath}`);
|
|
188
246
|
}
|
|
189
247
|
async function refresh() {
|
|
190
248
|
const clientId = process.env[`${config.envPrefix}_CLIENT_ID`];
|
|
@@ -199,7 +257,7 @@ ${authorizeUrl}
|
|
|
199
257
|
}
|
|
200
258
|
const refreshed = await refreshAccessToken(tokens.refresh_token, clientId, clientSecret);
|
|
201
259
|
await writeTokens(refreshed);
|
|
202
|
-
console.log(`Tokens refreshed and saved to ${
|
|
260
|
+
console.log(`Tokens refreshed and saved to ${encryptedTokensPath}`);
|
|
203
261
|
}
|
|
204
262
|
function runCli2(command) {
|
|
205
263
|
const cmd = command ?? process.argv[2];
|
|
@@ -233,4 +291,4 @@ export {
|
|
|
233
291
|
getAccessToken,
|
|
234
292
|
runCli
|
|
235
293
|
};
|
|
236
|
-
//# sourceMappingURL=chunk-
|
|
294
|
+
//# sourceMappingURL=chunk-226LPP43.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../shared/src/oauth.ts","../src/auth.ts"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport { createCipheriv, createDecipheriv, randomBytes } from \"node:crypto\";\nimport { mkdir, readFile, unlink, writeFile } from \"node:fs/promises\";\nimport {\n createServer,\n type IncomingMessage,\n type ServerResponse,\n} from \"node:http\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport interface OAuthConfig {\n name: string;\n authorizeUrl: string;\n tokenUrl: string;\n envPrefix: string;\n scope?: string;\n supportsRefresh: boolean;\n tokenAuthMethod?: \"body\" | \"basic\";\n}\n\ninterface BaseTokens {\n access_token: string;\n}\n\ninterface RefreshableTokens extends BaseTokens {\n refresh_token: string;\n expires_at: number;\n}\n\ntype StoredTokens = BaseTokens | RefreshableTokens;\n\nfunction isRefreshable(tokens: StoredTokens): tokens is RefreshableTokens {\n return \"refresh_token\" in tokens;\n}\n\ninterface RefreshableTokenResponse {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n}\n\nexport function createAuth(config: OAuthConfig): {\n getAccessToken: () => Promise<string>;\n runCli: (command?: string) => void;\n} {\n const configDir = join(\n process.env.MCP_CONFIG_DIR ?? join(homedir(), \".config\"),\n config.name,\n );\n const legacyTokensPath = join(configDir, \"tokens.json\");\n const encryptedTokensPath = join(configDir, \"tokens\");\n\n function getEncryptionKey(): Buffer {\n const key = process.env.NODE_MCP_SECRET_KEY;\n if (!key) {\n throw new Error(\n \"NODE_MCP_SECRET_KEY environment variable is required. \" +\n \"Generate one with: openssl rand -hex 32\",\n );\n }\n const buf = Buffer.from(key, \"hex\");\n if (buf.length !== 32) {\n throw new Error(\n \"NODE_MCP_SECRET_KEY must be a 64-character hex string (32 bytes). \" +\n \"Generate one with: openssl rand -hex 32\",\n );\n }\n return buf;\n }\n\n function encrypt(plaintext: string): Buffer {\n const key = getEncryptionKey();\n const iv = randomBytes(12);\n const cipher = createCipheriv(\"aes-256-gcm\", key, iv);\n const encrypted = Buffer.concat([\n cipher.update(plaintext, \"utf-8\"),\n cipher.final(),\n ]);\n const authTag = cipher.getAuthTag();\n return Buffer.concat([iv, authTag, encrypted]);\n }\n\n function decrypt(data: Buffer): string {\n const key = getEncryptionKey();\n const iv = data.subarray(0, 12);\n const authTag = data.subarray(12, 28);\n const ciphertext = data.subarray(28);\n const decipher = createDecipheriv(\"aes-256-gcm\", key, iv);\n decipher.setAuthTag(authTag);\n return (\n decipher.update(ciphertext, undefined, \"utf-8\") + decipher.final(\"utf-8\")\n );\n }\n\n async function readTokens(): Promise<StoredTokens | null> {\n try {\n const data = await readFile(encryptedTokensPath);\n return JSON.parse(decrypt(data)) as StoredTokens;\n } catch {\n // Fall back to legacy plaintext tokens.json\n try {\n const data = await readFile(legacyTokensPath, \"utf-8\");\n const tokens = JSON.parse(data) as StoredTokens;\n await writeTokens(tokens);\n await unlink(legacyTokensPath);\n return tokens;\n } catch {\n return null;\n }\n }\n }\n\n async function writeTokens(tokens: StoredTokens): Promise<void> {\n await mkdir(configDir, { recursive: true });\n await writeFile(encryptedTokensPath, encrypt(JSON.stringify(tokens)), {\n mode: 0o600,\n });\n }\n\n function openBrowser(url: string): void {\n const cmd =\n process.platform === \"darwin\"\n ? \"open\"\n : process.platform === \"win32\"\n ? \"start\"\n : \"xdg-open\";\n try {\n execSync(`${cmd} '${url}'`, { stdio: \"ignore\" });\n } catch {\n // No browser available (e.g. headless server) — URL is already printed to console\n }\n }\n\n async function exchangeCode(\n code: string,\n redirectUri: string,\n clientId: string,\n clientSecret: string,\n ): Promise<StoredTokens> {\n const useBasic = config.tokenAuthMethod === \"basic\";\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n };\n const bodyParams: Record<string, string> = {\n grant_type: \"authorization_code\",\n code,\n redirect_uri: redirectUri,\n };\n if (useBasic) {\n headers.Authorization = `Basic ${btoa(`${clientId}:${clientSecret}`)}`;\n } else {\n bodyParams.client_id = clientId;\n bodyParams.client_secret = clientSecret;\n }\n const res = await fetch(config.tokenUrl, {\n method: \"POST\",\n headers,\n body: new URLSearchParams(bodyParams),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Token exchange failed (${res.status}): ${text}`);\n }\n if (config.supportsRefresh) {\n const data = (await res.json()) as RefreshableTokenResponse;\n return {\n access_token: data.access_token,\n refresh_token: data.refresh_token,\n expires_at: Date.now() + data.expires_in * 1000,\n };\n }\n const data = (await res.json()) as { access_token: string };\n return { access_token: data.access_token };\n }\n\n async function refreshAccessToken(\n refreshToken: string,\n clientId: string,\n clientSecret: string,\n ): Promise<RefreshableTokens> {\n const useBasic = config.tokenAuthMethod === \"basic\";\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n };\n const bodyParams: Record<string, string> = {\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n };\n if (useBasic) {\n headers.Authorization = `Basic ${btoa(`${clientId}:${clientSecret}`)}`;\n } else {\n bodyParams.client_id = clientId;\n bodyParams.client_secret = clientSecret;\n }\n const res = await fetch(config.tokenUrl, {\n method: \"POST\",\n headers,\n body: new URLSearchParams(bodyParams),\n });\n if (!res.ok) {\n throw new Error(\"Run 'yarn auth' to re-authenticate.\");\n }\n const data = (await res.json()) as RefreshableTokenResponse;\n return {\n access_token: data.access_token,\n refresh_token: data.refresh_token,\n expires_at: Date.now() + data.expires_in * 1000,\n };\n }\n\n async function getAccessToken(): Promise<string> {\n const envToken = process.env[`${config.envPrefix}_ACCESS_TOKEN`];\n if (envToken) return envToken;\n\n const tokens = await readTokens();\n if (!tokens) {\n throw new Error(\n `No access token available. Set ${config.envPrefix}_ACCESS_TOKEN or run 'yarn auth'.`,\n );\n }\n\n if (config.supportsRefresh && isRefreshable(tokens)) {\n const fiveMinutes = 5 * 60 * 1000;\n if (tokens.expires_at - Date.now() < fiveMinutes) {\n const clientId = process.env[`${config.envPrefix}_CLIENT_ID`];\n const clientSecret = process.env[`${config.envPrefix}_CLIENT_SECRET`];\n if (!clientId || !clientSecret) {\n throw new Error(\n `Token is expiring and ${config.envPrefix}_CLIENT_ID/${config.envPrefix}_CLIENT_SECRET are not set for refresh. Run 'yarn auth'.`,\n );\n }\n const refreshed = await refreshAccessToken(\n tokens.refresh_token,\n clientId,\n clientSecret,\n );\n await writeTokens(refreshed);\n return refreshed.access_token;\n }\n }\n\n return tokens.access_token;\n }\n\n async function authorize(): Promise<void> {\n const clientId = process.env[`${config.envPrefix}_CLIENT_ID`];\n const clientSecret = process.env[`${config.envPrefix}_CLIENT_SECRET`];\n if (!clientId)\n throw new Error(\n `${config.envPrefix}_CLIENT_ID environment variable is required.`,\n );\n if (!clientSecret)\n throw new Error(\n `${config.envPrefix}_CLIENT_SECRET environment variable is required.`,\n );\n\n const redirectUri = process.env[`${config.envPrefix}_REDIRECT_URI`];\n if (!redirectUri)\n throw new Error(\n `${config.envPrefix}_REDIRECT_URI environment variable is required.`,\n );\n\n const redirectUrl = new URL(redirectUri);\n const port =\n Number(redirectUrl.port) ||\n (redirectUrl.protocol === \"https:\" ? 443 : 80);\n const callbackPath = redirectUrl.pathname;\n const state = randomBytes(16).toString(\"hex\");\n\n const { tokens } = await new Promise<{\n tokens: StoredTokens;\n }>((resolve, reject) => {\n const timeout = setTimeout(() => {\n server.close();\n reject(new Error(\"Authorization timed out after 120 seconds.\"));\n }, 120_000);\n\n const server = createServer(\n async (req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url ?? \"/\", `http://${req.headers.host}`);\n if (url.pathname !== callbackPath) {\n res.writeHead(404);\n res.end(\"Not found\");\n return;\n }\n\n const returnedState = url.searchParams.get(\"state\");\n const code = url.searchParams.get(\"code\");\n const error = url.searchParams.get(\"error\");\n\n if (error) {\n res.writeHead(400);\n res.end(`Authorization error: ${error}`);\n clearTimeout(timeout);\n server.close();\n reject(new Error(`Authorization denied: ${error}`));\n return;\n }\n\n if (returnedState !== state) {\n res.writeHead(400);\n res.end(\"State mismatch — possible CSRF attack.\");\n return;\n }\n\n if (!code) {\n res.writeHead(400);\n res.end(\"Missing authorization code.\");\n return;\n }\n\n try {\n const exchangedTokens = await exchangeCode(\n code,\n redirectUri,\n clientId,\n clientSecret,\n );\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(\n \"<h1>Authorization successful!</h1><p>You can close this tab.</p>\",\n );\n clearTimeout(timeout);\n server.close();\n resolve({ tokens: exchangedTokens });\n } catch (err) {\n res.writeHead(500);\n res.end(\"Token exchange failed.\");\n clearTimeout(timeout);\n server.close();\n reject(err);\n }\n },\n );\n\n const params: Record<string, string> = {\n response_type: \"code\",\n client_id: clientId,\n redirect_uri: redirectUri,\n state,\n };\n if (config.scope) {\n params.scope = config.scope;\n }\n\n server.listen(port, \"127.0.0.1\", () => {\n const authorizeUrl = `${config.authorizeUrl}?${new URLSearchParams(params)}`;\n\n console.log(\"Opening browser for authorization...\");\n console.log(`If the browser doesn't open, visit:\\n${authorizeUrl}\\n`);\n openBrowser(authorizeUrl);\n });\n });\n\n await writeTokens(tokens);\n console.log(`Tokens saved to ${encryptedTokensPath}`);\n }\n\n async function refresh(): Promise<void> {\n const clientId = process.env[`${config.envPrefix}_CLIENT_ID`];\n const clientSecret = process.env[`${config.envPrefix}_CLIENT_SECRET`];\n if (!clientId)\n throw new Error(\n `${config.envPrefix}_CLIENT_ID environment variable is required.`,\n );\n if (!clientSecret)\n throw new Error(\n `${config.envPrefix}_CLIENT_SECRET environment variable is required.`,\n );\n\n const tokens = await readTokens();\n if (!tokens || !isRefreshable(tokens)) {\n throw new Error(\n \"No tokens found. Run 'yarn auth' first to authenticate.\",\n );\n }\n\n const refreshed = await refreshAccessToken(\n tokens.refresh_token,\n clientId,\n clientSecret,\n );\n await writeTokens(refreshed);\n console.log(`Tokens refreshed and saved to ${encryptedTokensPath}`);\n }\n\n function runCli(command?: string): void {\n const cmd = command ?? process.argv[2];\n let run: () => Promise<void>;\n if (cmd === \"refresh\" && config.supportsRefresh) {\n run = refresh;\n } else {\n run = authorize;\n }\n run().catch((err) => {\n console.error(err.message ?? err);\n process.exit(1);\n });\n }\n\n return { getAccessToken, runCli };\n}\n","import { createAuth } from \"@mjquinlan2000/shared/oauth.js\";\n\nconst { getAccessToken, runCli } = createAuth({\n name: \"lawmatics-mcp\",\n authorizeUrl: \"https://app.lawmatics.com/oauth/authorize\",\n tokenUrl: \"https://api.lawmatics.com/oauth/token\",\n envPrefix: \"LM\",\n supportsRefresh: false,\n});\n\nexport { getAccessToken, runCli };\n\nif (process.argv[1] && import.meta.filename === process.argv[1]) {\n runCli();\n}\n"],"mappings":"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","names":["data","getAccessToken","runCli"]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getAccessToken
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-226LPP43.js";
|
|
4
4
|
|
|
5
5
|
// src/client/core/bodySerializer.gen.ts
|
|
6
6
|
var jsonBodySerializer = {
|
|
@@ -816,4 +816,4 @@ client.setConfig({
|
|
|
816
816
|
export {
|
|
817
817
|
client
|
|
818
818
|
};
|
|
819
|
-
//# sourceMappingURL=chunk-
|
|
819
|
+
//# sourceMappingURL=chunk-VBNUJ5ZR.js.map
|
package/dist/lm.js
CHANGED
package/dist/server.js
CHANGED
|
@@ -1,15 +1,104 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
client
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import "./chunk-
|
|
4
|
+
} from "./chunk-VBNUJ5ZR.js";
|
|
5
|
+
import "./chunk-226LPP43.js";
|
|
6
6
|
|
|
7
7
|
// src/server.ts
|
|
8
8
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
9
9
|
|
|
10
|
+
// ../shared/dist/helpers.js
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
function cleanQuery(q) {
|
|
13
|
+
return Object.fromEntries(Object.entries(q).filter(([, v]) => v !== void 0));
|
|
14
|
+
}
|
|
15
|
+
function err(e) {
|
|
16
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
17
|
+
return {
|
|
18
|
+
content: [{ type: "text", text: `Error: ${msg}` }],
|
|
19
|
+
isError: true
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// ../shared/dist/tool-handler.js
|
|
24
|
+
var commonListQueryParams = {
|
|
25
|
+
page: { description: "Page number for pagination (default: 1)" },
|
|
26
|
+
sort_order: { description: "Sort order: asc or desc (default: desc)" },
|
|
27
|
+
sort_by: {
|
|
28
|
+
description: "Field to sort by (e.g. id, created_at, updated_at)"
|
|
29
|
+
},
|
|
30
|
+
filter_by: { description: "Field name to filter on" },
|
|
31
|
+
filter_on: { description: "Value to filter for" },
|
|
32
|
+
filter_with: {
|
|
33
|
+
description: "Filter operator: =, !=, <=, <, >=, >, like, ilike, null, not_null"
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
function isZodType(v) {
|
|
37
|
+
return typeof v.parse === "function";
|
|
38
|
+
}
|
|
39
|
+
function getEffectiveQueryParams(tool) {
|
|
40
|
+
if (tool.commonListQueryParams && tool.name.startsWith("list_")) {
|
|
41
|
+
return { ...tool.commonListQueryParams, ...tool.queryParams };
|
|
42
|
+
}
|
|
43
|
+
return tool.queryParams;
|
|
44
|
+
}
|
|
45
|
+
function createToolHandler(tool) {
|
|
46
|
+
const effectiveQueryParams = getEffectiveQueryParams(tool);
|
|
47
|
+
return async (params) => {
|
|
48
|
+
try {
|
|
49
|
+
const options = {};
|
|
50
|
+
if (tool.pathParams) {
|
|
51
|
+
const path = {};
|
|
52
|
+
for (const [mcpName, spec] of Object.entries(tool.pathParams)) {
|
|
53
|
+
const sdkName = typeof spec === "string" ? mcpName : spec.sdkName;
|
|
54
|
+
path[sdkName] = params[mcpName];
|
|
55
|
+
}
|
|
56
|
+
options.path = path;
|
|
57
|
+
}
|
|
58
|
+
const query = {
|
|
59
|
+
...tool.defaultQuery ?? {}
|
|
60
|
+
};
|
|
61
|
+
if (effectiveQueryParams) {
|
|
62
|
+
for (const paramName of Object.keys(effectiveQueryParams)) {
|
|
63
|
+
if (params[paramName] !== void 0) {
|
|
64
|
+
query[paramName] = params[paramName];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const hasQueryEntries = Object.keys(query).length > 0;
|
|
69
|
+
if (hasQueryEntries) {
|
|
70
|
+
options.query = cleanQuery(query);
|
|
71
|
+
}
|
|
72
|
+
const res = await tool.sdkFn(Object.keys(options).length > 0 ? options : void 0);
|
|
73
|
+
if (tool.rawContent) {
|
|
74
|
+
return {
|
|
75
|
+
content: [
|
|
76
|
+
{
|
|
77
|
+
type: "text",
|
|
78
|
+
text: JSON.stringify(res.data, null, 2)
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const structured = tool.isList ? { items: res.data } : res.data;
|
|
84
|
+
return {
|
|
85
|
+
content: [
|
|
86
|
+
{
|
|
87
|
+
type: "text",
|
|
88
|
+
text: JSON.stringify(structured, null, 2)
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
structuredContent: tool.schema ? structured : void 0
|
|
92
|
+
};
|
|
93
|
+
} catch (e) {
|
|
94
|
+
return err(e);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
10
99
|
// src/create-server.ts
|
|
11
100
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
12
|
-
import { z } from "zod";
|
|
101
|
+
import { z as z2 } from "zod";
|
|
13
102
|
|
|
14
103
|
// src/client/sdk.gen.ts
|
|
15
104
|
var getV1Prospects = (options) => (options?.client ?? client).get({
|
|
@@ -443,73 +532,6 @@ var getV1UsersMe = (options) => (options?.client ?? client).get({
|
|
|
443
532
|
...options
|
|
444
533
|
});
|
|
445
534
|
|
|
446
|
-
// src/helpers.ts
|
|
447
|
-
function cleanQuery(q) {
|
|
448
|
-
return Object.fromEntries(
|
|
449
|
-
Object.entries(q).filter(([, v]) => v !== void 0)
|
|
450
|
-
);
|
|
451
|
-
}
|
|
452
|
-
function err(e) {
|
|
453
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
454
|
-
return {
|
|
455
|
-
content: [{ type: "text", text: `Error: ${msg}` }],
|
|
456
|
-
isError: true
|
|
457
|
-
};
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
// src/tool-handler.ts
|
|
461
|
-
var commonListQueryParams = {
|
|
462
|
-
page: { description: "Page number for pagination (default: 1)" },
|
|
463
|
-
sort_order: { description: "Sort order: asc or desc (default: desc)" },
|
|
464
|
-
sort_by: {
|
|
465
|
-
description: "Field to sort by (e.g. id, created_at, updated_at)"
|
|
466
|
-
},
|
|
467
|
-
filter_by: { description: "Field name to filter on" },
|
|
468
|
-
filter_on: { description: "Value to filter for" },
|
|
469
|
-
filter_with: {
|
|
470
|
-
description: "Filter operator: =, !=, <=, <, >=, >, like, ilike, null, not_null"
|
|
471
|
-
}
|
|
472
|
-
};
|
|
473
|
-
function getEffectiveQueryParams(tool) {
|
|
474
|
-
return tool.name.startsWith("list_") ? { ...commonListQueryParams, ...tool.queryParams } : tool.queryParams;
|
|
475
|
-
}
|
|
476
|
-
function createToolHandler(tool, effectiveQueryParams) {
|
|
477
|
-
return async (params) => {
|
|
478
|
-
try {
|
|
479
|
-
const options = {};
|
|
480
|
-
if (tool.pathParams) {
|
|
481
|
-
const path = {};
|
|
482
|
-
for (const [mcpName, { sdkName }] of Object.entries(tool.pathParams)) {
|
|
483
|
-
path[sdkName] = params[mcpName];
|
|
484
|
-
}
|
|
485
|
-
options.path = path;
|
|
486
|
-
}
|
|
487
|
-
const query = { fields: "all" };
|
|
488
|
-
if (effectiveQueryParams) {
|
|
489
|
-
for (const paramName of Object.keys(effectiveQueryParams)) {
|
|
490
|
-
if (params[paramName] !== void 0) {
|
|
491
|
-
query[paramName] = params[paramName];
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
options.query = cleanQuery(query);
|
|
496
|
-
const res = await tool.sdkFn(
|
|
497
|
-
Object.keys(options).length > 0 ? options : void 0
|
|
498
|
-
);
|
|
499
|
-
return {
|
|
500
|
-
content: [
|
|
501
|
-
{
|
|
502
|
-
type: "text",
|
|
503
|
-
text: JSON.stringify(res.data, null, 2)
|
|
504
|
-
}
|
|
505
|
-
]
|
|
506
|
-
};
|
|
507
|
-
} catch (e) {
|
|
508
|
-
return err(e);
|
|
509
|
-
}
|
|
510
|
-
};
|
|
511
|
-
}
|
|
512
|
-
|
|
513
535
|
// src/create-server.ts
|
|
514
536
|
function createServer() {
|
|
515
537
|
const server = new McpServer(
|
|
@@ -527,6 +549,10 @@ function createServer() {
|
|
|
527
549
|
].join(" ")
|
|
528
550
|
}
|
|
529
551
|
);
|
|
552
|
+
const lmDefaults = {
|
|
553
|
+
defaultQuery: { fields: "all" },
|
|
554
|
+
commonListQueryParams
|
|
555
|
+
};
|
|
530
556
|
const tools = [
|
|
531
557
|
// ── Prospects ──
|
|
532
558
|
{
|
|
@@ -586,7 +612,9 @@ function createServer() {
|
|
|
586
612
|
name: "get_contact",
|
|
587
613
|
description: "Get a single contact by ID.",
|
|
588
614
|
sdkFn: getV1ContactsByContactId,
|
|
589
|
-
pathParams: {
|
|
615
|
+
pathParams: {
|
|
616
|
+
id: { sdkName: "contact_id", description: "Contact ID" }
|
|
617
|
+
}
|
|
590
618
|
},
|
|
591
619
|
{
|
|
592
620
|
name: "find_contact_by_phone",
|
|
@@ -628,7 +656,9 @@ function createServer() {
|
|
|
628
656
|
name: "get_company",
|
|
629
657
|
description: "Get a single company by ID.",
|
|
630
658
|
sdkFn: getV1CompaniesByCompanyId,
|
|
631
|
-
pathParams: {
|
|
659
|
+
pathParams: {
|
|
660
|
+
id: { sdkName: "company_id", description: "Company ID" }
|
|
661
|
+
}
|
|
632
662
|
},
|
|
633
663
|
{
|
|
634
664
|
name: "find_company_by_phone",
|
|
@@ -670,7 +700,9 @@ function createServer() {
|
|
|
670
700
|
name: "get_address",
|
|
671
701
|
description: "Get a single address by ID.",
|
|
672
702
|
sdkFn: getV1AddressesByAddressId,
|
|
673
|
-
pathParams: {
|
|
703
|
+
pathParams: {
|
|
704
|
+
id: { sdkName: "address_id", description: "Address ID" }
|
|
705
|
+
}
|
|
674
706
|
},
|
|
675
707
|
// ── Email Addresses ──
|
|
676
708
|
{
|
|
@@ -1071,7 +1103,9 @@ function createServer() {
|
|
|
1071
1103
|
name: "get_invoice",
|
|
1072
1104
|
description: "Get a single invoice by ID.",
|
|
1073
1105
|
sdkFn: getV1InvoicesByInvoiceId,
|
|
1074
|
-
pathParams: {
|
|
1106
|
+
pathParams: {
|
|
1107
|
+
id: { sdkName: "invoice_id", description: "Invoice ID" }
|
|
1108
|
+
}
|
|
1075
1109
|
},
|
|
1076
1110
|
// ── Expenses ──
|
|
1077
1111
|
{
|
|
@@ -1083,7 +1117,9 @@ function createServer() {
|
|
|
1083
1117
|
name: "get_expense",
|
|
1084
1118
|
description: "Get a single expense by ID.",
|
|
1085
1119
|
sdkFn: getV1ExpensesByExpenseId,
|
|
1086
|
-
pathParams: {
|
|
1120
|
+
pathParams: {
|
|
1121
|
+
id: { sdkName: "expense_id", description: "Expense ID" }
|
|
1122
|
+
}
|
|
1087
1123
|
},
|
|
1088
1124
|
// ── Time Entries ──
|
|
1089
1125
|
{
|
|
@@ -1150,22 +1186,20 @@ function createServer() {
|
|
|
1150
1186
|
description: "Get the currently authenticated user.",
|
|
1151
1187
|
sdkFn: getV1UsersMe
|
|
1152
1188
|
}
|
|
1153
|
-
];
|
|
1189
|
+
].map((t) => ({ ...lmDefaults, ...t }));
|
|
1154
1190
|
for (const tool of tools) {
|
|
1155
1191
|
const effectiveQueryParams = getEffectiveQueryParams(tool);
|
|
1156
1192
|
const inputSchema = {};
|
|
1157
1193
|
if (tool.pathParams) {
|
|
1158
|
-
for (const [paramName,
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
inputSchema[paramName] = z.string().describe(description);
|
|
1194
|
+
for (const [paramName, spec] of Object.entries(tool.pathParams)) {
|
|
1195
|
+
const description = typeof spec === "string" ? spec : spec.description;
|
|
1196
|
+
inputSchema[paramName] = z2.string().describe(description);
|
|
1162
1197
|
}
|
|
1163
1198
|
}
|
|
1164
1199
|
if (effectiveQueryParams) {
|
|
1165
|
-
for (const [paramName,
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
inputSchema[paramName] = z.string().optional().describe(description);
|
|
1200
|
+
for (const [paramName, spec] of Object.entries(effectiveQueryParams)) {
|
|
1201
|
+
const description = isZodType(spec) ? "" : spec.description;
|
|
1202
|
+
inputSchema[paramName] = z2.string().optional().describe(description);
|
|
1169
1203
|
}
|
|
1170
1204
|
}
|
|
1171
1205
|
server.registerTool(
|
|
@@ -1174,7 +1208,7 @@ function createServer() {
|
|
|
1174
1208
|
description: tool.description,
|
|
1175
1209
|
inputSchema: Object.keys(inputSchema).length > 0 ? inputSchema : void 0
|
|
1176
1210
|
},
|
|
1177
|
-
createToolHandler(tool
|
|
1211
|
+
createToolHandler(tool)
|
|
1178
1212
|
);
|
|
1179
1213
|
}
|
|
1180
1214
|
return server;
|