@better-i18n/mcp 0.19.1 → 0.21.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/http.js +0 -0
- package/dist/index.d.ts +25 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +203 -25
- package/dist/index.js.map +1 -1
- package/dist/oauth-provider.d.ts +39 -0
- package/dist/oauth-provider.d.ts.map +1 -0
- package/dist/oauth-provider.js +123 -0
- package/dist/oauth-provider.js.map +1 -0
- package/package.json +1 -1
package/dist/http.js
CHANGED
|
File without changes
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* @better-i18n/mcp — stdio MCP server for Claude Code / Cursor / Codex.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* directly from IDEs like Cursor.
|
|
5
|
+
* Bridges an MCP client (stdio) to Better i18n's remote MCP endpoint
|
|
6
|
+
* (Streamable HTTP at https://mcp.better-i18n.com/mcp).
|
|
8
7
|
*
|
|
9
|
-
*
|
|
8
|
+
* Two auth modes:
|
|
9
|
+
* - OAuth (default): no key needed. First run opens your browser to
|
|
10
|
+
* sign in to Better i18n; tokens are cached in ~/.better-i18n and
|
|
11
|
+
* refreshed automatically on later runs.
|
|
12
|
+
* - API key: set BETTER_I18N_API_KEY=bi-… for headless tools (CI, scripts).
|
|
13
|
+
*
|
|
14
|
+
* The tool catalog is forwarded from the server — never hard-coded here,
|
|
15
|
+
* so new tools ship on an API deploy without an npm release.
|
|
16
|
+
*
|
|
17
|
+
* Config:
|
|
18
|
+
* {
|
|
19
|
+
* "mcpServers": {
|
|
20
|
+
* "better-i18n": { "command": "npx", "args": ["-y", "@better-i18n/mcp@latest"] }
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* Env / flags:
|
|
25
|
+
* --local / BETTER_I18N_LOCAL → http://localhost:8788
|
|
26
|
+
* BETTER_I18N_MCP_URL → explicit MCP endpoint host override
|
|
27
|
+
* BETTER_I18N_API_KEY → use API-key auth instead of OAuth
|
|
28
|
+
* --debug / BETTER_I18N_DEBUG → verbose stderr logging
|
|
29
|
+
* BETTER_I18N_OAUTH_PORT → loopback callback port (default 8976)
|
|
10
30
|
*/
|
|
11
31
|
export {};
|
|
12
32
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG"}
|
package/dist/index.js
CHANGED
|
@@ -1,43 +1,221 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* @better-i18n/mcp — stdio MCP server for Claude Code / Cursor / Codex.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* directly from IDEs like Cursor.
|
|
5
|
+
* Bridges an MCP client (stdio) to Better i18n's remote MCP endpoint
|
|
6
|
+
* (Streamable HTTP at https://mcp.better-i18n.com/mcp).
|
|
8
7
|
*
|
|
9
|
-
*
|
|
8
|
+
* Two auth modes:
|
|
9
|
+
* - OAuth (default): no key needed. First run opens your browser to
|
|
10
|
+
* sign in to Better i18n; tokens are cached in ~/.better-i18n and
|
|
11
|
+
* refreshed automatically on later runs.
|
|
12
|
+
* - API key: set BETTER_I18N_API_KEY=bi-… for headless tools (CI, scripts).
|
|
13
|
+
*
|
|
14
|
+
* The tool catalog is forwarded from the server — never hard-coded here,
|
|
15
|
+
* so new tools ship on an API deploy without an npm release.
|
|
16
|
+
*
|
|
17
|
+
* Config:
|
|
18
|
+
* {
|
|
19
|
+
* "mcpServers": {
|
|
20
|
+
* "better-i18n": { "command": "npx", "args": ["-y", "@better-i18n/mcp@latest"] }
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* Env / flags:
|
|
25
|
+
* --local / BETTER_I18N_LOCAL → http://localhost:8788
|
|
26
|
+
* BETTER_I18N_MCP_URL → explicit MCP endpoint host override
|
|
27
|
+
* BETTER_I18N_API_KEY → use API-key auth instead of OAuth
|
|
28
|
+
* --debug / BETTER_I18N_DEBUG → verbose stderr logging
|
|
29
|
+
* BETTER_I18N_OAUTH_PORT → loopback callback port (default 8976)
|
|
10
30
|
*/
|
|
11
31
|
import { createRequire } from "node:module";
|
|
32
|
+
import { createServer } from "node:http";
|
|
33
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
34
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
35
|
+
import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
36
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
12
37
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
13
|
-
import {
|
|
38
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
39
|
+
import { NodeOAuthProvider } from "./oauth-provider.js";
|
|
14
40
|
const require = createRequire(import.meta.url);
|
|
15
41
|
const pkg = require("../package.json");
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
process.
|
|
42
|
+
const VERSION = pkg.version;
|
|
43
|
+
const LOCAL_MCP_URL = "http://localhost:8788";
|
|
44
|
+
const PROD_MCP_URL = "https://mcp.better-i18n.com";
|
|
45
|
+
const DEFAULT_OAUTH_PORT = 8976;
|
|
46
|
+
function resolveConfig() {
|
|
47
|
+
const argv = process.argv.slice(2);
|
|
48
|
+
const local = argv.includes("--local") ||
|
|
49
|
+
process.env.BETTER_I18N_LOCAL === "true" ||
|
|
50
|
+
process.env.BETTER_I18N_LOCAL === "1";
|
|
51
|
+
const mcpUrl = process.env.BETTER_I18N_MCP_URL || (local ? LOCAL_MCP_URL : PROD_MCP_URL);
|
|
52
|
+
const apiKey = process.env.BETTER_I18N_API_KEY;
|
|
53
|
+
const debug = process.env.BETTER_I18N_DEBUG === "true" || argv.includes("--debug");
|
|
54
|
+
const oauthPort = Number(process.env.BETTER_I18N_OAUTH_PORT) || DEFAULT_OAUTH_PORT;
|
|
55
|
+
return { mcpUrl, apiKey, debug, local, oauthPort };
|
|
56
|
+
}
|
|
57
|
+
function log(debug, ...args) {
|
|
58
|
+
if (debug)
|
|
59
|
+
console.error("[better-i18n-mcp]", ...args);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Branded HTML for the OAuth loopback redirect — Better i18n login screen:
|
|
63
|
+
* single logo, status card, light/dark aware.
|
|
64
|
+
*/
|
|
65
|
+
function renderCallbackPage(status, detail) {
|
|
66
|
+
const isSuccess = status === "success";
|
|
67
|
+
return `<!DOCTYPE html>
|
|
68
|
+
<html lang="en">
|
|
69
|
+
<head>
|
|
70
|
+
<meta charset="utf-8" />
|
|
71
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
72
|
+
<title>Better i18n MCP</title>
|
|
73
|
+
<style>
|
|
74
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
75
|
+
body { font-family: system-ui, -apple-system, sans-serif; min-height: 100vh; display: flex; align-items: center; justify-content: center; background: #fafafa; color: #111; }
|
|
76
|
+
@media (prefers-color-scheme: dark) { body { background: #0a0a0a; color: #fafafa; } }
|
|
77
|
+
.page { width: 480px; max-width: 100%; padding: 0 16px; text-align: center; }
|
|
78
|
+
.logos { display: flex; align-items: center; justify-content: center; margin-bottom: 20px; }
|
|
79
|
+
.logo-circle { width: 64px; height: 64px; border-radius: 50%; border: 1px solid #e5e5e5; background: #fff; display: flex; align-items: center; justify-content: center; }
|
|
80
|
+
@media (prefers-color-scheme: dark) { .logo-circle { border-color: #262626; background: #171717; } }
|
|
81
|
+
h1 { font-size: 22px; font-weight: 600; margin-bottom: 24px; }
|
|
82
|
+
.card { overflow: hidden; border-radius: 12px; border: 1px solid #e5e5e5; background: #fff; text-align: center; }
|
|
83
|
+
@media (prefers-color-scheme: dark) { .card { border-color: #262626; background: #171717; } }
|
|
84
|
+
.card-body { padding: 28px 24px; }
|
|
85
|
+
.icon-wrap { width: 48px; height: 48px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 16px; }
|
|
86
|
+
.icon-success { background: #ecfdf5; color: #059669; }
|
|
87
|
+
@media (prefers-color-scheme: dark) { .icon-success { background: rgba(16,185,129,0.12); color: #34d399; } }
|
|
88
|
+
.icon-error { background: #fef2f2; color: #dc2626; }
|
|
89
|
+
@media (prefers-color-scheme: dark) { .icon-error { background: rgba(220,38,38,0.12); color: #f87171; } }
|
|
90
|
+
.title { font-size: 15px; font-weight: 600; margin-bottom: 6px; }
|
|
91
|
+
.desc { font-size: 13px; color: #6b7280; line-height: 1.5; }
|
|
92
|
+
@media (prefers-color-scheme: dark) { .desc { color: #9ca3af; } }
|
|
93
|
+
.footer { padding: 0 24px 20px; text-align: center; font-size: 12px; color: #9ca3af; }
|
|
94
|
+
@media (prefers-color-scheme: dark) { .footer { color: #6b7280; } }
|
|
95
|
+
</style>
|
|
96
|
+
</head>
|
|
97
|
+
<body>
|
|
98
|
+
<div class="page">
|
|
99
|
+
<div class="logos">
|
|
100
|
+
<div class="logo-circle">
|
|
101
|
+
<svg width="30" height="30" viewBox="0 0 42 42" fill="none"><path fill-rule="evenodd" clip-rule="evenodd" d="M28.7 0H12.8L0 12.8V28.7L12.8 41.5H28.7L41.5 28.7V12.8L28.7 0ZM15 28.9L6.80002 20.7L15 12.5C18.1 9.4 23.2 9.4 26.3 12.5L34.5 20.7L26.3 28.9C23.2 32 18.2 32 15 28.9Z" fill="currentColor"/></svg>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<h1>${isSuccess ? "Better i18n connected" : "Connection failed"}</h1>
|
|
106
|
+
|
|
107
|
+
<div class="card">
|
|
108
|
+
<div class="card-body">
|
|
109
|
+
<div class="icon-wrap ${isSuccess ? "icon-success" : "icon-error"}">
|
|
110
|
+
${isSuccess
|
|
111
|
+
? '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>'
|
|
112
|
+
: '<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>'}
|
|
113
|
+
</div>
|
|
114
|
+
<p class="title">${isSuccess ? "You're all set" : "Something went wrong"}</p>
|
|
115
|
+
<p class="desc">${isSuccess ? "You can close this tab and return to your editor." : detail || "No authorization code was received. Please try connecting again."}</p>
|
|
116
|
+
</div>
|
|
117
|
+
<p class="footer">${isSuccess ? "Your AI client is now connected to Better i18n." : "If this keeps happening, check that you're signed in to Better i18n."}</p>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</body>
|
|
121
|
+
</html>`;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Wait for the OAuth provider's loopback redirect, resolving with the
|
|
125
|
+
* authorization code. Runs a one-shot HTTP server on the callback port.
|
|
126
|
+
*/
|
|
127
|
+
function waitForAuthCode(port) {
|
|
128
|
+
let resolveCode;
|
|
129
|
+
let rejectCode;
|
|
130
|
+
const promise = new Promise((res, rej) => {
|
|
131
|
+
resolveCode = res;
|
|
132
|
+
rejectCode = rej;
|
|
133
|
+
});
|
|
134
|
+
const server = createServer((req, res) => {
|
|
135
|
+
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
136
|
+
if (url.pathname !== "/callback") {
|
|
137
|
+
res.writeHead(404).end();
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const code = url.searchParams.get("code");
|
|
141
|
+
const error = url.searchParams.get("error");
|
|
142
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
143
|
+
if (code) {
|
|
144
|
+
res.end(renderCallbackPage("success"));
|
|
145
|
+
resolveCode(code);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
res.end(renderCallbackPage("error", error ?? undefined));
|
|
149
|
+
rejectCode(new Error(error ?? "Authorization failed"));
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
server.listen(port);
|
|
153
|
+
return { promise, close: () => server.close() };
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Connect an SDK Client to the remote MCP endpoint, performing the OAuth
|
|
157
|
+
* dance interactively if needed. Returns the connected client.
|
|
158
|
+
*/
|
|
159
|
+
async function connectRemote(cfg) {
|
|
160
|
+
const url = new URL(`${cfg.mcpUrl}/mcp`);
|
|
161
|
+
const client = new Client({ name: "better-i18n-bridge", version: VERSION }, { capabilities: {} });
|
|
162
|
+
// API-key mode: simple bearer header, no OAuth.
|
|
163
|
+
if (cfg.apiKey) {
|
|
164
|
+
const transport = new StreamableHTTPClientTransport(url, {
|
|
165
|
+
requestInit: { headers: { Authorization: `Bearer ${cfg.apiKey}` } },
|
|
166
|
+
});
|
|
167
|
+
await client.connect(transport);
|
|
168
|
+
log(cfg.debug, `connected to ${cfg.mcpUrl}${cfg.local ? " (local)" : ""} via API key`);
|
|
169
|
+
return client;
|
|
170
|
+
}
|
|
171
|
+
// OAuth mode: cached tokens → connect; otherwise interactive consent.
|
|
172
|
+
const redirectUrl = `http://localhost:${cfg.oauthPort}/callback`;
|
|
173
|
+
const authProvider = new NodeOAuthProvider({ mcpUrl: cfg.mcpUrl, redirectUrl });
|
|
174
|
+
const makeTransport = () => new StreamableHTTPClientTransport(url, { authProvider });
|
|
175
|
+
try {
|
|
176
|
+
await client.connect(makeTransport());
|
|
177
|
+
log(cfg.debug, `connected to ${cfg.mcpUrl}${cfg.local ? " (local)" : ""} via cached OAuth token`);
|
|
178
|
+
return client;
|
|
24
179
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
180
|
+
catch (err) {
|
|
181
|
+
if (!(err instanceof UnauthorizedError))
|
|
182
|
+
throw err;
|
|
183
|
+
}
|
|
184
|
+
// Interactive: provider already opened the browser via redirectToAuthorization
|
|
185
|
+
// during the failed connect. Catch the loopback redirect, finish auth, reconnect.
|
|
186
|
+
const callback = waitForAuthCode(cfg.oauthPort);
|
|
187
|
+
let code;
|
|
188
|
+
try {
|
|
189
|
+
code = await callback.promise;
|
|
190
|
+
}
|
|
191
|
+
finally {
|
|
192
|
+
callback.close();
|
|
193
|
+
}
|
|
194
|
+
const transport = makeTransport();
|
|
195
|
+
await transport.finishAuth(code);
|
|
196
|
+
await client.connect(transport);
|
|
197
|
+
log(cfg.debug, `connected to ${cfg.mcpUrl}${cfg.local ? " (local)" : ""} via OAuth (fresh login)`);
|
|
198
|
+
return client;
|
|
199
|
+
}
|
|
200
|
+
async function main() {
|
|
201
|
+
const cfg = resolveConfig();
|
|
202
|
+
const remote = await connectRemote(cfg);
|
|
203
|
+
const server = new Server({ name: "better-i18n", version: VERSION }, { capabilities: { tools: {} } });
|
|
204
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
205
|
+
return await remote.listTools();
|
|
29
206
|
});
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
207
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
208
|
+
return (await remote.callTool({
|
|
209
|
+
name: request.params.name,
|
|
210
|
+
arguments: request.params.arguments,
|
|
211
|
+
}));
|
|
33
212
|
});
|
|
34
|
-
console.error("[better-i18n] MCP Server ready");
|
|
35
213
|
const transport = new StdioServerTransport();
|
|
36
214
|
await server.connect(transport);
|
|
37
|
-
|
|
215
|
+
log(cfg.debug, `bridge ready (v${VERSION})`);
|
|
38
216
|
}
|
|
39
|
-
main().catch((
|
|
40
|
-
console.error("[better-i18n]
|
|
217
|
+
main().catch((err) => {
|
|
218
|
+
console.error("[better-i18n-mcp] fatal:", err instanceof Error ? err.message : err);
|
|
41
219
|
process.exit(1);
|
|
42
220
|
});
|
|
43
221
|
//# 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":";AAEA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node OAuth client provider for the Better i18n MCP stdio bridge.
|
|
3
|
+
*
|
|
4
|
+
* Implements the SDK's OAuthClientProvider so the bridge can authenticate
|
|
5
|
+
* via the browser consent flow instead of a pasted API key. State that
|
|
6
|
+
* must survive across runs (dynamic client registration, tokens, PKCE
|
|
7
|
+
* verifier) is persisted to ~/.better-i18n/, keyed by the MCP host so a
|
|
8
|
+
* user can run against prod and local without clobbering credentials.
|
|
9
|
+
*
|
|
10
|
+
* No npm deps — pure Node built-ins. Browser is opened via the platform
|
|
11
|
+
* opener; the redirect lands on a local loopback server (see index.ts).
|
|
12
|
+
*/
|
|
13
|
+
import type { OAuthClientInformationFull, OAuthClientMetadata, OAuthTokens } from "@modelcontextprotocol/sdk/shared/auth.js";
|
|
14
|
+
import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
15
|
+
export declare class NodeOAuthProvider implements OAuthClientProvider {
|
|
16
|
+
private readonly file;
|
|
17
|
+
private cache;
|
|
18
|
+
private readonly _redirectUrl;
|
|
19
|
+
constructor(opts: {
|
|
20
|
+
mcpUrl: string;
|
|
21
|
+
redirectUrl: string;
|
|
22
|
+
});
|
|
23
|
+
private read;
|
|
24
|
+
private write;
|
|
25
|
+
get redirectUrl(): string;
|
|
26
|
+
get clientMetadata(): OAuthClientMetadata;
|
|
27
|
+
state(): string;
|
|
28
|
+
clientInformation(): OAuthClientInformationFull | undefined;
|
|
29
|
+
saveClientInformation(info: OAuthClientInformationFull): void;
|
|
30
|
+
tokens(): OAuthTokens | undefined;
|
|
31
|
+
saveTokens(tokens: OAuthTokens): void;
|
|
32
|
+
saveCodeVerifier(codeVerifier: string): void;
|
|
33
|
+
codeVerifier(): string;
|
|
34
|
+
redirectToAuthorization(authorizationUrl: URL): void;
|
|
35
|
+
/** Wipe persisted tokens — used when the server rejects them as expired
|
|
36
|
+
* beyond refresh, so the next connect re-runs the consent flow. */
|
|
37
|
+
clearTokens(): void;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=oauth-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-provider.d.ts","sourceRoot":"","sources":["../src/oauth-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,KAAK,EACV,0BAA0B,EAC1B,mBAAmB,EACnB,WAAW,EACZ,MAAM,0CAA0C,CAAC;AAClD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0CAA0C,CAAC;AAoBpF,qBAAa,iBAAkB,YAAW,mBAAmB;IAC3D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAE1B,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE;IAazD,OAAO,CAAC,IAAI;IASZ,OAAO,CAAC,KAAK;IAUb,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,IAAI,cAAc,IAAI,mBAAmB,CASxC;IAED,KAAK,IAAI,MAAM;IAOf,iBAAiB,IAAI,0BAA0B,GAAG,SAAS;IAI3D,qBAAqB,CAAC,IAAI,EAAE,0BAA0B,GAAG,IAAI;IAK7D,MAAM,IAAI,WAAW,GAAG,SAAS;IAIjC,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAKrC,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAK5C,YAAY,IAAI,MAAM;IAKtB,uBAAuB,CAAC,gBAAgB,EAAE,GAAG,GAAG,IAAI;IAUpD;uEACmE;IACnE,WAAW,IAAI,IAAI;CAKpB"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node OAuth client provider for the Better i18n MCP stdio bridge.
|
|
3
|
+
*
|
|
4
|
+
* Implements the SDK's OAuthClientProvider so the bridge can authenticate
|
|
5
|
+
* via the browser consent flow instead of a pasted API key. State that
|
|
6
|
+
* must survive across runs (dynamic client registration, tokens, PKCE
|
|
7
|
+
* verifier) is persisted to ~/.better-i18n/, keyed by the MCP host so a
|
|
8
|
+
* user can run against prod and local without clobbering credentials.
|
|
9
|
+
*
|
|
10
|
+
* No npm deps — pure Node built-ins. Browser is opened via the platform
|
|
11
|
+
* opener; the redirect lands on a local loopback server (see index.ts).
|
|
12
|
+
*/
|
|
13
|
+
import { createHash } from "node:crypto";
|
|
14
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
15
|
+
import { homedir } from "node:os";
|
|
16
|
+
import { join } from "node:path";
|
|
17
|
+
import { spawn } from "node:child_process";
|
|
18
|
+
function openBrowser(url) {
|
|
19
|
+
const platform = process.platform;
|
|
20
|
+
const cmd = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
21
|
+
const args = platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
22
|
+
try {
|
|
23
|
+
spawn(cmd, args, { stdio: "ignore", detached: true }).unref();
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// Headless / no opener — fall through; the URL is also printed to stderr.
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export class NodeOAuthProvider {
|
|
30
|
+
file;
|
|
31
|
+
cache;
|
|
32
|
+
_redirectUrl;
|
|
33
|
+
constructor(opts) {
|
|
34
|
+
const dir = join(homedir(), ".better-i18n");
|
|
35
|
+
if (!existsSync(dir))
|
|
36
|
+
mkdirSync(dir, { recursive: true });
|
|
37
|
+
// Key the credential file by MCP host so prod/local don't collide.
|
|
38
|
+
const hostKey = createHash("sha256")
|
|
39
|
+
.update(opts.mcpUrl)
|
|
40
|
+
.digest("hex")
|
|
41
|
+
.slice(0, 12);
|
|
42
|
+
this.file = join(dir, `mcp-auth-${hostKey}.json`);
|
|
43
|
+
this.cache = this.read();
|
|
44
|
+
this._redirectUrl = opts.redirectUrl;
|
|
45
|
+
}
|
|
46
|
+
read() {
|
|
47
|
+
try {
|
|
48
|
+
if (!existsSync(this.file))
|
|
49
|
+
return {};
|
|
50
|
+
return JSON.parse(readFileSync(this.file, "utf8"));
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return {};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
write() {
|
|
57
|
+
try {
|
|
58
|
+
writeFileSync(this.file, JSON.stringify(this.cache, null, 2), {
|
|
59
|
+
mode: 0o600,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
console.error("[better-i18n-mcp] failed to persist auth:", e);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
get redirectUrl() {
|
|
67
|
+
return this._redirectUrl;
|
|
68
|
+
}
|
|
69
|
+
get clientMetadata() {
|
|
70
|
+
return {
|
|
71
|
+
client_name: "Better i18n MCP (CLI)",
|
|
72
|
+
redirect_uris: [this._redirectUrl],
|
|
73
|
+
grant_types: ["authorization_code", "refresh_token"],
|
|
74
|
+
response_types: ["code"],
|
|
75
|
+
token_endpoint_auth_method: "none",
|
|
76
|
+
scope: "openid profile email offline_access",
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
state() {
|
|
80
|
+
return createHash("sha256")
|
|
81
|
+
.update(`${Date.now()}-${Math.random()}`)
|
|
82
|
+
.digest("hex")
|
|
83
|
+
.slice(0, 24);
|
|
84
|
+
}
|
|
85
|
+
clientInformation() {
|
|
86
|
+
return this.cache.clientInformation;
|
|
87
|
+
}
|
|
88
|
+
saveClientInformation(info) {
|
|
89
|
+
this.cache.clientInformation = info;
|
|
90
|
+
this.write();
|
|
91
|
+
}
|
|
92
|
+
tokens() {
|
|
93
|
+
return this.cache.tokens;
|
|
94
|
+
}
|
|
95
|
+
saveTokens(tokens) {
|
|
96
|
+
this.cache.tokens = tokens;
|
|
97
|
+
this.write();
|
|
98
|
+
}
|
|
99
|
+
saveCodeVerifier(codeVerifier) {
|
|
100
|
+
this.cache.codeVerifier = codeVerifier;
|
|
101
|
+
this.write();
|
|
102
|
+
}
|
|
103
|
+
codeVerifier() {
|
|
104
|
+
if (!this.cache.codeVerifier)
|
|
105
|
+
throw new Error("No PKCE code verifier saved");
|
|
106
|
+
return this.cache.codeVerifier;
|
|
107
|
+
}
|
|
108
|
+
redirectToAuthorization(authorizationUrl) {
|
|
109
|
+
const url = authorizationUrl.toString();
|
|
110
|
+
console.error("\n[better-i18n-mcp] Opening your browser to sign in to Better i18n…\n" +
|
|
111
|
+
"If it doesn't open automatically, visit:\n" +
|
|
112
|
+
` ${url}\n`);
|
|
113
|
+
openBrowser(url);
|
|
114
|
+
}
|
|
115
|
+
/** Wipe persisted tokens — used when the server rejects them as expired
|
|
116
|
+
* beyond refresh, so the next connect re-runs the consent flow. */
|
|
117
|
+
clearTokens() {
|
|
118
|
+
this.cache.tokens = undefined;
|
|
119
|
+
this.cache.codeVerifier = undefined;
|
|
120
|
+
this.write();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=oauth-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth-provider.js","sourceRoot":"","sources":["../src/oauth-provider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAc3C,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAClC,MAAM,GAAG,GACP,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC;IAC7E,MAAM,IAAI,GAAG,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACrE,IAAI,CAAC;QACH,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;IAC5E,CAAC;AACH,CAAC;AAED,MAAM,OAAO,iBAAiB;IACX,IAAI,CAAS;IACtB,KAAK,CAAgB;IACZ,YAAY,CAAS;IAEtC,YAAY,IAA6C;QACvD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;QAC5C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,mEAAmE;QACnE,MAAM,OAAO,GAAG,UAAU,CAAC,QAAQ,CAAC;aACjC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC;aACnB,MAAM,CAAC,KAAK,CAAC;aACb,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAChB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,YAAY,OAAO,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC;IACvC,CAAC;IAEO,IAAI;QACV,IAAI,CAAC;YACH,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO,EAAE,CAAC;YACtC,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAkB,CAAC;QACtE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAEO,KAAK;QACX,IAAI,CAAC;YACH,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;gBAC5D,IAAI,EAAE,KAAK;aACZ,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CAAC,2CAA2C,EAAE,CAAC,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAED,IAAI,WAAW;QACb,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,IAAI,cAAc;QAChB,OAAO;YACL,WAAW,EAAE,uBAAuB;YACpC,aAAa,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC;YAClC,WAAW,EAAE,CAAC,oBAAoB,EAAE,eAAe,CAAC;YACpD,cAAc,EAAE,CAAC,MAAM,CAAC;YACxB,0BAA0B,EAAE,MAAM;YAClC,KAAK,EAAE,qCAAqC;SAC7C,CAAC;IACJ,CAAC;IAED,KAAK;QACH,OAAO,UAAU,CAAC,QAAQ,CAAC;aACxB,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;aACxC,MAAM,CAAC,KAAK,CAAC;aACb,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAClB,CAAC;IAED,iBAAiB;QACf,OAAO,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC;IACtC,CAAC;IAED,qBAAqB,CAAC,IAAgC;QACpD,IAAI,CAAC,KAAK,CAAC,iBAAiB,GAAG,IAAI,CAAC;QACpC,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED,UAAU,CAAC,MAAmB;QAC5B,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;QAC3B,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;IAED,gBAAgB,CAAC,YAAoB;QACnC,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,YAAY,CAAC;QACvC,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;IAED,YAAY;QACV,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QAC7E,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC;IACjC,CAAC;IAED,uBAAuB,CAAC,gBAAqB;QAC3C,MAAM,GAAG,GAAG,gBAAgB,CAAC,QAAQ,EAAE,CAAC;QACxC,OAAO,CAAC,KAAK,CACX,uEAAuE;YACrE,4CAA4C;YAC5C,KAAK,GAAG,IAAI,CACf,CAAC;QACF,WAAW,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAED;uEACmE;IACnE,WAAW;QACT,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,SAAS,CAAC;QAC9B,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,SAAS,CAAC;QACpC,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;CACF"}
|
package/package.json
CHANGED