@hasna/mcps 0.0.12 → 0.0.13
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/bin/index.js +749 -597
- package/bin/mcp.js +21460 -21306
- package/dist/mcp/index.d.ts +4 -0
- package/dist/mcp/index.js +35019 -0
- package/dist/mcp/server.d.ts +10 -0
- package/dist/mcp/tools.d.ts +14 -0
- package/package.json +10 -2
package/bin/index.js
CHANGED
|
@@ -19288,15 +19288,23 @@ var init_sources = __esm(() => {
|
|
|
19288
19288
|
var require_package = __commonJS((exports, module) => {
|
|
19289
19289
|
module.exports = {
|
|
19290
19290
|
name: "@hasna/mcps",
|
|
19291
|
-
version: "0.0.
|
|
19291
|
+
version: "0.0.13",
|
|
19292
19292
|
description: "Meta-MCP registry & CLI \u2014 discover, manage, and proxy MCP servers",
|
|
19293
19293
|
type: "module",
|
|
19294
|
+
repository: {
|
|
19295
|
+
type: "git",
|
|
19296
|
+
url: "https://github.com/hasna/mcps.git"
|
|
19297
|
+
},
|
|
19294
19298
|
main: "dist/index.js",
|
|
19295
19299
|
types: "dist/index.d.ts",
|
|
19296
19300
|
exports: {
|
|
19297
19301
|
".": {
|
|
19298
19302
|
import: "./dist/index.js",
|
|
19299
19303
|
types: "./dist/index.d.ts"
|
|
19304
|
+
},
|
|
19305
|
+
"./mcp": {
|
|
19306
|
+
import: "./dist/mcp/index.js",
|
|
19307
|
+
types: "./dist/mcp/index.d.ts"
|
|
19300
19308
|
}
|
|
19301
19309
|
},
|
|
19302
19310
|
bin: {
|
|
@@ -19311,7 +19319,7 @@ var require_package = __commonJS((exports, module) => {
|
|
|
19311
19319
|
"README.md"
|
|
19312
19320
|
],
|
|
19313
19321
|
scripts: {
|
|
19314
|
-
build: "bun run build:dashboard && bun build ./src/cli/index.tsx --outdir ./bin --target bun --external ink --external react --external chalk && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun run scripts/fix-shebangs.ts && bun build ./src/index.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
19322
|
+
build: "bun run build:dashboard && bun build ./src/cli/index.tsx --outdir ./bin --target bun --external ink --external react --external chalk && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun run scripts/fix-shebangs.ts && bun build ./src/index.ts --outdir ./dist --target bun && bun build ./src/mcp/index.ts --outdir ./dist/mcp --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
|
|
19315
19323
|
"build:dashboard": "cd dashboard && bun install && bun run build",
|
|
19316
19324
|
dev: "bun run src/cli/index.tsx",
|
|
19317
19325
|
"dev:mcp": "bun run src/mcp/index.ts",
|
|
@@ -36762,6 +36770,68 @@ async function runFleetInstall(options = {}, dependencies = {}) {
|
|
|
36762
36770
|
// src/cli/index.tsx
|
|
36763
36771
|
import * as readline from "readline";
|
|
36764
36772
|
|
|
36773
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
36774
|
+
import process3 from "process";
|
|
36775
|
+
class StdioServerTransport {
|
|
36776
|
+
constructor(_stdin = process3.stdin, _stdout = process3.stdout) {
|
|
36777
|
+
this._stdin = _stdin;
|
|
36778
|
+
this._stdout = _stdout;
|
|
36779
|
+
this._readBuffer = new ReadBuffer;
|
|
36780
|
+
this._started = false;
|
|
36781
|
+
this._ondata = (chunk) => {
|
|
36782
|
+
this._readBuffer.append(chunk);
|
|
36783
|
+
this.processReadBuffer();
|
|
36784
|
+
};
|
|
36785
|
+
this._onerror = (error2) => {
|
|
36786
|
+
this.onerror?.(error2);
|
|
36787
|
+
};
|
|
36788
|
+
}
|
|
36789
|
+
async start() {
|
|
36790
|
+
if (this._started) {
|
|
36791
|
+
throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");
|
|
36792
|
+
}
|
|
36793
|
+
this._started = true;
|
|
36794
|
+
this._stdin.on("data", this._ondata);
|
|
36795
|
+
this._stdin.on("error", this._onerror);
|
|
36796
|
+
}
|
|
36797
|
+
processReadBuffer() {
|
|
36798
|
+
while (true) {
|
|
36799
|
+
try {
|
|
36800
|
+
const message = this._readBuffer.readMessage();
|
|
36801
|
+
if (message === null) {
|
|
36802
|
+
break;
|
|
36803
|
+
}
|
|
36804
|
+
this.onmessage?.(message);
|
|
36805
|
+
} catch (error2) {
|
|
36806
|
+
this.onerror?.(error2);
|
|
36807
|
+
}
|
|
36808
|
+
}
|
|
36809
|
+
}
|
|
36810
|
+
async close() {
|
|
36811
|
+
this._stdin.off("data", this._ondata);
|
|
36812
|
+
this._stdin.off("error", this._onerror);
|
|
36813
|
+
const remainingDataListeners = this._stdin.listenerCount("data");
|
|
36814
|
+
if (remainingDataListeners === 0) {
|
|
36815
|
+
this._stdin.pause();
|
|
36816
|
+
}
|
|
36817
|
+
this._readBuffer.clear();
|
|
36818
|
+
this.onclose?.();
|
|
36819
|
+
}
|
|
36820
|
+
send(message) {
|
|
36821
|
+
return new Promise((resolve) => {
|
|
36822
|
+
const json = serializeMessage(message);
|
|
36823
|
+
if (this._stdout.write(json)) {
|
|
36824
|
+
resolve();
|
|
36825
|
+
} else {
|
|
36826
|
+
this._stdout.once("drain", resolve);
|
|
36827
|
+
}
|
|
36828
|
+
});
|
|
36829
|
+
}
|
|
36830
|
+
}
|
|
36831
|
+
|
|
36832
|
+
// src/mcp/server.ts
|
|
36833
|
+
init_dist();
|
|
36834
|
+
|
|
36765
36835
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
|
|
36766
36836
|
class ExperimentalServerTasks {
|
|
36767
36837
|
constructor(_server) {
|
|
@@ -37923,71 +37993,6 @@ var EMPTY_COMPLETION_RESULT = {
|
|
|
37923
37993
|
}
|
|
37924
37994
|
};
|
|
37925
37995
|
|
|
37926
|
-
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
37927
|
-
import process3 from "process";
|
|
37928
|
-
class StdioServerTransport {
|
|
37929
|
-
constructor(_stdin = process3.stdin, _stdout = process3.stdout) {
|
|
37930
|
-
this._stdin = _stdin;
|
|
37931
|
-
this._stdout = _stdout;
|
|
37932
|
-
this._readBuffer = new ReadBuffer;
|
|
37933
|
-
this._started = false;
|
|
37934
|
-
this._ondata = (chunk) => {
|
|
37935
|
-
this._readBuffer.append(chunk);
|
|
37936
|
-
this.processReadBuffer();
|
|
37937
|
-
};
|
|
37938
|
-
this._onerror = (error2) => {
|
|
37939
|
-
this.onerror?.(error2);
|
|
37940
|
-
};
|
|
37941
|
-
}
|
|
37942
|
-
async start() {
|
|
37943
|
-
if (this._started) {
|
|
37944
|
-
throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");
|
|
37945
|
-
}
|
|
37946
|
-
this._started = true;
|
|
37947
|
-
this._stdin.on("data", this._ondata);
|
|
37948
|
-
this._stdin.on("error", this._onerror);
|
|
37949
|
-
}
|
|
37950
|
-
processReadBuffer() {
|
|
37951
|
-
while (true) {
|
|
37952
|
-
try {
|
|
37953
|
-
const message = this._readBuffer.readMessage();
|
|
37954
|
-
if (message === null) {
|
|
37955
|
-
break;
|
|
37956
|
-
}
|
|
37957
|
-
this.onmessage?.(message);
|
|
37958
|
-
} catch (error2) {
|
|
37959
|
-
this.onerror?.(error2);
|
|
37960
|
-
}
|
|
37961
|
-
}
|
|
37962
|
-
}
|
|
37963
|
-
async close() {
|
|
37964
|
-
this._stdin.off("data", this._ondata);
|
|
37965
|
-
this._stdin.off("error", this._onerror);
|
|
37966
|
-
const remainingDataListeners = this._stdin.listenerCount("data");
|
|
37967
|
-
if (remainingDataListeners === 0) {
|
|
37968
|
-
this._stdin.pause();
|
|
37969
|
-
}
|
|
37970
|
-
this._readBuffer.clear();
|
|
37971
|
-
this.onclose?.();
|
|
37972
|
-
}
|
|
37973
|
-
send(message) {
|
|
37974
|
-
return new Promise((resolve) => {
|
|
37975
|
-
const json = serializeMessage(message);
|
|
37976
|
-
if (this._stdout.write(json)) {
|
|
37977
|
-
resolve();
|
|
37978
|
-
} else {
|
|
37979
|
-
this._stdout.once("drain", resolve);
|
|
37980
|
-
}
|
|
37981
|
-
});
|
|
37982
|
-
}
|
|
37983
|
-
}
|
|
37984
|
-
|
|
37985
|
-
// src/mcp/index.ts
|
|
37986
|
-
init_dist();
|
|
37987
|
-
init_sources();
|
|
37988
|
-
init_config2();
|
|
37989
|
-
init_db();
|
|
37990
|
-
|
|
37991
37996
|
// src/lib/version.ts
|
|
37992
37997
|
import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
|
|
37993
37998
|
import { dirname as dirname3, join as join10 } from "path";
|
|
@@ -38012,463 +38017,610 @@ function readPackageVersion(moduleUrl, fallback = FALLBACK_VERSION) {
|
|
|
38012
38017
|
return fallback;
|
|
38013
38018
|
}
|
|
38014
38019
|
|
|
38015
|
-
// src/mcp/
|
|
38020
|
+
// src/mcp/tools.ts
|
|
38021
|
+
init_sources();
|
|
38022
|
+
init_config2();
|
|
38023
|
+
init_db();
|
|
38024
|
+
var VERSION = readPackageVersion(import.meta.url);
|
|
38025
|
+
var mcpsAgents = new Map;
|
|
38016
38026
|
function redactServerEnv(server) {
|
|
38017
38027
|
return { ...server, env: {} };
|
|
38018
38028
|
}
|
|
38019
|
-
|
|
38020
|
-
return
|
|
38021
|
-
}
|
|
38022
|
-
|
|
38023
|
-
|
|
38024
|
-
|
|
38025
|
-
|
|
38026
|
-
|
|
38027
|
-
|
|
38028
|
-
|
|
38029
|
-
|
|
38030
|
-
|
|
38031
|
-
|
|
38032
|
-
|
|
38033
|
-
|
|
38034
|
-
|
|
38035
|
-
|
|
38036
|
-
|
|
38037
|
-
|
|
38038
|
-
|
|
38039
|
-
|
|
38040
|
-
|
|
38041
|
-
|
|
38042
|
-
|
|
38043
|
-
|
|
38044
|
-
|
|
38045
|
-
|
|
38046
|
-
|
|
38047
|
-
|
|
38048
|
-
|
|
38049
|
-
|
|
38050
|
-
|
|
38051
|
-
|
|
38052
|
-
|
|
38053
|
-
|
|
38054
|
-
|
|
38055
|
-
|
|
38056
|
-
|
|
38057
|
-
|
|
38058
|
-
|
|
38059
|
-
|
|
38060
|
-
|
|
38061
|
-
|
|
38062
|
-
|
|
38063
|
-
|
|
38064
|
-
|
|
38065
|
-
|
|
38066
|
-
|
|
38067
|
-
|
|
38068
|
-
|
|
38069
|
-
|
|
38070
|
-
|
|
38071
|
-
|
|
38072
|
-
|
|
38073
|
-
|
|
38074
|
-
|
|
38075
|
-
|
|
38076
|
-
|
|
38077
|
-
|
|
38078
|
-
|
|
38079
|
-
});
|
|
38080
|
-
|
|
38081
|
-
|
|
38082
|
-
|
|
38083
|
-
|
|
38084
|
-
|
|
38085
|
-
|
|
38086
|
-
|
|
38029
|
+
function textContent(text) {
|
|
38030
|
+
return { content: [{ type: "text", text }] };
|
|
38031
|
+
}
|
|
38032
|
+
function jsonContent(value) {
|
|
38033
|
+
return textContent(JSON.stringify(value, null, 2));
|
|
38034
|
+
}
|
|
38035
|
+
function errorContent(text) {
|
|
38036
|
+
return { ...textContent(text), isError: true };
|
|
38037
|
+
}
|
|
38038
|
+
function buildMcpTools() {
|
|
38039
|
+
const definitions = [
|
|
38040
|
+
{
|
|
38041
|
+
name: "list_servers",
|
|
38042
|
+
description: "List all registered MCP servers",
|
|
38043
|
+
paramsSchema: {},
|
|
38044
|
+
run: () => jsonContent(listServers().map(redactServerEnv))
|
|
38045
|
+
},
|
|
38046
|
+
{
|
|
38047
|
+
name: "search_registry",
|
|
38048
|
+
description: "Search the official MCP registry for servers",
|
|
38049
|
+
paramsSchema: { query: exports_external2.string().describe("Search query") },
|
|
38050
|
+
run: async ({ query }) => jsonContent(await searchRegistry(String(query)))
|
|
38051
|
+
},
|
|
38052
|
+
{
|
|
38053
|
+
name: "add_server",
|
|
38054
|
+
description: "Register a new MCP server",
|
|
38055
|
+
paramsSchema: {
|
|
38056
|
+
command: exports_external2.string().describe("Command to run the server (e.g., npx, bunx, node)"),
|
|
38057
|
+
args: exports_external2.array(exports_external2.string()).optional().describe("Arguments for the command"),
|
|
38058
|
+
name: exports_external2.string().optional().describe("Display name"),
|
|
38059
|
+
description: exports_external2.string().optional().describe("Description"),
|
|
38060
|
+
transport: exports_external2.enum(["stdio", "sse", "streamable-http"]).optional().describe("Transport type"),
|
|
38061
|
+
url: exports_external2.string().optional().describe("URL for remote transports"),
|
|
38062
|
+
env: exports_external2.record(exports_external2.string()).optional().describe("Environment variables")
|
|
38063
|
+
},
|
|
38064
|
+
run: ({ command, args, name, description, transport, url: url2, env }) => jsonContent(addServer({
|
|
38065
|
+
command: String(command),
|
|
38066
|
+
args: Array.isArray(args) ? args.map(String) : [],
|
|
38067
|
+
name: typeof name === "string" ? name : undefined,
|
|
38068
|
+
description: typeof description === "string" ? description : undefined,
|
|
38069
|
+
transport,
|
|
38070
|
+
url: typeof url2 === "string" ? url2 : undefined,
|
|
38071
|
+
env: isRecordOfStrings(env) ? env : {}
|
|
38072
|
+
}))
|
|
38073
|
+
},
|
|
38074
|
+
{
|
|
38075
|
+
name: "install_from_registry",
|
|
38076
|
+
description: "Install an MCP server from the official registry",
|
|
38077
|
+
paramsSchema: { id: exports_external2.string().describe("Registry server ID") },
|
|
38078
|
+
run: async ({ id }) => jsonContent(await installFromRegistry(String(id)))
|
|
38079
|
+
},
|
|
38080
|
+
{
|
|
38081
|
+
name: "remove_server",
|
|
38082
|
+
description: "Remove a registered MCP server",
|
|
38083
|
+
paramsSchema: { id: exports_external2.string().describe("Server ID to remove") },
|
|
38084
|
+
run: ({ id }) => {
|
|
38085
|
+
const existing = getServer(String(id));
|
|
38086
|
+
if (!existing)
|
|
38087
|
+
return errorContent(`Server "${String(id)}" not found.`);
|
|
38088
|
+
removeServer(String(id));
|
|
38089
|
+
return textContent(`Removed server: ${existing.name} [${String(id)}]`);
|
|
38090
|
+
}
|
|
38091
|
+
},
|
|
38092
|
+
{
|
|
38093
|
+
name: "enable_server",
|
|
38094
|
+
description: "Enable a registered MCP server",
|
|
38095
|
+
paramsSchema: { id: exports_external2.string().describe("Server ID to enable") },
|
|
38096
|
+
run: ({ id }) => {
|
|
38097
|
+
const existing = getServer(String(id));
|
|
38098
|
+
if (!existing)
|
|
38099
|
+
return errorContent(`Server "${String(id)}" not found.`);
|
|
38100
|
+
return jsonContent(enableServer(String(id)));
|
|
38101
|
+
}
|
|
38102
|
+
},
|
|
38103
|
+
{
|
|
38104
|
+
name: "disable_server",
|
|
38105
|
+
description: "Disable a registered MCP server",
|
|
38106
|
+
paramsSchema: { id: exports_external2.string().describe("Server ID to disable") },
|
|
38107
|
+
run: ({ id }) => {
|
|
38108
|
+
const existing = getServer(String(id));
|
|
38109
|
+
if (!existing)
|
|
38110
|
+
return errorContent(`Server "${String(id)}" not found.`);
|
|
38111
|
+
return jsonContent(disableServer(String(id)));
|
|
38112
|
+
}
|
|
38113
|
+
},
|
|
38114
|
+
{
|
|
38115
|
+
name: "update_server",
|
|
38116
|
+
description: "Update fields of a registered MCP server",
|
|
38117
|
+
paramsSchema: {
|
|
38118
|
+
id: exports_external2.string().describe("Server ID to update"),
|
|
38119
|
+
name: exports_external2.string().optional().describe("New display name"),
|
|
38120
|
+
description: exports_external2.string().optional().describe("New description"),
|
|
38121
|
+
command: exports_external2.string().optional().describe("New command"),
|
|
38122
|
+
args: exports_external2.array(exports_external2.string()).optional().describe("New args list"),
|
|
38123
|
+
transport: exports_external2.enum(["stdio", "sse", "streamable-http"]).optional().describe("New transport type"),
|
|
38124
|
+
url: exports_external2.string().optional().describe("New URL for remote transports")
|
|
38125
|
+
},
|
|
38126
|
+
run: ({ id, name, description, command, args, transport, url: url2 }) => {
|
|
38127
|
+
const serverId = String(id);
|
|
38128
|
+
const existing = getServer(serverId);
|
|
38129
|
+
if (!existing)
|
|
38130
|
+
return errorContent(`Server "${serverId}" not found.`);
|
|
38131
|
+
const fields = {};
|
|
38132
|
+
if (typeof name === "string")
|
|
38133
|
+
fields.name = name;
|
|
38134
|
+
if (typeof description === "string")
|
|
38135
|
+
fields.description = description;
|
|
38136
|
+
if (typeof command === "string")
|
|
38137
|
+
fields.command = command;
|
|
38138
|
+
if (Array.isArray(args))
|
|
38139
|
+
fields.args = args.map(String);
|
|
38140
|
+
if (transport === "stdio" || transport === "sse" || transport === "streamable-http")
|
|
38141
|
+
fields.transport = transport;
|
|
38142
|
+
if (typeof url2 === "string")
|
|
38143
|
+
fields.url = url2;
|
|
38144
|
+
return jsonContent(redactServerEnv(updateServer(serverId, fields)));
|
|
38145
|
+
}
|
|
38146
|
+
},
|
|
38147
|
+
{
|
|
38148
|
+
name: "list_tools",
|
|
38149
|
+
description: "List all cached tools across registered servers without connecting. Optionally filter by server_id.",
|
|
38150
|
+
paramsSchema: { server_id: exports_external2.string().optional().describe("Server ID to filter by (optional)") },
|
|
38151
|
+
run: ({ server_id }) => {
|
|
38152
|
+
if (typeof server_id === "string" && server_id) {
|
|
38153
|
+
const toolsForServer = getCachedTools(server_id);
|
|
38154
|
+
return jsonContent(toolsForServer.map((tool) => ({ ...tool, server_id })));
|
|
38155
|
+
}
|
|
38156
|
+
const allTools = [];
|
|
38157
|
+
for (const server of listServers()) {
|
|
38158
|
+
for (const tool of getCachedTools(server.id)) {
|
|
38159
|
+
allTools.push({ server_id: server.id, ...tool });
|
|
38160
|
+
}
|
|
38161
|
+
}
|
|
38162
|
+
return jsonContent(allTools);
|
|
38163
|
+
}
|
|
38164
|
+
},
|
|
38165
|
+
{
|
|
38166
|
+
name: "get_server_info",
|
|
38167
|
+
description: "Get detailed information about a registered MCP server",
|
|
38168
|
+
paramsSchema: { id: exports_external2.string().describe("Server ID") },
|
|
38169
|
+
run: ({ id }) => {
|
|
38170
|
+
const entry = getServer(String(id));
|
|
38171
|
+
if (!entry)
|
|
38172
|
+
return errorContent(`Server "${String(id)}" not found.`);
|
|
38173
|
+
return jsonContent(redactServerEnv(entry));
|
|
38174
|
+
}
|
|
38175
|
+
},
|
|
38176
|
+
{
|
|
38177
|
+
name: "find_mcp_servers",
|
|
38178
|
+
description: "Search for MCP servers across configured sources (official registry, npm, GitHub topics, awesome lists). Use list_sources to see available source IDs.",
|
|
38179
|
+
paramsSchema: {
|
|
38180
|
+
query: exports_external2.string().describe("Search query (e.g., 'filesystem', 'postgres', 'browser')"),
|
|
38181
|
+
sources: exports_external2.array(exports_external2.string()).optional().describe("Source IDs to search (default: all enabled). Use list_sources to get IDs."),
|
|
38182
|
+
limit: exports_external2.number().optional().describe("Max results per source (default: 20)")
|
|
38183
|
+
},
|
|
38184
|
+
run: async ({ query, sources, limit }) => jsonContent(await findServers(String(query), {
|
|
38185
|
+
sources: Array.isArray(sources) ? sources.map(String) : undefined,
|
|
38186
|
+
limit: typeof limit === "number" ? limit : undefined
|
|
38187
|
+
}))
|
|
38188
|
+
},
|
|
38189
|
+
{
|
|
38190
|
+
name: "list_sources",
|
|
38191
|
+
description: "List all configured search sources for finding MCP servers",
|
|
38192
|
+
paramsSchema: {},
|
|
38193
|
+
run: () => jsonContent(listSources())
|
|
38194
|
+
},
|
|
38195
|
+
{
|
|
38196
|
+
name: "add_source",
|
|
38197
|
+
description: "Add a new search source for finding MCP servers",
|
|
38198
|
+
paramsSchema: {
|
|
38199
|
+
name: exports_external2.string().describe("Source name"),
|
|
38200
|
+
type: exports_external2.enum(["mcp-registry", "awesome-list", "npm-search", "github-topic"]).describe("Source type"),
|
|
38201
|
+
url: exports_external2.string().describe("Source URL endpoint"),
|
|
38202
|
+
description: exports_external2.string().optional().describe("Description")
|
|
38203
|
+
},
|
|
38204
|
+
run: ({ name, type, url: url2, description }) => jsonContent(addSource({
|
|
38205
|
+
name: String(name),
|
|
38206
|
+
type,
|
|
38207
|
+
url: String(url2),
|
|
38208
|
+
description: typeof description === "string" ? description : undefined
|
|
38209
|
+
}))
|
|
38210
|
+
},
|
|
38211
|
+
{
|
|
38212
|
+
name: "remove_source",
|
|
38213
|
+
description: "Remove a search source by ID",
|
|
38214
|
+
paramsSchema: { id: exports_external2.string().describe("Source ID to remove") },
|
|
38215
|
+
run: ({ id }) => {
|
|
38216
|
+
const sourceId = String(id);
|
|
38217
|
+
const existing = getSource(sourceId);
|
|
38218
|
+
if (!existing)
|
|
38219
|
+
return errorContent(`Source "${sourceId}" not found.`);
|
|
38220
|
+
removeSource(sourceId);
|
|
38221
|
+
return textContent(`Removed source: ${existing.name} [${sourceId}]`);
|
|
38222
|
+
}
|
|
38223
|
+
},
|
|
38224
|
+
{
|
|
38225
|
+
name: "enable_source_finder",
|
|
38226
|
+
description: "Enable a search source",
|
|
38227
|
+
paramsSchema: { id: exports_external2.string().describe("Source ID to enable") },
|
|
38228
|
+
run: ({ id }) => {
|
|
38229
|
+
const sourceId = String(id);
|
|
38230
|
+
const existing = getSource(sourceId);
|
|
38231
|
+
if (!existing)
|
|
38232
|
+
return errorContent(`Source "${sourceId}" not found.`);
|
|
38233
|
+
enableSource(sourceId);
|
|
38234
|
+
return textContent(`Enabled source: ${existing.name}`);
|
|
38235
|
+
}
|
|
38236
|
+
},
|
|
38237
|
+
{
|
|
38238
|
+
name: "disable_source_finder",
|
|
38239
|
+
description: "Disable a search source",
|
|
38240
|
+
paramsSchema: { id: exports_external2.string().describe("Source ID to disable") },
|
|
38241
|
+
run: ({ id }) => {
|
|
38242
|
+
const sourceId = String(id);
|
|
38243
|
+
const existing = getSource(sourceId);
|
|
38244
|
+
if (!existing)
|
|
38245
|
+
return errorContent(`Source "${sourceId}" not found.`);
|
|
38246
|
+
disableSource(sourceId);
|
|
38247
|
+
return textContent(`Disabled source: ${existing.name}`);
|
|
38248
|
+
}
|
|
38249
|
+
},
|
|
38250
|
+
{
|
|
38251
|
+
name: "install_to_agents",
|
|
38252
|
+
description: "Install a registered MCP server into Claude Code, Codex, and/or Gemini",
|
|
38253
|
+
paramsSchema: {
|
|
38254
|
+
id: exports_external2.string().describe("Server ID to install (from list_servers)"),
|
|
38255
|
+
targets: exports_external2.array(exports_external2.enum(["claude", "codex", "gemini"])).optional().describe("Target agents to install into (default: all)")
|
|
38256
|
+
},
|
|
38257
|
+
run: ({ id, targets }) => {
|
|
38258
|
+
const serverId = String(id);
|
|
38259
|
+
const entry = getServer(serverId);
|
|
38260
|
+
if (!entry)
|
|
38261
|
+
return errorContent(`Server "${serverId}" not found.`);
|
|
38262
|
+
const agentTargets = Array.isArray(targets) ? targets : undefined;
|
|
38263
|
+
return jsonContent(installToAgents(entry, agentTargets ?? ["claude", "codex", "gemini"]));
|
|
38264
|
+
}
|
|
38265
|
+
},
|
|
38266
|
+
{
|
|
38267
|
+
name: "list_awesome_servers",
|
|
38268
|
+
description: "List all MCP servers from the curated punkpeye/awesome-mcp-servers GitHub list",
|
|
38269
|
+
paramsSchema: {},
|
|
38270
|
+
run: async () => jsonContent(await listAwesomeServers())
|
|
38271
|
+
},
|
|
38272
|
+
{
|
|
38273
|
+
name: "connect_and_list_tools",
|
|
38274
|
+
description: "Connect to all enabled MCP servers and list their available tools",
|
|
38275
|
+
paramsSchema: {},
|
|
38276
|
+
run: async () => {
|
|
38277
|
+
let liveTools = [];
|
|
38278
|
+
try {
|
|
38279
|
+
await connectAllEnabled();
|
|
38280
|
+
liveTools = listAllTools();
|
|
38281
|
+
} finally {
|
|
38282
|
+
await disconnectAll().catch(() => {
|
|
38283
|
+
return;
|
|
38284
|
+
});
|
|
38285
|
+
}
|
|
38286
|
+
return jsonContent(liveTools);
|
|
38287
|
+
}
|
|
38288
|
+
},
|
|
38289
|
+
{
|
|
38290
|
+
name: "call_upstream_tool",
|
|
38291
|
+
description: `Call a tool on a connected upstream MCP server. Tool name format: server_id${TOOL_PREFIX_SEPARATOR}tool_name`,
|
|
38292
|
+
paramsSchema: {
|
|
38293
|
+
tool_name: exports_external2.string().describe(`Prefixed tool name (server_id${TOOL_PREFIX_SEPARATOR}tool_name)`),
|
|
38294
|
+
arguments: exports_external2.record(exports_external2.unknown()).optional().describe("Tool arguments as key-value pairs")
|
|
38295
|
+
},
|
|
38296
|
+
run: async ({ tool_name, arguments: args }) => {
|
|
38297
|
+
try {
|
|
38298
|
+
const toolName = String(tool_name);
|
|
38299
|
+
const sepIdx = toolName.indexOf(TOOL_PREFIX_SEPARATOR);
|
|
38300
|
+
if (sepIdx === -1)
|
|
38301
|
+
return errorContent(`Error: Invalid tool name "${toolName}"`);
|
|
38302
|
+
const serverId = toolName.slice(0, sepIdx);
|
|
38303
|
+
const entry = getServer(serverId);
|
|
38304
|
+
if (!entry)
|
|
38305
|
+
return errorContent(`Error: Server "${serverId}" not found.`);
|
|
38306
|
+
if (!entry.enabled)
|
|
38307
|
+
return errorContent(`Error: Server "${serverId}" is disabled.`);
|
|
38308
|
+
await connectToServer(entry);
|
|
38309
|
+
const result = await callTool(toolName, readRecord(args));
|
|
38310
|
+
return { content: result.content };
|
|
38311
|
+
} catch (error2) {
|
|
38312
|
+
return errorContent(`Error: ${error2.message}`);
|
|
38313
|
+
}
|
|
38314
|
+
}
|
|
38315
|
+
},
|
|
38316
|
+
{
|
|
38317
|
+
name: "diagnose_server",
|
|
38318
|
+
description: "Run health checks on a registered MCP server",
|
|
38319
|
+
paramsSchema: { id: exports_external2.string().describe("Server ID") },
|
|
38320
|
+
run: async ({ id }) => {
|
|
38321
|
+
const serverId = String(id);
|
|
38322
|
+
const entry = getServer(serverId);
|
|
38323
|
+
if (!entry)
|
|
38324
|
+
return errorContent(`Server "${serverId}" not found.`);
|
|
38325
|
+
return jsonContent(await diagnoseServer(entry));
|
|
38326
|
+
}
|
|
38327
|
+
},
|
|
38328
|
+
{
|
|
38329
|
+
name: "list_machines",
|
|
38330
|
+
description: "List registered fleet machines",
|
|
38331
|
+
paramsSchema: {
|
|
38332
|
+
enabled_only: exports_external2.boolean().optional().describe("When true, only return enabled machines")
|
|
38333
|
+
},
|
|
38334
|
+
run: ({ enabled_only }) => jsonContent(listMachines().filter((machine) => enabled_only === true ? machine.enabled : true))
|
|
38335
|
+
},
|
|
38336
|
+
{
|
|
38337
|
+
name: "add_machine",
|
|
38338
|
+
description: "Register a machine for fleet health checks and installs",
|
|
38339
|
+
paramsSchema: {
|
|
38340
|
+
host: exports_external2.string().describe("Hostname or SSH target"),
|
|
38341
|
+
id: exports_external2.string().optional().describe("Stable machine ID"),
|
|
38342
|
+
name: exports_external2.string().optional().describe("Display name"),
|
|
38343
|
+
username: exports_external2.string().optional().describe("SSH username"),
|
|
38344
|
+
port: exports_external2.number().int().min(1).max(65535).optional().describe("SSH port"),
|
|
38345
|
+
platform: exports_external2.enum(["linux", "darwin", "unknown"]).optional().describe("Machine platform"),
|
|
38346
|
+
arch: exports_external2.enum(["arm64", "x64", "unknown"]).optional().describe("Machine architecture"),
|
|
38347
|
+
bun_path: exports_external2.string().optional().describe("Explicit path to bun on the remote machine"),
|
|
38348
|
+
npm_path: exports_external2.string().optional().describe("Explicit path to npm on the remote machine"),
|
|
38349
|
+
installer: exports_external2.enum(["auto", "bun", "npm"]).optional().describe("Preferred installer"),
|
|
38350
|
+
ssh_key_path: exports_external2.string().optional().describe("SSH private key path"),
|
|
38351
|
+
enabled: exports_external2.boolean().optional().describe("Whether the machine should be enabled")
|
|
38352
|
+
},
|
|
38353
|
+
run: ({ host, id, name, username, port, platform: platform2, arch, bun_path, npm_path, installer, ssh_key_path, enabled }) => jsonContent(addMachine({
|
|
38354
|
+
host: String(host),
|
|
38355
|
+
id: typeof id === "string" ? id : undefined,
|
|
38356
|
+
name: typeof name === "string" ? name : undefined,
|
|
38357
|
+
username: typeof username === "string" ? username : undefined,
|
|
38358
|
+
port: typeof port === "number" ? port : undefined,
|
|
38359
|
+
platform: platform2,
|
|
38360
|
+
arch,
|
|
38361
|
+
bun_path: typeof bun_path === "string" ? bun_path : undefined,
|
|
38362
|
+
npm_path: typeof npm_path === "string" ? npm_path : undefined,
|
|
38363
|
+
installer,
|
|
38364
|
+
ssh_key_path: typeof ssh_key_path === "string" ? ssh_key_path : undefined,
|
|
38365
|
+
enabled: typeof enabled === "boolean" ? enabled : undefined
|
|
38366
|
+
}))
|
|
38367
|
+
},
|
|
38368
|
+
{
|
|
38369
|
+
name: "remove_machine",
|
|
38370
|
+
description: "Remove a registered machine",
|
|
38371
|
+
paramsSchema: { id: exports_external2.string().describe("Machine ID to remove") },
|
|
38372
|
+
run: ({ id }) => {
|
|
38373
|
+
const machineId = String(id);
|
|
38374
|
+
const machine = getMachine(machineId);
|
|
38375
|
+
if (!machine)
|
|
38376
|
+
return errorContent(`Machine "${machineId}" not found.`);
|
|
38377
|
+
removeMachine(machineId);
|
|
38378
|
+
return jsonContent({ removed: true, machine });
|
|
38379
|
+
}
|
|
38380
|
+
},
|
|
38381
|
+
{
|
|
38382
|
+
name: "seed_default_machines",
|
|
38383
|
+
description: "Seed the standard spark/apple machine inventory",
|
|
38384
|
+
paramsSchema: {},
|
|
38385
|
+
run: () => jsonContent(seedDefaultMachines())
|
|
38386
|
+
},
|
|
38387
|
+
{
|
|
38388
|
+
name: "list_hasna_mcp_catalog",
|
|
38389
|
+
description: "List the discovered @hasna MCP package catalog",
|
|
38390
|
+
paramsSchema: {
|
|
38391
|
+
packages: exports_external2.array(exports_external2.string()).optional().describe("Optional package-name filter"),
|
|
38392
|
+
refresh: exports_external2.boolean().optional().describe("Refresh npm metadata instead of using cache")
|
|
38393
|
+
},
|
|
38394
|
+
run: async ({ packages, refresh }) => {
|
|
38395
|
+
const catalog = await listHasnaMcpCatalog({ refresh: refresh === true });
|
|
38396
|
+
const filtered = Array.isArray(packages) && packages.length > 0 ? catalog.filter((entry) => packages.map(String).includes(entry.name)) : catalog;
|
|
38397
|
+
return jsonContent(filtered);
|
|
38398
|
+
}
|
|
38399
|
+
},
|
|
38400
|
+
{
|
|
38401
|
+
name: "fleet_health",
|
|
38402
|
+
description: "Run fleet-wide MCP health checks across registered machines",
|
|
38403
|
+
paramsSchema: {
|
|
38404
|
+
machine_ids: exports_external2.array(exports_external2.string()).optional().describe("Optional machine IDs to check"),
|
|
38405
|
+
packages: exports_external2.array(exports_external2.string()).optional().describe("Optional @hasna package-name filter"),
|
|
38406
|
+
refresh_catalog: exports_external2.boolean().optional().describe("Refresh npm metadata before checking"),
|
|
38407
|
+
timeout_ms: exports_external2.number().int().min(1000).optional().describe("Remote timeout in milliseconds")
|
|
38408
|
+
},
|
|
38409
|
+
run: async ({ machine_ids, packages, refresh_catalog, timeout_ms }) => jsonContent(await runFleetHealthCheck({
|
|
38410
|
+
machineIds: Array.isArray(machine_ids) ? machine_ids.map(String) : undefined,
|
|
38411
|
+
packages: Array.isArray(packages) ? packages.map(String) : undefined,
|
|
38412
|
+
refreshCatalog: refresh_catalog === true,
|
|
38413
|
+
timeoutMs: typeof timeout_ms === "number" ? timeout_ms : undefined
|
|
38414
|
+
}))
|
|
38415
|
+
},
|
|
38416
|
+
{
|
|
38417
|
+
name: "fleet_install",
|
|
38418
|
+
description: "Batch-install missing or outdated @hasna MCP packages across machines",
|
|
38419
|
+
paramsSchema: {
|
|
38420
|
+
machine_ids: exports_external2.array(exports_external2.string()).optional().describe("Optional machine IDs to target"),
|
|
38421
|
+
packages: exports_external2.array(exports_external2.string()).optional().describe("Optional @hasna package-name filter"),
|
|
38422
|
+
mode: exports_external2.enum(["missing", "missing-or-outdated", "all"]).optional().describe("Install selection mode"),
|
|
38423
|
+
installer: exports_external2.enum(["auto", "bun", "npm"]).optional().describe("Override installer"),
|
|
38424
|
+
refresh_catalog: exports_external2.boolean().optional().describe("Refresh npm metadata before installing"),
|
|
38425
|
+
timeout_ms: exports_external2.number().int().min(1000).optional().describe("Remote timeout in milliseconds")
|
|
38426
|
+
},
|
|
38427
|
+
run: async ({ machine_ids, packages, mode, installer, refresh_catalog, timeout_ms }) => jsonContent(await runFleetInstall({
|
|
38428
|
+
machineIds: Array.isArray(machine_ids) ? machine_ids.map(String) : undefined,
|
|
38429
|
+
packages: Array.isArray(packages) ? packages.map(String) : undefined,
|
|
38430
|
+
mode: mode === "missing" || mode === "missing-or-outdated" || mode === "all" ? mode : undefined,
|
|
38431
|
+
installer: installer === "auto" || installer === "bun" || installer === "npm" ? installer : undefined,
|
|
38432
|
+
refreshCatalog: refresh_catalog === true,
|
|
38433
|
+
timeoutMs: typeof timeout_ms === "number" ? timeout_ms : undefined
|
|
38434
|
+
}))
|
|
38435
|
+
},
|
|
38436
|
+
{
|
|
38437
|
+
name: "send_feedback",
|
|
38438
|
+
description: "Send feedback about this service",
|
|
38439
|
+
paramsSchema: {
|
|
38440
|
+
message: exports_external2.string().describe("Feedback message"),
|
|
38441
|
+
email: exports_external2.string().optional().describe("Contact email (optional)"),
|
|
38442
|
+
category: exports_external2.enum(["bug", "feature", "general"]).optional().describe("Feedback category")
|
|
38443
|
+
},
|
|
38444
|
+
run: ({ message, email: email2, category }) => {
|
|
38445
|
+
const adapter = getAdapter();
|
|
38446
|
+
adapter.run("INSERT INTO feedback (message, email, category, version) VALUES (?, ?, ?, ?)", String(message), typeof email2 === "string" ? email2 : null, typeof category === "string" ? category : "general", VERSION);
|
|
38447
|
+
return textContent("Feedback saved. Thank you!");
|
|
38448
|
+
}
|
|
38449
|
+
},
|
|
38450
|
+
{
|
|
38451
|
+
name: "register_agent",
|
|
38452
|
+
description: "Register an agent session. Returns agent_id. Auto-triggers a heartbeat.",
|
|
38453
|
+
paramsSchema: {
|
|
38454
|
+
name: exports_external2.string(),
|
|
38455
|
+
session_id: exports_external2.string().optional()
|
|
38456
|
+
},
|
|
38457
|
+
run: ({ name, session_id }) => {
|
|
38458
|
+
const agentName = String(name);
|
|
38459
|
+
const existing = [...mcpsAgents.values()].find((agent2) => agent2.name === agentName);
|
|
38460
|
+
if (existing) {
|
|
38461
|
+
existing.last_seen_at = new Date().toISOString();
|
|
38462
|
+
if (typeof session_id === "string")
|
|
38463
|
+
existing.session_id = session_id;
|
|
38464
|
+
return jsonContent(existing);
|
|
38465
|
+
}
|
|
38466
|
+
const id = Math.random().toString(36).slice(2, 10);
|
|
38467
|
+
const agent = {
|
|
38468
|
+
id,
|
|
38469
|
+
name: agentName,
|
|
38470
|
+
session_id: typeof session_id === "string" ? session_id : undefined,
|
|
38471
|
+
last_seen_at: new Date().toISOString()
|
|
38472
|
+
};
|
|
38473
|
+
mcpsAgents.set(id, agent);
|
|
38474
|
+
return jsonContent(agent);
|
|
38475
|
+
}
|
|
38476
|
+
},
|
|
38477
|
+
{
|
|
38478
|
+
name: "heartbeat",
|
|
38479
|
+
description: "Update last_seen_at to signal agent is active.",
|
|
38480
|
+
paramsSchema: { agent_id: exports_external2.string() },
|
|
38481
|
+
run: ({ agent_id }) => {
|
|
38482
|
+
const agentId = String(agent_id);
|
|
38483
|
+
const agent = mcpsAgents.get(agentId);
|
|
38484
|
+
if (!agent)
|
|
38485
|
+
return errorContent(`Agent not found: ${agentId}`);
|
|
38486
|
+
agent.last_seen_at = new Date().toISOString();
|
|
38487
|
+
return jsonContent({ agent_id: agent.id, last_seen_at: agent.last_seen_at });
|
|
38488
|
+
}
|
|
38489
|
+
},
|
|
38490
|
+
{
|
|
38491
|
+
name: "set_focus",
|
|
38492
|
+
description: "Set active project context for this agent session.",
|
|
38493
|
+
paramsSchema: {
|
|
38494
|
+
agent_id: exports_external2.string(),
|
|
38495
|
+
project_id: exports_external2.string().optional()
|
|
38496
|
+
},
|
|
38497
|
+
run: ({ agent_id, project_id }) => {
|
|
38498
|
+
const agentId = String(agent_id);
|
|
38499
|
+
const agent = mcpsAgents.get(agentId);
|
|
38500
|
+
if (!agent)
|
|
38501
|
+
return errorContent(`Agent not found: ${agentId}`);
|
|
38502
|
+
agent.project_id = typeof project_id === "string" ? project_id : undefined;
|
|
38503
|
+
return jsonContent({ agent_id: agent.id, project_id: agent.project_id ?? null });
|
|
38504
|
+
}
|
|
38505
|
+
},
|
|
38506
|
+
{
|
|
38507
|
+
name: "list_agents",
|
|
38508
|
+
description: "List all registered agents.",
|
|
38509
|
+
paramsSchema: {},
|
|
38510
|
+
run: () => jsonContent([...mcpsAgents.values()])
|
|
38511
|
+
}
|
|
38512
|
+
];
|
|
38513
|
+
return definitions.map((definition) => ({
|
|
38514
|
+
...definition,
|
|
38515
|
+
inputSchema: zodRawShapeToJsonSchema(definition.paramsSchema)
|
|
38516
|
+
}));
|
|
38517
|
+
}
|
|
38518
|
+
var tools = buildMcpTools();
|
|
38519
|
+
function registerMcpTools(server, toolDefinitions = buildMcpTools()) {
|
|
38520
|
+
for (const tool of toolDefinitions) {
|
|
38521
|
+
server.tool(tool.name, tool.description, tool.paramsSchema ?? {}, async (input) => tool.run(readRecord(input)));
|
|
38087
38522
|
}
|
|
38088
|
-
|
|
38089
|
-
|
|
38090
|
-
|
|
38091
|
-
};
|
|
38092
|
-
|
|
38093
|
-
|
|
38094
|
-
|
|
38095
|
-
|
|
38096
|
-
|
|
38097
|
-
content: [{ type: "text", text: `Server "${id}" not found.` }],
|
|
38098
|
-
isError: true
|
|
38099
|
-
};
|
|
38523
|
+
return toolDefinitions;
|
|
38524
|
+
}
|
|
38525
|
+
function zodRawShapeToJsonSchema(shape) {
|
|
38526
|
+
const properties = {};
|
|
38527
|
+
const required2 = [];
|
|
38528
|
+
for (const [key, schema] of Object.entries(shape)) {
|
|
38529
|
+
properties[key] = zodSchemaToJsonSchema(schema);
|
|
38530
|
+
if (!isOptionalSchema(schema))
|
|
38531
|
+
required2.push(key);
|
|
38100
38532
|
}
|
|
38101
|
-
const entry = disableServer(id);
|
|
38102
38533
|
return {
|
|
38103
|
-
|
|
38534
|
+
type: "object",
|
|
38535
|
+
properties,
|
|
38536
|
+
...required2.length > 0 ? { required: required2 } : {},
|
|
38537
|
+
additionalProperties: false
|
|
38104
38538
|
};
|
|
38105
|
-
}
|
|
38106
|
-
|
|
38107
|
-
|
|
38108
|
-
|
|
38109
|
-
description:
|
|
38110
|
-
|
|
38111
|
-
|
|
38112
|
-
transport: exports_external2.enum(["stdio", "sse", "streamable-http"]).optional().describe("New transport type"),
|
|
38113
|
-
url: exports_external2.string().optional().describe("New URL for remote transports")
|
|
38114
|
-
}, async ({ id, name, description, command, args, transport, url: url2 }) => {
|
|
38115
|
-
const existing = getServer(id);
|
|
38116
|
-
if (!existing) {
|
|
38117
|
-
return {
|
|
38118
|
-
content: [{ type: "text", text: `Server "${id}" not found.` }],
|
|
38119
|
-
isError: true
|
|
38120
|
-
};
|
|
38539
|
+
}
|
|
38540
|
+
function zodSchemaToJsonSchema(schema) {
|
|
38541
|
+
const def = schema._def;
|
|
38542
|
+
const typeName = String(def?.typeName ?? "");
|
|
38543
|
+
const description = schema.description ? { description: schema.description } : {};
|
|
38544
|
+
if (typeName === exports_external2.ZodFirstPartyTypeKind.ZodOptional || typeName === exports_external2.ZodFirstPartyTypeKind.ZodDefault) {
|
|
38545
|
+
return { ...asJsonSchemaObject(zodSchemaToJsonSchema(def.innerType)), ...description };
|
|
38121
38546
|
}
|
|
38122
|
-
|
|
38123
|
-
|
|
38124
|
-
fields.name = name;
|
|
38125
|
-
if (description !== undefined)
|
|
38126
|
-
fields.description = description;
|
|
38127
|
-
if (command !== undefined)
|
|
38128
|
-
fields.command = command;
|
|
38129
|
-
if (args !== undefined)
|
|
38130
|
-
fields.args = args;
|
|
38131
|
-
if (transport !== undefined)
|
|
38132
|
-
fields.transport = transport;
|
|
38133
|
-
if (url2 !== undefined)
|
|
38134
|
-
fields.url = url2;
|
|
38135
|
-
const updated = updateServer(id, fields);
|
|
38136
|
-
return {
|
|
38137
|
-
content: [{ type: "text", text: JSON.stringify(redactServerEnv(updated), null, 2) }]
|
|
38138
|
-
};
|
|
38139
|
-
});
|
|
38140
|
-
server.tool("list_tools", "List all cached tools across registered servers without connecting. Optionally filter by server_id.", { server_id: exports_external2.string().optional().describe("Server ID to filter by (optional)") }, async ({ server_id }) => {
|
|
38141
|
-
if (server_id) {
|
|
38142
|
-
const tools = getCachedTools(server_id);
|
|
38143
|
-
return {
|
|
38144
|
-
content: [{ type: "text", text: JSON.stringify(tools.map((t) => ({ ...t, server_id })), null, 2) }]
|
|
38145
|
-
};
|
|
38547
|
+
if (typeName === exports_external2.ZodFirstPartyTypeKind.ZodNullable) {
|
|
38548
|
+
return { ...asJsonSchemaObject(zodSchemaToJsonSchema(def.innerType)), nullable: true, ...description };
|
|
38146
38549
|
}
|
|
38147
|
-
|
|
38148
|
-
|
|
38149
|
-
for (const s of servers) {
|
|
38150
|
-
const tools = getCachedTools(s.id);
|
|
38151
|
-
for (const t of tools) {
|
|
38152
|
-
allTools.push({ server_id: s.id, ...t });
|
|
38153
|
-
}
|
|
38550
|
+
if (typeName === exports_external2.ZodFirstPartyTypeKind.ZodString) {
|
|
38551
|
+
return { type: "string", ...description };
|
|
38154
38552
|
}
|
|
38155
|
-
|
|
38156
|
-
|
|
38157
|
-
};
|
|
38158
|
-
});
|
|
38159
|
-
server.tool("get_server_info", "Get detailed information about a registered MCP server", { id: exports_external2.string().describe("Server ID") }, async ({ id }) => {
|
|
38160
|
-
const entry = getServer(id);
|
|
38161
|
-
if (!entry) {
|
|
38162
|
-
return {
|
|
38163
|
-
content: [{ type: "text", text: `Server "${id}" not found.` }],
|
|
38164
|
-
isError: true
|
|
38165
|
-
};
|
|
38553
|
+
if (typeName === exports_external2.ZodFirstPartyTypeKind.ZodBoolean) {
|
|
38554
|
+
return { type: "boolean", ...description };
|
|
38166
38555
|
}
|
|
38167
|
-
|
|
38168
|
-
|
|
38169
|
-
};
|
|
38170
|
-
});
|
|
38171
|
-
server.tool("find_mcp_servers", "Search for MCP servers across configured sources (official registry, npm, GitHub topics, awesome lists). Use list_sources to see available source IDs.", {
|
|
38172
|
-
query: exports_external2.string().describe("Search query (e.g. 'filesystem', 'postgres', 'browser')"),
|
|
38173
|
-
sources: exports_external2.array(exports_external2.string()).optional().describe("Source IDs to search (default: all enabled). Use list_sources to get IDs."),
|
|
38174
|
-
limit: exports_external2.number().optional().describe("Max results per source (default: 20)")
|
|
38175
|
-
}, async ({ query, sources, limit }) => {
|
|
38176
|
-
const results = await findServers(query, { sources, limit });
|
|
38177
|
-
return {
|
|
38178
|
-
content: [{ type: "text", text: JSON.stringify(results, null, 2) }]
|
|
38179
|
-
};
|
|
38180
|
-
});
|
|
38181
|
-
server.tool("list_sources", "List all configured search sources for finding MCP servers", {}, async () => {
|
|
38182
|
-
const sources = listSources();
|
|
38183
|
-
return {
|
|
38184
|
-
content: [{ type: "text", text: JSON.stringify(sources, null, 2) }]
|
|
38185
|
-
};
|
|
38186
|
-
});
|
|
38187
|
-
server.tool("add_source", "Add a new search source for finding MCP servers", {
|
|
38188
|
-
name: exports_external2.string().describe("Source name"),
|
|
38189
|
-
type: exports_external2.enum(["mcp-registry", "awesome-list", "npm-search", "github-topic"]).describe("Source type"),
|
|
38190
|
-
url: exports_external2.string().describe("Source URL endpoint"),
|
|
38191
|
-
description: exports_external2.string().optional().describe("Description")
|
|
38192
|
-
}, async ({ name, type, url: url2, description }) => {
|
|
38193
|
-
const source = addSource({ name, type, url: url2, description });
|
|
38194
|
-
return {
|
|
38195
|
-
content: [{ type: "text", text: JSON.stringify(source, null, 2) }]
|
|
38196
|
-
};
|
|
38197
|
-
});
|
|
38198
|
-
server.tool("remove_source", "Remove a search source by ID", { id: exports_external2.string().describe("Source ID to remove") }, async ({ id }) => {
|
|
38199
|
-
const existing = getSource(id);
|
|
38200
|
-
if (!existing) {
|
|
38201
|
-
return {
|
|
38202
|
-
content: [{ type: "text", text: `Source "${id}" not found.` }],
|
|
38203
|
-
isError: true
|
|
38204
|
-
};
|
|
38556
|
+
if (typeName === exports_external2.ZodFirstPartyTypeKind.ZodUnknown || typeName === exports_external2.ZodFirstPartyTypeKind.ZodAny) {
|
|
38557
|
+
return Object.keys(description).length > 0 ? description : true;
|
|
38205
38558
|
}
|
|
38206
|
-
|
|
38207
|
-
|
|
38208
|
-
|
|
38209
|
-
|
|
38210
|
-
|
|
38211
|
-
server.tool("enable_source_finder", "Enable a search source", { id: exports_external2.string().describe("Source ID to enable") }, async ({ id }) => {
|
|
38212
|
-
const existing = getSource(id);
|
|
38213
|
-
if (!existing) {
|
|
38214
|
-
return {
|
|
38215
|
-
content: [{ type: "text", text: `Source "${id}" not found.` }],
|
|
38216
|
-
isError: true
|
|
38559
|
+
if (typeName === exports_external2.ZodFirstPartyTypeKind.ZodNumber) {
|
|
38560
|
+
const checks4 = Array.isArray(def.checks) ? def.checks : [];
|
|
38561
|
+
const schemaJson = {
|
|
38562
|
+
type: checks4.some((check2) => check2.kind === "int") ? "integer" : "number",
|
|
38563
|
+
...description
|
|
38217
38564
|
};
|
|
38565
|
+
for (const check2 of checks4) {
|
|
38566
|
+
if (check2.kind === "min")
|
|
38567
|
+
schemaJson.minimum = check2.value;
|
|
38568
|
+
if (check2.kind === "max")
|
|
38569
|
+
schemaJson.maximum = check2.value;
|
|
38570
|
+
}
|
|
38571
|
+
return schemaJson;
|
|
38218
38572
|
}
|
|
38219
|
-
|
|
38220
|
-
|
|
38221
|
-
content: [{ type: "text", text: `Enabled source: ${existing.name}` }]
|
|
38222
|
-
};
|
|
38223
|
-
});
|
|
38224
|
-
server.tool("disable_source_finder", "Disable a search source", { id: exports_external2.string().describe("Source ID to disable") }, async ({ id }) => {
|
|
38225
|
-
const existing = getSource(id);
|
|
38226
|
-
if (!existing) {
|
|
38227
|
-
return {
|
|
38228
|
-
content: [{ type: "text", text: `Source "${id}" not found.` }],
|
|
38229
|
-
isError: true
|
|
38230
|
-
};
|
|
38573
|
+
if (typeName === exports_external2.ZodFirstPartyTypeKind.ZodEnum) {
|
|
38574
|
+
return { type: "string", enum: def.values, ...description };
|
|
38231
38575
|
}
|
|
38232
|
-
|
|
38233
|
-
|
|
38234
|
-
content: [{ type: "text", text: `Disabled source: ${existing.name}` }]
|
|
38235
|
-
};
|
|
38236
|
-
});
|
|
38237
|
-
server.tool("install_to_agents", "Install a registered MCP server into Claude Code, Codex, and/or Gemini", {
|
|
38238
|
-
id: exports_external2.string().describe("Server ID to install (from list_servers)"),
|
|
38239
|
-
targets: exports_external2.array(exports_external2.enum(["claude", "codex", "gemini"])).optional().describe("Target agents to install into (default: all)")
|
|
38240
|
-
}, async ({ id, targets }) => {
|
|
38241
|
-
const entry = getServer(id);
|
|
38242
|
-
if (!entry) {
|
|
38243
|
-
return {
|
|
38244
|
-
content: [{ type: "text", text: `Server "${id}" not found.` }],
|
|
38245
|
-
isError: true
|
|
38246
|
-
};
|
|
38576
|
+
if (typeName === exports_external2.ZodFirstPartyTypeKind.ZodArray) {
|
|
38577
|
+
return { type: "array", items: zodSchemaToJsonSchema(def.type), ...description };
|
|
38247
38578
|
}
|
|
38248
|
-
|
|
38249
|
-
|
|
38250
|
-
|
|
38251
|
-
content: [{ type: "text", text: JSON.stringify(results, null, 2) }]
|
|
38252
|
-
};
|
|
38253
|
-
});
|
|
38254
|
-
server.tool("list_awesome_servers", "List all MCP servers from the curated punkpeye/awesome-mcp-servers GitHub list", {}, async () => {
|
|
38255
|
-
const results = await listAwesomeServers();
|
|
38256
|
-
return {
|
|
38257
|
-
content: [{ type: "text", text: JSON.stringify(results, null, 2) }]
|
|
38258
|
-
};
|
|
38259
|
-
});
|
|
38260
|
-
server.tool("connect_and_list_tools", "Connect to all enabled MCP servers and list their available tools", {}, async () => {
|
|
38261
|
-
let tools = [];
|
|
38262
|
-
try {
|
|
38263
|
-
await connectAllEnabled();
|
|
38264
|
-
tools = listAllTools();
|
|
38265
|
-
} finally {
|
|
38266
|
-
await disconnectAll().catch(() => {
|
|
38267
|
-
return;
|
|
38268
|
-
});
|
|
38579
|
+
if (typeName === exports_external2.ZodFirstPartyTypeKind.ZodRecord) {
|
|
38580
|
+
const valueType = def.valueType ? zodSchemaToJsonSchema(def.valueType) : true;
|
|
38581
|
+
return { type: "object", additionalProperties: valueType, ...description };
|
|
38269
38582
|
}
|
|
38270
|
-
|
|
38271
|
-
|
|
38272
|
-
|
|
38273
|
-
});
|
|
38274
|
-
server.tool("call_upstream_tool", `Call a tool on a connected upstream MCP server. Tool name format: server_id${TOOL_PREFIX_SEPARATOR}tool_name`, {
|
|
38275
|
-
tool_name: exports_external2.string().describe(`Prefixed tool name (server_id${TOOL_PREFIX_SEPARATOR}tool_name)`),
|
|
38276
|
-
arguments: exports_external2.record(exports_external2.unknown()).optional().describe("Tool arguments as key-value pairs")
|
|
38277
|
-
}, async ({ tool_name, arguments: args }) => {
|
|
38278
|
-
try {
|
|
38279
|
-
const sepIdx = tool_name.indexOf(TOOL_PREFIX_SEPARATOR);
|
|
38280
|
-
if (sepIdx === -1) {
|
|
38281
|
-
return {
|
|
38282
|
-
content: [{ type: "text", text: `Error: Invalid tool name "${tool_name}"` }],
|
|
38283
|
-
isError: true
|
|
38284
|
-
};
|
|
38285
|
-
}
|
|
38286
|
-
const serverId = tool_name.slice(0, sepIdx);
|
|
38287
|
-
const entry = getServer(serverId);
|
|
38288
|
-
if (!entry) {
|
|
38289
|
-
return {
|
|
38290
|
-
content: [{ type: "text", text: `Error: Server "${serverId}" not found.` }],
|
|
38291
|
-
isError: true
|
|
38292
|
-
};
|
|
38293
|
-
}
|
|
38294
|
-
if (!entry.enabled) {
|
|
38295
|
-
return {
|
|
38296
|
-
content: [{ type: "text", text: `Error: Server "${serverId}" is disabled.` }],
|
|
38297
|
-
isError: true
|
|
38298
|
-
};
|
|
38299
|
-
}
|
|
38300
|
-
await connectToServer(entry);
|
|
38301
|
-
const result = await callTool(tool_name, args || {});
|
|
38302
|
-
return { content: result.content };
|
|
38303
|
-
} catch (err) {
|
|
38304
|
-
return {
|
|
38305
|
-
content: [{ type: "text", text: `Error: ${err.message}` }],
|
|
38306
|
-
isError: true
|
|
38307
|
-
};
|
|
38583
|
+
if (typeName === exports_external2.ZodFirstPartyTypeKind.ZodObject) {
|
|
38584
|
+
const objectShape = typeof def.shape === "function" ? def.shape() : def.shape;
|
|
38585
|
+
return { ...zodRawShapeToJsonSchema(objectShape ?? {}), ...description };
|
|
38308
38586
|
}
|
|
38309
|
-
}
|
|
38310
|
-
|
|
38311
|
-
|
|
38312
|
-
|
|
38313
|
-
|
|
38314
|
-
|
|
38315
|
-
|
|
38316
|
-
|
|
38317
|
-
|
|
38318
|
-
|
|
38319
|
-
|
|
38320
|
-
|
|
38321
|
-
|
|
38322
|
-
|
|
38323
|
-
|
|
38324
|
-
|
|
38325
|
-
|
|
38326
|
-
|
|
38327
|
-
|
|
38328
|
-
|
|
38329
|
-
|
|
38330
|
-
|
|
38331
|
-
|
|
38332
|
-
|
|
38333
|
-
|
|
38334
|
-
npm_path: exports_external2.string().optional().describe("Explicit path to npm on the remote machine"),
|
|
38335
|
-
installer: exports_external2.enum(["auto", "bun", "npm"]).optional().describe("Preferred installer"),
|
|
38336
|
-
ssh_key_path: exports_external2.string().optional().describe("SSH private key path"),
|
|
38337
|
-
enabled: exports_external2.boolean().optional().describe("Whether the machine should be enabled")
|
|
38338
|
-
}, async ({ host, id, name, username, port, platform: platform2, arch, bun_path, npm_path, installer, ssh_key_path, enabled }) => {
|
|
38339
|
-
const machine = addMachine({
|
|
38340
|
-
host,
|
|
38341
|
-
id,
|
|
38342
|
-
name,
|
|
38343
|
-
username,
|
|
38344
|
-
port,
|
|
38345
|
-
platform: platform2,
|
|
38346
|
-
arch,
|
|
38347
|
-
bun_path,
|
|
38348
|
-
npm_path,
|
|
38349
|
-
installer,
|
|
38350
|
-
ssh_key_path,
|
|
38351
|
-
enabled
|
|
38587
|
+
return Object.keys(description).length > 0 ? description : {};
|
|
38588
|
+
}
|
|
38589
|
+
function asJsonSchemaObject(schema) {
|
|
38590
|
+
return typeof schema === "boolean" ? {} : schema;
|
|
38591
|
+
}
|
|
38592
|
+
function isOptionalSchema(schema) {
|
|
38593
|
+
const def = schema._def;
|
|
38594
|
+
const typeName = String(def?.typeName ?? "");
|
|
38595
|
+
return typeName === exports_external2.ZodFirstPartyTypeKind.ZodOptional || typeName === exports_external2.ZodFirstPartyTypeKind.ZodDefault;
|
|
38596
|
+
}
|
|
38597
|
+
function readRecord(value) {
|
|
38598
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
38599
|
+
}
|
|
38600
|
+
function isRecordOfStrings(value) {
|
|
38601
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
38602
|
+
return false;
|
|
38603
|
+
return Object.values(value).every((item) => typeof item === "string");
|
|
38604
|
+
}
|
|
38605
|
+
|
|
38606
|
+
// src/mcp/server.ts
|
|
38607
|
+
var VERSION2 = readPackageVersion(import.meta.url);
|
|
38608
|
+
function createMcpServer(options = {}) {
|
|
38609
|
+
const server = new McpServer({
|
|
38610
|
+
name: options.name ?? "mcps",
|
|
38611
|
+
version: options.version ?? VERSION2
|
|
38352
38612
|
});
|
|
38353
|
-
|
|
38354
|
-
|
|
38355
|
-
|
|
38356
|
-
});
|
|
38357
|
-
server.tool("remove_machine", "Remove a registered machine", { id: exports_external2.string().describe("Machine ID to remove") }, async ({ id }) => {
|
|
38358
|
-
const machine = getMachine(id);
|
|
38359
|
-
if (!machine) {
|
|
38360
|
-
return {
|
|
38361
|
-
content: [{ type: "text", text: `Machine "${id}" not found.` }],
|
|
38362
|
-
isError: true
|
|
38363
|
-
};
|
|
38613
|
+
registerMcpTools(server, options.tools);
|
|
38614
|
+
if (options.cloudTools !== false) {
|
|
38615
|
+
registerCloudTools(server, "mcps");
|
|
38364
38616
|
}
|
|
38365
|
-
|
|
38366
|
-
|
|
38367
|
-
|
|
38368
|
-
|
|
38369
|
-
});
|
|
38370
|
-
server.tool("seed_default_machines", "Seed the standard spark/apple machine inventory", {}, async () => {
|
|
38371
|
-
const machines = seedDefaultMachines();
|
|
38372
|
-
return {
|
|
38373
|
-
content: [{ type: "text", text: JSON.stringify(machines, null, 2) }]
|
|
38374
|
-
};
|
|
38375
|
-
});
|
|
38376
|
-
server.tool("list_hasna_mcp_catalog", "List the discovered @hasna MCP package catalog", {
|
|
38377
|
-
packages: exports_external2.array(exports_external2.string()).optional().describe("Optional package-name filter"),
|
|
38378
|
-
refresh: exports_external2.boolean().optional().describe("Refresh npm metadata instead of using cache")
|
|
38379
|
-
}, async ({ packages, refresh }) => {
|
|
38380
|
-
const catalog = await listHasnaMcpCatalog({ refresh });
|
|
38381
|
-
const filtered = packages?.length ? catalog.filter((entry) => packages.includes(entry.name)) : catalog;
|
|
38382
|
-
return {
|
|
38383
|
-
content: [{ type: "text", text: JSON.stringify(filtered, null, 2) }]
|
|
38384
|
-
};
|
|
38385
|
-
});
|
|
38386
|
-
server.tool("fleet_health", "Run fleet-wide MCP health checks across registered machines", {
|
|
38387
|
-
machine_ids: exports_external2.array(exports_external2.string()).optional().describe("Optional machine IDs to check"),
|
|
38388
|
-
packages: exports_external2.array(exports_external2.string()).optional().describe("Optional @hasna package-name filter"),
|
|
38389
|
-
refresh_catalog: exports_external2.boolean().optional().describe("Refresh npm metadata before checking"),
|
|
38390
|
-
timeout_ms: exports_external2.number().int().min(1000).optional().describe("Remote timeout in milliseconds")
|
|
38391
|
-
}, async ({ machine_ids, packages, refresh_catalog, timeout_ms }) => {
|
|
38392
|
-
const reports = await runFleetHealthCheck({
|
|
38393
|
-
machineIds: machine_ids,
|
|
38394
|
-
packages,
|
|
38395
|
-
refreshCatalog: refresh_catalog,
|
|
38396
|
-
timeoutMs: timeout_ms
|
|
38397
|
-
});
|
|
38398
|
-
return {
|
|
38399
|
-
content: [{ type: "text", text: JSON.stringify(reports, null, 2) }]
|
|
38400
|
-
};
|
|
38401
|
-
});
|
|
38402
|
-
server.tool("fleet_install", "Batch-install missing or outdated @hasna MCP packages across machines", {
|
|
38403
|
-
machine_ids: exports_external2.array(exports_external2.string()).optional().describe("Optional machine IDs to target"),
|
|
38404
|
-
packages: exports_external2.array(exports_external2.string()).optional().describe("Optional @hasna package-name filter"),
|
|
38405
|
-
mode: exports_external2.enum(["missing", "missing-or-outdated", "all"]).optional().describe("Install selection mode"),
|
|
38406
|
-
installer: exports_external2.enum(["auto", "bun", "npm"]).optional().describe("Override installer"),
|
|
38407
|
-
refresh_catalog: exports_external2.boolean().optional().describe("Refresh npm metadata before installing"),
|
|
38408
|
-
timeout_ms: exports_external2.number().int().min(1000).optional().describe("Remote timeout in milliseconds")
|
|
38409
|
-
}, async ({ machine_ids, packages, mode, installer, refresh_catalog, timeout_ms }) => {
|
|
38410
|
-
const reports = await runFleetInstall({
|
|
38411
|
-
machineIds: machine_ids,
|
|
38412
|
-
packages,
|
|
38413
|
-
mode,
|
|
38414
|
-
installer,
|
|
38415
|
-
refreshCatalog: refresh_catalog,
|
|
38416
|
-
timeoutMs: timeout_ms
|
|
38417
|
-
});
|
|
38418
|
-
return {
|
|
38419
|
-
content: [{ type: "text", text: JSON.stringify(reports, null, 2) }]
|
|
38420
|
-
};
|
|
38421
|
-
});
|
|
38422
|
-
server.tool("send_feedback", "Send feedback about this service", {
|
|
38423
|
-
message: exports_external2.string().describe("Feedback message"),
|
|
38424
|
-
email: exports_external2.string().optional().describe("Contact email (optional)"),
|
|
38425
|
-
category: exports_external2.enum(["bug", "feature", "general"]).optional().describe("Feedback category")
|
|
38426
|
-
}, async (params) => {
|
|
38427
|
-
const adapter = getAdapter();
|
|
38428
|
-
adapter.run("INSERT INTO feedback (message, email, category, version) VALUES (?, ?, ?, ?)", params.message, params.email || null, params.category || "general", VERSION);
|
|
38429
|
-
return { content: [{ type: "text", text: "Feedback saved. Thank you!" }] };
|
|
38430
|
-
});
|
|
38431
|
-
server.tool("register_agent", "Register an agent session. Returns agent_id. Auto-triggers a heartbeat.", {
|
|
38432
|
-
name: exports_external2.string(),
|
|
38433
|
-
session_id: exports_external2.string().optional()
|
|
38434
|
-
}, async (params) => {
|
|
38435
|
-
const existing = [..._mcpsAgents.values()].find((a) => a.name === params.name);
|
|
38436
|
-
if (existing) {
|
|
38437
|
-
existing.last_seen_at = new Date().toISOString();
|
|
38438
|
-
if (params.session_id)
|
|
38439
|
-
existing.session_id = params.session_id;
|
|
38440
|
-
return { content: [{ type: "text", text: JSON.stringify(existing) }] };
|
|
38441
|
-
}
|
|
38442
|
-
const id = Math.random().toString(36).slice(2, 10);
|
|
38443
|
-
const ag = { id, name: params.name, session_id: params.session_id, last_seen_at: new Date().toISOString() };
|
|
38444
|
-
_mcpsAgents.set(id, ag);
|
|
38445
|
-
return { content: [{ type: "text", text: JSON.stringify(ag) }] };
|
|
38446
|
-
});
|
|
38447
|
-
server.tool("heartbeat", "Update last_seen_at to signal agent is active.", {
|
|
38448
|
-
agent_id: exports_external2.string()
|
|
38449
|
-
}, async (params) => {
|
|
38450
|
-
const ag = _mcpsAgents.get(params.agent_id);
|
|
38451
|
-
if (!ag)
|
|
38452
|
-
return { content: [{ type: "text", text: `Agent not found: ${params.agent_id}` }], isError: true };
|
|
38453
|
-
ag.last_seen_at = new Date().toISOString();
|
|
38454
|
-
return { content: [{ type: "text", text: JSON.stringify({ agent_id: ag.id, last_seen_at: ag.last_seen_at }) }] };
|
|
38455
|
-
});
|
|
38456
|
-
server.tool("set_focus", "Set active project context for this agent session.", {
|
|
38457
|
-
agent_id: exports_external2.string(),
|
|
38458
|
-
project_id: exports_external2.string().optional()
|
|
38459
|
-
}, async (params) => {
|
|
38460
|
-
const ag = _mcpsAgents.get(params.agent_id);
|
|
38461
|
-
if (!ag)
|
|
38462
|
-
return { content: [{ type: "text", text: `Agent not found: ${params.agent_id}` }], isError: true };
|
|
38463
|
-
ag.project_id = params.project_id;
|
|
38464
|
-
return { content: [{ type: "text", text: JSON.stringify({ agent_id: ag.id, project_id: ag.project_id ?? null }) }] };
|
|
38465
|
-
});
|
|
38466
|
-
server.tool("list_agents", "List all registered agents.", {}, async () => {
|
|
38467
|
-
return { content: [{ type: "text", text: JSON.stringify([..._mcpsAgents.values()]) }] };
|
|
38468
|
-
});
|
|
38617
|
+
return server;
|
|
38618
|
+
}
|
|
38619
|
+
|
|
38620
|
+
// src/mcp/index.ts
|
|
38469
38621
|
async function startMcpServer() {
|
|
38622
|
+
const server = createMcpServer();
|
|
38470
38623
|
const transport = new StdioServerTransport;
|
|
38471
|
-
registerCloudTools(server, "mcps");
|
|
38472
38624
|
await server.connect(transport);
|
|
38473
38625
|
}
|
|
38474
38626
|
var isDirectRun = import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("/mcp/index.ts") || process.argv[1]?.endsWith("/bin/mcp.js");
|
|
@@ -38485,8 +38637,8 @@ import { join as join11, dirname as dirname4, extname, resolve, relative as rela
|
|
|
38485
38637
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
38486
38638
|
init_sources();
|
|
38487
38639
|
init_db();
|
|
38488
|
-
function redactServer(
|
|
38489
|
-
return { ...
|
|
38640
|
+
function redactServer(server) {
|
|
38641
|
+
return { ...server, env: {} };
|
|
38490
38642
|
}
|
|
38491
38643
|
function resolveDashboardDir() {
|
|
38492
38644
|
const candidates = [];
|
|
@@ -38635,7 +38787,7 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
38635
38787
|
console.error(` cd dashboard && bun install && bun run build
|
|
38636
38788
|
`);
|
|
38637
38789
|
}
|
|
38638
|
-
const
|
|
38790
|
+
const server = Bun.serve({
|
|
38639
38791
|
port,
|
|
38640
38792
|
hostname: host,
|
|
38641
38793
|
async fetch(req) {
|
|
@@ -38706,8 +38858,8 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
38706
38858
|
const entry = getServer(id);
|
|
38707
38859
|
if (!entry)
|
|
38708
38860
|
return json({ error: `Server '${id}' not found` }, 404, port);
|
|
38709
|
-
const
|
|
38710
|
-
return json({ ...redactServer(entry), toolCount:
|
|
38861
|
+
const tools2 = getCachedTools(id);
|
|
38862
|
+
return json({ ...redactServer(entry), toolCount: tools2.length, tools: tools2 }, 200, port);
|
|
38711
38863
|
}
|
|
38712
38864
|
if (singleMatch && method === "DELETE") {
|
|
38713
38865
|
const id = singleMatch[1];
|
|
@@ -38835,8 +38987,8 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
38835
38987
|
const entry = getServer(id);
|
|
38836
38988
|
if (!entry)
|
|
38837
38989
|
return json({ error: `Server '${id}' not found` }, 404, port);
|
|
38838
|
-
const
|
|
38839
|
-
return json(
|
|
38990
|
+
const tools2 = getCachedTools(id);
|
|
38991
|
+
return json(tools2, 200, port);
|
|
38840
38992
|
}
|
|
38841
38993
|
const serverCallMatch = path.match(/^\/api\/servers\/([^/]+)\/call$/);
|
|
38842
38994
|
if (serverCallMatch && method === "POST") {
|
|
@@ -39019,7 +39171,7 @@ Dashboard not found at: ${dashboardDir}`);
|
|
|
39019
39171
|
}
|
|
39020
39172
|
});
|
|
39021
39173
|
const shutdown = () => {
|
|
39022
|
-
|
|
39174
|
+
server.stop();
|
|
39023
39175
|
closeDb();
|
|
39024
39176
|
process.exit(0);
|
|
39025
39177
|
};
|
|
@@ -39532,18 +39684,18 @@ var build_default = Spinner;
|
|
|
39532
39684
|
|
|
39533
39685
|
// src/cli/components/ServerDetail.tsx
|
|
39534
39686
|
import { jsxDEV as jsxDEV2, Fragment } from "react/jsx-dev-runtime";
|
|
39535
|
-
function ServerDetail({ server
|
|
39536
|
-
const [
|
|
39687
|
+
function ServerDetail({ server, onSelectTool, onBack }) {
|
|
39688
|
+
const [tools2, setTools] = useState3([]);
|
|
39537
39689
|
const [loading, setLoading] = useState3(false);
|
|
39538
39690
|
const [error2, setError] = useState3(null);
|
|
39539
|
-
const cachedTools = getCachedTools(
|
|
39691
|
+
const cachedTools = getCachedTools(server.id);
|
|
39540
39692
|
const cachedKey = cachedTools.map((t) => `${t.name}|${t.description}|${JSON.stringify(t.input_schema)}`).join(";");
|
|
39541
39693
|
useEffect3(() => {
|
|
39542
39694
|
setLoading(false);
|
|
39543
39695
|
setError(null);
|
|
39544
39696
|
if (cachedTools.length > 0) {
|
|
39545
39697
|
setTools(cachedTools.map((t) => ({
|
|
39546
|
-
server_id:
|
|
39698
|
+
server_id: server.id,
|
|
39547
39699
|
name: t.name,
|
|
39548
39700
|
description: t.description,
|
|
39549
39701
|
input_schema: t.input_schema
|
|
@@ -39551,12 +39703,12 @@ function ServerDetail({ server: server2, onSelectTool, onBack }) {
|
|
|
39551
39703
|
} else {
|
|
39552
39704
|
setTools([]);
|
|
39553
39705
|
}
|
|
39554
|
-
}, [
|
|
39706
|
+
}, [server.id, cachedKey]);
|
|
39555
39707
|
const handleConnect = async () => {
|
|
39556
39708
|
setLoading(true);
|
|
39557
39709
|
setError(null);
|
|
39558
39710
|
try {
|
|
39559
|
-
const conn = await connectToServer(
|
|
39711
|
+
const conn = await connectToServer(server);
|
|
39560
39712
|
setTools(conn.tools);
|
|
39561
39713
|
} catch (err) {
|
|
39562
39714
|
setError(err.message);
|
|
@@ -39565,8 +39717,8 @@ function ServerDetail({ server: server2, onSelectTool, onBack }) {
|
|
|
39565
39717
|
}
|
|
39566
39718
|
};
|
|
39567
39719
|
const items = [
|
|
39568
|
-
...
|
|
39569
|
-
...
|
|
39720
|
+
...tools2.length === 0 && !loading ? [{ label: "Connect & fetch tools", value: "__connect" }] : [],
|
|
39721
|
+
...tools2.map((t) => ({
|
|
39570
39722
|
label: `${t.name} \u2014 ${t.description || "No description"}`,
|
|
39571
39723
|
value: t.name,
|
|
39572
39724
|
tool: t
|
|
@@ -39575,7 +39727,7 @@ function ServerDetail({ server: server2, onSelectTool, onBack }) {
|
|
|
39575
39727
|
];
|
|
39576
39728
|
const handleSelect = (item) => {
|
|
39577
39729
|
if (item.value === "__back") {
|
|
39578
|
-
disconnectServer(
|
|
39730
|
+
disconnectServer(server.id);
|
|
39579
39731
|
onBack();
|
|
39580
39732
|
} else if (item.value === "__connect") {
|
|
39581
39733
|
handleConnect();
|
|
@@ -39588,36 +39740,36 @@ function ServerDetail({ server: server2, onSelectTool, onBack }) {
|
|
|
39588
39740
|
children: [
|
|
39589
39741
|
/* @__PURE__ */ jsxDEV2(Text5, {
|
|
39590
39742
|
bold: true,
|
|
39591
|
-
children:
|
|
39743
|
+
children: server.name
|
|
39592
39744
|
}, undefined, false, undefined, this),
|
|
39593
39745
|
/* @__PURE__ */ jsxDEV2(Text5, {
|
|
39594
39746
|
dimColor: true,
|
|
39595
39747
|
children: [
|
|
39596
39748
|
"ID: ",
|
|
39597
|
-
|
|
39749
|
+
server.id
|
|
39598
39750
|
]
|
|
39599
39751
|
}, undefined, true, undefined, this),
|
|
39600
39752
|
/* @__PURE__ */ jsxDEV2(Text5, {
|
|
39601
39753
|
dimColor: true,
|
|
39602
39754
|
children: [
|
|
39603
39755
|
"Status: ",
|
|
39604
|
-
|
|
39756
|
+
server.enabled ? "enabled" : "disabled",
|
|
39605
39757
|
" | Transport: ",
|
|
39606
|
-
|
|
39758
|
+
server.transport
|
|
39607
39759
|
]
|
|
39608
39760
|
}, undefined, true, undefined, this),
|
|
39609
39761
|
/* @__PURE__ */ jsxDEV2(Text5, {
|
|
39610
39762
|
dimColor: true,
|
|
39611
39763
|
children: [
|
|
39612
39764
|
"Command: ",
|
|
39613
|
-
|
|
39765
|
+
server.command,
|
|
39614
39766
|
" ",
|
|
39615
|
-
|
|
39767
|
+
server.args.join(" ")
|
|
39616
39768
|
]
|
|
39617
39769
|
}, undefined, true, undefined, this),
|
|
39618
|
-
|
|
39770
|
+
server.description && /* @__PURE__ */ jsxDEV2(Text5, {
|
|
39619
39771
|
dimColor: true,
|
|
39620
|
-
children:
|
|
39772
|
+
children: server.description
|
|
39621
39773
|
}, undefined, false, undefined, this),
|
|
39622
39774
|
/* @__PURE__ */ jsxDEV2(Box4, {
|
|
39623
39775
|
marginTop: 1,
|
|
@@ -39639,7 +39791,7 @@ function ServerDetail({ server: server2, onSelectTool, onBack }) {
|
|
|
39639
39791
|
children: [
|
|
39640
39792
|
/* @__PURE__ */ jsxDEV2(Text5, {
|
|
39641
39793
|
bold: true,
|
|
39642
|
-
children:
|
|
39794
|
+
children: tools2.length > 0 ? `Tools (${tools2.length}):` : "Tools:"
|
|
39643
39795
|
}, undefined, false, undefined, this),
|
|
39644
39796
|
/* @__PURE__ */ jsxDEV2(SelectInput_default, {
|
|
39645
39797
|
items,
|
|
@@ -39783,8 +39935,8 @@ function SearchView({ onBack }) {
|
|
|
39783
39935
|
setInstalling(item.value);
|
|
39784
39936
|
setMessage(null);
|
|
39785
39937
|
try {
|
|
39786
|
-
const
|
|
39787
|
-
setMessage(`Installed: ${
|
|
39938
|
+
const server = await installFromRegistry(item.value);
|
|
39939
|
+
setMessage(`Installed: ${server.name} [${server.id}]`);
|
|
39788
39940
|
} catch (err) {
|
|
39789
39941
|
setMessage(`Install failed: ${err.message}`);
|
|
39790
39942
|
} finally {
|
|
@@ -39877,7 +40029,7 @@ import { useState as useState6 } from "react";
|
|
|
39877
40029
|
import { Box as Box6, Text as Text8 } from "ink";
|
|
39878
40030
|
init_config2();
|
|
39879
40031
|
import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
|
|
39880
|
-
function ToolCall({ server
|
|
40032
|
+
function ToolCall({ server, tool, onBack }) {
|
|
39881
40033
|
const [argsInput, setArgsInput] = useState6("{}");
|
|
39882
40034
|
const [calling, setCalling] = useState6(false);
|
|
39883
40035
|
const [result, setResult] = useState6(null);
|
|
@@ -39894,8 +40046,8 @@ function ToolCall({ server: server2, tool, onBack }) {
|
|
|
39894
40046
|
setError(null);
|
|
39895
40047
|
setResult(null);
|
|
39896
40048
|
try {
|
|
39897
|
-
await connectToServer(
|
|
39898
|
-
const prefixed = `${
|
|
40049
|
+
await connectToServer(server);
|
|
40050
|
+
const prefixed = `${server.id}${TOOL_PREFIX_SEPARATOR}${tool.name}`;
|
|
39899
40051
|
const res = await callTool(prefixed, args);
|
|
39900
40052
|
const text = res.content.map((c) => c.text).join(`
|
|
39901
40053
|
`);
|
|
@@ -39923,9 +40075,9 @@ function ToolCall({ server: server2, tool, onBack }) {
|
|
|
39923
40075
|
dimColor: true,
|
|
39924
40076
|
children: [
|
|
39925
40077
|
"Server: ",
|
|
39926
|
-
|
|
40078
|
+
server.name,
|
|
39927
40079
|
" [",
|
|
39928
|
-
|
|
40080
|
+
server.id,
|
|
39929
40081
|
"]"
|
|
39930
40082
|
]
|
|
39931
40083
|
}, undefined, true, undefined, this),
|
|
@@ -40038,8 +40190,8 @@ function App() {
|
|
|
40038
40190
|
}).finally(() => closeDb());
|
|
40039
40191
|
};
|
|
40040
40192
|
}, []);
|
|
40041
|
-
const handleSelectServer = (
|
|
40042
|
-
setSelectedServer(
|
|
40193
|
+
const handleSelectServer = (server) => {
|
|
40194
|
+
setSelectedServer(server);
|
|
40043
40195
|
setView("detail");
|
|
40044
40196
|
};
|
|
40045
40197
|
const handleSearch = () => {
|
|
@@ -40107,7 +40259,7 @@ function App() {
|
|
|
40107
40259
|
}
|
|
40108
40260
|
|
|
40109
40261
|
// src/cli/index.tsx
|
|
40110
|
-
var
|
|
40262
|
+
var VERSION3 = (() => {
|
|
40111
40263
|
return readPackageVersion(import.meta.url);
|
|
40112
40264
|
})();
|
|
40113
40265
|
var MACHINE_PLATFORMS = ["linux", "darwin", "unknown"];
|
|
@@ -40212,7 +40364,7 @@ function renderFleetInstall(reports) {
|
|
|
40212
40364
|
}
|
|
40213
40365
|
}
|
|
40214
40366
|
var program2 = new Command;
|
|
40215
|
-
program2.name("mcps").description("Meta-MCP registry & CLI \u2014 discover, manage, and proxy MCP servers").version(
|
|
40367
|
+
program2.name("mcps").description("Meta-MCP registry & CLI \u2014 discover, manage, and proxy MCP servers").version(VERSION3).enablePositionalOptions();
|
|
40216
40368
|
program2.command("list").description("List registered MCP servers").option("--json", "Output as JSON").option("--verbose", "Show detailed info including health, command, and transport").action((opts) => {
|
|
40217
40369
|
const servers = listServers();
|
|
40218
40370
|
if (opts.json) {
|
|
@@ -40304,9 +40456,9 @@ program2.command("add").passThroughOptions().argument("[command]", "Command to r
|
|
|
40304
40456
|
try {
|
|
40305
40457
|
if (opts.fromRegistry) {
|
|
40306
40458
|
console.log(chalk2.dim(`Installing "${opts.fromRegistry}" from registry...`));
|
|
40307
|
-
const
|
|
40308
|
-
console.log(chalk2.green(`Added server: ${
|
|
40309
|
-
console.log(chalk2.dim(` ${
|
|
40459
|
+
const server2 = await installFromRegistry(opts.fromRegistry);
|
|
40460
|
+
console.log(chalk2.green(`Added server: ${server2.name} [${server2.id}]`));
|
|
40461
|
+
console.log(chalk2.dim(` ${server2.command} ${server2.args.join(" ")}`));
|
|
40310
40462
|
closeDb();
|
|
40311
40463
|
return;
|
|
40312
40464
|
}
|
|
@@ -40355,7 +40507,7 @@ Server to add:`));
|
|
|
40355
40507
|
closeDb();
|
|
40356
40508
|
return;
|
|
40357
40509
|
}
|
|
40358
|
-
const
|
|
40510
|
+
const server2 = addServer({
|
|
40359
40511
|
command: wizardCommand,
|
|
40360
40512
|
args: wizardArgs,
|
|
40361
40513
|
name: wizardName || undefined,
|
|
@@ -40363,7 +40515,7 @@ Server to add:`));
|
|
|
40363
40515
|
transport,
|
|
40364
40516
|
env
|
|
40365
40517
|
});
|
|
40366
|
-
console.log(chalk2.green(`Added: ${
|
|
40518
|
+
console.log(chalk2.green(`Added: ${server2.name} [${server2.id}]`));
|
|
40367
40519
|
closeDb();
|
|
40368
40520
|
return;
|
|
40369
40521
|
}
|
|
@@ -40391,7 +40543,7 @@ Server to add:`));
|
|
|
40391
40543
|
envMap[key] = rest.join("=");
|
|
40392
40544
|
}
|
|
40393
40545
|
}
|
|
40394
|
-
const
|
|
40546
|
+
const server = addServer({
|
|
40395
40547
|
name: opts.name,
|
|
40396
40548
|
description: opts.description,
|
|
40397
40549
|
command,
|
|
@@ -40400,8 +40552,8 @@ Server to add:`));
|
|
|
40400
40552
|
url: opts.url,
|
|
40401
40553
|
env: envMap
|
|
40402
40554
|
});
|
|
40403
|
-
console.log(chalk2.green(`Added server: ${
|
|
40404
|
-
console.log(chalk2.dim(` ${
|
|
40555
|
+
console.log(chalk2.green(`Added server: ${server.name} [${server.id}]`));
|
|
40556
|
+
console.log(chalk2.dim(` ${server.command} ${server.args.join(" ")}`));
|
|
40405
40557
|
} catch (err) {
|
|
40406
40558
|
if (err.message?.includes("UNIQUE constraint")) {
|
|
40407
40559
|
console.error(chalk2.red("A server with that ID already exists."));
|
|
@@ -40414,8 +40566,8 @@ Server to add:`));
|
|
|
40414
40566
|
closeDb();
|
|
40415
40567
|
});
|
|
40416
40568
|
program2.command("update-server").argument("<id>", "Server ID to update").description("Update fields of a registered server").option("--name <name>", "New display name").option("--description <desc>", "New description").option("--command <cmd>", "New command").option("--args <args...>", "New args list").option("--transport <type>", "New transport type").option("--url <url>", "New URL").action((id, opts) => {
|
|
40417
|
-
const
|
|
40418
|
-
if (!
|
|
40569
|
+
const server = getServer(id);
|
|
40570
|
+
if (!server) {
|
|
40419
40571
|
console.error(chalk2.red(`Server "${id}" not found.`));
|
|
40420
40572
|
closeDb();
|
|
40421
40573
|
process.exit(1);
|
|
@@ -40450,53 +40602,53 @@ program2.command("clone").argument("<id>", "Server ID to clone").argument("<new-
|
|
|
40450
40602
|
closeDb();
|
|
40451
40603
|
});
|
|
40452
40604
|
program2.command("remove").argument("<id>", "Server ID to remove").description("Remove a registered server").action((id) => {
|
|
40453
|
-
const
|
|
40454
|
-
if (!
|
|
40605
|
+
const server = getServer(id);
|
|
40606
|
+
if (!server) {
|
|
40455
40607
|
console.error(chalk2.red(`Server "${id}" not found.`));
|
|
40456
40608
|
closeDb();
|
|
40457
40609
|
process.exit(1);
|
|
40458
40610
|
}
|
|
40459
40611
|
removeServer(id);
|
|
40460
|
-
console.log(chalk2.green(`Removed server: ${
|
|
40612
|
+
console.log(chalk2.green(`Removed server: ${server.name} [${id}]`));
|
|
40461
40613
|
closeDb();
|
|
40462
40614
|
});
|
|
40463
40615
|
program2.command("enable").argument("<id>", "Server ID to enable").description("Enable a server").action((id) => {
|
|
40464
|
-
const
|
|
40465
|
-
if (!
|
|
40616
|
+
const server = getServer(id);
|
|
40617
|
+
if (!server) {
|
|
40466
40618
|
console.error(chalk2.red(`Server "${id}" not found.`));
|
|
40467
40619
|
closeDb();
|
|
40468
40620
|
process.exit(1);
|
|
40469
40621
|
}
|
|
40470
40622
|
enableServer(id);
|
|
40471
|
-
console.log(chalk2.green(`Enabled server: ${
|
|
40623
|
+
console.log(chalk2.green(`Enabled server: ${server.name}`));
|
|
40472
40624
|
closeDb();
|
|
40473
40625
|
});
|
|
40474
40626
|
program2.command("disable").argument("<id>", "Server ID to disable").description("Disable a server").action((id) => {
|
|
40475
|
-
const
|
|
40476
|
-
if (!
|
|
40627
|
+
const server = getServer(id);
|
|
40628
|
+
if (!server) {
|
|
40477
40629
|
console.error(chalk2.red(`Server "${id}" not found.`));
|
|
40478
40630
|
closeDb();
|
|
40479
40631
|
process.exit(1);
|
|
40480
40632
|
}
|
|
40481
40633
|
disableServer(id);
|
|
40482
|
-
console.log(chalk2.yellow(`Disabled server: ${
|
|
40634
|
+
console.log(chalk2.yellow(`Disabled server: ${server.name}`));
|
|
40483
40635
|
closeDb();
|
|
40484
40636
|
});
|
|
40485
40637
|
program2.command("tools").argument("[server-id]", "Optional server ID to filter by").description("List tools (all or per server)").option("--connect", "Connect to servers to fetch live tools").action(async (serverId, opts) => {
|
|
40486
40638
|
if (opts.connect) {
|
|
40487
40639
|
console.log(chalk2.dim("Connecting to enabled servers..."));
|
|
40488
40640
|
await connectAllEnabled();
|
|
40489
|
-
const
|
|
40490
|
-
if (
|
|
40641
|
+
const tools2 = listAllTools();
|
|
40642
|
+
if (tools2.length === 0) {
|
|
40491
40643
|
console.log(chalk2.dim("No tools available."));
|
|
40492
40644
|
} else {
|
|
40493
|
-
for (const t of
|
|
40645
|
+
for (const t of tools2) {
|
|
40494
40646
|
console.log(` ${chalk2.bold(t.name)}`);
|
|
40495
40647
|
if (t.description)
|
|
40496
40648
|
console.log(` ${chalk2.dim(t.description)}`);
|
|
40497
40649
|
}
|
|
40498
40650
|
console.log(chalk2.dim(`
|
|
40499
|
-
${
|
|
40651
|
+
${tools2.length} tool(s) available.`));
|
|
40500
40652
|
}
|
|
40501
40653
|
await disconnectAll();
|
|
40502
40654
|
} else if (serverId) {
|
|
@@ -40576,26 +40728,26 @@ program2.command("call").argument("<tool>", "Tool name (server_id__tool_name)").
|
|
|
40576
40728
|
process.exit(exitCode);
|
|
40577
40729
|
});
|
|
40578
40730
|
program2.command("info").argument("<id>", "Server ID").description("Show server details & tools").action((id) => {
|
|
40579
|
-
const
|
|
40580
|
-
if (!
|
|
40731
|
+
const server = getServer(id);
|
|
40732
|
+
if (!server) {
|
|
40581
40733
|
console.error(chalk2.red(`Server "${id}" not found.`));
|
|
40582
40734
|
closeDb();
|
|
40583
40735
|
process.exit(1);
|
|
40584
40736
|
}
|
|
40585
|
-
console.log(chalk2.bold(
|
|
40586
|
-
console.log(` Status: ${
|
|
40587
|
-
console.log(` Source: ${
|
|
40588
|
-
console.log(` Transport: ${
|
|
40589
|
-
console.log(` Command: ${
|
|
40590
|
-
if (
|
|
40591
|
-
console.log(` URL: ${
|
|
40592
|
-
if (
|
|
40593
|
-
console.log(` Desc: ${
|
|
40594
|
-
if (Object.keys(
|
|
40595
|
-
console.log(` Env: ${Object.entries(
|
|
40596
|
-
}
|
|
40597
|
-
console.log(` Created: ${
|
|
40598
|
-
console.log(` Updated: ${
|
|
40737
|
+
console.log(chalk2.bold(server.name) + " " + chalk2.dim(`[${server.id}]`));
|
|
40738
|
+
console.log(` Status: ${server.enabled ? chalk2.green("enabled") : chalk2.red("disabled")}`);
|
|
40739
|
+
console.log(` Source: ${server.source}`);
|
|
40740
|
+
console.log(` Transport: ${server.transport}`);
|
|
40741
|
+
console.log(` Command: ${server.command} ${server.args.join(" ")}`);
|
|
40742
|
+
if (server.url)
|
|
40743
|
+
console.log(` URL: ${server.url}`);
|
|
40744
|
+
if (server.description)
|
|
40745
|
+
console.log(` Desc: ${server.description}`);
|
|
40746
|
+
if (Object.keys(server.env).length > 0) {
|
|
40747
|
+
console.log(` Env: ${Object.entries(server.env).map(([k, v]) => `${k}=${v}`).join(", ")}`);
|
|
40748
|
+
}
|
|
40749
|
+
console.log(` Created: ${server.created_at}`);
|
|
40750
|
+
console.log(` Updated: ${server.updated_at}`);
|
|
40599
40751
|
const cached2 = getCachedTools(id);
|
|
40600
40752
|
if (cached2.length > 0) {
|
|
40601
40753
|
console.log(chalk2.bold(`
|
|
@@ -40635,10 +40787,10 @@ program2.command("doctor").argument("[id]", "Server ID to check (omit to check a
|
|
|
40635
40787
|
return;
|
|
40636
40788
|
}
|
|
40637
40789
|
let allHealthy = true;
|
|
40638
|
-
for (const
|
|
40790
|
+
for (const server of servers) {
|
|
40639
40791
|
console.log(chalk2.bold(`
|
|
40640
|
-
${
|
|
40641
|
-
const report = await diagnoseServer(
|
|
40792
|
+
${server.name} [${server.id}]`));
|
|
40793
|
+
const report = await diagnoseServer(server);
|
|
40642
40794
|
for (const check2 of report.checks) {
|
|
40643
40795
|
const icon = check2.pass ? chalk2.green("\u2713") : chalk2.red("\u2717");
|
|
40644
40796
|
console.log(` ${icon} ${check2.name}: ${chalk2.dim(check2.message)}`);
|
|
@@ -40834,14 +40986,14 @@ Enter number to install (1-${results.length}), or 0 to cancel: `), resolve2);
|
|
|
40834
40986
|
return;
|
|
40835
40987
|
}
|
|
40836
40988
|
console.log(chalk2.dim(`Installing ${chosen.name}...`));
|
|
40837
|
-
const
|
|
40989
|
+
const server = addServer({
|
|
40838
40990
|
command: "npx",
|
|
40839
40991
|
args: ["-y", pkg],
|
|
40840
40992
|
name: chosen.name,
|
|
40841
40993
|
description: chosen.description,
|
|
40842
40994
|
transport: "stdio"
|
|
40843
40995
|
});
|
|
40844
|
-
const results2 = installToAgents(
|
|
40996
|
+
const results2 = installToAgents(server, ["claude", "codex", "gemini"]);
|
|
40845
40997
|
for (const r of results2) {
|
|
40846
40998
|
if (r.success) {
|
|
40847
40999
|
console.log(chalk2.green(` \u2713 ${r.agent}`));
|
|
@@ -40850,7 +41002,7 @@ Enter number to install (1-${results.length}), or 0 to cancel: `), resolve2);
|
|
|
40850
41002
|
}
|
|
40851
41003
|
}
|
|
40852
41004
|
console.log(chalk2.green(`
|
|
40853
|
-
Installed ${
|
|
41005
|
+
Installed ${server.name} [${server.id}]`));
|
|
40854
41006
|
}
|
|
40855
41007
|
} catch (err) {
|
|
40856
41008
|
console.error(chalk2.red(`Find failed: ${err.message}`));
|
|
@@ -41008,12 +41160,12 @@ program2.command("install").argument("[id]", "Server ID (from `mcps list`) to in
|
|
|
41008
41160
|
if (!targets.includes("gemini"))
|
|
41009
41161
|
targets.push("gemini");
|
|
41010
41162
|
}
|
|
41011
|
-
let
|
|
41163
|
+
let server;
|
|
41012
41164
|
if (opts.fromRegistry) {
|
|
41013
41165
|
console.log(chalk2.dim(`Installing "${opts.fromRegistry}" from registry...`));
|
|
41014
41166
|
try {
|
|
41015
|
-
|
|
41016
|
-
console.log(chalk2.green(`Added server: ${
|
|
41167
|
+
server = await installFromRegistry(opts.fromRegistry);
|
|
41168
|
+
console.log(chalk2.green(`Added server: ${server.name} [${server.id}]`));
|
|
41017
41169
|
} catch (err) {
|
|
41018
41170
|
console.error(chalk2.red(`Failed to install from registry: ${err.message}`));
|
|
41019
41171
|
closeDb();
|
|
@@ -41021,23 +41173,23 @@ program2.command("install").argument("[id]", "Server ID (from `mcps list`) to in
|
|
|
41021
41173
|
}
|
|
41022
41174
|
} else if (opts.npm) {
|
|
41023
41175
|
const pkg = opts.npm;
|
|
41024
|
-
|
|
41025
|
-
console.log(chalk2.green(`Added server: ${
|
|
41176
|
+
server = addServer({ command: "npx", args: ["-y", pkg], name: pkg, transport: "stdio" });
|
|
41177
|
+
console.log(chalk2.green(`Added server: ${server.name} [${server.id}]`));
|
|
41026
41178
|
} else {
|
|
41027
41179
|
if (!id) {
|
|
41028
41180
|
console.error(chalk2.red("Error: server ID is required (or use --from-registry or --npm)"));
|
|
41029
41181
|
closeDb();
|
|
41030
41182
|
process.exit(1);
|
|
41031
41183
|
}
|
|
41032
|
-
|
|
41033
|
-
if (!
|
|
41184
|
+
server = getServer(id);
|
|
41185
|
+
if (!server) {
|
|
41034
41186
|
console.error(chalk2.red(`Server "${id}" not found. Use \`mcps add\` first.`));
|
|
41035
41187
|
closeDb();
|
|
41036
41188
|
process.exit(1);
|
|
41037
41189
|
}
|
|
41038
41190
|
}
|
|
41039
|
-
console.log(chalk2.dim(`Installing "${
|
|
41040
|
-
const results = installToAgents(
|
|
41191
|
+
console.log(chalk2.dim(`Installing "${server.name}" to: ${targets.join(", ")}...`));
|
|
41192
|
+
const results = installToAgents(server, targets);
|
|
41041
41193
|
for (const r of results) {
|
|
41042
41194
|
if (r.success) {
|
|
41043
41195
|
console.log(chalk2.green(` \u2713 ${r.agent}`));
|
|
@@ -41280,13 +41432,13 @@ program2.command("import").argument("<file>", "Path to the export JSON file").de
|
|
|
41280
41432
|
});
|
|
41281
41433
|
var envCmd = program2.command("env").description("Manage server environment variables");
|
|
41282
41434
|
envCmd.command("list").argument("<id>").description("List env vars for a server").action((id) => {
|
|
41283
|
-
const
|
|
41284
|
-
if (!
|
|
41435
|
+
const server = getServer(id);
|
|
41436
|
+
if (!server) {
|
|
41285
41437
|
console.error(chalk2.red(`Server "${id}" not found.`));
|
|
41286
41438
|
closeDb();
|
|
41287
41439
|
process.exit(1);
|
|
41288
41440
|
}
|
|
41289
|
-
const entries = Object.entries(
|
|
41441
|
+
const entries = Object.entries(server.env);
|
|
41290
41442
|
if (entries.length === 0) {
|
|
41291
41443
|
console.log(chalk2.dim("No env vars set."));
|
|
41292
41444
|
closeDb();
|
|
@@ -41331,7 +41483,7 @@ program2.command("mcp").description("Start meta-MCP server (stdio)").action(asyn
|
|
|
41331
41483
|
});
|
|
41332
41484
|
program2.command("feedback <message>").description("Send feedback").option("--email <email>", "Contact email").option("--category <category>", "Category: bug, feature, general").action((message, opts) => {
|
|
41333
41485
|
const adapter = getAdapter();
|
|
41334
|
-
adapter.run("INSERT INTO feedback (message, email, category, version) VALUES (?, ?, ?, ?)", message, opts.email || null, opts.category || "general",
|
|
41486
|
+
adapter.run("INSERT INTO feedback (message, email, category, version) VALUES (?, ?, ?, ?)", message, opts.email || null, opts.category || "general", VERSION3);
|
|
41335
41487
|
console.log(chalk2.green("Feedback saved. Thank you!"));
|
|
41336
41488
|
closeDb();
|
|
41337
41489
|
});
|