Reduce MCP tool bloat by exposing your tools as commands in a Bash interpreter, using Vercel's just-bash.
mcp-bash-mode
Reduce MCP tool bloat by exposing your tools as commands in a Bash interpreter.
Instead of registering dozens of MCP tools (each consuming context window space), register a single exec_bash tool that gives the LLM a Bash interpreter with your custom commands built in. The LLM composes commands using pipes, redirects, and standard Unix utilities -- getting the work done in fewer tool calls with a smaller tool definition.
Built on just-bash and the MCP TypeScript SDK v2.
Install
npm install mcp-bash-mode
Quickstart
A product catalog server that lets an AI agent query, filter, and transform data -- all through a single MCP tool:
import { McpServer } from "@modelcontextprotocol/server";
import { bashModeTool } from "mcp-bash-mode";
const products = [
{ id: 1, name: "Flux Capacitor", price: 199.99, category: "time-travel" },
{ id: 2, name: "Hoverboard", price: 499.99, category: "transport" },
{ id: 3, name: "Mr. Fusion", price: 89.99, category: "energy" },
{ id: 4, name: "Time Circuit", price: 299.99, category: "time-travel" },
{ id: 5, name: "DeLorean DMC-12", price: 42000.0, category: "transport" },
];
const server = new McpServer({ name: "catalog", version: "1.0.0" });
server.registerTool(
"exec_bash",
...bashModeTool({
commands: {
products: {
description: "Query the product catalog. Returns JSON array.",
execute: async (args) => {
if (args.includes("--help")) {
return [
"Usage: products",
"",
"Returns the full product catalog as a JSON array.",
"Each product has the following fields:",
" id number Unique product ID",
" name string Product name",
" price number Price in USD",
" category string One of: time-travel, transport, energy",
].join("\n");
}
return JSON.stringify(products, null, 2);
},
},
},
}),
);
The LLM sees one tool (exec_bash) and can do things like:
# Discover the output format
products --help
# Get all products
products
# Find products under $200
products | jq '.[] | select(.price < 200)'
# List product names in the "time-travel" category, sorted
products | jq -r '.[] | select(.category == "time-travel") | .name' | sort
# Count products per category
products | jq -r '.[].category' | sort | uniq -c | sort -rn
Without mcp-bash-mode, each of these operations would typically require a separate MCP tool with its own schema.
API
bashModeTool(options?)
Returns a [config, callback] tuple designed to be spread into McpServer.registerTool():
server.registerTool("exec_bash", ...bashModeTool(options));
Options
| Option | Type | Description |
|--------|------|-------------|
| commands | Record<string, CommandConfig> | Custom commands to register. Each key is the command name. |
| description | string | Override the auto-generated tool description entirely. |
CommandConfig
| Field | Type | Description |
|-------|------|-------------|
| description | string | One-line description shown to the LLM in the tool definition. |
| execute | (args: string[], ctx: CommandContext) => Promise<string \| ExecResult> | Command implementation. Return a string (becomes stdout) or an ExecResult with stdout, stderr, and exitCode. Throwing an Error produces stderr output. |
Exports
mcp-bash-mode re-exports CommandContext and ExecResult from just-bash for convenience.
License
MIT