@infigure/mcp-bridge 1.0.0 → 1.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/index.js +95 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,6 +3,8 @@ import fs from "fs";
|
|
|
3
3
|
import path from "path";
|
|
4
4
|
import os from "os";
|
|
5
5
|
import readline from "readline";
|
|
6
|
+
import http from "http";
|
|
7
|
+
import { exec } from "child_process";
|
|
6
8
|
const CREDENTIALS_PATH = path.join(os.homedir(), ".infigure", "credentials");
|
|
7
9
|
const DEFAULT_URL = "https://www.infigured.com";
|
|
8
10
|
const USAGE = `Infigure MCP Bridge
|
|
@@ -13,7 +15,8 @@ Usage:
|
|
|
13
15
|
|
|
14
16
|
Commands:
|
|
15
17
|
serve Start stdio-to-HTTP JSON-RPC proxy (default)
|
|
16
|
-
|
|
18
|
+
login Authenticate with your Infigure account via browser
|
|
19
|
+
configure Set up ~/.infigure/credentials file manually
|
|
17
20
|
whoami Verify target URL and authentication status
|
|
18
21
|
install <name> Register config with local client (claude-code | claude-desktop | codex | all)
|
|
19
22
|
|
|
@@ -39,6 +42,10 @@ function parseArgs() {
|
|
|
39
42
|
config.command = "configure";
|
|
40
43
|
args.shift();
|
|
41
44
|
}
|
|
45
|
+
else if (args[0] === "login") {
|
|
46
|
+
config.command = "login";
|
|
47
|
+
args.shift();
|
|
48
|
+
}
|
|
42
49
|
else if (args[0] === "whoami") {
|
|
43
50
|
config.command = "whoami";
|
|
44
51
|
args.shift();
|
|
@@ -113,7 +120,7 @@ function ensureCredentialsOrExit(creds) {
|
|
|
113
120
|
if (!creds.token || !creds.teamId) {
|
|
114
121
|
console.error("Error: Credentials or Team ID not configured.\n\n" +
|
|
115
122
|
"Provide them via args, env vars, or run:\n" +
|
|
116
|
-
" infigure-mcp
|
|
123
|
+
" infigure-mcp login");
|
|
117
124
|
process.exit(1);
|
|
118
125
|
}
|
|
119
126
|
}
|
|
@@ -129,6 +136,89 @@ function askQuestion(query) {
|
|
|
129
136
|
});
|
|
130
137
|
});
|
|
131
138
|
}
|
|
139
|
+
function openBrowser(url) {
|
|
140
|
+
const start = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
141
|
+
const escaped = url.replace(/"/g, '\\"');
|
|
142
|
+
exec(`${start} "${escaped}"`);
|
|
143
|
+
}
|
|
144
|
+
async function runLogin(cliConfig) {
|
|
145
|
+
const fileData = loadCredentialsFile();
|
|
146
|
+
const targetUrl = cliConfig.url || process.env.INFIGURE_BASE_URL || fileData.base_url || DEFAULT_URL;
|
|
147
|
+
const teamId = cliConfig.teamId || process.env.INFIGURE_TEAM_ID || fileData.team_id || "";
|
|
148
|
+
console.log(`Starting login session for: ${targetUrl}`);
|
|
149
|
+
console.log("Opening your browser to authenticate...");
|
|
150
|
+
const port = 5566;
|
|
151
|
+
const server = http.createServer(async (req, res) => {
|
|
152
|
+
const reqUrl = new URL(req.url || "", `http://localhost:${port}`);
|
|
153
|
+
if (reqUrl.pathname === "/callback") {
|
|
154
|
+
const token = reqUrl.searchParams.get("token") || "";
|
|
155
|
+
const resolvedTeamId = reqUrl.searchParams.get("teamId") || teamId;
|
|
156
|
+
if (!token) {
|
|
157
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
158
|
+
res.end("<h1>Authentication Failed</h1><p>Missing token in authorization redirect.</p>");
|
|
159
|
+
console.error("Error: Authentication failed: No token received.");
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
const data = {
|
|
163
|
+
base_url: targetUrl.replace(/\/$/, ""),
|
|
164
|
+
token,
|
|
165
|
+
team_id: resolvedTeamId,
|
|
166
|
+
};
|
|
167
|
+
try {
|
|
168
|
+
const parentDir = path.dirname(CREDENTIALS_PATH);
|
|
169
|
+
if (!fs.existsSync(parentDir)) {
|
|
170
|
+
fs.mkdirSync(parentDir, { recursive: true });
|
|
171
|
+
}
|
|
172
|
+
fs.writeFileSync(CREDENTIALS_PATH, JSON.stringify(data, null, 2) + "\n", {
|
|
173
|
+
mode: 0o600,
|
|
174
|
+
});
|
|
175
|
+
try {
|
|
176
|
+
fs.chmodSync(CREDENTIALS_PATH, 0o600);
|
|
177
|
+
}
|
|
178
|
+
catch { }
|
|
179
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
180
|
+
res.end(`
|
|
181
|
+
<!DOCTYPE html>
|
|
182
|
+
<html>
|
|
183
|
+
<head>
|
|
184
|
+
<title>Authentication Successful</title>
|
|
185
|
+
<style>
|
|
186
|
+
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #0b0c10; color: #c5c6c7; display: flex; align-items: center; justify-content: center; height: 100vh; margin: 0; }
|
|
187
|
+
.card { background: #1f2833; padding: 2.5rem; border-radius: 1rem; text-align: center; max-width: 400px; box-shadow: 0 4px 12px rgba(0,0,0,0.5); border: 1px solid #334155; }
|
|
188
|
+
h1 { color: #10b981; margin-top: 0; font-size: 1.5rem; }
|
|
189
|
+
p { font-size: 0.9rem; color: #94a3b8; }
|
|
190
|
+
</style>
|
|
191
|
+
</head>
|
|
192
|
+
<body>
|
|
193
|
+
<div class="card">
|
|
194
|
+
<h1>Infigure Login Successful</h1>
|
|
195
|
+
<p>Your local CLI is authenticated. You can close this window and return to your terminal.</p>
|
|
196
|
+
</div>
|
|
197
|
+
</body>
|
|
198
|
+
</html>
|
|
199
|
+
`);
|
|
200
|
+
console.log(`\n✓ Login successful. Credentials saved securely to ${CREDENTIALS_PATH}`);
|
|
201
|
+
server.close();
|
|
202
|
+
process.exit(0);
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
res.writeHead(500, { "Content-Type": "text/html" });
|
|
206
|
+
res.end(`<h1>Error</h1><p>Failed to save credentials: ${err.message}</p>`);
|
|
207
|
+
console.error(`Error: Failed to write credentials file: ${err.message}`);
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
213
|
+
res.end("Not Found");
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
server.listen(port, () => {
|
|
217
|
+
const authUrl = `${targetUrl}/auth/mcp?callback=http://localhost:${port}/callback&teamId=${encodeURIComponent(teamId)}`;
|
|
218
|
+
openBrowser(authUrl);
|
|
219
|
+
console.log(`\nIf the browser does not open automatically, navigate to:\n${authUrl}\n`);
|
|
220
|
+
});
|
|
221
|
+
}
|
|
132
222
|
async function runConfigure() {
|
|
133
223
|
const current = loadCredentialsFile();
|
|
134
224
|
const baseUrl = await askQuestion(`Infigure URL [${current.base_url || DEFAULT_URL}]: `);
|
|
@@ -435,6 +525,9 @@ async function main() {
|
|
|
435
525
|
}
|
|
436
526
|
const creds = resolveCredentials(cliConfig);
|
|
437
527
|
switch (cliConfig.command) {
|
|
528
|
+
case "login":
|
|
529
|
+
await runLogin(cliConfig);
|
|
530
|
+
break;
|
|
438
531
|
case "configure":
|
|
439
532
|
await runConfigure();
|
|
440
533
|
break;
|