Conduit is a secure Code Mode execution substrate for MCP agents. It functions as a standard MCP server, allowing native integration with clients like Claude Desktop or VS Code without extra adapters.
It lets agents:
- generate real TypeScript or Python code
- call tools via language-native APIs (
tools.github.create_issue()) - run that code in isolated, resource-governed sandboxes
- without exposing credentials or the host environment
Conduit is optimized for:
- Code Mode (not JSON tool calling)
- composable multi-tool execution
- strict safety, limits, and observability
- ❌ A general-purpose script runner
- ❌ An LLM gateway or provider abstraction
- ❌ A plugin UI or agent framework
- ❌ A long-lived compute environment
Conduit executes short-lived, isolated programs with explicit limits.
npm install @mhingston5/conduitpnpm install
# Build the project
npm run build
# Start the server
node dist/index.jsCreate a conduit.yaml in the root:
upstreams:
- id: github
type: http
url: "http://localhost:3000/mcp"
# Remote MCP servers that use Streamable HTTP (preferred) / SSE:
- id: atlassian
type: streamableHttp
url: "https://mcp.atlassian.com/v1/sse"
credentials:
type: oauth2
clientId: ${ATLASSIAN_CLIENT_ID}
clientSecret: ${ATLASSIAN_CLIENT_SECRET}
tokenUrl: "https://auth.atlassian.com/oauth/token"
refreshToken: ${ATLASSIAN_REFRESH_TOKEN}
# Atlassian expects JSON token requests:
tokenRequestFormat: json
- id: slack
type: http
url: "https://your-mcp-server/mcp"
credentials:
type: oauth2
clientId: ${SLACK_CLIENT_ID}
clientSecret: ${SLACK_CLIENT_SECRET}
tokenUrl: "https://slack.com/api/oauth.v2.access"
refreshToken: ${SLACK_REFRESH_TOKEN}
# Or use local stdio for testing:
- id: filesystem
type: stdio
command: npx
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]If your upstream requires an initial OAuth flow (like Jira), you can use the built-in helper to obtain a refresh token:
npx conduit auth \
--client-id <id> \
--client-secret <secret> \
--auth-url <url> \
--token-url <url> \
--scopes <scopes>For Atlassian (3LO), include offline_access and set the audience:
npx conduit auth \
--client-id <id> \
--client-secret <secret> \
--auth-url "https://auth.atlassian.com/authorize?audience=api.atlassian.com&prompt=consent" \
--token-url "https://auth.atlassian.com/oauth/token" \
--scopes "offline_access,read:me"This will start a temporary local server, open your browser for authorization, and print the generated credentials block for your conduit.yaml.
Note: some providers (including Atlassian) use rotating refresh tokens. Conduit will cache the latest refresh token in-memory while running, but it does not currently persist the rotated token back into conduit.yaml. If you restart Conduit and your old refresh token has expired/rotated, re-run conduit auth and update your config.
For GitHub MCP (remote server OAuth), you can auto-discover endpoints and use PKCE:
npx conduit auth \
--client-id <id> \
--client-secret <secret> \
--mcp-url https://api.githubcopilot.com/mcp/ \
--scopes repo,read:org \
--pkceUsing any MCP Client (Claude Desktop, etc.), call mcp_execute_typescript:
// The agent writes this code:
const result = await tools.filesystem.list_allowed_directories();
console.log("Directories:", JSON.stringify(result.content));Conduit runs the code, handles the tool call securely, and returns:
{
"stdout": "Directories: [{\"type\":\"text\",\"text\":\"/tmp\"}]\n",
"stderr": "",
"exitCode": 0
}{
"mcpServers": {
"conduit": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@mhingston5/conduit",
"--stdio"
],
"env": {}
}
}
}LLM → generates code
↓
Client → sends code to Conduit
↓
Conduit:
- injects a `tools.*` SDK
- enforces limits + allowlists
- runs code in an isolated runtime (Deno / Pyodide / Isolate)
↓
Tools are called via the Gateway
↓
Results returned as stdout / stderr
For implementation details, see Architecture.
Each execution:
- runs in a fresh sandbox (no state reuse)
- has strict CPU, memory, output, and log limits
- cannot access host credentials or filesystem
- can only call explicitly allowed tools
- is forcibly terminated on violation
SSRF protection:
- private IP ranges blocked
- DNS rebinding prevented
- IPv6-mapped IPv4 handled
Secrets:
- never injected into user code
- redacted from logs by default
See Security for the full threat model.
By default, Conduit runs in Permissive Mode to allow easy exploration.
Strict mode:
- blocks unknown tools
- blocks tools without schemas
- enforces argument validation
Recommended:
- permissive mode for exploration
- strict mode for production agents
To get the most out of Conduit, you should guide your LLM (agent) to prefer multi-tool scripts over individual tool calls.
Recommended System Prompt Additions:
You are equipped with a "Code Mode" execution environment via Conduit.
- Prefer
mcp_execute_typescript: Use this for any task requiring multiple steps, data transformation, or logical branching.- Use
tools.*SDK: Within your scripts, access all upstream tools via thetoolsnamespace (e.g.,await tools.github.create_issue(...)).- Avoid JSON tool-calling overhead: Instead of making 5 separate tool calls and waiting for 5 round-trips, write one script that orchestrates the entire operation.
- Data Transformation: Perform loops, filters, and aggregations directly in your code rather than asking the user (or yourself) to process large datasets in the chat context.
Example of a high-efficiency prompt: "Scan the last 50 emails for invoices, total their amounts by currency, and create a single summary ticket in Jira if the total exceeds $1000."
- Code over configuration: Logic belongs in code, not yaml.
- Isolation over reuse: Every execution is fresh.
- Explicit limits over best-effort: Fail fast if limits are breached.
- SDKs over RPC: Agents should write code against libraries, not protocols.
- Architecture - Internals, IPC, Executors
- Security - Threat model, specific mitigations
- Code Mode Philosophy - Why we generate code
When using Unix domain sockets (path in configuration), Conduit does not automatically unlink the socket file on startup. It is recommended to ensure the socket path is cleaned up by the deployment environment or startup script to avoid EADDRINUSE errors.
MIT
