mcp-tool-hub
A modular, extensible MCP multi-server hub that gives LLMs sandboxed file access, Git operations, web fetching, and persistent memory, deployable via Ansible.
Ask AI about mcp-tool-hub
Powered by Claude Β· Grounded in docs
I know everything about mcp-tool-hub. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
MCP Tool Hub
A modular, extensible Model Context Protocol multi-server hub β built in TypeScript for IT automation teams.
Give your LLM access to real-world tools: files, Git, web content, and persistent memory. Deploy to any number of client machines simultaneously via Ansible.
Architecture
mcp-tool-hub/
βββ packages/
β βββ core/ β Shared types + BaseMCPServer abstract class
β βββ server-filesystem/ β Sandboxed local file access (read/write/list/delete)
β βββ server-git/ β Git log, diff, file contents, branches, status
β βββ server-fetch/ β Web fetching: HTML, JSON APIs, URL health checks
β βββ server-memory/ β Persistent JSON knowledge base (survives restarts)
βββ host/ β Orchestrator: registry + CLI + stdio JSON interface
βββ ansible/ β Playbook, inventory, systemd service templates
βββ docs/ β How to add new servers (with template)
The architecture follows the Model Context Protocol pattern:
- Each server is completely independent β its own package, its own build
- The registry in the host maps
toolName β serverat runtime - The CLI exposes a stdio JSON interface β any LLM integration sends
{"toolName":"...", "arguments":{...}}on stdin, reads the result from stdout - Adding a new server = create a package, extend
BaseMCPServer, register incli.ts
Quick Start
1. Install & Build
git clone https://github.com/your-org/mcp-tool-hub.git
cd mcp-tool-hub
npm install
npm run build
2. Configure
cp .env.example .env
# Edit .env with your paths and settings
3. Run
# Via npm
npm run start --workspace=host
# Or directly
node host/dist/cli.js
4. Call a tool
Send JSON to stdin, get JSON from stdout:
echo '{"toolName":"read_file","arguments":{"path":"hello.txt"}}' | node host/dist/cli.js
Available Tools
π Filesystem Server
All operations sandboxed to MCP_FS_ROOT. Path traversal (../) is blocked.
| Tool | Description |
|---|---|
read_file | Read file contents (utf8 or base64) |
write_file | Write or append to a file |
list_directory | List directory contents (optionally recursive) |
delete_file | Delete a file |
move_file | Move or rename a file |
get_file_info | Get size, dates, and type of a path |
π Git Server
Read-only. No write operations.
| Tool | Description |
|---|---|
git_log | Commit history for a repo or file |
git_show_file | File contents at a specific commit/branch |
git_diff | Diff between two refs |
git_status | Working tree status |
git_branches | List branches (local + optional remote) |
git_show_commit | Full commit details and diff |
π Fetch Server
Supports optional domain allowlist via MCP_FETCH_ALLOWED_DOMAINS.
| Tool | Description |
|---|---|
fetch_url | Fetch HTML or text from a URL |
fetch_json | Fetch and parse a JSON API response |
check_url | Check if a URL is reachable (HEAD request) |
π§ Memory Server
Persistent across restarts. Backed by a JSON file.
| Tool | Description |
|---|---|
memory_set | Store a value with key, namespace, and tags |
memory_get | Retrieve a value by key |
memory_search | Full-text search across all entries |
memory_delete | Delete an entry |
memory_list_namespaces | List all namespaces with counts |
memory_clear_namespace | Delete all entries in a namespace |
Ansible Deployment
Deploy to all your client machines simultaneously:
cd ansible
# First time
ansible-playbook -i inventory.yml deploy-mcp-hub.yml
# Update only (rebuild + restart)
ansible-playbook -i inventory.yml deploy-mcp-hub.yml --tags update
# Deploy to specific group
ansible-playbook -i inventory.yml deploy-mcp-hub.yml --limit servers
The playbook:
- Installs Node.js 20 (if not present)
- Creates a dedicated
mcp-hubsystem user - Copies and builds the project
- Writes the
.envconfig from your Ansible variables - Installs and starts a systemd service (auto-restart on failure)
Per-host variables in inventory.yml let you configure different allowed domains, log levels, and paths per machine group.
Adding a New Server
See docs/adding-a-new-server.template.ts for the full template with comments.
In short:
// 1. Create packages/server-myservice/src/my-server.ts
export class MyServer extends BaseMCPServer {
constructor(options: MyOptions) {
super(SERVER_INFO, options);
this.registerTool("my_tool", this.handleMyTool.bind(this));
}
private async handleMyTool(args) {
return this.ok({ result: "done" });
}
}
// 2. Register in host/src/cli.ts
hub.use(new MyServer({ apiKey: process.env.MY_API_KEY! }));
Ideas: server-slack, server-postgres, server-docker, server-ansible, server-ssh, server-jira
Environment Variables
| Variable | Default | Description |
|---|---|---|
MCP_DATA_DIR | ./mcp-data | Root for all hub data |
MCP_FS_ROOT | ./mcp-data/files | Filesystem sandbox root |
MCP_GIT_WORKSPACE | ./mcp-data/repos | Git repos base path |
MCP_MEMORY_PATH | ./mcp-data/memory.json | Memory store file |
MCP_FETCH_ALLOWED_DOMAINS | (empty = all) | Comma-separated domain allowlist |
MCP_LOG_LEVEL | info | debug|info|warn|error |
Security Notes
- Filesystem: Strictly sandboxed. Path traversal attacks return an error, not data.
- Git: Read-only. No
commit,push, orcloneoperations exposed. - Fetch: Optional domain allowlist prevents SSRF to internal services.
- Systemd service: Runs as a non-root user with
PrivateTmp=trueandNoNewPrivileges=true.
Requirements
- Node.js β₯ 18 (for native
fetchAPI) - Git (for
server-git) - Linux with systemd (for Ansible deployment)
