@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 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.12",
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/index.ts
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
- var VERSION = (() => {
38020
- return readPackageVersion(import.meta.url);
38021
- })();
38022
- var server = new McpServer({
38023
- name: "mcps",
38024
- version: VERSION
38025
- });
38026
- var _mcpsAgents = new Map;
38027
- server.tool("list_servers", "List all registered MCP servers", {}, async () => {
38028
- const servers = listServers();
38029
- return {
38030
- content: [{ type: "text", text: JSON.stringify(servers.map(redactServerEnv), null, 2) }]
38031
- };
38032
- });
38033
- server.tool("search_registry", "Search the official MCP registry for servers", { query: exports_external2.string().describe("Search query") }, async ({ query }) => {
38034
- const results = await searchRegistry(query);
38035
- return {
38036
- content: [{ type: "text", text: JSON.stringify(results, null, 2) }]
38037
- };
38038
- });
38039
- server.tool("add_server", "Register a new MCP server", {
38040
- command: exports_external2.string().describe("Command to run the server (e.g., npx, bunx, node)"),
38041
- args: exports_external2.array(exports_external2.string()).optional().describe("Arguments for the command"),
38042
- name: exports_external2.string().optional().describe("Display name"),
38043
- description: exports_external2.string().optional().describe("Description"),
38044
- transport: exports_external2.enum(["stdio", "sse", "streamable-http"]).optional().describe("Transport type"),
38045
- url: exports_external2.string().optional().describe("URL for remote transports"),
38046
- env: exports_external2.record(exports_external2.string()).optional().describe("Environment variables")
38047
- }, async ({ command, args, name, description, transport, url: url2, env }) => {
38048
- const entry = addServer({
38049
- command,
38050
- args: args || [],
38051
- name,
38052
- description,
38053
- transport,
38054
- url: url2,
38055
- env: env || {}
38056
- });
38057
- return {
38058
- content: [{ type: "text", text: JSON.stringify(entry, null, 2) }]
38059
- };
38060
- });
38061
- server.tool("install_from_registry", "Install an MCP server from the official registry", { id: exports_external2.string().describe("Registry server ID") }, async ({ id }) => {
38062
- const entry = await installFromRegistry(id);
38063
- return {
38064
- content: [{ type: "text", text: JSON.stringify(entry, null, 2) }]
38065
- };
38066
- });
38067
- server.tool("remove_server", "Remove a registered MCP server", { id: exports_external2.string().describe("Server ID to remove") }, async ({ id }) => {
38068
- const existing = getServer(id);
38069
- if (!existing) {
38070
- return {
38071
- content: [{ type: "text", text: `Server "${id}" not found.` }],
38072
- isError: true
38073
- };
38074
- }
38075
- removeServer(id);
38076
- return {
38077
- content: [{ type: "text", text: `Removed server: ${existing.name} [${id}]` }]
38078
- };
38079
- });
38080
- server.tool("enable_server", "Enable a registered MCP server", { id: exports_external2.string().describe("Server ID to enable") }, async ({ id }) => {
38081
- const existing = getServer(id);
38082
- if (!existing) {
38083
- return {
38084
- content: [{ type: "text", text: `Server "${id}" not found.` }],
38085
- isError: true
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
- const entry = enableServer(id);
38089
- return {
38090
- content: [{ type: "text", text: JSON.stringify(entry, null, 2) }]
38091
- };
38092
- });
38093
- server.tool("disable_server", "Disable a registered MCP server", { id: exports_external2.string().describe("Server ID to disable") }, async ({ id }) => {
38094
- const existing = getServer(id);
38095
- if (!existing) {
38096
- return {
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
- content: [{ type: "text", text: JSON.stringify(entry, null, 2) }]
38534
+ type: "object",
38535
+ properties,
38536
+ ...required2.length > 0 ? { required: required2 } : {},
38537
+ additionalProperties: false
38104
38538
  };
38105
- });
38106
- server.tool("update_server", "Update fields of a registered MCP server", {
38107
- id: exports_external2.string().describe("Server ID to update"),
38108
- name: exports_external2.string().optional().describe("New display name"),
38109
- description: exports_external2.string().optional().describe("New description"),
38110
- command: exports_external2.string().optional().describe("New command"),
38111
- args: exports_external2.array(exports_external2.string()).optional().describe("New args list"),
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
- const fields = {};
38123
- if (name !== undefined)
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
- const servers = listServers();
38148
- const allTools = [];
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
- return {
38156
- content: [{ type: "text", text: JSON.stringify(allTools, null, 2) }]
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
- return {
38168
- content: [{ type: "text", text: JSON.stringify(redactServerEnv(entry), null, 2) }]
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
- removeSource(id);
38207
- return {
38208
- content: [{ type: "text", text: `Removed source: ${existing.name} [${id}]` }]
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
- enableSource(id);
38220
- return {
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
- disableSource(id);
38233
- return {
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
- const agentTargets = targets ?? ["claude", "codex", "gemini"];
38249
- const results = installToAgents(entry, agentTargets);
38250
- return {
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
- return {
38271
- content: [{ type: "text", text: JSON.stringify(tools, null, 2) }]
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
- server.tool("diagnose_server", "Run health checks on a registered MCP server", { id: exports_external2.string().describe("Server ID") }, async ({ id }) => {
38311
- const entry = getServer(id);
38312
- if (!entry)
38313
- return { content: [{ type: "text", text: `Server "${id}" not found.` }], isError: true };
38314
- const report = await diagnoseServer(entry);
38315
- return { content: [{ type: "text", text: JSON.stringify(report, null, 2) }] };
38316
- });
38317
- server.tool("list_machines", "List registered fleet machines", {
38318
- enabled_only: exports_external2.boolean().optional().describe("When true, only return enabled machines")
38319
- }, async ({ enabled_only }) => {
38320
- const machines = listMachines().filter((machine) => enabled_only ? machine.enabled : true);
38321
- return {
38322
- content: [{ type: "text", text: JSON.stringify(machines, null, 2) }]
38323
- };
38324
- });
38325
- server.tool("add_machine", "Register a machine for fleet health checks and installs", {
38326
- host: exports_external2.string().describe("Hostname or SSH target"),
38327
- id: exports_external2.string().optional().describe("Stable machine ID"),
38328
- name: exports_external2.string().optional().describe("Display name"),
38329
- username: exports_external2.string().optional().describe("SSH username"),
38330
- port: exports_external2.number().int().min(1).max(65535).optional().describe("SSH port"),
38331
- platform: exports_external2.enum(["linux", "darwin", "unknown"]).optional().describe("Machine platform"),
38332
- arch: exports_external2.enum(["arm64", "x64", "unknown"]).optional().describe("Machine architecture"),
38333
- bun_path: exports_external2.string().optional().describe("Explicit path to bun on the remote machine"),
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
- return {
38354
- content: [{ type: "text", text: JSON.stringify(machine, null, 2) }]
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
- removeMachine(id);
38366
- return {
38367
- content: [{ type: "text", text: JSON.stringify({ removed: true, machine }, null, 2) }]
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(server2) {
38489
- return { ...server2, env: {} };
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 server2 = Bun.serve({
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 tools = getCachedTools(id);
38710
- return json({ ...redactServer(entry), toolCount: tools.length, tools }, 200, port);
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 tools = getCachedTools(id);
38839
- return json(tools, 200, port);
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
- server2.stop();
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: server2, onSelectTool, onBack }) {
39536
- const [tools, setTools] = useState3([]);
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(server2.id);
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: server2.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
- }, [server2.id, cachedKey]);
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(server2);
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
- ...tools.length === 0 && !loading ? [{ label: "Connect & fetch tools", value: "__connect" }] : [],
39569
- ...tools.map((t) => ({
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(server2.id);
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: server2.name
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
- server2.id
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
- server2.enabled ? "enabled" : "disabled",
39756
+ server.enabled ? "enabled" : "disabled",
39605
39757
  " | Transport: ",
39606
- server2.transport
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
- server2.command,
39765
+ server.command,
39614
39766
  " ",
39615
- server2.args.join(" ")
39767
+ server.args.join(" ")
39616
39768
  ]
39617
39769
  }, undefined, true, undefined, this),
39618
- server2.description && /* @__PURE__ */ jsxDEV2(Text5, {
39770
+ server.description && /* @__PURE__ */ jsxDEV2(Text5, {
39619
39771
  dimColor: true,
39620
- children: server2.description
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: tools.length > 0 ? `Tools (${tools.length}):` : "Tools:"
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 server2 = await installFromRegistry(item.value);
39787
- setMessage(`Installed: ${server2.name} [${server2.id}]`);
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: server2, tool, onBack }) {
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(server2);
39898
- const prefixed = `${server2.id}${TOOL_PREFIX_SEPARATOR}${tool.name}`;
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
- server2.name,
40078
+ server.name,
39927
40079
  " [",
39928
- server2.id,
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 = (server2) => {
40042
- setSelectedServer(server2);
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 VERSION2 = (() => {
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(VERSION2).enablePositionalOptions();
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 server3 = await installFromRegistry(opts.fromRegistry);
40308
- console.log(chalk2.green(`Added server: ${server3.name} [${server3.id}]`));
40309
- console.log(chalk2.dim(` ${server3.command} ${server3.args.join(" ")}`));
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 server3 = addServer({
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: ${server3.name} [${server3.id}]`));
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 server2 = addServer({
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: ${server2.name} [${server2.id}]`));
40404
- console.log(chalk2.dim(` ${server2.command} ${server2.args.join(" ")}`));
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 server2 = getServer(id);
40418
- if (!server2) {
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 server2 = getServer(id);
40454
- if (!server2) {
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: ${server2.name} [${id}]`));
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 server2 = getServer(id);
40465
- if (!server2) {
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: ${server2.name}`));
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 server2 = getServer(id);
40476
- if (!server2) {
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: ${server2.name}`));
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 tools = listAllTools();
40490
- if (tools.length === 0) {
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 tools) {
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
- ${tools.length} tool(s) available.`));
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 server2 = getServer(id);
40580
- if (!server2) {
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(server2.name) + " " + chalk2.dim(`[${server2.id}]`));
40586
- console.log(` Status: ${server2.enabled ? chalk2.green("enabled") : chalk2.red("disabled")}`);
40587
- console.log(` Source: ${server2.source}`);
40588
- console.log(` Transport: ${server2.transport}`);
40589
- console.log(` Command: ${server2.command} ${server2.args.join(" ")}`);
40590
- if (server2.url)
40591
- console.log(` URL: ${server2.url}`);
40592
- if (server2.description)
40593
- console.log(` Desc: ${server2.description}`);
40594
- if (Object.keys(server2.env).length > 0) {
40595
- console.log(` Env: ${Object.entries(server2.env).map(([k, v]) => `${k}=${v}`).join(", ")}`);
40596
- }
40597
- console.log(` Created: ${server2.created_at}`);
40598
- console.log(` Updated: ${server2.updated_at}`);
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 server2 of servers) {
40790
+ for (const server of servers) {
40639
40791
  console.log(chalk2.bold(`
40640
- ${server2.name} [${server2.id}]`));
40641
- const report = await diagnoseServer(server2);
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 server2 = addServer({
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(server2, ["claude", "codex", "gemini"]);
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 ${server2.name} [${server2.id}]`));
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 server2;
41163
+ let server;
41012
41164
  if (opts.fromRegistry) {
41013
41165
  console.log(chalk2.dim(`Installing "${opts.fromRegistry}" from registry...`));
41014
41166
  try {
41015
- server2 = await installFromRegistry(opts.fromRegistry);
41016
- console.log(chalk2.green(`Added server: ${server2.name} [${server2.id}]`));
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
- server2 = addServer({ command: "npx", args: ["-y", pkg], name: pkg, transport: "stdio" });
41025
- console.log(chalk2.green(`Added server: ${server2.name} [${server2.id}]`));
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
- server2 = getServer(id);
41033
- if (!server2) {
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 "${server2.name}" to: ${targets.join(", ")}...`));
41040
- const results = installToAgents(server2, targets);
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 server2 = getServer(id);
41284
- if (!server2) {
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(server2.env);
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", VERSION2);
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
  });