Skip to content

mhingston/conduit

Repository files navigation

Conduit Logo

Conduit

npm version License: MIT TypeScript Node.js Version MCP Standard MCP Server

What is Conduit?

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

What Conduit Is Not

  • ❌ 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.


Installation

npm install @mhingston5/conduit

5-Minute Quick Start (Code Mode)

1. Start Conduit

pnpm install
# Build the project
npm run build
# Start the server
node dist/index.js

2. Register an upstream MCP server

Create 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"]

3. OAuth Setup Helper

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 \
  --pkce

4. Execute TypeScript

Using 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));

5. Result

Conduit runs the code, handles the tool call securely, and returns:

{
  "stdout": "Directories: [{\"type\":\"text\",\"text\":\"/tmp\"}]\n",
  "stderr": "",
  "exitCode": 0
}

Example usage with VS Code

{
  "mcpServers": {
    "conduit": {
      "type": "stdio",
      "command": "npx",
      "args": [
        "-y",
        "@mhingston5/conduit",
        "--stdio"
      ],
      "env": {}
    }
  }
}

How It Works (High Level)

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.


Security & Isolation Guarantees

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.


Strict vs Permissive Tool Validation

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

Code Mode Prompting Guide

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 the tools namespace (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."


Design Principles

  • 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.

Advanced Documentation

Note on Unix Sockets

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.

License

MIT

About

A secure Code Mode execution substrate for MCP agents.

Resources

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •