@hostafrica/connector-core 1.0.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/LICENSE +21 -0
- package/dist/clients/claudeCode.d.ts +9 -0
- package/dist/clients/claudeCode.js +53 -0
- package/dist/clients/claudeCode.js.map +1 -0
- package/dist/clients/codex.d.ts +12 -0
- package/dist/clients/codex.js +106 -0
- package/dist/clients/codex.js.map +1 -0
- package/dist/clients/jsonClient.d.ts +20 -0
- package/dist/clients/jsonClient.js +62 -0
- package/dist/clients/jsonClient.js.map +1 -0
- package/dist/clients/registry.d.ts +17 -0
- package/dist/clients/registry.js +220 -0
- package/dist/clients/registry.js.map +1 -0
- package/dist/constants.d.ts +11 -0
- package/dist/constants.js +15 -0
- package/dist/constants.js.map +1 -0
- package/dist/deeplinks.d.ts +6 -0
- package/dist/deeplinks.js +15 -0
- package/dist/deeplinks.js.map +1 -0
- package/dist/fsutil.d.ts +14 -0
- package/dist/fsutil.js +89 -0
- package/dist/fsutil.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +40 -0
- package/dist/types.js +15 -0
- package/dist/types.js.map +1 -0
- package/package.json +28 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 HostAfrica
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AuthMode, McpClient } from "../types";
|
|
2
|
+
/** Pure builder for the `claude mcp add` argument list — unit-testable. */
|
|
3
|
+
export declare function claudeAddArgs(auth: AuthMode): string[];
|
|
4
|
+
/**
|
|
5
|
+
* Claude Code manages its own MCP config; drive it through `claude mcp`
|
|
6
|
+
* rather than editing files, so scope handling stays Claude Code's problem.
|
|
7
|
+
* Registration is user-scoped so it works across every project.
|
|
8
|
+
*/
|
|
9
|
+
export declare const claudeCode: McpClient;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.claudeCode = void 0;
|
|
4
|
+
exports.claudeAddArgs = claudeAddArgs;
|
|
5
|
+
const constants_1 = require("../constants");
|
|
6
|
+
const types_1 = require("../types");
|
|
7
|
+
const fsutil_1 = require("../fsutil");
|
|
8
|
+
/** Pure builder for the `claude mcp add` argument list — unit-testable. */
|
|
9
|
+
function claudeAddArgs(auth) {
|
|
10
|
+
const { url, headers } = (0, types_1.endpointFor)(auth);
|
|
11
|
+
const args = ["mcp", "add", "--scope", "user", "--transport", "http", constants_1.SERVER_KEY, url];
|
|
12
|
+
for (const [k, v] of Object.entries(headers ?? {})) {
|
|
13
|
+
args.push("--header", `${k}: ${v}`);
|
|
14
|
+
}
|
|
15
|
+
return args;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Claude Code manages its own MCP config; drive it through `claude mcp`
|
|
19
|
+
* rather than editing files, so scope handling stays Claude Code's problem.
|
|
20
|
+
* Registration is user-scoped so it works across every project.
|
|
21
|
+
*/
|
|
22
|
+
exports.claudeCode = {
|
|
23
|
+
id: "claude-code",
|
|
24
|
+
name: "Claude Code",
|
|
25
|
+
supportsOAuth: true,
|
|
26
|
+
describeTarget: () => "claude mcp (user scope)",
|
|
27
|
+
async detect() {
|
|
28
|
+
return (await (0, fsutil_1.whichBin)("claude")) !== undefined;
|
|
29
|
+
},
|
|
30
|
+
async isRegistered() {
|
|
31
|
+
try {
|
|
32
|
+
await (0, fsutil_1.execFileP)("claude", ["mcp", "get", constants_1.SERVER_KEY]);
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
async register(opts) {
|
|
40
|
+
// `claude mcp add` refuses duplicate names, so make register idempotent.
|
|
41
|
+
await this.unregister();
|
|
42
|
+
await (0, fsutil_1.execFileP)("claude", claudeAddArgs(opts.auth));
|
|
43
|
+
},
|
|
44
|
+
async unregister() {
|
|
45
|
+
try {
|
|
46
|
+
await (0, fsutil_1.execFileP)("claude", ["mcp", "remove", "--scope", "user", constants_1.SERVER_KEY]);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// already gone
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=claudeCode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeCode.js","sourceRoot":"","sources":["../../src/clients/claudeCode.ts"],"names":[],"mappings":";;;AAKA,sCAOC;AAZD,4CAA0C;AAC1C,oCAA6E;AAC7E,sCAAgD;AAEhD,2EAA2E;AAC3E,SAAgB,aAAa,CAAC,IAAc;IAC1C,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,IAAA,mBAAW,EAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,sBAAU,EAAE,GAAG,CAAC,CAAC;IACvF,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,CAAC;QACnD,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACU,QAAA,UAAU,GAAc;IACnC,EAAE,EAAE,aAAa;IACjB,IAAI,EAAE,aAAa;IACnB,aAAa,EAAE,IAAI;IACnB,cAAc,EAAE,GAAG,EAAE,CAAC,yBAAyB;IAE/C,KAAK,CAAC,MAAM;QACV,OAAO,CAAC,MAAM,IAAA,iBAAQ,EAAC,QAAQ,CAAC,CAAC,KAAK,SAAS,CAAC;IAClD,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,IAAI,CAAC;YACH,MAAM,IAAA,kBAAS,EAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,sBAAU,CAAC,CAAC,CAAC;YACtD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,IAAqB;QAClC,yEAAyE;QACzE,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QACxB,MAAM,IAAA,kBAAS,EAAC,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,UAAU;QACd,IAAI,CAAC;YACH,MAAM,IAAA,kBAAS,EAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,sBAAU,CAAC,CAAC,CAAC;QAC9E,CAAC;QAAC,MAAM,CAAC;YACP,eAAe;QACjB,CAAC;IACH,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { McpClient } from "../types";
|
|
2
|
+
/**
|
|
3
|
+
* OpenAI Codex CLI reads TOML at ~/.codex/config.toml with an `mcp_servers`
|
|
4
|
+
* table. Streamable-HTTP servers use `url` (no experimental flag needed since
|
|
5
|
+
* ~v0.44). OAuth is supported per the MCP authorization spec — `auth` defaults
|
|
6
|
+
* to "oauth" and `codex mcp login <name>` runs the browser flow — so a bare
|
|
7
|
+
* `url` entry is the OAuth-first registration. Token fallback writes
|
|
8
|
+
* `http_headers`; `bearer_token_env_var` is the secretless alternative when
|
|
9
|
+
* the user prefers env vars.
|
|
10
|
+
*/
|
|
11
|
+
export declare function makeCodex(home?: string): McpClient;
|
|
12
|
+
export declare const codex: McpClient;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.codex = void 0;
|
|
37
|
+
exports.makeCodex = makeCodex;
|
|
38
|
+
const os = __importStar(require("node:os"));
|
|
39
|
+
const path = __importStar(require("node:path"));
|
|
40
|
+
const smol_toml_1 = require("smol-toml");
|
|
41
|
+
const constants_1 = require("../constants");
|
|
42
|
+
const types_1 = require("../types");
|
|
43
|
+
const fsutil_1 = require("../fsutil");
|
|
44
|
+
/**
|
|
45
|
+
* OpenAI Codex CLI reads TOML at ~/.codex/config.toml with an `mcp_servers`
|
|
46
|
+
* table. Streamable-HTTP servers use `url` (no experimental flag needed since
|
|
47
|
+
* ~v0.44). OAuth is supported per the MCP authorization spec — `auth` defaults
|
|
48
|
+
* to "oauth" and `codex mcp login <name>` runs the browser flow — so a bare
|
|
49
|
+
* `url` entry is the OAuth-first registration. Token fallback writes
|
|
50
|
+
* `http_headers`; `bearer_token_env_var` is the secretless alternative when
|
|
51
|
+
* the user prefers env vars.
|
|
52
|
+
*/
|
|
53
|
+
function makeCodex(home = os.homedir()) {
|
|
54
|
+
const configPath = path.join(home, ".codex", "config.toml");
|
|
55
|
+
async function readConfig() {
|
|
56
|
+
const raw = await (0, fsutil_1.readTextIfPresent)(configPath);
|
|
57
|
+
if (raw === undefined || raw.trim() === "")
|
|
58
|
+
return {};
|
|
59
|
+
try {
|
|
60
|
+
return (0, smol_toml_1.parse)(raw);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
throw new Error(`Codex config at ${configPath} is not valid TOML — fix or remove it, then retry (${String(err)})`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
id: "codex",
|
|
68
|
+
name: "OpenAI Codex CLI",
|
|
69
|
+
supportsOAuth: true, // `codex mcp login` — DCR and CIMD both supported
|
|
70
|
+
describeTarget: () => configPath,
|
|
71
|
+
async detect() {
|
|
72
|
+
return (0, fsutil_1.exists)(path.join(home, ".codex"));
|
|
73
|
+
},
|
|
74
|
+
async isRegistered() {
|
|
75
|
+
try {
|
|
76
|
+
const cfg = await readConfig();
|
|
77
|
+
return Boolean(cfg["mcp_servers"]?.[constants_1.SERVER_KEY]);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
async register(opts) {
|
|
84
|
+
const cfg = await readConfig();
|
|
85
|
+
const { url, headers } = (0, types_1.endpointFor)(opts.auth);
|
|
86
|
+
const entry = { url };
|
|
87
|
+
if (headers)
|
|
88
|
+
entry["http_headers"] = headers;
|
|
89
|
+
cfg["mcp_servers"] = cfg["mcp_servers"] ?? {};
|
|
90
|
+
cfg["mcp_servers"][constants_1.SERVER_KEY] = entry;
|
|
91
|
+
await (0, fsutil_1.writePrivate)(configPath, (0, smol_toml_1.stringify)(cfg) + "\n");
|
|
92
|
+
},
|
|
93
|
+
async unregister() {
|
|
94
|
+
const raw = await (0, fsutil_1.readTextIfPresent)(configPath);
|
|
95
|
+
if (raw === undefined)
|
|
96
|
+
return;
|
|
97
|
+
const cfg = await readConfig();
|
|
98
|
+
if (cfg["mcp_servers"]?.[constants_1.SERVER_KEY]) {
|
|
99
|
+
delete cfg["mcp_servers"][constants_1.SERVER_KEY];
|
|
100
|
+
await (0, fsutil_1.writePrivate)(configPath, (0, smol_toml_1.stringify)(cfg) + "\n");
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
exports.codex = makeCodex();
|
|
106
|
+
//# sourceMappingURL=codex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/clients/codex.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgBA,8BAsDC;AAtED,4CAA8B;AAC9B,gDAAkC;AAClC,yCAA2E;AAC3E,4CAA0C;AAC1C,oCAAmE;AACnE,sCAAoE;AAEpE;;;;;;;;GAQG;AACH,SAAgB,SAAS,CAAC,OAAe,EAAE,CAAC,OAAO,EAAE;IACnD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;IAE5D,KAAK,UAAU,UAAU;QACvB,MAAM,GAAG,GAAG,MAAM,IAAA,0BAAiB,EAAC,UAAU,CAAC,CAAC;QAChD,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,EAAE,CAAC;QACtD,IAAI,CAAC;YACH,OAAO,IAAA,iBAAS,EAAC,GAAG,CAAwB,CAAC;QAC/C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,mBAAmB,UAAU,sDAAsD,MAAM,CAAC,GAAG,CAAC,GAAG,CAClG,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO;QACL,EAAE,EAAE,OAAO;QACX,IAAI,EAAE,kBAAkB;QACxB,aAAa,EAAE,IAAI,EAAE,kDAAkD;QACvE,cAAc,EAAE,GAAG,EAAE,CAAC,UAAU;QAEhC,KAAK,CAAC,MAAM;YACV,OAAO,IAAA,eAAM,EAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC3C,CAAC;QAED,KAAK,CAAC,YAAY;YAChB,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,UAAU,EAAE,CAAC;gBAC/B,OAAO,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC,sBAAU,CAAC,CAAC,CAAC;YACnD,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QAED,KAAK,CAAC,QAAQ,CAAC,IAAqB;YAClC,MAAM,GAAG,GAAG,MAAM,UAAU,EAAE,CAAC;YAC/B,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,IAAA,mBAAW,EAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAChD,MAAM,KAAK,GAA4B,EAAE,GAAG,EAAE,CAAC;YAC/C,IAAI,OAAO;gBAAE,KAAK,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC;YAC7C,GAAG,CAAC,aAAa,CAAC,GAAG,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;YAC9C,GAAG,CAAC,aAAa,CAAC,CAAC,sBAAU,CAAC,GAAG,KAAK,CAAC;YACvC,MAAM,IAAA,qBAAY,EAAC,UAAU,EAAE,IAAA,qBAAa,EAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;QAC5D,CAAC;QAED,KAAK,CAAC,UAAU;YACd,MAAM,GAAG,GAAG,MAAM,IAAA,0BAAiB,EAAC,UAAU,CAAC,CAAC;YAChD,IAAI,GAAG,KAAK,SAAS;gBAAE,OAAO;YAC9B,MAAM,GAAG,GAAG,MAAM,UAAU,EAAE,CAAC;YAC/B,IAAI,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC,sBAAU,CAAC,EAAE,CAAC;gBACrC,OAAO,GAAG,CAAC,aAAa,CAAC,CAAC,sBAAU,CAAC,CAAC;gBACtC,MAAM,IAAA,qBAAY,EAAC,UAAU,EAAE,IAAA,qBAAa,EAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAEY,QAAA,KAAK,GAAc,SAAS,EAAE,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AuthMode, McpClient } from "../types";
|
|
2
|
+
export interface JsonClientSpec {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
supportsOAuth: boolean;
|
|
6
|
+
/** Absolute path of the MCP config file this client reads. */
|
|
7
|
+
configPath: string;
|
|
8
|
+
/** Paths whose existence indicates the client is installed. */
|
|
9
|
+
detectPaths: string[];
|
|
10
|
+
/** Top-level key holding the server map, e.g. "mcpServers". */
|
|
11
|
+
rootKey: string;
|
|
12
|
+
/** Build this client's server entry for the given auth mode. */
|
|
13
|
+
buildEntry(auth: AuthMode): Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Most AI clients read a JSON file with a `{ [rootKey]: { [name]: entry } }`
|
|
17
|
+
* shape and differ only in path and entry fields. This factory covers them;
|
|
18
|
+
* merge is read–modify–write so entries for other servers are preserved.
|
|
19
|
+
*/
|
|
20
|
+
export declare function jsonClient(spec: JsonClientSpec): McpClient;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.jsonClient = jsonClient;
|
|
4
|
+
const constants_1 = require("../constants");
|
|
5
|
+
const fsutil_1 = require("../fsutil");
|
|
6
|
+
/**
|
|
7
|
+
* Most AI clients read a JSON file with a `{ [rootKey]: { [name]: entry } }`
|
|
8
|
+
* shape and differ only in path and entry fields. This factory covers them;
|
|
9
|
+
* merge is read–modify–write so entries for other servers are preserved.
|
|
10
|
+
*/
|
|
11
|
+
function jsonClient(spec) {
|
|
12
|
+
async function readConfig() {
|
|
13
|
+
const raw = await (0, fsutil_1.readTextIfPresent)(spec.configPath);
|
|
14
|
+
if (raw === undefined || raw.trim() === "")
|
|
15
|
+
return {};
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(raw);
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
throw new Error(`${spec.name} config at ${spec.configPath} is not valid JSON — fix or remove it, then retry (${String(err)})`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return {
|
|
24
|
+
id: spec.id,
|
|
25
|
+
name: spec.name,
|
|
26
|
+
supportsOAuth: spec.supportsOAuth,
|
|
27
|
+
describeTarget: () => spec.configPath,
|
|
28
|
+
async detect() {
|
|
29
|
+
for (const p of spec.detectPaths) {
|
|
30
|
+
if (await (0, fsutil_1.exists)(p))
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
},
|
|
35
|
+
async isRegistered() {
|
|
36
|
+
try {
|
|
37
|
+
const cfg = await readConfig();
|
|
38
|
+
return Boolean(cfg[spec.rootKey]?.[constants_1.SERVER_KEY]);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
async register(opts) {
|
|
45
|
+
const cfg = await readConfig();
|
|
46
|
+
cfg[spec.rootKey] = cfg[spec.rootKey] ?? {};
|
|
47
|
+
cfg[spec.rootKey][constants_1.SERVER_KEY] = spec.buildEntry(opts.auth);
|
|
48
|
+
await (0, fsutil_1.writePrivate)(spec.configPath, JSON.stringify(cfg, null, 2) + "\n");
|
|
49
|
+
},
|
|
50
|
+
async unregister() {
|
|
51
|
+
const raw = await (0, fsutil_1.readTextIfPresent)(spec.configPath);
|
|
52
|
+
if (raw === undefined)
|
|
53
|
+
return;
|
|
54
|
+
const cfg = await readConfig();
|
|
55
|
+
if (cfg[spec.rootKey]?.[constants_1.SERVER_KEY]) {
|
|
56
|
+
delete cfg[spec.rootKey][constants_1.SERVER_KEY];
|
|
57
|
+
await (0, fsutil_1.writePrivate)(spec.configPath, JSON.stringify(cfg, null, 2) + "\n");
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=jsonClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonClient.js","sourceRoot":"","sources":["../../src/clients/jsonClient.ts"],"names":[],"mappings":";;AAuBA,gCAoDC;AA3ED,4CAA0C;AAE1C,sCAAoE;AAgBpE;;;;GAIG;AACH,SAAgB,UAAU,CAAC,IAAoB;IAC7C,KAAK,UAAU,UAAU;QACvB,MAAM,GAAG,GAAG,MAAM,IAAA,0BAAiB,EAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrD,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO,EAAE,CAAC;QACtD,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,GAAG,IAAI,CAAC,IAAI,cAAc,IAAI,CAAC,UAAU,sDAAsD,MAAM,CAAC,GAAG,CAAC,GAAG,CAC9G,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,aAAa,EAAE,IAAI,CAAC,aAAa;QACjC,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU;QAErC,KAAK,CAAC,MAAM;YACV,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjC,IAAI,MAAM,IAAA,eAAM,EAAC,CAAC,CAAC;oBAAE,OAAO,IAAI,CAAC;YACnC,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,KAAK,CAAC,YAAY;YAChB,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,MAAM,UAAU,EAAE,CAAC;gBAC/B,OAAO,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,sBAAU,CAAC,CAAC,CAAC;YAClD,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;QAED,KAAK,CAAC,QAAQ,CAAC,IAAqB;YAClC,MAAM,GAAG,GAAG,MAAM,UAAU,EAAE,CAAC;YAC/B,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAC5C,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,sBAAU,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC3D,MAAM,IAAA,qBAAY,EAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAC3E,CAAC;QAED,KAAK,CAAC,UAAU;YACd,MAAM,GAAG,GAAG,MAAM,IAAA,0BAAiB,EAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACrD,IAAI,GAAG,KAAK,SAAS;gBAAE,OAAO;YAC9B,MAAM,GAAG,GAAG,MAAM,UAAU,EAAE,CAAC;YAC/B,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,sBAAU,CAAC,EAAE,CAAC;gBACpC,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,sBAAU,CAAC,CAAC;gBACrC,MAAM,IAAA,qBAAY,EAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;YAC3E,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ClientStatus, McpClient } from "../types";
|
|
2
|
+
/** Per-OS location of Claude Desktop's config file. */
|
|
3
|
+
export declare function claudeDesktopConfigPath(home: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* Build the client set rooted at a given home directory. Production callers
|
|
6
|
+
* use the real home (the default); tests pass a temp dir.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createClients(home?: string): McpClient[];
|
|
9
|
+
/**
|
|
10
|
+
* All clients the registrar can configure directly. VS Code itself is not in
|
|
11
|
+
* this list: the extension registers the server natively through the
|
|
12
|
+
* McpServerDefinitionProvider API instead of writing config files.
|
|
13
|
+
*/
|
|
14
|
+
export declare function allClients(): McpClient[];
|
|
15
|
+
export declare function clientById(id: string): McpClient | undefined;
|
|
16
|
+
/** Installed/registered status for every known client. */
|
|
17
|
+
export declare function clientStatuses(): Promise<ClientStatus[]>;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.claudeDesktopConfigPath = claudeDesktopConfigPath;
|
|
37
|
+
exports.createClients = createClients;
|
|
38
|
+
exports.allClients = allClients;
|
|
39
|
+
exports.clientById = clientById;
|
|
40
|
+
exports.clientStatuses = clientStatuses;
|
|
41
|
+
const os = __importStar(require("node:os"));
|
|
42
|
+
const path = __importStar(require("node:path"));
|
|
43
|
+
const constants_1 = require("../constants");
|
|
44
|
+
const types_1 = require("../types");
|
|
45
|
+
const jsonClient_1 = require("./jsonClient");
|
|
46
|
+
const claudeCode_1 = require("./claudeCode");
|
|
47
|
+
const codex_1 = require("./codex");
|
|
48
|
+
/** Per-OS location of Claude Desktop's config file. */
|
|
49
|
+
function claudeDesktopConfigPath(home) {
|
|
50
|
+
if (process.platform === "win32") {
|
|
51
|
+
return path.join(home, "AppData", "Roaming", "Claude", "claude_desktop_config.json");
|
|
52
|
+
}
|
|
53
|
+
if (process.platform === "darwin") {
|
|
54
|
+
return path.join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
55
|
+
}
|
|
56
|
+
return path.join(home, ".config", "Claude", "claude_desktop_config.json");
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Build the client set rooted at a given home directory. Production callers
|
|
60
|
+
* use the real home (the default); tests pass a temp dir.
|
|
61
|
+
*/
|
|
62
|
+
function createClients(home = os.homedir()) {
|
|
63
|
+
/** Cursor: supports remote HTTP MCP + the MCP authorization spec. */
|
|
64
|
+
const cursor = (0, jsonClient_1.jsonClient)({
|
|
65
|
+
id: "cursor",
|
|
66
|
+
name: "Cursor",
|
|
67
|
+
supportsOAuth: true,
|
|
68
|
+
configPath: path.join(home, ".cursor", "mcp.json"),
|
|
69
|
+
detectPaths: [path.join(home, ".cursor")],
|
|
70
|
+
rootKey: "mcpServers",
|
|
71
|
+
buildEntry(auth) {
|
|
72
|
+
const { url, headers } = (0, types_1.endpointFor)(auth);
|
|
73
|
+
return headers ? { url, headers } : { url };
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
/**
|
|
77
|
+
* Windsurf (now Cognition/Devin Desktop): HTTP servers use `serverUrl`
|
|
78
|
+
* (also accepts `url`; serverUrl is the long-supported key). OAuth for
|
|
79
|
+
* URL-only entries confirmed in docs.devin.ai/desktop/cascade/mcp.
|
|
80
|
+
*/
|
|
81
|
+
const windsurf = (0, jsonClient_1.jsonClient)({
|
|
82
|
+
id: "windsurf",
|
|
83
|
+
name: "Windsurf",
|
|
84
|
+
supportsOAuth: true,
|
|
85
|
+
configPath: path.join(home, ".codeium", "windsurf", "mcp_config.json"),
|
|
86
|
+
detectPaths: [path.join(home, ".codeium", "windsurf")],
|
|
87
|
+
rootKey: "mcpServers",
|
|
88
|
+
buildEntry(auth) {
|
|
89
|
+
const { url, headers } = (0, types_1.endpointFor)(auth);
|
|
90
|
+
return headers ? { serverUrl: url, headers } : { serverUrl: url };
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
/**
|
|
94
|
+
* Google Antigravity: `serverUrl` (legacy `url`/`httpUrl` are rejected),
|
|
95
|
+
* headers supported, OAuth automatic for DCR-capable servers.
|
|
96
|
+
* Global config: ~/.gemini/config/mcp_config.json.
|
|
97
|
+
*/
|
|
98
|
+
const antigravity = (0, jsonClient_1.jsonClient)({
|
|
99
|
+
id: "antigravity",
|
|
100
|
+
name: "Google Antigravity",
|
|
101
|
+
supportsOAuth: true,
|
|
102
|
+
configPath: path.join(home, ".gemini", "config", "mcp_config.json"),
|
|
103
|
+
detectPaths: [
|
|
104
|
+
path.join(home, ".gemini", "antigravity"),
|
|
105
|
+
path.join(home, ".gemini", "config", "mcp_config.json"),
|
|
106
|
+
],
|
|
107
|
+
rootKey: "mcpServers",
|
|
108
|
+
buildEntry(auth) {
|
|
109
|
+
const { url, headers } = (0, types_1.endpointFor)(auth);
|
|
110
|
+
return headers ? { serverUrl: url, headers } : { serverUrl: url };
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
/**
|
|
114
|
+
* Devin CLI / Devin for Terminal: ~/.config/devin/mcp_config.json,
|
|
115
|
+
* `url` + optional `transport: "http"` + headers; OAuth via
|
|
116
|
+
* `devin mcp login <name>` browser flow.
|
|
117
|
+
*/
|
|
118
|
+
const devinCli = (0, jsonClient_1.jsonClient)({
|
|
119
|
+
id: "devin-cli",
|
|
120
|
+
name: "Devin CLI",
|
|
121
|
+
supportsOAuth: true,
|
|
122
|
+
configPath: path.join(home, ".config", "devin", "mcp_config.json"),
|
|
123
|
+
detectPaths: [path.join(home, ".config", "devin")],
|
|
124
|
+
rootKey: "mcpServers",
|
|
125
|
+
buildEntry(auth) {
|
|
126
|
+
const { url, headers } = (0, types_1.endpointFor)(auth);
|
|
127
|
+
return headers
|
|
128
|
+
? { url, transport: "http", headers }
|
|
129
|
+
: { url, transport: "http" };
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
/**
|
|
133
|
+
* JetBrains Junie: user-level ~/.junie/mcp/mcp.json, `url` + headers,
|
|
134
|
+
* OAuth browser flow on "Authorization required". (JetBrains AI Assistant
|
|
135
|
+
* itself is UI-configured only — covered by docs, not the registrar.)
|
|
136
|
+
*/
|
|
137
|
+
const junie = (0, jsonClient_1.jsonClient)({
|
|
138
|
+
id: "junie",
|
|
139
|
+
name: "JetBrains Junie",
|
|
140
|
+
supportsOAuth: true,
|
|
141
|
+
configPath: path.join(home, ".junie", "mcp", "mcp.json"),
|
|
142
|
+
detectPaths: [path.join(home, ".junie")],
|
|
143
|
+
rootKey: "mcpServers",
|
|
144
|
+
buildEntry(auth) {
|
|
145
|
+
const { url, headers } = (0, types_1.endpointFor)(auth);
|
|
146
|
+
return headers ? { url, headers } : { url };
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
/**
|
|
150
|
+
* Claude Desktop: its config file only supports stdio servers, so bridge to
|
|
151
|
+
* the remote endpoint with `mcp-remote` (npx). OAuth mode runs mcp-remote's
|
|
152
|
+
* own browser flow against the OAuth endpoint; token mode passes the bearer
|
|
153
|
+
* header via an env var (mcp-remote expands ${...} in --header, and this
|
|
154
|
+
* avoids the arg-splitting some stdio clients do on spaces). Requires Node on
|
|
155
|
+
* the user's machine — inherent to the bridge.
|
|
156
|
+
*/
|
|
157
|
+
const claudeDesktop = (0, jsonClient_1.jsonClient)({
|
|
158
|
+
id: "claude-desktop",
|
|
159
|
+
name: "Claude Desktop",
|
|
160
|
+
supportsOAuth: true,
|
|
161
|
+
configPath: claudeDesktopConfigPath(home),
|
|
162
|
+
detectPaths: [path.dirname(claudeDesktopConfigPath(home))],
|
|
163
|
+
rootKey: "mcpServers",
|
|
164
|
+
buildEntry(auth) {
|
|
165
|
+
if (auth.kind === "oauth") {
|
|
166
|
+
return { command: "npx", args: ["-y", "mcp-remote", constants_1.MCP_OAUTH_URL] };
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
command: "npx",
|
|
170
|
+
args: ["-y", "mcp-remote", constants_1.MCP_BEARER_URL, "--header", "Authorization:${HOSTAFRICA_AUTH}"],
|
|
171
|
+
env: { HOSTAFRICA_AUTH: `Bearer ${auth.token}` },
|
|
172
|
+
};
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
/** Gemini CLI: HTTP servers use `httpUrl` in ~/.gemini/settings.json. */
|
|
176
|
+
const geminiCli = (0, jsonClient_1.jsonClient)({
|
|
177
|
+
id: "gemini-cli",
|
|
178
|
+
name: "Gemini CLI",
|
|
179
|
+
supportsOAuth: true,
|
|
180
|
+
configPath: path.join(home, ".gemini", "settings.json"),
|
|
181
|
+
detectPaths: [path.join(home, ".gemini")],
|
|
182
|
+
rootKey: "mcpServers",
|
|
183
|
+
buildEntry(auth) {
|
|
184
|
+
const { url, headers } = (0, types_1.endpointFor)(auth);
|
|
185
|
+
return headers ? { httpUrl: url, headers } : { httpUrl: url };
|
|
186
|
+
},
|
|
187
|
+
});
|
|
188
|
+
// claudeCode drives the `claude` CLI, which resolves its own home.
|
|
189
|
+
return [
|
|
190
|
+
claudeCode_1.claudeCode,
|
|
191
|
+
cursor,
|
|
192
|
+
windsurf,
|
|
193
|
+
geminiCli,
|
|
194
|
+
(0, codex_1.makeCodex)(home),
|
|
195
|
+
antigravity,
|
|
196
|
+
devinCli,
|
|
197
|
+
junie,
|
|
198
|
+
claudeDesktop,
|
|
199
|
+
];
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* All clients the registrar can configure directly. VS Code itself is not in
|
|
203
|
+
* this list: the extension registers the server natively through the
|
|
204
|
+
* McpServerDefinitionProvider API instead of writing config files.
|
|
205
|
+
*/
|
|
206
|
+
function allClients() {
|
|
207
|
+
return createClients();
|
|
208
|
+
}
|
|
209
|
+
function clientById(id) {
|
|
210
|
+
return allClients().find((c) => c.id === id);
|
|
211
|
+
}
|
|
212
|
+
/** Installed/registered status for every known client. */
|
|
213
|
+
async function clientStatuses() {
|
|
214
|
+
return Promise.all(allClients().map(async (client) => {
|
|
215
|
+
const installed = await client.detect();
|
|
216
|
+
const registered = installed ? await client.isRegistered() : false;
|
|
217
|
+
return { client, installed, registered };
|
|
218
|
+
}));
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/clients/registry.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AASA,0DAQC;AAMD,sCAiJC;AAOD,gCAEC;AAED,gCAEC;AAGD,wCAQC;AAhMD,4CAA8B;AAC9B,gDAAkC;AAClC,4CAA6D;AAC7D,oCAAgE;AAChE,6CAA0C;AAC1C,6CAA0C;AAC1C,mCAAoC;AAEpC,uDAAuD;AACvD,SAAgB,uBAAuB,CAAC,IAAY;IAClD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,4BAA4B,CAAC,CAAC;IACvF,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,qBAAqB,EAAE,QAAQ,EAAE,4BAA4B,CAAC,CAAC;IACnG,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,4BAA4B,CAAC,CAAC;AAC5E,CAAC;AAED;;;GAGG;AACH,SAAgB,aAAa,CAAC,OAAe,EAAE,CAAC,OAAO,EAAE;IACvD,qEAAqE;IACrE,MAAM,MAAM,GAAG,IAAA,uBAAU,EAAC;QACxB,EAAE,EAAE,QAAQ;QACZ,IAAI,EAAE,QAAQ;QACd,aAAa,EAAE,IAAI;QACnB,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC;QAClD,WAAW,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACzC,OAAO,EAAE,YAAY;QACrB,UAAU,CAAC,IAAI;YACb,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,IAAA,mBAAW,EAAC,IAAI,CAAC,CAAC;YAC3C,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC;QAC9C,CAAC;KACF,CAAC,CAAC;IAEH;;;;OAIG;IACH,MAAM,QAAQ,GAAG,IAAA,uBAAU,EAAC;QAC1B,EAAE,EAAE,UAAU;QACd,IAAI,EAAE,UAAU;QAChB,aAAa,EAAE,IAAI;QACnB,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,iBAAiB,CAAC;QACtE,WAAW,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;QACtD,OAAO,EAAE,YAAY;QACrB,UAAU,CAAC,IAAI;YACb,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,IAAA,mBAAW,EAAC,IAAI,CAAC,CAAC;YAC3C,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;QACpE,CAAC;KACF,CAAC,CAAC;IAEH;;;;OAIG;IACH,MAAM,WAAW,GAAG,IAAA,uBAAU,EAAC;QAC7B,EAAE,EAAE,aAAa;QACjB,IAAI,EAAE,oBAAoB;QAC1B,aAAa,EAAE,IAAI;QACnB,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,iBAAiB,CAAC;QACnE,WAAW,EAAE;YACX,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,aAAa,CAAC;YACzC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,iBAAiB,CAAC;SACxD;QACD,OAAO,EAAE,YAAY;QACrB,UAAU,CAAC,IAAI;YACb,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,IAAA,mBAAW,EAAC,IAAI,CAAC,CAAC;YAC3C,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;QACpE,CAAC;KACF,CAAC,CAAC;IAEH;;;;OAIG;IACH,MAAM,QAAQ,GAAG,IAAA,uBAAU,EAAC;QAC1B,EAAE,EAAE,WAAW;QACf,IAAI,EAAE,WAAW;QACjB,aAAa,EAAE,IAAI;QACnB,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,CAAC;QAClE,WAAW,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QAClD,OAAO,EAAE,YAAY;QACrB,UAAU,CAAC,IAAI;YACb,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,IAAA,mBAAW,EAAC,IAAI,CAAC,CAAC;YAC3C,OAAO,OAAO;gBACZ,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE;gBACrC,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;QACjC,CAAC;KACF,CAAC,CAAC;IAEH;;;;OAIG;IACH,MAAM,KAAK,GAAG,IAAA,uBAAU,EAAC;QACvB,EAAE,EAAE,OAAO;QACX,IAAI,EAAE,iBAAiB;QACvB,aAAa,EAAE,IAAI;QACnB,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,CAAC;QACxD,WAAW,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QACxC,OAAO,EAAE,YAAY;QACrB,UAAU,CAAC,IAAI;YACb,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,IAAA,mBAAW,EAAC,IAAI,CAAC,CAAC;YAC3C,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC;QAC9C,CAAC;KACF,CAAC,CAAC;IAEH;;;;;;;OAOG;IACH,MAAM,aAAa,GAAG,IAAA,uBAAU,EAAC;QAC/B,EAAE,EAAE,gBAAgB;QACpB,IAAI,EAAE,gBAAgB;QACtB,aAAa,EAAE,IAAI;QACnB,UAAU,EAAE,uBAAuB,CAAC,IAAI,CAAC;QACzC,WAAW,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1D,OAAO,EAAE,YAAY;QACrB,UAAU,CAAC,IAAI;YACb,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC1B,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,yBAAa,CAAC,EAAE,CAAC;YACvE,CAAC;YACD,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,IAAI,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,0BAAc,EAAE,UAAU,EAAE,kCAAkC,CAAC;gBAC1F,GAAG,EAAE,EAAE,eAAe,EAAE,UAAU,IAAI,CAAC,KAAK,EAAE,EAAE;aACjD,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;IAEH,yEAAyE;IACzE,MAAM,SAAS,GAAG,IAAA,uBAAU,EAAC;QAC3B,EAAE,EAAE,YAAY;QAChB,IAAI,EAAE,YAAY;QAClB,aAAa,EAAE,IAAI;QACnB,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,eAAe,CAAC;QACvD,WAAW,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACzC,OAAO,EAAE,YAAY;QACrB,UAAU,CAAC,IAAI;YACb,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,IAAA,mBAAW,EAAC,IAAI,CAAC,CAAC;YAC3C,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC;QAChE,CAAC;KACF,CAAC,CAAC;IAEH,mEAAmE;IACnE,OAAO;QACL,uBAAU;QACV,MAAM;QACN,QAAQ;QACR,SAAS;QACT,IAAA,iBAAS,EAAC,IAAI,CAAC;QACf,WAAW;QACX,QAAQ;QACR,KAAK;QACL,aAAa;KACd,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAgB,UAAU;IACxB,OAAO,aAAa,EAAE,CAAC;AACzB,CAAC;AAED,SAAgB,UAAU,CAAC,EAAU;IACnC,OAAO,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AAC/C,CAAC;AAED,0DAA0D;AACnD,KAAK,UAAU,cAAc;IAClC,OAAO,OAAO,CAAC,GAAG,CAChB,UAAU,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;QAChC,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;QACxC,MAAM,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;QACnE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC;IAC3C,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** OAuth 2.0 MCP endpoint — clients implementing the MCP authorization spec
|
|
2
|
+
* drive the browser flow themselves; no credentials are written anywhere. */
|
|
3
|
+
export declare const MCP_OAUTH_URL = "https://mcp.hostafrica.com/mcp";
|
|
4
|
+
/** Bearer-token MCP endpoint — fallback for clients without MCP OAuth support. */
|
|
5
|
+
export declare const MCP_BEARER_URL = "https://api.hostafrica.com/mcp";
|
|
6
|
+
/** Key under which the server is registered in every client's config. */
|
|
7
|
+
export declare const SERVER_KEY = "hostafrica";
|
|
8
|
+
/** Human-facing label for the server. */
|
|
9
|
+
export declare const SERVER_LABEL = "HostAfrica";
|
|
10
|
+
export declare const CLIENT_AREA_URL = "https://panel.hostafrica.com/";
|
|
11
|
+
export declare const DEVELOPER_DOCS_URL = "https://www.hostafrica.com/developers/";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEVELOPER_DOCS_URL = exports.CLIENT_AREA_URL = exports.SERVER_LABEL = exports.SERVER_KEY = exports.MCP_BEARER_URL = exports.MCP_OAUTH_URL = void 0;
|
|
4
|
+
/** OAuth 2.0 MCP endpoint — clients implementing the MCP authorization spec
|
|
5
|
+
* drive the browser flow themselves; no credentials are written anywhere. */
|
|
6
|
+
exports.MCP_OAUTH_URL = "https://mcp.hostafrica.com/mcp";
|
|
7
|
+
/** Bearer-token MCP endpoint — fallback for clients without MCP OAuth support. */
|
|
8
|
+
exports.MCP_BEARER_URL = "https://api.hostafrica.com/mcp";
|
|
9
|
+
/** Key under which the server is registered in every client's config. */
|
|
10
|
+
exports.SERVER_KEY = "hostafrica";
|
|
11
|
+
/** Human-facing label for the server. */
|
|
12
|
+
exports.SERVER_LABEL = "HostAfrica";
|
|
13
|
+
exports.CLIENT_AREA_URL = "https://panel.hostafrica.com/";
|
|
14
|
+
exports.DEVELOPER_DOCS_URL = "https://www.hostafrica.com/developers/";
|
|
15
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAA;8EAC8E;AACjE,QAAA,aAAa,GAAG,gCAAgC,CAAC;AAE9D,kFAAkF;AACrE,QAAA,cAAc,GAAG,gCAAgC,CAAC;AAE/D,yEAAyE;AAC5D,QAAA,UAAU,GAAG,YAAY,CAAC;AAEvC,yCAAyC;AAC5B,QAAA,YAAY,GAAG,YAAY,CAAC;AAE5B,QAAA,eAAe,GAAG,+BAA+B,CAAC;AAClD,QAAA,kBAAkB,GAAG,wCAAwC,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-click Cursor install link for the docs site / client panel — registers
|
|
3
|
+
* the OAuth endpoint with no extension involved. Format per
|
|
4
|
+
* cursor.com/docs/mcp/install-links: base64 of the server's config object.
|
|
5
|
+
*/
|
|
6
|
+
export declare function cursorInstallDeeplink(): string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cursorInstallDeeplink = cursorInstallDeeplink;
|
|
4
|
+
const constants_1 = require("./constants");
|
|
5
|
+
/**
|
|
6
|
+
* One-click Cursor install link for the docs site / client panel — registers
|
|
7
|
+
* the OAuth endpoint with no extension involved. Format per
|
|
8
|
+
* cursor.com/docs/mcp/install-links: base64 of the server's config object.
|
|
9
|
+
*/
|
|
10
|
+
function cursorInstallDeeplink() {
|
|
11
|
+
const config = { type: "http", url: constants_1.MCP_OAUTH_URL };
|
|
12
|
+
const b64 = Buffer.from(JSON.stringify(config), "utf8").toString("base64");
|
|
13
|
+
return `cursor://anysphere.cursor-deeplink/mcp/install?name=${constants_1.SERVER_KEY}&config=${encodeURIComponent(b64)}`;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=deeplinks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deeplinks.js","sourceRoot":"","sources":["../src/deeplinks.ts"],"names":[],"mappings":";;AAOA,sDAIC;AAXD,2CAAwD;AAExD;;;;GAIG;AACH,SAAgB,qBAAqB;IACnC,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,yBAAa,EAAE,CAAC;IACpD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC3E,OAAO,uDAAuD,sBAAU,WAAW,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;AAC/G,CAAC"}
|
package/dist/fsutil.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
declare const execFileP: typeof execFile.__promisify__;
|
|
3
|
+
export declare function exists(p: string): Promise<boolean>;
|
|
4
|
+
/** Locate a binary on PATH (`which` on POSIX, `where` on Windows). */
|
|
5
|
+
export declare function whichBin(bin: string): Promise<string | undefined>;
|
|
6
|
+
export declare function readTextIfPresent(p: string): Promise<string | undefined>;
|
|
7
|
+
/**
|
|
8
|
+
* Write a config file that may contain a bearer token: parent dirs created,
|
|
9
|
+
* mode 600 so other local users can't read it. The mode option on writeFile
|
|
10
|
+
* only applies to newly created files, so chmod explicitly for existing ones
|
|
11
|
+
* (no-op semantics on Windows, where fs permissions work differently).
|
|
12
|
+
*/
|
|
13
|
+
export declare function writePrivate(p: string, content: string): Promise<void>;
|
|
14
|
+
export { execFileP };
|
package/dist/fsutil.js
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.execFileP = void 0;
|
|
37
|
+
exports.exists = exists;
|
|
38
|
+
exports.whichBin = whichBin;
|
|
39
|
+
exports.readTextIfPresent = readTextIfPresent;
|
|
40
|
+
exports.writePrivate = writePrivate;
|
|
41
|
+
const fs = __importStar(require("node:fs/promises"));
|
|
42
|
+
const path = __importStar(require("node:path"));
|
|
43
|
+
const node_child_process_1 = require("node:child_process");
|
|
44
|
+
const node_util_1 = require("node:util");
|
|
45
|
+
const execFileP = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
46
|
+
exports.execFileP = execFileP;
|
|
47
|
+
async function exists(p) {
|
|
48
|
+
try {
|
|
49
|
+
await fs.access(p);
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** Locate a binary on PATH (`which` on POSIX, `where` on Windows). */
|
|
57
|
+
async function whichBin(bin) {
|
|
58
|
+
const finder = process.platform === "win32" ? "where" : "which";
|
|
59
|
+
try {
|
|
60
|
+
const { stdout } = await execFileP(finder, [bin]);
|
|
61
|
+
const first = stdout.split(/\r?\n/).find((l) => l.trim().length > 0);
|
|
62
|
+
return first?.trim();
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function readTextIfPresent(p) {
|
|
69
|
+
try {
|
|
70
|
+
return await fs.readFile(p, "utf8");
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Write a config file that may contain a bearer token: parent dirs created,
|
|
78
|
+
* mode 600 so other local users can't read it. The mode option on writeFile
|
|
79
|
+
* only applies to newly created files, so chmod explicitly for existing ones
|
|
80
|
+
* (no-op semantics on Windows, where fs permissions work differently).
|
|
81
|
+
*/
|
|
82
|
+
async function writePrivate(p, content) {
|
|
83
|
+
await fs.mkdir(path.dirname(p), { recursive: true });
|
|
84
|
+
await fs.writeFile(p, content, { encoding: "utf8", mode: 0o600 });
|
|
85
|
+
if (process.platform !== "win32") {
|
|
86
|
+
await fs.chmod(p, 0o600);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=fsutil.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fsutil.js","sourceRoot":"","sources":["../src/fsutil.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA,wBAOC;AAGD,4BASC;AAED,8CAMC;AAQD,oCAMC;AAhDD,qDAAuC;AACvC,gDAAkC;AAClC,2DAA8C;AAC9C,yCAAsC;AAEtC,MAAM,SAAS,GAAG,IAAA,qBAAS,EAAC,6BAAQ,CAAC,CAAC;AA6C7B,8BAAS;AA3CX,KAAK,UAAU,MAAM,CAAC,CAAS;IACpC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,sEAAsE;AAC/D,KAAK,UAAU,QAAQ,CAAC,GAAW;IACxC,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;IAChE,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACrE,OAAO,KAAK,EAAE,IAAI,EAAE,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,iBAAiB,CAAC,CAAS;IAC/C,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACI,KAAK,UAAU,YAAY,CAAC,CAAS,EAAE,OAAe;IAC3D,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAClE,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from "./constants";
|
|
2
|
+
export * from "./types";
|
|
3
|
+
export { allClients, clientById, clientStatuses, createClients } from "./clients/registry";
|
|
4
|
+
export { jsonClient } from "./clients/jsonClient";
|
|
5
|
+
export type { JsonClientSpec } from "./clients/jsonClient";
|
|
6
|
+
export { claudeAddArgs } from "./clients/claudeCode";
|
|
7
|
+
export { makeCodex } from "./clients/codex";
|
|
8
|
+
export { cursorInstallDeeplink } from "./deeplinks";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.cursorInstallDeeplink = exports.makeCodex = exports.claudeAddArgs = exports.jsonClient = exports.createClients = exports.clientStatuses = exports.clientById = exports.allClients = void 0;
|
|
18
|
+
__exportStar(require("./constants"), exports);
|
|
19
|
+
__exportStar(require("./types"), exports);
|
|
20
|
+
var registry_1 = require("./clients/registry");
|
|
21
|
+
Object.defineProperty(exports, "allClients", { enumerable: true, get: function () { return registry_1.allClients; } });
|
|
22
|
+
Object.defineProperty(exports, "clientById", { enumerable: true, get: function () { return registry_1.clientById; } });
|
|
23
|
+
Object.defineProperty(exports, "clientStatuses", { enumerable: true, get: function () { return registry_1.clientStatuses; } });
|
|
24
|
+
Object.defineProperty(exports, "createClients", { enumerable: true, get: function () { return registry_1.createClients; } });
|
|
25
|
+
var jsonClient_1 = require("./clients/jsonClient");
|
|
26
|
+
Object.defineProperty(exports, "jsonClient", { enumerable: true, get: function () { return jsonClient_1.jsonClient; } });
|
|
27
|
+
var claudeCode_1 = require("./clients/claudeCode");
|
|
28
|
+
Object.defineProperty(exports, "claudeAddArgs", { enumerable: true, get: function () { return claudeCode_1.claudeAddArgs; } });
|
|
29
|
+
var codex_1 = require("./clients/codex");
|
|
30
|
+
Object.defineProperty(exports, "makeCodex", { enumerable: true, get: function () { return codex_1.makeCodex; } });
|
|
31
|
+
var deeplinks_1 = require("./deeplinks");
|
|
32
|
+
Object.defineProperty(exports, "cursorInstallDeeplink", { enumerable: true, get: function () { return deeplinks_1.cursorInstallDeeplink; } });
|
|
33
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,8CAA4B;AAC5B,0CAAwB;AACxB,+CAA2F;AAAlF,sGAAA,UAAU,OAAA;AAAE,sGAAA,UAAU,OAAA;AAAE,0GAAA,cAAc,OAAA;AAAE,yGAAA,aAAa,OAAA;AAC9D,mDAAkD;AAAzC,wGAAA,UAAU,OAAA;AAEnB,mDAAqD;AAA5C,2GAAA,aAAa,OAAA;AACtB,yCAA4C;AAAnC,kGAAA,SAAS,OAAA;AAClB,yCAAoD;AAA3C,kHAAA,qBAAqB,OAAA"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type AuthMode = {
|
|
2
|
+
kind: "oauth";
|
|
3
|
+
} | {
|
|
4
|
+
kind: "token";
|
|
5
|
+
token: string;
|
|
6
|
+
};
|
|
7
|
+
export interface Endpoint {
|
|
8
|
+
url: string;
|
|
9
|
+
headers?: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
/** Resolve the endpoint + headers a given auth mode maps to. */
|
|
12
|
+
export declare function endpointFor(auth: AuthMode): Endpoint;
|
|
13
|
+
export interface RegisterOptions {
|
|
14
|
+
auth: AuthMode;
|
|
15
|
+
}
|
|
16
|
+
export interface McpClient {
|
|
17
|
+
/** Stable id, e.g. "cursor". */
|
|
18
|
+
id: string;
|
|
19
|
+
/** Display name, e.g. "Cursor". */
|
|
20
|
+
name: string;
|
|
21
|
+
/**
|
|
22
|
+
* Whether this client currently implements the MCP authorization spec for
|
|
23
|
+
* remote HTTP servers. Flip per client as support lands — the registrar
|
|
24
|
+
* picks OAuth whenever this is true, token fallback otherwise.
|
|
25
|
+
*/
|
|
26
|
+
supportsOAuth: boolean;
|
|
27
|
+
/** Whether the client appears to be installed on this machine. */
|
|
28
|
+
detect(): Promise<boolean>;
|
|
29
|
+
/** Whether the HostAfrica server is currently registered with this client. */
|
|
30
|
+
isRegistered(): Promise<boolean>;
|
|
31
|
+
register(opts: RegisterOptions): Promise<void>;
|
|
32
|
+
unregister(): Promise<void>;
|
|
33
|
+
/** Where the registration lives (config path or command), for display. */
|
|
34
|
+
describeTarget(): string;
|
|
35
|
+
}
|
|
36
|
+
export interface ClientStatus {
|
|
37
|
+
client: McpClient;
|
|
38
|
+
installed: boolean;
|
|
39
|
+
registered: boolean;
|
|
40
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.endpointFor = endpointFor;
|
|
4
|
+
const constants_1 = require("./constants");
|
|
5
|
+
/** Resolve the endpoint + headers a given auth mode maps to. */
|
|
6
|
+
function endpointFor(auth) {
|
|
7
|
+
if (auth.kind === "oauth") {
|
|
8
|
+
return { url: constants_1.MCP_OAUTH_URL };
|
|
9
|
+
}
|
|
10
|
+
return {
|
|
11
|
+
url: constants_1.MCP_BEARER_URL,
|
|
12
|
+
headers: { Authorization: `Bearer ${auth.token}` },
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;AAYA,kCAQC;AApBD,2CAA4D;AAW5D,gEAAgE;AAChE,SAAgB,WAAW,CAAC,IAAc;IACxC,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QAC1B,OAAO,EAAE,GAAG,EAAE,yBAAa,EAAE,CAAC;IAChC,CAAC;IACD,OAAO;QACL,GAAG,EAAE,0BAAc;QACnB,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,KAAK,EAAE,EAAE;KACnD,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hostafrica/connector-core",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Registrar core for the HostAfrica Connector: detects AI clients and registers the HostAfrica MCP server with each, OAuth-first",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/hostafrica-dev/ha-connector.git",
|
|
9
|
+
"directory": "packages/core"
|
|
10
|
+
},
|
|
11
|
+
"main": "dist/index.js",
|
|
12
|
+
"types": "dist/index.d.ts",
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc -p .",
|
|
18
|
+
"check": "tsc -p . --noEmit",
|
|
19
|
+
"test": "tsc -p tsconfig.test.json && node --test \"dist-test/test/*.test.js\""
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"smol-toml": "^1.3.1"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/node": "^20.14.0",
|
|
26
|
+
"typescript": "^5.5.4"
|
|
27
|
+
}
|
|
28
|
+
}
|