nuwax-mcp-stdio-proxy 1.4.0 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -23761,7 +23761,7 @@ var StdioServerTransport = class {
23761
23761
 
23762
23762
  // src/constants.ts
23763
23763
  var PKG_NAME = "nuwax-mcp-stdio-proxy";
23764
- var PKG_VERSION = "1.4.0";
23764
+ var PKG_VERSION = "1.4.1";
23765
23765
 
23766
23766
  // src/shared.ts
23767
23767
  async function discoverTools(client) {
@@ -23825,8 +23825,19 @@ function setupGracefulShutdown(cleanupFn) {
23825
23825
  process.on("SIGTERM", () => void shutdown("SIGTERM"));
23826
23826
  }
23827
23827
 
23828
+ // src/filter.ts
23829
+ function filterTools(tools, filter) {
23830
+ if (filter.allowTools && filter.allowTools.size > 0) {
23831
+ return tools.filter((t) => filter.allowTools.has(t.name));
23832
+ }
23833
+ if (filter.denyTools && filter.denyTools.size > 0) {
23834
+ return tools.filter((t) => !filter.denyTools.has(t.name));
23835
+ }
23836
+ return tools;
23837
+ }
23838
+
23828
23839
  // src/modes/stdio.ts
23829
- async function runStdio(config2) {
23840
+ async function runStdio(config2, allowTools, denyTools) {
23830
23841
  const entries = Object.entries(config2.mcpServers);
23831
23842
  if (entries.length === 0) {
23832
23843
  logError("No MCP servers configured in mcpServers");
@@ -23878,9 +23889,17 @@ async function runStdio(config2) {
23878
23889
  }
23879
23890
  const aggregatedTools = Array.from(toolsByName.values());
23880
23891
  logInfo(`Aggregated ${aggregatedTools.length} unique tool(s) from ${clients.size} server(s)`);
23892
+ const toolFilter = {};
23893
+ if (allowTools) toolFilter.allowTools = new Set(allowTools);
23894
+ if (denyTools) toolFilter.denyTools = new Set(denyTools);
23895
+ const filteredTools = filterTools(aggregatedTools, toolFilter);
23896
+ const filteredNames = new Set(filteredTools.map((t) => t.name));
23897
+ if (filteredTools.length !== aggregatedTools.length) {
23898
+ logInfo(`After filtering: ${filteredTools.length} tool(s) \u2014 ${filteredTools.map((t) => t.name).join(", ")}`);
23899
+ }
23881
23900
  const { server } = await createToolProxyServer({
23882
- tools: aggregatedTools,
23883
- resolveClient: (name) => toolToClient.get(name),
23901
+ tools: filteredTools,
23902
+ resolveClient: (name) => filteredNames.has(name) ? toolToClient.get(name) : void 0,
23884
23903
  errorLabel: (name) => `"${name}" (server: "${toolToServer.get(name) || "unknown"}")`
23885
23904
  });
23886
23905
  logInfo("Proxy server running on stdio");
@@ -23907,17 +23926,6 @@ async function runStdio(config2) {
23907
23926
  });
23908
23927
  }
23909
23928
 
23910
- // src/filter.ts
23911
- function filterTools(tools, filter) {
23912
- if (filter.allowTools && filter.allowTools.size > 0) {
23913
- return tools.filter((t) => filter.allowTools.has(t.name));
23914
- }
23915
- if (filter.denyTools && filter.denyTools.size > 0) {
23916
- return tools.filter((t) => !filter.denyTools.has(t.name));
23917
- }
23918
- return tools;
23919
- }
23920
-
23921
23929
  // src/detect.ts
23922
23930
  async function detectProtocol(url2, headers) {
23923
23931
  logInfo(`Auto-detecting protocol for ${url2}...`);
@@ -25753,14 +25761,33 @@ function parseCliArgs() {
25753
25761
  return parseStdioArgs(args);
25754
25762
  }
25755
25763
  function parseStdioArgs(args) {
25756
- const idx = args.indexOf("--config");
25757
- if (idx === -1 || idx + 1 >= args.length) {
25764
+ let configJson;
25765
+ let allowTools;
25766
+ let denyTools;
25767
+ for (let i = 0; i < args.length; i++) {
25768
+ const arg = args[i];
25769
+ if (arg === "--config" && i + 1 < args.length) {
25770
+ i++;
25771
+ configJson = args[i];
25772
+ } else if (arg === "--allow-tools" && i + 1 < args.length) {
25773
+ i++;
25774
+ allowTools = args[i].split(",").map((s) => s.trim()).filter(Boolean);
25775
+ } else if (arg === "--deny-tools" && i + 1 < args.length) {
25776
+ i++;
25777
+ denyTools = args[i].split(",").map((s) => s.trim()).filter(Boolean);
25778
+ }
25779
+ }
25780
+ if (!configJson) {
25758
25781
  logError("Missing --config argument");
25759
25782
  logError(`Usage: nuwax-mcp-stdio-proxy --config '{"mcpServers":{...}}'`);
25760
25783
  process.exit(1);
25761
25784
  }
25762
- const config2 = parseConfigJson(args[idx + 1]);
25763
- return { mode: "stdio", config: config2 };
25785
+ if (allowTools && denyTools) {
25786
+ logError("Cannot use both --allow-tools and --deny-tools");
25787
+ process.exit(1);
25788
+ }
25789
+ const config2 = parseConfigJson(configJson);
25790
+ return { mode: "stdio", config: config2, allowTools, denyTools };
25764
25791
  }
25765
25792
  function parseConvertArgs(args) {
25766
25793
  let url2;
@@ -25858,9 +25885,13 @@ function parseConfigJson(json2) {
25858
25885
  }
25859
25886
  function printUsage() {
25860
25887
  logError("Usage:");
25861
- logError(` nuwax-mcp-stdio-proxy --config '{"mcpServers":{...}}' (stdio aggregation)`);
25862
- logError(" nuwax-mcp-stdio-proxy convert [URL] [OPTIONS] (remote \u2192 stdio)");
25863
- logError(" nuwax-mcp-stdio-proxy proxy --port <PORT> --config '...' (HTTP server)");
25888
+ logError(` nuwax-mcp-stdio-proxy --config '{"mcpServers":{...}}' [OPTIONS] (stdio aggregation)`);
25889
+ logError(" nuwax-mcp-stdio-proxy convert [URL] [OPTIONS] (remote \u2192 stdio)");
25890
+ logError(" nuwax-mcp-stdio-proxy proxy --port <PORT> --config '...' (HTTP server)");
25891
+ logError("");
25892
+ logError("Options (stdio / convert):");
25893
+ logError(" --allow-tools <TOOLS> Tool whitelist (comma-separated)");
25894
+ logError(" --deny-tools <TOOLS> Tool blacklist (comma-separated)");
25864
25895
  }
25865
25896
  function printConvertUsage() {
25866
25897
  logError("Usage: nuwax-mcp-stdio-proxy convert [URL] [OPTIONS]");
@@ -25882,7 +25913,7 @@ async function main() {
25882
25913
  const args = parseCliArgs();
25883
25914
  switch (args.mode) {
25884
25915
  case "stdio":
25885
- await runStdio(args.config);
25916
+ await runStdio(args.config, args.allowTools, args.denyTools);
25886
25917
  break;
25887
25918
  case "convert":
25888
25919
  await runConvert(args);
@@ -5,4 +5,4 @@
5
5
  * into a single stdio MCP endpoint.
6
6
  */
7
7
  import type { McpServersConfig } from '../types.js';
8
- export declare function runStdio(config: McpServersConfig): Promise<void>;
8
+ export declare function runStdio(config: McpServersConfig, allowTools?: string[], denyTools?: string[]): Promise<void>;
@@ -8,7 +8,8 @@ import { isSseEntry, isStreamableEntry } from '../types.js';
8
8
  import { logInfo, logWarn, logError } from '../logger.js';
9
9
  import { buildBaseEnv, connectStdio, connectStreamable, connectSse } from '../transport.js';
10
10
  import { discoverTools, createToolProxyServer, setupGracefulShutdown } from '../shared.js';
11
- export async function runStdio(config) {
11
+ import { filterTools } from '../filter.js';
12
+ export async function runStdio(config, allowTools, denyTools) {
12
13
  const entries = Object.entries(config.mcpServers);
13
14
  if (entries.length === 0) {
14
15
  logError('No MCP servers configured in mcpServers');
@@ -59,10 +60,21 @@ export async function runStdio(config) {
59
60
  }
60
61
  const aggregatedTools = Array.from(toolsByName.values());
61
62
  logInfo(`Aggregated ${aggregatedTools.length} unique tool(s) from ${clients.size} server(s)`);
63
+ // ---- Phase 1.5: Apply tool filtering (allow/deny) ----
64
+ const toolFilter = {};
65
+ if (allowTools)
66
+ toolFilter.allowTools = new Set(allowTools);
67
+ if (denyTools)
68
+ toolFilter.denyTools = new Set(denyTools);
69
+ const filteredTools = filterTools(aggregatedTools, toolFilter);
70
+ const filteredNames = new Set(filteredTools.map((t) => t.name));
71
+ if (filteredTools.length !== aggregatedTools.length) {
72
+ logInfo(`After filtering: ${filteredTools.length} tool(s) — ${filteredTools.map((t) => t.name).join(', ')}`);
73
+ }
62
74
  // ---- Phase 2: Create the aggregating MCP server ----
63
75
  const { server } = await createToolProxyServer({
64
- tools: aggregatedTools,
65
- resolveClient: (name) => toolToClient.get(name),
76
+ tools: filteredTools,
77
+ resolveClient: (name) => filteredNames.has(name) ? toolToClient.get(name) : undefined,
66
78
  errorLabel: (name) => `"${name}" (server: "${toolToServer.get(name) || 'unknown'}")`,
67
79
  });
68
80
  logInfo('Proxy server running on stdio');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nuwax-mcp-stdio-proxy",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
4
4
  "description": "TypeScript MCP proxy — aggregates multiple MCP servers (stdio + streamable-http + SSE) with convert & proxy modes",
5
5
  "type": "module",
6
6
  "bin": {