@hasna/mcps 0.0.11 → 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.11",
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",
@@ -21011,8 +21019,6 @@ import React10 from "react";
21011
21019
  import { render } from "ink";
21012
21020
  import chalk2 from "chalk";
21013
21021
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
21014
- import { join as join12, dirname as dirname5 } from "path";
21015
- import { fileURLToPath as fileURLToPath3 } from "url";
21016
21022
 
21017
21023
  // src/lib/registry.ts
21018
21024
  init_db();
@@ -36764,6 +36770,68 @@ async function runFleetInstall(options = {}, dependencies = {}) {
36764
36770
  // src/cli/index.tsx
36765
36771
  import * as readline from "readline";
36766
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
+
36767
36835
  // node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
36768
36836
  class ExperimentalServerTasks {
36769
36837
  constructor(_server) {
@@ -37925,535 +37993,634 @@ var EMPTY_COMPLETION_RESULT = {
37925
37993
  }
37926
37994
  };
37927
37995
 
37928
- // node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
37929
- import process3 from "process";
37930
- class StdioServerTransport {
37931
- constructor(_stdin = process3.stdin, _stdout = process3.stdout) {
37932
- this._stdin = _stdin;
37933
- this._stdout = _stdout;
37934
- this._readBuffer = new ReadBuffer;
37935
- this._started = false;
37936
- this._ondata = (chunk) => {
37937
- this._readBuffer.append(chunk);
37938
- this.processReadBuffer();
37939
- };
37940
- this._onerror = (error2) => {
37941
- this.onerror?.(error2);
37942
- };
37943
- }
37944
- async start() {
37945
- if (this._started) {
37946
- throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");
37947
- }
37948
- this._started = true;
37949
- this._stdin.on("data", this._ondata);
37950
- this._stdin.on("error", this._onerror);
37951
- }
37952
- processReadBuffer() {
37953
- while (true) {
37954
- try {
37955
- const message = this._readBuffer.readMessage();
37956
- if (message === null) {
37957
- break;
37958
- }
37959
- this.onmessage?.(message);
37960
- } catch (error2) {
37961
- this.onerror?.(error2);
37962
- }
37963
- }
37964
- }
37965
- async close() {
37966
- this._stdin.off("data", this._ondata);
37967
- this._stdin.off("error", this._onerror);
37968
- const remainingDataListeners = this._stdin.listenerCount("data");
37969
- if (remainingDataListeners === 0) {
37970
- this._stdin.pause();
37971
- }
37972
- this._readBuffer.clear();
37973
- this.onclose?.();
37974
- }
37975
- send(message) {
37976
- return new Promise((resolve) => {
37977
- const json = serializeMessage(message);
37978
- if (this._stdout.write(json)) {
37979
- resolve();
37980
- } else {
37981
- this._stdout.once("drain", resolve);
37982
- }
37983
- });
37996
+ // src/lib/version.ts
37997
+ import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
37998
+ import { dirname as dirname3, join as join10 } from "path";
37999
+ import { fileURLToPath } from "url";
38000
+ var FALLBACK_VERSION = "0.0.1";
38001
+ function readPackageVersion(moduleUrl, fallback = FALLBACK_VERSION) {
38002
+ const baseDir = dirname3(fileURLToPath(moduleUrl));
38003
+ const candidates = [
38004
+ join10(baseDir, "..", "..", "package.json"),
38005
+ join10(baseDir, "..", "package.json"),
38006
+ join10(baseDir, "package.json")
38007
+ ];
38008
+ for (const candidate of candidates) {
38009
+ if (!existsSync9(candidate))
38010
+ continue;
38011
+ try {
38012
+ const pkg = JSON.parse(readFileSync5(candidate, "utf-8"));
38013
+ if (pkg.version)
38014
+ return pkg.version;
38015
+ } catch {}
37984
38016
  }
38017
+ return fallback;
37985
38018
  }
37986
38019
 
37987
- // src/mcp/index.ts
37988
- init_dist();
37989
- import { readFileSync as readFileSync5 } from "fs";
37990
- import { join as join10, dirname as dirname3 } from "path";
37991
- import { fileURLToPath } from "url";
38020
+ // src/mcp/tools.ts
37992
38021
  init_sources();
37993
38022
  init_config2();
37994
38023
  init_db();
38024
+ var VERSION = readPackageVersion(import.meta.url);
38025
+ var mcpsAgents = new Map;
37995
38026
  function redactServerEnv(server) {
37996
38027
  return { ...server, env: {} };
37997
38028
  }
37998
- var VERSION = (() => {
37999
- try {
38000
- const pkgPath = join10(dirname3(fileURLToPath(import.meta.url)), "..", "..", "package.json");
38001
- const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
38002
- return pkg.version || "0.0.1";
38003
- } catch {
38004
- return "0.0.1";
38005
- }
38006
- })();
38007
- var server = new McpServer({
38008
- name: "mcps",
38009
- version: VERSION
38010
- });
38011
- var _mcpsAgents = new Map;
38012
- server.tool("list_servers", "List all registered MCP servers", {}, async () => {
38013
- const servers = listServers();
38014
- return {
38015
- content: [{ type: "text", text: JSON.stringify(servers.map(redactServerEnv), null, 2) }]
38016
- };
38017
- });
38018
- server.tool("search_registry", "Search the official MCP registry for servers", { query: exports_external2.string().describe("Search query") }, async ({ query }) => {
38019
- const results = await searchRegistry(query);
38020
- return {
38021
- content: [{ type: "text", text: JSON.stringify(results, null, 2) }]
38022
- };
38023
- });
38024
- server.tool("add_server", "Register a new MCP server", {
38025
- command: exports_external2.string().describe("Command to run the server (e.g., npx, bunx, node)"),
38026
- args: exports_external2.array(exports_external2.string()).optional().describe("Arguments for the command"),
38027
- name: exports_external2.string().optional().describe("Display name"),
38028
- description: exports_external2.string().optional().describe("Description"),
38029
- transport: exports_external2.enum(["stdio", "sse", "streamable-http"]).optional().describe("Transport type"),
38030
- url: exports_external2.string().optional().describe("URL for remote transports"),
38031
- env: exports_external2.record(exports_external2.string()).optional().describe("Environment variables")
38032
- }, async ({ command, args, name, description, transport, url: url2, env }) => {
38033
- const entry = addServer({
38034
- command,
38035
- args: args || [],
38036
- name,
38037
- description,
38038
- transport,
38039
- url: url2,
38040
- env: env || {}
38041
- });
38042
- return {
38043
- content: [{ type: "text", text: JSON.stringify(entry, null, 2) }]
38044
- };
38045
- });
38046
- server.tool("install_from_registry", "Install an MCP server from the official registry", { id: exports_external2.string().describe("Registry server ID") }, async ({ id }) => {
38047
- const entry = await installFromRegistry(id);
38048
- return {
38049
- content: [{ type: "text", text: JSON.stringify(entry, null, 2) }]
38050
- };
38051
- });
38052
- server.tool("remove_server", "Remove a registered MCP server", { id: exports_external2.string().describe("Server ID to remove") }, async ({ id }) => {
38053
- const existing = getServer(id);
38054
- if (!existing) {
38055
- return {
38056
- content: [{ type: "text", text: `Server "${id}" not found.` }],
38057
- isError: true
38058
- };
38059
- }
38060
- removeServer(id);
38061
- return {
38062
- content: [{ type: "text", text: `Removed server: ${existing.name} [${id}]` }]
38063
- };
38064
- });
38065
- server.tool("enable_server", "Enable a registered MCP server", { id: exports_external2.string().describe("Server ID to enable") }, async ({ id }) => {
38066
- const existing = getServer(id);
38067
- if (!existing) {
38068
- return {
38069
- content: [{ type: "text", text: `Server "${id}" not found.` }],
38070
- isError: true
38071
- };
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)));
38072
38522
  }
38073
- const entry = enableServer(id);
38074
- return {
38075
- content: [{ type: "text", text: JSON.stringify(entry, null, 2) }]
38076
- };
38077
- });
38078
- server.tool("disable_server", "Disable a registered MCP server", { id: exports_external2.string().describe("Server ID to disable") }, async ({ id }) => {
38079
- const existing = getServer(id);
38080
- if (!existing) {
38081
- return {
38082
- content: [{ type: "text", text: `Server "${id}" not found.` }],
38083
- isError: true
38084
- };
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);
38085
38532
  }
38086
- const entry = disableServer(id);
38087
38533
  return {
38088
- content: [{ type: "text", text: JSON.stringify(entry, null, 2) }]
38534
+ type: "object",
38535
+ properties,
38536
+ ...required2.length > 0 ? { required: required2 } : {},
38537
+ additionalProperties: false
38089
38538
  };
38090
- });
38091
- server.tool("update_server", "Update fields of a registered MCP server", {
38092
- id: exports_external2.string().describe("Server ID to update"),
38093
- name: exports_external2.string().optional().describe("New display name"),
38094
- description: exports_external2.string().optional().describe("New description"),
38095
- command: exports_external2.string().optional().describe("New command"),
38096
- args: exports_external2.array(exports_external2.string()).optional().describe("New args list"),
38097
- transport: exports_external2.enum(["stdio", "sse", "streamable-http"]).optional().describe("New transport type"),
38098
- url: exports_external2.string().optional().describe("New URL for remote transports")
38099
- }, async ({ id, name, description, command, args, transport, url: url2 }) => {
38100
- const existing = getServer(id);
38101
- if (!existing) {
38102
- return {
38103
- content: [{ type: "text", text: `Server "${id}" not found.` }],
38104
- isError: true
38105
- };
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 };
38106
38546
  }
38107
- const fields = {};
38108
- if (name !== undefined)
38109
- fields.name = name;
38110
- if (description !== undefined)
38111
- fields.description = description;
38112
- if (command !== undefined)
38113
- fields.command = command;
38114
- if (args !== undefined)
38115
- fields.args = args;
38116
- if (transport !== undefined)
38117
- fields.transport = transport;
38118
- if (url2 !== undefined)
38119
- fields.url = url2;
38120
- const updated = updateServer(id, fields);
38121
- return {
38122
- content: [{ type: "text", text: JSON.stringify(redactServerEnv(updated), null, 2) }]
38123
- };
38124
- });
38125
- 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 }) => {
38126
- if (server_id) {
38127
- const tools = getCachedTools(server_id);
38128
- return {
38129
- content: [{ type: "text", text: JSON.stringify(tools.map((t) => ({ ...t, server_id })), null, 2) }]
38130
- };
38547
+ if (typeName === exports_external2.ZodFirstPartyTypeKind.ZodNullable) {
38548
+ return { ...asJsonSchemaObject(zodSchemaToJsonSchema(def.innerType)), nullable: true, ...description };
38131
38549
  }
38132
- const servers = listServers();
38133
- const allTools = [];
38134
- for (const s of servers) {
38135
- const tools = getCachedTools(s.id);
38136
- for (const t of tools) {
38137
- allTools.push({ server_id: s.id, ...t });
38138
- }
38550
+ if (typeName === exports_external2.ZodFirstPartyTypeKind.ZodString) {
38551
+ return { type: "string", ...description };
38139
38552
  }
38140
- return {
38141
- content: [{ type: "text", text: JSON.stringify(allTools, null, 2) }]
38142
- };
38143
- });
38144
- server.tool("get_server_info", "Get detailed information about a registered MCP server", { id: exports_external2.string().describe("Server ID") }, async ({ id }) => {
38145
- const entry = getServer(id);
38146
- if (!entry) {
38147
- return {
38148
- content: [{ type: "text", text: `Server "${id}" not found.` }],
38149
- isError: true
38150
- };
38553
+ if (typeName === exports_external2.ZodFirstPartyTypeKind.ZodBoolean) {
38554
+ return { type: "boolean", ...description };
38151
38555
  }
38152
- return {
38153
- content: [{ type: "text", text: JSON.stringify(redactServerEnv(entry), null, 2) }]
38154
- };
38155
- });
38156
- 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.", {
38157
- query: exports_external2.string().describe("Search query (e.g. 'filesystem', 'postgres', 'browser')"),
38158
- sources: exports_external2.array(exports_external2.string()).optional().describe("Source IDs to search (default: all enabled). Use list_sources to get IDs."),
38159
- limit: exports_external2.number().optional().describe("Max results per source (default: 20)")
38160
- }, async ({ query, sources, limit }) => {
38161
- const results = await findServers(query, { sources, limit });
38162
- return {
38163
- content: [{ type: "text", text: JSON.stringify(results, null, 2) }]
38164
- };
38165
- });
38166
- server.tool("list_sources", "List all configured search sources for finding MCP servers", {}, async () => {
38167
- const sources = listSources();
38168
- return {
38169
- content: [{ type: "text", text: JSON.stringify(sources, null, 2) }]
38170
- };
38171
- });
38172
- server.tool("add_source", "Add a new search source for finding MCP servers", {
38173
- name: exports_external2.string().describe("Source name"),
38174
- type: exports_external2.enum(["mcp-registry", "awesome-list", "npm-search", "github-topic"]).describe("Source type"),
38175
- url: exports_external2.string().describe("Source URL endpoint"),
38176
- description: exports_external2.string().optional().describe("Description")
38177
- }, async ({ name, type, url: url2, description }) => {
38178
- const source = addSource({ name, type, url: url2, description });
38179
- return {
38180
- content: [{ type: "text", text: JSON.stringify(source, null, 2) }]
38181
- };
38182
- });
38183
- server.tool("remove_source", "Remove a search source by ID", { id: exports_external2.string().describe("Source ID to remove") }, async ({ id }) => {
38184
- const existing = getSource(id);
38185
- if (!existing) {
38186
- return {
38187
- content: [{ type: "text", text: `Source "${id}" not found.` }],
38188
- isError: true
38189
- };
38556
+ if (typeName === exports_external2.ZodFirstPartyTypeKind.ZodUnknown || typeName === exports_external2.ZodFirstPartyTypeKind.ZodAny) {
38557
+ return Object.keys(description).length > 0 ? description : true;
38190
38558
  }
38191
- removeSource(id);
38192
- return {
38193
- content: [{ type: "text", text: `Removed source: ${existing.name} [${id}]` }]
38194
- };
38195
- });
38196
- server.tool("enable_source_finder", "Enable a search source", { id: exports_external2.string().describe("Source ID to enable") }, async ({ id }) => {
38197
- const existing = getSource(id);
38198
- if (!existing) {
38199
- return {
38200
- content: [{ type: "text", text: `Source "${id}" not found.` }],
38201
- 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
38202
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;
38203
38572
  }
38204
- enableSource(id);
38205
- return {
38206
- content: [{ type: "text", text: `Enabled source: ${existing.name}` }]
38207
- };
38208
- });
38209
- server.tool("disable_source_finder", "Disable a search source", { id: exports_external2.string().describe("Source ID to disable") }, async ({ id }) => {
38210
- const existing = getSource(id);
38211
- if (!existing) {
38212
- return {
38213
- content: [{ type: "text", text: `Source "${id}" not found.` }],
38214
- isError: true
38215
- };
38573
+ if (typeName === exports_external2.ZodFirstPartyTypeKind.ZodEnum) {
38574
+ return { type: "string", enum: def.values, ...description };
38216
38575
  }
38217
- disableSource(id);
38218
- return {
38219
- content: [{ type: "text", text: `Disabled source: ${existing.name}` }]
38220
- };
38221
- });
38222
- server.tool("install_to_agents", "Install a registered MCP server into Claude Code, Codex, and/or Gemini", {
38223
- id: exports_external2.string().describe("Server ID to install (from list_servers)"),
38224
- targets: exports_external2.array(exports_external2.enum(["claude", "codex", "gemini"])).optional().describe("Target agents to install into (default: all)")
38225
- }, async ({ id, targets }) => {
38226
- const entry = getServer(id);
38227
- if (!entry) {
38228
- return {
38229
- content: [{ type: "text", text: `Server "${id}" not found.` }],
38230
- isError: true
38231
- };
38576
+ if (typeName === exports_external2.ZodFirstPartyTypeKind.ZodArray) {
38577
+ return { type: "array", items: zodSchemaToJsonSchema(def.type), ...description };
38232
38578
  }
38233
- const agentTargets = targets ?? ["claude", "codex", "gemini"];
38234
- const results = installToAgents(entry, agentTargets);
38235
- return {
38236
- content: [{ type: "text", text: JSON.stringify(results, null, 2) }]
38237
- };
38238
- });
38239
- server.tool("list_awesome_servers", "List all MCP servers from the curated punkpeye/awesome-mcp-servers GitHub list", {}, async () => {
38240
- const results = await listAwesomeServers();
38241
- return {
38242
- content: [{ type: "text", text: JSON.stringify(results, null, 2) }]
38243
- };
38244
- });
38245
- server.tool("connect_and_list_tools", "Connect to all enabled MCP servers and list their available tools", {}, async () => {
38246
- let tools = [];
38247
- try {
38248
- await connectAllEnabled();
38249
- tools = listAllTools();
38250
- } finally {
38251
- await disconnectAll().catch(() => {
38252
- return;
38253
- });
38579
+ if (typeName === exports_external2.ZodFirstPartyTypeKind.ZodRecord) {
38580
+ const valueType = def.valueType ? zodSchemaToJsonSchema(def.valueType) : true;
38581
+ return { type: "object", additionalProperties: valueType, ...description };
38254
38582
  }
38255
- return {
38256
- content: [{ type: "text", text: JSON.stringify(tools, null, 2) }]
38257
- };
38258
- });
38259
- server.tool("call_upstream_tool", `Call a tool on a connected upstream MCP server. Tool name format: server_id${TOOL_PREFIX_SEPARATOR}tool_name`, {
38260
- tool_name: exports_external2.string().describe(`Prefixed tool name (server_id${TOOL_PREFIX_SEPARATOR}tool_name)`),
38261
- arguments: exports_external2.record(exports_external2.unknown()).optional().describe("Tool arguments as key-value pairs")
38262
- }, async ({ tool_name, arguments: args }) => {
38263
- try {
38264
- const sepIdx = tool_name.indexOf(TOOL_PREFIX_SEPARATOR);
38265
- if (sepIdx === -1) {
38266
- return {
38267
- content: [{ type: "text", text: `Error: Invalid tool name "${tool_name}"` }],
38268
- isError: true
38269
- };
38270
- }
38271
- const serverId = tool_name.slice(0, sepIdx);
38272
- const entry = getServer(serverId);
38273
- if (!entry) {
38274
- return {
38275
- content: [{ type: "text", text: `Error: Server "${serverId}" not found.` }],
38276
- isError: true
38277
- };
38278
- }
38279
- if (!entry.enabled) {
38280
- return {
38281
- content: [{ type: "text", text: `Error: Server "${serverId}" is disabled.` }],
38282
- isError: true
38283
- };
38284
- }
38285
- await connectToServer(entry);
38286
- const result = await callTool(tool_name, args || {});
38287
- return { content: result.content };
38288
- } catch (err) {
38289
- return {
38290
- content: [{ type: "text", text: `Error: ${err.message}` }],
38291
- isError: true
38292
- };
38583
+ if (typeName === exports_external2.ZodFirstPartyTypeKind.ZodObject) {
38584
+ const objectShape = typeof def.shape === "function" ? def.shape() : def.shape;
38585
+ return { ...zodRawShapeToJsonSchema(objectShape ?? {}), ...description };
38293
38586
  }
38294
- });
38295
- server.tool("diagnose_server", "Run health checks on a registered MCP server", { id: exports_external2.string().describe("Server ID") }, async ({ id }) => {
38296
- const entry = getServer(id);
38297
- if (!entry)
38298
- return { content: [{ type: "text", text: `Server "${id}" not found.` }], isError: true };
38299
- const report = await diagnoseServer(entry);
38300
- return { content: [{ type: "text", text: JSON.stringify(report, null, 2) }] };
38301
- });
38302
- server.tool("list_machines", "List registered fleet machines", {
38303
- enabled_only: exports_external2.boolean().optional().describe("When true, only return enabled machines")
38304
- }, async ({ enabled_only }) => {
38305
- const machines = listMachines().filter((machine) => enabled_only ? machine.enabled : true);
38306
- return {
38307
- content: [{ type: "text", text: JSON.stringify(machines, null, 2) }]
38308
- };
38309
- });
38310
- server.tool("add_machine", "Register a machine for fleet health checks and installs", {
38311
- host: exports_external2.string().describe("Hostname or SSH target"),
38312
- id: exports_external2.string().optional().describe("Stable machine ID"),
38313
- name: exports_external2.string().optional().describe("Display name"),
38314
- username: exports_external2.string().optional().describe("SSH username"),
38315
- port: exports_external2.number().int().min(1).max(65535).optional().describe("SSH port"),
38316
- platform: exports_external2.enum(["linux", "darwin", "unknown"]).optional().describe("Machine platform"),
38317
- arch: exports_external2.enum(["arm64", "x64", "unknown"]).optional().describe("Machine architecture"),
38318
- bun_path: exports_external2.string().optional().describe("Explicit path to bun on the remote machine"),
38319
- npm_path: exports_external2.string().optional().describe("Explicit path to npm on the remote machine"),
38320
- installer: exports_external2.enum(["auto", "bun", "npm"]).optional().describe("Preferred installer"),
38321
- ssh_key_path: exports_external2.string().optional().describe("SSH private key path"),
38322
- enabled: exports_external2.boolean().optional().describe("Whether the machine should be enabled")
38323
- }, async ({ host, id, name, username, port, platform: platform2, arch, bun_path, npm_path, installer, ssh_key_path, enabled }) => {
38324
- const machine = addMachine({
38325
- host,
38326
- id,
38327
- name,
38328
- username,
38329
- port,
38330
- platform: platform2,
38331
- arch,
38332
- bun_path,
38333
- npm_path,
38334
- installer,
38335
- ssh_key_path,
38336
- 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
38337
38612
  });
38338
- return {
38339
- content: [{ type: "text", text: JSON.stringify(machine, null, 2) }]
38340
- };
38341
- });
38342
- server.tool("remove_machine", "Remove a registered machine", { id: exports_external2.string().describe("Machine ID to remove") }, async ({ id }) => {
38343
- const machine = getMachine(id);
38344
- if (!machine) {
38345
- return {
38346
- content: [{ type: "text", text: `Machine "${id}" not found.` }],
38347
- isError: true
38348
- };
38613
+ registerMcpTools(server, options.tools);
38614
+ if (options.cloudTools !== false) {
38615
+ registerCloudTools(server, "mcps");
38349
38616
  }
38350
- removeMachine(id);
38351
- return {
38352
- content: [{ type: "text", text: JSON.stringify({ removed: true, machine }, null, 2) }]
38353
- };
38354
- });
38355
- server.tool("seed_default_machines", "Seed the standard spark/apple machine inventory", {}, async () => {
38356
- const machines = seedDefaultMachines();
38357
- return {
38358
- content: [{ type: "text", text: JSON.stringify(machines, null, 2) }]
38359
- };
38360
- });
38361
- server.tool("list_hasna_mcp_catalog", "List the discovered @hasna MCP package catalog", {
38362
- packages: exports_external2.array(exports_external2.string()).optional().describe("Optional package-name filter"),
38363
- refresh: exports_external2.boolean().optional().describe("Refresh npm metadata instead of using cache")
38364
- }, async ({ packages, refresh }) => {
38365
- const catalog = await listHasnaMcpCatalog({ refresh });
38366
- const filtered = packages?.length ? catalog.filter((entry) => packages.includes(entry.name)) : catalog;
38367
- return {
38368
- content: [{ type: "text", text: JSON.stringify(filtered, null, 2) }]
38369
- };
38370
- });
38371
- server.tool("fleet_health", "Run fleet-wide MCP health checks across registered machines", {
38372
- machine_ids: exports_external2.array(exports_external2.string()).optional().describe("Optional machine IDs to check"),
38373
- packages: exports_external2.array(exports_external2.string()).optional().describe("Optional @hasna package-name filter"),
38374
- refresh_catalog: exports_external2.boolean().optional().describe("Refresh npm metadata before checking"),
38375
- timeout_ms: exports_external2.number().int().min(1000).optional().describe("Remote timeout in milliseconds")
38376
- }, async ({ machine_ids, packages, refresh_catalog, timeout_ms }) => {
38377
- const reports = await runFleetHealthCheck({
38378
- machineIds: machine_ids,
38379
- packages,
38380
- refreshCatalog: refresh_catalog,
38381
- timeoutMs: timeout_ms
38382
- });
38383
- return {
38384
- content: [{ type: "text", text: JSON.stringify(reports, null, 2) }]
38385
- };
38386
- });
38387
- server.tool("fleet_install", "Batch-install missing or outdated @hasna MCP packages across machines", {
38388
- machine_ids: exports_external2.array(exports_external2.string()).optional().describe("Optional machine IDs to target"),
38389
- packages: exports_external2.array(exports_external2.string()).optional().describe("Optional @hasna package-name filter"),
38390
- mode: exports_external2.enum(["missing", "missing-or-outdated", "all"]).optional().describe("Install selection mode"),
38391
- installer: exports_external2.enum(["auto", "bun", "npm"]).optional().describe("Override installer"),
38392
- refresh_catalog: exports_external2.boolean().optional().describe("Refresh npm metadata before installing"),
38393
- timeout_ms: exports_external2.number().int().min(1000).optional().describe("Remote timeout in milliseconds")
38394
- }, async ({ machine_ids, packages, mode, installer, refresh_catalog, timeout_ms }) => {
38395
- const reports = await runFleetInstall({
38396
- machineIds: machine_ids,
38397
- packages,
38398
- mode,
38399
- installer,
38400
- refreshCatalog: refresh_catalog,
38401
- timeoutMs: timeout_ms
38402
- });
38403
- return {
38404
- content: [{ type: "text", text: JSON.stringify(reports, null, 2) }]
38405
- };
38406
- });
38407
- server.tool("send_feedback", "Send feedback about this service", {
38408
- message: exports_external2.string().describe("Feedback message"),
38409
- email: exports_external2.string().optional().describe("Contact email (optional)"),
38410
- category: exports_external2.enum(["bug", "feature", "general"]).optional().describe("Feedback category")
38411
- }, async (params) => {
38412
- const adapter = getAdapter();
38413
- adapter.run("INSERT INTO feedback (message, email, category, version) VALUES (?, ?, ?, ?)", params.message, params.email || null, params.category || "general", VERSION);
38414
- return { content: [{ type: "text", text: "Feedback saved. Thank you!" }] };
38415
- });
38416
- server.tool("register_agent", "Register an agent session. Returns agent_id. Auto-triggers a heartbeat.", {
38417
- name: exports_external2.string(),
38418
- session_id: exports_external2.string().optional()
38419
- }, async (params) => {
38420
- const existing = [..._mcpsAgents.values()].find((a) => a.name === params.name);
38421
- if (existing) {
38422
- existing.last_seen_at = new Date().toISOString();
38423
- if (params.session_id)
38424
- existing.session_id = params.session_id;
38425
- return { content: [{ type: "text", text: JSON.stringify(existing) }] };
38426
- }
38427
- const id = Math.random().toString(36).slice(2, 10);
38428
- const ag = { id, name: params.name, session_id: params.session_id, last_seen_at: new Date().toISOString() };
38429
- _mcpsAgents.set(id, ag);
38430
- return { content: [{ type: "text", text: JSON.stringify(ag) }] };
38431
- });
38432
- server.tool("heartbeat", "Update last_seen_at to signal agent is active.", {
38433
- agent_id: exports_external2.string()
38434
- }, async (params) => {
38435
- const ag = _mcpsAgents.get(params.agent_id);
38436
- if (!ag)
38437
- return { content: [{ type: "text", text: `Agent not found: ${params.agent_id}` }], isError: true };
38438
- ag.last_seen_at = new Date().toISOString();
38439
- return { content: [{ type: "text", text: JSON.stringify({ agent_id: ag.id, last_seen_at: ag.last_seen_at }) }] };
38440
- });
38441
- server.tool("set_focus", "Set active project context for this agent session.", {
38442
- agent_id: exports_external2.string(),
38443
- project_id: exports_external2.string().optional()
38444
- }, async (params) => {
38445
- const ag = _mcpsAgents.get(params.agent_id);
38446
- if (!ag)
38447
- return { content: [{ type: "text", text: `Agent not found: ${params.agent_id}` }], isError: true };
38448
- ag.project_id = params.project_id;
38449
- return { content: [{ type: "text", text: JSON.stringify({ agent_id: ag.id, project_id: ag.project_id ?? null }) }] };
38450
- });
38451
- server.tool("list_agents", "List all registered agents.", {}, async () => {
38452
- return { content: [{ type: "text", text: JSON.stringify([..._mcpsAgents.values()]) }] };
38453
- });
38617
+ return server;
38618
+ }
38619
+
38620
+ // src/mcp/index.ts
38454
38621
  async function startMcpServer() {
38622
+ const server = createMcpServer();
38455
38623
  const transport = new StdioServerTransport;
38456
- registerCloudTools(server, "mcps");
38457
38624
  await server.connect(transport);
38458
38625
  }
38459
38626
  var isDirectRun = import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("/mcp/index.ts") || process.argv[1]?.endsWith("/bin/mcp.js");
@@ -38465,13 +38632,13 @@ if (isDirectRun) {
38465
38632
  }
38466
38633
 
38467
38634
  // src/server/serve.ts
38468
- import { existsSync as existsSync9 } from "fs";
38635
+ import { existsSync as existsSync10 } from "fs";
38469
38636
  import { join as join11, dirname as dirname4, extname, resolve, relative as relative2, sep } from "path";
38470
38637
  import { fileURLToPath as fileURLToPath2 } from "url";
38471
38638
  init_sources();
38472
38639
  init_db();
38473
- function redactServer(server2) {
38474
- return { ...server2, env: {} };
38640
+ function redactServer(server) {
38641
+ return { ...server, env: {} };
38475
38642
  }
38476
38643
  function resolveDashboardDir() {
38477
38644
  const candidates = [];
@@ -38487,7 +38654,7 @@ function resolveDashboardDir() {
38487
38654
  }
38488
38655
  candidates.push(join11(process.cwd(), "dashboard", "dist"));
38489
38656
  for (const candidate of candidates) {
38490
- if (existsSync9(candidate))
38657
+ if (existsSync10(candidate))
38491
38658
  return candidate;
38492
38659
  }
38493
38660
  return join11(process.cwd(), "dashboard", "dist");
@@ -38578,7 +38745,7 @@ function getAllServersWithToolCount() {
38578
38745
  }));
38579
38746
  }
38580
38747
  function serveStaticFile(filePath) {
38581
- if (!existsSync9(filePath))
38748
+ if (!existsSync10(filePath))
38582
38749
  return null;
38583
38750
  const ext = extname(filePath);
38584
38751
  const contentType = MIME_TYPES[ext] || "application/octet-stream";
@@ -38611,7 +38778,7 @@ async function startServer(port, options) {
38611
38778
  const host = options?.host ?? "127.0.0.1";
38612
38779
  getDb();
38613
38780
  const dashboardDir = resolveDashboardDir();
38614
- const dashboardExists = existsSync9(dashboardDir);
38781
+ const dashboardExists = existsSync10(dashboardDir);
38615
38782
  if (!dashboardExists) {
38616
38783
  console.error(`
38617
38784
  Dashboard not found at: ${dashboardDir}`);
@@ -38620,7 +38787,7 @@ Dashboard not found at: ${dashboardDir}`);
38620
38787
  console.error(` cd dashboard && bun install && bun run build
38621
38788
  `);
38622
38789
  }
38623
- const server2 = Bun.serve({
38790
+ const server = Bun.serve({
38624
38791
  port,
38625
38792
  hostname: host,
38626
38793
  async fetch(req) {
@@ -38691,8 +38858,8 @@ Dashboard not found at: ${dashboardDir}`);
38691
38858
  const entry = getServer(id);
38692
38859
  if (!entry)
38693
38860
  return json({ error: `Server '${id}' not found` }, 404, port);
38694
- const tools = getCachedTools(id);
38695
- 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);
38696
38863
  }
38697
38864
  if (singleMatch && method === "DELETE") {
38698
38865
  const id = singleMatch[1];
@@ -38820,8 +38987,8 @@ Dashboard not found at: ${dashboardDir}`);
38820
38987
  const entry = getServer(id);
38821
38988
  if (!entry)
38822
38989
  return json({ error: `Server '${id}' not found` }, 404, port);
38823
- const tools = getCachedTools(id);
38824
- return json(tools, 200, port);
38990
+ const tools2 = getCachedTools(id);
38991
+ return json(tools2, 200, port);
38825
38992
  }
38826
38993
  const serverCallMatch = path.match(/^\/api\/servers\/([^/]+)\/call$/);
38827
38994
  if (serverCallMatch && method === "POST") {
@@ -39004,7 +39171,7 @@ Dashboard not found at: ${dashboardDir}`);
39004
39171
  }
39005
39172
  });
39006
39173
  const shutdown = () => {
39007
- server2.stop();
39174
+ server.stop();
39008
39175
  closeDb();
39009
39176
  process.exit(0);
39010
39177
  };
@@ -39517,18 +39684,18 @@ var build_default = Spinner;
39517
39684
 
39518
39685
  // src/cli/components/ServerDetail.tsx
39519
39686
  import { jsxDEV as jsxDEV2, Fragment } from "react/jsx-dev-runtime";
39520
- function ServerDetail({ server: server2, onSelectTool, onBack }) {
39521
- const [tools, setTools] = useState3([]);
39687
+ function ServerDetail({ server, onSelectTool, onBack }) {
39688
+ const [tools2, setTools] = useState3([]);
39522
39689
  const [loading, setLoading] = useState3(false);
39523
39690
  const [error2, setError] = useState3(null);
39524
- const cachedTools = getCachedTools(server2.id);
39691
+ const cachedTools = getCachedTools(server.id);
39525
39692
  const cachedKey = cachedTools.map((t) => `${t.name}|${t.description}|${JSON.stringify(t.input_schema)}`).join(";");
39526
39693
  useEffect3(() => {
39527
39694
  setLoading(false);
39528
39695
  setError(null);
39529
39696
  if (cachedTools.length > 0) {
39530
39697
  setTools(cachedTools.map((t) => ({
39531
- server_id: server2.id,
39698
+ server_id: server.id,
39532
39699
  name: t.name,
39533
39700
  description: t.description,
39534
39701
  input_schema: t.input_schema
@@ -39536,12 +39703,12 @@ function ServerDetail({ server: server2, onSelectTool, onBack }) {
39536
39703
  } else {
39537
39704
  setTools([]);
39538
39705
  }
39539
- }, [server2.id, cachedKey]);
39706
+ }, [server.id, cachedKey]);
39540
39707
  const handleConnect = async () => {
39541
39708
  setLoading(true);
39542
39709
  setError(null);
39543
39710
  try {
39544
- const conn = await connectToServer(server2);
39711
+ const conn = await connectToServer(server);
39545
39712
  setTools(conn.tools);
39546
39713
  } catch (err) {
39547
39714
  setError(err.message);
@@ -39550,8 +39717,8 @@ function ServerDetail({ server: server2, onSelectTool, onBack }) {
39550
39717
  }
39551
39718
  };
39552
39719
  const items = [
39553
- ...tools.length === 0 && !loading ? [{ label: "Connect & fetch tools", value: "__connect" }] : [],
39554
- ...tools.map((t) => ({
39720
+ ...tools2.length === 0 && !loading ? [{ label: "Connect & fetch tools", value: "__connect" }] : [],
39721
+ ...tools2.map((t) => ({
39555
39722
  label: `${t.name} \u2014 ${t.description || "No description"}`,
39556
39723
  value: t.name,
39557
39724
  tool: t
@@ -39560,7 +39727,7 @@ function ServerDetail({ server: server2, onSelectTool, onBack }) {
39560
39727
  ];
39561
39728
  const handleSelect = (item) => {
39562
39729
  if (item.value === "__back") {
39563
- disconnectServer(server2.id);
39730
+ disconnectServer(server.id);
39564
39731
  onBack();
39565
39732
  } else if (item.value === "__connect") {
39566
39733
  handleConnect();
@@ -39573,36 +39740,36 @@ function ServerDetail({ server: server2, onSelectTool, onBack }) {
39573
39740
  children: [
39574
39741
  /* @__PURE__ */ jsxDEV2(Text5, {
39575
39742
  bold: true,
39576
- children: server2.name
39743
+ children: server.name
39577
39744
  }, undefined, false, undefined, this),
39578
39745
  /* @__PURE__ */ jsxDEV2(Text5, {
39579
39746
  dimColor: true,
39580
39747
  children: [
39581
39748
  "ID: ",
39582
- server2.id
39749
+ server.id
39583
39750
  ]
39584
39751
  }, undefined, true, undefined, this),
39585
39752
  /* @__PURE__ */ jsxDEV2(Text5, {
39586
39753
  dimColor: true,
39587
39754
  children: [
39588
39755
  "Status: ",
39589
- server2.enabled ? "enabled" : "disabled",
39756
+ server.enabled ? "enabled" : "disabled",
39590
39757
  " | Transport: ",
39591
- server2.transport
39758
+ server.transport
39592
39759
  ]
39593
39760
  }, undefined, true, undefined, this),
39594
39761
  /* @__PURE__ */ jsxDEV2(Text5, {
39595
39762
  dimColor: true,
39596
39763
  children: [
39597
39764
  "Command: ",
39598
- server2.command,
39765
+ server.command,
39599
39766
  " ",
39600
- server2.args.join(" ")
39767
+ server.args.join(" ")
39601
39768
  ]
39602
39769
  }, undefined, true, undefined, this),
39603
- server2.description && /* @__PURE__ */ jsxDEV2(Text5, {
39770
+ server.description && /* @__PURE__ */ jsxDEV2(Text5, {
39604
39771
  dimColor: true,
39605
- children: server2.description
39772
+ children: server.description
39606
39773
  }, undefined, false, undefined, this),
39607
39774
  /* @__PURE__ */ jsxDEV2(Box4, {
39608
39775
  marginTop: 1,
@@ -39624,7 +39791,7 @@ function ServerDetail({ server: server2, onSelectTool, onBack }) {
39624
39791
  children: [
39625
39792
  /* @__PURE__ */ jsxDEV2(Text5, {
39626
39793
  bold: true,
39627
- children: tools.length > 0 ? `Tools (${tools.length}):` : "Tools:"
39794
+ children: tools2.length > 0 ? `Tools (${tools2.length}):` : "Tools:"
39628
39795
  }, undefined, false, undefined, this),
39629
39796
  /* @__PURE__ */ jsxDEV2(SelectInput_default, {
39630
39797
  items,
@@ -39768,8 +39935,8 @@ function SearchView({ onBack }) {
39768
39935
  setInstalling(item.value);
39769
39936
  setMessage(null);
39770
39937
  try {
39771
- const server2 = await installFromRegistry(item.value);
39772
- setMessage(`Installed: ${server2.name} [${server2.id}]`);
39938
+ const server = await installFromRegistry(item.value);
39939
+ setMessage(`Installed: ${server.name} [${server.id}]`);
39773
39940
  } catch (err) {
39774
39941
  setMessage(`Install failed: ${err.message}`);
39775
39942
  } finally {
@@ -39862,7 +40029,7 @@ import { useState as useState6 } from "react";
39862
40029
  import { Box as Box6, Text as Text8 } from "ink";
39863
40030
  init_config2();
39864
40031
  import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
39865
- function ToolCall({ server: server2, tool, onBack }) {
40032
+ function ToolCall({ server, tool, onBack }) {
39866
40033
  const [argsInput, setArgsInput] = useState6("{}");
39867
40034
  const [calling, setCalling] = useState6(false);
39868
40035
  const [result, setResult] = useState6(null);
@@ -39879,8 +40046,8 @@ function ToolCall({ server: server2, tool, onBack }) {
39879
40046
  setError(null);
39880
40047
  setResult(null);
39881
40048
  try {
39882
- await connectToServer(server2);
39883
- const prefixed = `${server2.id}${TOOL_PREFIX_SEPARATOR}${tool.name}`;
40049
+ await connectToServer(server);
40050
+ const prefixed = `${server.id}${TOOL_PREFIX_SEPARATOR}${tool.name}`;
39884
40051
  const res = await callTool(prefixed, args);
39885
40052
  const text = res.content.map((c) => c.text).join(`
39886
40053
  `);
@@ -39908,9 +40075,9 @@ function ToolCall({ server: server2, tool, onBack }) {
39908
40075
  dimColor: true,
39909
40076
  children: [
39910
40077
  "Server: ",
39911
- server2.name,
40078
+ server.name,
39912
40079
  " [",
39913
- server2.id,
40080
+ server.id,
39914
40081
  "]"
39915
40082
  ]
39916
40083
  }, undefined, true, undefined, this),
@@ -40023,8 +40190,8 @@ function App() {
40023
40190
  }).finally(() => closeDb());
40024
40191
  };
40025
40192
  }, []);
40026
- const handleSelectServer = (server2) => {
40027
- setSelectedServer(server2);
40193
+ const handleSelectServer = (server) => {
40194
+ setSelectedServer(server);
40028
40195
  setView("detail");
40029
40196
  };
40030
40197
  const handleSearch = () => {
@@ -40092,14 +40259,8 @@ function App() {
40092
40259
  }
40093
40260
 
40094
40261
  // src/cli/index.tsx
40095
- var VERSION2 = (() => {
40096
- try {
40097
- const pkgPath = join12(dirname5(fileURLToPath3(import.meta.url)), "..", "..", "package.json");
40098
- const pkg = JSON.parse(readFileSync6(pkgPath, "utf-8"));
40099
- return pkg.version || "0.0.1";
40100
- } catch {
40101
- return "0.0.1";
40102
- }
40262
+ var VERSION3 = (() => {
40263
+ return readPackageVersion(import.meta.url);
40103
40264
  })();
40104
40265
  var MACHINE_PLATFORMS = ["linux", "darwin", "unknown"];
40105
40266
  var MACHINE_ARCHES = ["arm64", "x64", "unknown"];
@@ -40203,7 +40364,7 @@ function renderFleetInstall(reports) {
40203
40364
  }
40204
40365
  }
40205
40366
  var program2 = new Command;
40206
- 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();
40207
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) => {
40208
40369
  const servers = listServers();
40209
40370
  if (opts.json) {
@@ -40295,9 +40456,9 @@ program2.command("add").passThroughOptions().argument("[command]", "Command to r
40295
40456
  try {
40296
40457
  if (opts.fromRegistry) {
40297
40458
  console.log(chalk2.dim(`Installing "${opts.fromRegistry}" from registry...`));
40298
- const server3 = await installFromRegistry(opts.fromRegistry);
40299
- console.log(chalk2.green(`Added server: ${server3.name} [${server3.id}]`));
40300
- 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(" ")}`));
40301
40462
  closeDb();
40302
40463
  return;
40303
40464
  }
@@ -40346,7 +40507,7 @@ Server to add:`));
40346
40507
  closeDb();
40347
40508
  return;
40348
40509
  }
40349
- const server3 = addServer({
40510
+ const server2 = addServer({
40350
40511
  command: wizardCommand,
40351
40512
  args: wizardArgs,
40352
40513
  name: wizardName || undefined,
@@ -40354,7 +40515,7 @@ Server to add:`));
40354
40515
  transport,
40355
40516
  env
40356
40517
  });
40357
- console.log(chalk2.green(`Added: ${server3.name} [${server3.id}]`));
40518
+ console.log(chalk2.green(`Added: ${server2.name} [${server2.id}]`));
40358
40519
  closeDb();
40359
40520
  return;
40360
40521
  }
@@ -40382,7 +40543,7 @@ Server to add:`));
40382
40543
  envMap[key] = rest.join("=");
40383
40544
  }
40384
40545
  }
40385
- const server2 = addServer({
40546
+ const server = addServer({
40386
40547
  name: opts.name,
40387
40548
  description: opts.description,
40388
40549
  command,
@@ -40391,8 +40552,8 @@ Server to add:`));
40391
40552
  url: opts.url,
40392
40553
  env: envMap
40393
40554
  });
40394
- console.log(chalk2.green(`Added server: ${server2.name} [${server2.id}]`));
40395
- 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(" ")}`));
40396
40557
  } catch (err) {
40397
40558
  if (err.message?.includes("UNIQUE constraint")) {
40398
40559
  console.error(chalk2.red("A server with that ID already exists."));
@@ -40405,8 +40566,8 @@ Server to add:`));
40405
40566
  closeDb();
40406
40567
  });
40407
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) => {
40408
- const server2 = getServer(id);
40409
- if (!server2) {
40569
+ const server = getServer(id);
40570
+ if (!server) {
40410
40571
  console.error(chalk2.red(`Server "${id}" not found.`));
40411
40572
  closeDb();
40412
40573
  process.exit(1);
@@ -40441,53 +40602,53 @@ program2.command("clone").argument("<id>", "Server ID to clone").argument("<new-
40441
40602
  closeDb();
40442
40603
  });
40443
40604
  program2.command("remove").argument("<id>", "Server ID to remove").description("Remove a registered server").action((id) => {
40444
- const server2 = getServer(id);
40445
- if (!server2) {
40605
+ const server = getServer(id);
40606
+ if (!server) {
40446
40607
  console.error(chalk2.red(`Server "${id}" not found.`));
40447
40608
  closeDb();
40448
40609
  process.exit(1);
40449
40610
  }
40450
40611
  removeServer(id);
40451
- console.log(chalk2.green(`Removed server: ${server2.name} [${id}]`));
40612
+ console.log(chalk2.green(`Removed server: ${server.name} [${id}]`));
40452
40613
  closeDb();
40453
40614
  });
40454
40615
  program2.command("enable").argument("<id>", "Server ID to enable").description("Enable a server").action((id) => {
40455
- const server2 = getServer(id);
40456
- if (!server2) {
40616
+ const server = getServer(id);
40617
+ if (!server) {
40457
40618
  console.error(chalk2.red(`Server "${id}" not found.`));
40458
40619
  closeDb();
40459
40620
  process.exit(1);
40460
40621
  }
40461
40622
  enableServer(id);
40462
- console.log(chalk2.green(`Enabled server: ${server2.name}`));
40623
+ console.log(chalk2.green(`Enabled server: ${server.name}`));
40463
40624
  closeDb();
40464
40625
  });
40465
40626
  program2.command("disable").argument("<id>", "Server ID to disable").description("Disable a server").action((id) => {
40466
- const server2 = getServer(id);
40467
- if (!server2) {
40627
+ const server = getServer(id);
40628
+ if (!server) {
40468
40629
  console.error(chalk2.red(`Server "${id}" not found.`));
40469
40630
  closeDb();
40470
40631
  process.exit(1);
40471
40632
  }
40472
40633
  disableServer(id);
40473
- console.log(chalk2.yellow(`Disabled server: ${server2.name}`));
40634
+ console.log(chalk2.yellow(`Disabled server: ${server.name}`));
40474
40635
  closeDb();
40475
40636
  });
40476
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) => {
40477
40638
  if (opts.connect) {
40478
40639
  console.log(chalk2.dim("Connecting to enabled servers..."));
40479
40640
  await connectAllEnabled();
40480
- const tools = listAllTools();
40481
- if (tools.length === 0) {
40641
+ const tools2 = listAllTools();
40642
+ if (tools2.length === 0) {
40482
40643
  console.log(chalk2.dim("No tools available."));
40483
40644
  } else {
40484
- for (const t of tools) {
40645
+ for (const t of tools2) {
40485
40646
  console.log(` ${chalk2.bold(t.name)}`);
40486
40647
  if (t.description)
40487
40648
  console.log(` ${chalk2.dim(t.description)}`);
40488
40649
  }
40489
40650
  console.log(chalk2.dim(`
40490
- ${tools.length} tool(s) available.`));
40651
+ ${tools2.length} tool(s) available.`));
40491
40652
  }
40492
40653
  await disconnectAll();
40493
40654
  } else if (serverId) {
@@ -40567,26 +40728,26 @@ program2.command("call").argument("<tool>", "Tool name (server_id__tool_name)").
40567
40728
  process.exit(exitCode);
40568
40729
  });
40569
40730
  program2.command("info").argument("<id>", "Server ID").description("Show server details & tools").action((id) => {
40570
- const server2 = getServer(id);
40571
- if (!server2) {
40731
+ const server = getServer(id);
40732
+ if (!server) {
40572
40733
  console.error(chalk2.red(`Server "${id}" not found.`));
40573
40734
  closeDb();
40574
40735
  process.exit(1);
40575
40736
  }
40576
- console.log(chalk2.bold(server2.name) + " " + chalk2.dim(`[${server2.id}]`));
40577
- console.log(` Status: ${server2.enabled ? chalk2.green("enabled") : chalk2.red("disabled")}`);
40578
- console.log(` Source: ${server2.source}`);
40579
- console.log(` Transport: ${server2.transport}`);
40580
- console.log(` Command: ${server2.command} ${server2.args.join(" ")}`);
40581
- if (server2.url)
40582
- console.log(` URL: ${server2.url}`);
40583
- if (server2.description)
40584
- console.log(` Desc: ${server2.description}`);
40585
- if (Object.keys(server2.env).length > 0) {
40586
- console.log(` Env: ${Object.entries(server2.env).map(([k, v]) => `${k}=${v}`).join(", ")}`);
40587
- }
40588
- console.log(` Created: ${server2.created_at}`);
40589
- 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}`);
40590
40751
  const cached2 = getCachedTools(id);
40591
40752
  if (cached2.length > 0) {
40592
40753
  console.log(chalk2.bold(`
@@ -40626,10 +40787,10 @@ program2.command("doctor").argument("[id]", "Server ID to check (omit to check a
40626
40787
  return;
40627
40788
  }
40628
40789
  let allHealthy = true;
40629
- for (const server2 of servers) {
40790
+ for (const server of servers) {
40630
40791
  console.log(chalk2.bold(`
40631
- ${server2.name} [${server2.id}]`));
40632
- const report = await diagnoseServer(server2);
40792
+ ${server.name} [${server.id}]`));
40793
+ const report = await diagnoseServer(server);
40633
40794
  for (const check2 of report.checks) {
40634
40795
  const icon = check2.pass ? chalk2.green("\u2713") : chalk2.red("\u2717");
40635
40796
  console.log(` ${icon} ${check2.name}: ${chalk2.dim(check2.message)}`);
@@ -40825,14 +40986,14 @@ Enter number to install (1-${results.length}), or 0 to cancel: `), resolve2);
40825
40986
  return;
40826
40987
  }
40827
40988
  console.log(chalk2.dim(`Installing ${chosen.name}...`));
40828
- const server2 = addServer({
40989
+ const server = addServer({
40829
40990
  command: "npx",
40830
40991
  args: ["-y", pkg],
40831
40992
  name: chosen.name,
40832
40993
  description: chosen.description,
40833
40994
  transport: "stdio"
40834
40995
  });
40835
- const results2 = installToAgents(server2, ["claude", "codex", "gemini"]);
40996
+ const results2 = installToAgents(server, ["claude", "codex", "gemini"]);
40836
40997
  for (const r of results2) {
40837
40998
  if (r.success) {
40838
40999
  console.log(chalk2.green(` \u2713 ${r.agent}`));
@@ -40841,7 +41002,7 @@ Enter number to install (1-${results.length}), or 0 to cancel: `), resolve2);
40841
41002
  }
40842
41003
  }
40843
41004
  console.log(chalk2.green(`
40844
- Installed ${server2.name} [${server2.id}]`));
41005
+ Installed ${server.name} [${server.id}]`));
40845
41006
  }
40846
41007
  } catch (err) {
40847
41008
  console.error(chalk2.red(`Find failed: ${err.message}`));
@@ -40999,12 +41160,12 @@ program2.command("install").argument("[id]", "Server ID (from `mcps list`) to in
40999
41160
  if (!targets.includes("gemini"))
41000
41161
  targets.push("gemini");
41001
41162
  }
41002
- let server2;
41163
+ let server;
41003
41164
  if (opts.fromRegistry) {
41004
41165
  console.log(chalk2.dim(`Installing "${opts.fromRegistry}" from registry...`));
41005
41166
  try {
41006
- server2 = await installFromRegistry(opts.fromRegistry);
41007
- 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}]`));
41008
41169
  } catch (err) {
41009
41170
  console.error(chalk2.red(`Failed to install from registry: ${err.message}`));
41010
41171
  closeDb();
@@ -41012,23 +41173,23 @@ program2.command("install").argument("[id]", "Server ID (from `mcps list`) to in
41012
41173
  }
41013
41174
  } else if (opts.npm) {
41014
41175
  const pkg = opts.npm;
41015
- server2 = addServer({ command: "npx", args: ["-y", pkg], name: pkg, transport: "stdio" });
41016
- 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}]`));
41017
41178
  } else {
41018
41179
  if (!id) {
41019
41180
  console.error(chalk2.red("Error: server ID is required (or use --from-registry or --npm)"));
41020
41181
  closeDb();
41021
41182
  process.exit(1);
41022
41183
  }
41023
- server2 = getServer(id);
41024
- if (!server2) {
41184
+ server = getServer(id);
41185
+ if (!server) {
41025
41186
  console.error(chalk2.red(`Server "${id}" not found. Use \`mcps add\` first.`));
41026
41187
  closeDb();
41027
41188
  process.exit(1);
41028
41189
  }
41029
41190
  }
41030
- console.log(chalk2.dim(`Installing "${server2.name}" to: ${targets.join(", ")}...`));
41031
- const results = installToAgents(server2, targets);
41191
+ console.log(chalk2.dim(`Installing "${server.name}" to: ${targets.join(", ")}...`));
41192
+ const results = installToAgents(server, targets);
41032
41193
  for (const r of results) {
41033
41194
  if (r.success) {
41034
41195
  console.log(chalk2.green(` \u2713 ${r.agent}`));
@@ -41271,13 +41432,13 @@ program2.command("import").argument("<file>", "Path to the export JSON file").de
41271
41432
  });
41272
41433
  var envCmd = program2.command("env").description("Manage server environment variables");
41273
41434
  envCmd.command("list").argument("<id>").description("List env vars for a server").action((id) => {
41274
- const server2 = getServer(id);
41275
- if (!server2) {
41435
+ const server = getServer(id);
41436
+ if (!server) {
41276
41437
  console.error(chalk2.red(`Server "${id}" not found.`));
41277
41438
  closeDb();
41278
41439
  process.exit(1);
41279
41440
  }
41280
- const entries = Object.entries(server2.env);
41441
+ const entries = Object.entries(server.env);
41281
41442
  if (entries.length === 0) {
41282
41443
  console.log(chalk2.dim("No env vars set."));
41283
41444
  closeDb();
@@ -41322,7 +41483,7 @@ program2.command("mcp").description("Start meta-MCP server (stdio)").action(asyn
41322
41483
  });
41323
41484
  program2.command("feedback <message>").description("Send feedback").option("--email <email>", "Contact email").option("--category <category>", "Category: bug, feature, general").action((message, opts) => {
41324
41485
  const adapter = getAdapter();
41325
- 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);
41326
41487
  console.log(chalk2.green("Feedback saved. Thank you!"));
41327
41488
  closeDb();
41328
41489
  });