Home / Servers

mduct

by TheFox666

<p align="center"><img src="docs/banner.png" alt="mduct — because it glues shit together" width="100%"></p>

One binary. Any number of MCP servers and plain CLIs behind a single command, with none of their tool schemas anywhere near your model's context.

mduct call gitlab list_issues state=opened --json | jq '.[].title'

That's the whole idea. It is a duct. Things go through it.


Why

An MCP client loads every connected server's tool schemas up front, all of them. Measured on one GitLab server: 186 tools, about 168 kB of JSON Schema. That is roughly 40k tokens spent before the model has read your question, paid again on every context refresh, mostly for tools nobody calls.

mduct puts one line per server in the prompt and leaves the schemas on disk until something actually calls a tool:

MCP tools via `mduct` (list: mduct tools <server>; call: mduct call <server> <tool> key=value):
  gitlab       — GitLab: MRs, pipelines, issues, repos
  kubectl      — read-only cluster access

One line is about 20 tokens. A full index of seven servers and three CLI tools measures 789 bytes. The tool stays discoverable, it just stops being expensive.

That last part is why the index exists at all instead of loading schemas lazily. Lazy loading fixes the token bill and introduces a worse problem: out of context, out of mind. An agent will not use a capability it cannot see.

What you get

Warm daemonConnections and OAuth sessions survive between calls. A stdio server isn't respawned and a remote isn't re-handshaked every time you invoke it.
Pipe-ready output--json strips the prose some servers wrap around their payload, so | jq works. --compact minifies. Exit codes mean what you think they mean.
Guards in the daemonPer-server allow/deny patterns, living somewhere the model cannot argue with them.
Secrets out of the config${VAR} refs resolve from a 0600 store. Plaintext tokens never touch servers.jsonc.
MCP and plain CLIskubectl, playwright and friends show up in the same list and are called the same way. Nobody has to care which is which.
Isolated instancesOne env var gives a second agent its own config, secrets, auth and daemon.

Install

curl -fsSL https://raw.githubusercontent.com/TheFox666/mduct/main/install.sh | sh

Fetches the release binary, checks its sha256, puts mduct in ~/.local/bin. From a checkout: bun run build && cp dist/mduct ~/.local/bin/.

Quickstart

Stash a token. ${VAR} refs resolve from a 0600 store, so it never reaches the config file:

echo "$YOUR_GITLAB_PAT" | mduct secret set GITLAB_PAT

Declare a server in ~/.config/mduct/servers.jsonc:

{
  "servers": {
    // local: mduct launches the process and talks stdio
    "gitlab": {
      "command": "npx",
      "args": ["-y", "@yoda.digital/gitlab-mcp-server"],
      "env": { "GITLAB_PERSONAL_ACCESS_TOKEN": "${GITLAB_PAT}" },
      "guard": { "deny": ["delete_*"] },
      "note": "GitLab: MRs, pipelines, issues, repos"
    },
    // remote: nothing to install, mduct speaks HTTP to it
    "notes": { "url": "https://mcp.example.com/mcp", "auth": "oauth" }
  }
}

You don't have to hand-edit it. mduct add opens a picker and mduct import lifts servers out of an existing Claude config.

Call things. The daemon autostarts:

mduct servers                 # what's configured
mduct tools gitlab            # tool names + signatures, no schemas
mduct schema gitlab create_issue
mduct call gitlab create_issue project=42 title="it broke again"
mduct status                  # which instance answered, and from where

Wire an agent to it. Claude Code has hooks for this. Anything else: paste mduct index into the system prompt.

mduct hook install claude

How it works

flowchart TD
    A["you / your agent<br/><code>mduct call gitlab list_issues</code>"] -->|unix socket| D
    D["daemon

Related servers

n8n

by n8n-io

Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.

NOASSERTION198,904

@modelcontextprotocol/server-everything

Official

by modelcontextprotocol

MCP server that exercises all the features of the MCP protocol

89,105

@modelcontextprotocol/server-filesystem

Official

by modelcontextprotocol

MCP server for filesystem access

SEE LICENSE IN LICENSE89,105

mcp-server-fetch

Official

by modelcontextprotocol

A Model Context Protocol server providing tools to fetch and convert web content for usage by LLMs

89,105