@mhingston5/conduit 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/.env.example +13 -0
  2. package/.github/workflows/ci.yml +88 -0
  3. package/.github/workflows/pr-checks.yml +90 -0
  4. package/.tool-versions +2 -0
  5. package/README.md +177 -0
  6. package/conduit.yaml.test +3 -0
  7. package/docs/ARCHITECTURE.md +35 -0
  8. package/docs/CODE_MODE.md +33 -0
  9. package/docs/SECURITY.md +52 -0
  10. package/logo.png +0 -0
  11. package/package.json +74 -0
  12. package/src/assets/deno-shim.ts +93 -0
  13. package/src/assets/python-shim.py +21 -0
  14. package/src/core/asset.utils.ts +42 -0
  15. package/src/core/concurrency.service.ts +70 -0
  16. package/src/core/config.service.ts +147 -0
  17. package/src/core/execution.context.ts +37 -0
  18. package/src/core/execution.service.ts +209 -0
  19. package/src/core/interfaces/app.config.ts +17 -0
  20. package/src/core/interfaces/executor.interface.ts +31 -0
  21. package/src/core/interfaces/middleware.interface.ts +12 -0
  22. package/src/core/interfaces/url.validator.interface.ts +3 -0
  23. package/src/core/logger.ts +64 -0
  24. package/src/core/metrics.service.ts +112 -0
  25. package/src/core/middleware/auth.middleware.ts +56 -0
  26. package/src/core/middleware/error.middleware.ts +21 -0
  27. package/src/core/middleware/logging.middleware.ts +25 -0
  28. package/src/core/middleware/middleware.builder.ts +24 -0
  29. package/src/core/middleware/ratelimit.middleware.ts +31 -0
  30. package/src/core/network.policy.service.ts +106 -0
  31. package/src/core/ops.server.ts +74 -0
  32. package/src/core/otel.service.ts +41 -0
  33. package/src/core/policy.service.ts +77 -0
  34. package/src/core/registries/executor.registry.ts +26 -0
  35. package/src/core/request.controller.ts +297 -0
  36. package/src/core/security.service.ts +68 -0
  37. package/src/core/session.manager.ts +44 -0
  38. package/src/core/types.ts +47 -0
  39. package/src/executors/deno.executor.ts +342 -0
  40. package/src/executors/isolate.executor.ts +281 -0
  41. package/src/executors/pyodide.executor.ts +327 -0
  42. package/src/executors/pyodide.worker.ts +195 -0
  43. package/src/gateway/auth.service.ts +104 -0
  44. package/src/gateway/gateway.service.ts +345 -0
  45. package/src/gateway/schema.cache.ts +46 -0
  46. package/src/gateway/upstream.client.ts +244 -0
  47. package/src/index.ts +92 -0
  48. package/src/sdk/index.ts +2 -0
  49. package/src/sdk/sdk-generator.ts +245 -0
  50. package/src/sdk/tool-binding.ts +86 -0
  51. package/src/transport/socket.transport.ts +203 -0
  52. package/tests/__snapshots__/assets.test.ts.snap +97 -0
  53. package/tests/assets.test.ts +50 -0
  54. package/tests/auth.service.test.ts +78 -0
  55. package/tests/code-mode-lite-execution.test.ts +84 -0
  56. package/tests/code-mode-lite-gateway.test.ts +150 -0
  57. package/tests/concurrency.service.test.ts +50 -0
  58. package/tests/concurrency.test.ts +41 -0
  59. package/tests/config.service.test.ts +70 -0
  60. package/tests/contract.test.ts +43 -0
  61. package/tests/deno.executor.test.ts +68 -0
  62. package/tests/deno_hardening.test.ts +45 -0
  63. package/tests/dynamic.tool.test.ts +237 -0
  64. package/tests/e2e_stdio_upstream.test.ts +197 -0
  65. package/tests/fixtures/stdio-server.ts +42 -0
  66. package/tests/gateway.manifest.test.ts +82 -0
  67. package/tests/gateway.service.test.ts +58 -0
  68. package/tests/gateway.strict.unit.test.ts +74 -0
  69. package/tests/gateway.validation.unit.test.ts +89 -0
  70. package/tests/gateway_validation.test.ts +86 -0
  71. package/tests/hardening.test.ts +139 -0
  72. package/tests/hardening_v1.test.ts +72 -0
  73. package/tests/isolate.executor.test.ts +100 -0
  74. package/tests/log-limit.test.ts +55 -0
  75. package/tests/middleware.test.ts +106 -0
  76. package/tests/ops.server.test.ts +65 -0
  77. package/tests/policy.service.test.ts +90 -0
  78. package/tests/pyodide.executor.test.ts +101 -0
  79. package/tests/reference_mcp.ts +40 -0
  80. package/tests/remediation.test.ts +119 -0
  81. package/tests/routing.test.ts +148 -0
  82. package/tests/schema.cache.test.ts +27 -0
  83. package/tests/sdk/sdk-generator.test.ts +205 -0
  84. package/tests/socket.transport.test.ts +182 -0
  85. package/tests/stdio_upstream.test.ts +54 -0
  86. package/tsconfig.json +25 -0
  87. package/tsup.config.ts +22 -0
package/.env.example ADDED
@@ -0,0 +1,13 @@
1
+ # Server Configuration
2
+ PORT=3000
3
+ LOG_LEVEL=info
4
+ NODE_ENV=development
5
+
6
+ # Security
7
+ # Set this to a secure secret for production
8
+ IPC_BEARER_TOKEN=change_me_to_a_secure_token
9
+
10
+ # Upstream Configuration Examples
11
+ # GITHUB_MCP_URL=http://localhost:8080/mcp
12
+ # GITHUB_CLIENT_ID=...
13
+ # GITHUB_CLIENT_SECRET=...
@@ -0,0 +1,88 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, develop]
6
+ pull_request:
7
+ branches: [main, develop]
8
+
9
+ jobs:
10
+ test:
11
+ name: Test
12
+ runs-on: ubuntu-latest
13
+
14
+ steps:
15
+ - name: Checkout code
16
+ uses: actions/checkout@v4
17
+
18
+ - name: Install pnpm
19
+ uses: pnpm/action-setup@v4
20
+ with:
21
+ version: 10.8.0
22
+
23
+ - name: Setup Node.js
24
+ uses: actions/setup-node@v4
25
+ with:
26
+ node-version: 24.x
27
+ cache: 'pnpm'
28
+
29
+ - name: Install build dependencies
30
+ run: |
31
+ sudo apt-get update
32
+ sudo apt-get install -y python3 make g++
33
+
34
+ - name: Setup Deno
35
+ uses: denoland/setup-deno@v2
36
+ with:
37
+ deno-version: v2.x
38
+
39
+ - name: Install dependencies
40
+ run: pnpm install --frozen-lockfile
41
+
42
+ - name: Rebuild native modules
43
+ env:
44
+ PYTHON: python3
45
+ run: |
46
+ # Force rebuild isolated-vm which sometimes fails to build automatically
47
+ # Find the directory and build it
48
+ find node_modules/.pnpm -name "isolated-vm" -type d -exec bash -c 'cd "$0" && npm install --build-from-source' {} \;
49
+ # Also run general rebuild just in case
50
+ pnpm rebuild --recursive
51
+
52
+ - name: Run tests
53
+ run: pnpm test
54
+
55
+ - name: Build
56
+ run: pnpm build
57
+
58
+ lint:
59
+ name: Lint
60
+ runs-on: ubuntu-latest
61
+
62
+ steps:
63
+ - name: Checkout code
64
+ uses: actions/checkout@v4
65
+
66
+ - name: Install pnpm
67
+ uses: pnpm/action-setup@v4
68
+ with:
69
+ version: 10.8.0
70
+
71
+ - name: Setup Node.js
72
+ uses: actions/setup-node@v4
73
+ with:
74
+ node-version: 24.x
75
+ cache: 'pnpm'
76
+
77
+ - name: Install dependencies
78
+ run: pnpm install --frozen-lockfile
79
+
80
+ - name: Rebuild native modules
81
+ env:
82
+ PYTHON: python3
83
+ run: |
84
+ find node_modules/.pnpm -name "isolated-vm" -type d -exec bash -c 'cd "$0" && npm install --build-from-source' {} \;
85
+ pnpm rebuild --recursive
86
+
87
+ - name: Check TypeScript
88
+ run: pnpm exec tsc --noEmit
@@ -0,0 +1,90 @@
1
+ name: PR Checks
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [main, develop]
6
+
7
+ jobs:
8
+ validate:
9
+ name: Validate PR
10
+ runs-on: ubuntu-latest
11
+
12
+ steps:
13
+ - name: Checkout code
14
+ uses: actions/checkout@v4
15
+ with:
16
+ fetch-depth: 0
17
+
18
+ - name: Install pnpm
19
+ uses: pnpm/action-setup@v4
20
+ with:
21
+ version: 10.8.0
22
+
23
+ - name: Setup Node.js
24
+ uses: actions/setup-node@v4
25
+ with:
26
+ node-version: 24.x
27
+ cache: 'pnpm'
28
+
29
+ - name: Setup Deno
30
+ uses: denoland/setup-deno@v2
31
+ with:
32
+ deno-version: v2.x
33
+
34
+ - name: Install dependencies
35
+ run: pnpm install --frozen-lockfile
36
+
37
+ - name: Rebuild native modules
38
+ env:
39
+ PYTHON: python3
40
+ run: |
41
+ find node_modules/.pnpm -name "isolated-vm" -type d -exec bash -c 'cd "$0" && npm install --build-from-source' {} \;
42
+ pnpm rebuild --recursive
43
+
44
+ - name: Run tests
45
+ run: pnpm test
46
+
47
+ - name: Build
48
+ run: pnpm build
49
+
50
+ - name: Check TypeScript
51
+ run: pnpm exec tsc --noEmit
52
+
53
+ - name: Check for uncommitted changes
54
+ run: |
55
+ if [ -n "$(git status --porcelain)" ]; then
56
+ echo "Error: Found uncommitted changes after build"
57
+ git status --porcelain
58
+ exit 1
59
+ fi
60
+
61
+ size-check:
62
+ name: Bundle Size Check
63
+ runs-on: ubuntu-latest
64
+
65
+ steps:
66
+ - name: Checkout code
67
+ uses: actions/checkout@v4
68
+
69
+ - name: Install pnpm
70
+ uses: pnpm/action-setup@v4
71
+ with:
72
+ version: 10.8.0
73
+
74
+ - name: Setup Node.js
75
+ uses: actions/setup-node@v4
76
+ with:
77
+ node-version: 24.x
78
+ cache: 'pnpm'
79
+
80
+ - name: Install dependencies
81
+ run: pnpm install --frozen-lockfile
82
+
83
+ - name: Build
84
+ run: pnpm build
85
+
86
+ - name: Check bundle size
87
+ run: |
88
+ echo "Bundle size:"
89
+ du -sh dist/
90
+ find dist/ -name "*.js" -exec du -h {} \; | sort -h
package/.tool-versions ADDED
@@ -0,0 +1,2 @@
1
+ nodejs 24.0.0
2
+ deno 2.0.0
package/README.md ADDED
@@ -0,0 +1,177 @@
1
+ <div align="center">
2
+ <img src="./logo.png" alt="Conduit Logo" width="400"/>
3
+ </div>
4
+
5
+ # Conduit
6
+
7
+ <div align="center">
8
+
9
+ [![npm version](https://badge.fury.io/js/@mhingston5%2Fconduit.svg)](https://www.npmjs.com/package/@mhingston/conduit)
10
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
11
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/)
12
+ [![Node.js Version](https://img.shields.io/badge/node-24-brightgreen.svg)](https://nodejs.org/)
13
+ [![MCP](https://img.shields.io/badge/MCP-Compatible-purple.svg)](https://modelcontextprotocol.io/)
14
+
15
+ </div>
16
+
17
+ ## What is Conduit?
18
+
19
+ Conduit is a **secure Code Mode execution substrate** for [MCP](https://modelcontextprotocol.io/) agents.
20
+
21
+ It lets agents:
22
+ - generate **real TypeScript or Python code**
23
+ - call tools via **language-native APIs** (`tools.github.createIssue()`)
24
+ - run that code in **isolated, resource-governed sandboxes**
25
+ - without exposing credentials or the host environment
26
+
27
+ Conduit is optimized for:
28
+ - [Code Mode](./docs/CODE_MODE.md) (not JSON tool calling)
29
+ - composable multi-tool execution
30
+ - strict safety, limits, and observability
31
+
32
+ ## What Conduit Is Not
33
+
34
+ - ❌ A general-purpose script runner
35
+ - ❌ An LLM gateway or provider abstraction
36
+ - ❌ A plugin UI or agent framework
37
+ - ❌ A long-lived compute environment
38
+
39
+ Conduit executes **short-lived, isolated programs** with explicit limits.
40
+
41
+ ---
42
+
43
+ ## Installation
44
+
45
+ ```bash
46
+ npm install @mhingston5/conduit
47
+ ```
48
+
49
+ ## 5-Minute Quick Start (Code Mode)
50
+
51
+ ### 1. Start Conduit
52
+ ```bash
53
+ pnpm install
54
+ # Build the project
55
+ npm run build
56
+ # Start the server
57
+ node dist/index.js
58
+ ```
59
+
60
+ ### 2. Register an upstream MCP server
61
+
62
+ Create a `conduit.yaml` in the root:
63
+ ```yaml
64
+ upstreams:
65
+ - id: github
66
+ type: http
67
+ url: "http://localhost:3000/mcp"
68
+ # Or use local stdio for testing:
69
+ - id: filesystem
70
+ type: stdio
71
+ command: npx
72
+ args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
73
+ ```
74
+
75
+ ### 3. Execute TypeScript
76
+
77
+ Using any [MCP Client](https://modelcontextprotocol.io/clients) (Claude Desktop, etc.), call `mcp.executeTypeScript`:
78
+
79
+ ```ts
80
+ // The agent writes this code:
81
+ const result = await tools.filesystem.list_allowed_directories();
82
+ console.log("Files:", result);
83
+ ```
84
+
85
+ ### 4. Result
86
+
87
+ Conduit runs the code, handles the tool call securely, and returns:
88
+
89
+ ```json
90
+ {
91
+ "stdout": "Files: ['/tmp']\n",
92
+ "stderr": "",
93
+ "exitCode": 0
94
+ }
95
+ ```
96
+
97
+ ---
98
+
99
+ ## How It Works (High Level)
100
+
101
+ ```
102
+ LLM → generates code
103
+
104
+ Client → sends code to Conduit
105
+
106
+ Conduit:
107
+ - injects a `tools.*` SDK
108
+ - enforces limits + allowlists
109
+ - runs code in an isolated runtime (Deno / Pyodide / Isolate)
110
+
111
+ Tools are called via the Gateway
112
+
113
+ Results returned as stdout / stderr
114
+ ```
115
+
116
+ For implementation details, see [Architecture](./docs/ARCHITECTURE.md).
117
+
118
+ ---
119
+
120
+ ## Security & Isolation Guarantees
121
+
122
+ Each execution:
123
+ - runs in a fresh sandbox (no state reuse)
124
+ - has strict CPU, memory, output, and log limits
125
+ - cannot access host credentials or filesystem
126
+ - can only call explicitly allowed tools
127
+ - is forcibly terminated on violation
128
+
129
+ **SSRF protection**:
130
+ - private IP ranges blocked
131
+ - DNS rebinding prevented
132
+ - IPv6-mapped IPv4 handled
133
+
134
+ **Secrets**:
135
+ - never injected into user code
136
+ - redacted from logs by default
137
+
138
+ See [Security](./docs/SECURITY.md) for the full threat model.
139
+
140
+ ---
141
+
142
+ ## Strict vs Permissive Tool Validation
143
+
144
+ By default, Conduit runs in **Permissive Mode** to allow easy exploration.
145
+
146
+ **Strict mode**:
147
+ - blocks unknown tools
148
+ - blocks tools without schemas
149
+ - enforces argument validation
150
+
151
+ **Recommended**:
152
+ - permissive mode for exploration
153
+ - strict mode for production agents
154
+
155
+ ---
156
+
157
+ ## Design Principles
158
+
159
+ - **Code over configuration**: Logic belongs in code, not yaml.
160
+ - **Isolation over reuse**: Every execution is fresh.
161
+ - **Explicit limits over best-effort**: Fail fast if limits are breached.
162
+ - **SDKs over RPC**: Agents should write code against libraries, not protocols.
163
+
164
+ ---
165
+
166
+ ## Advanced Documentation
167
+
168
+ - [Architecture](./docs/ARCHITECTURE.md) - Internals, IPC, Executors
169
+ - [Security](./docs/SECURITY.md) - Threat model, specific mitigations
170
+ - [Code Mode Philosophy](./docs/CODE_MODE.md) - Why we generate code
171
+
172
+ ## Note on Unix Sockets
173
+
174
+ 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.
175
+
176
+ ## License
177
+ MIT
@@ -0,0 +1,3 @@
1
+ port: ${TEST_PORT:-5555}
2
+ envTest: ${TEST_ENV}
3
+
@@ -0,0 +1,35 @@
1
+ # Conduit Architecture
2
+
3
+ Conduit is built with a modular architecture, designed to be secure, observable, and composable.
4
+
5
+ ## Core Components
6
+
7
+ - **`src/core`**: Core services (Config, Logger, Concurrency, Ops, Request Dispatching).
8
+ - **`src/executors`**: Secure runtime environments for code execution.
9
+ - **`src/gateway`**: Upstream client management, auth (OAuth2/API Keys), and schema caching.
10
+ - **`src/transport`**: Network abstraction layer.
11
+ - **`src/sdk`**: SDK generation for typed tool bindings.
12
+
13
+ ## Detailed Flow
14
+
15
+ 1. **Client Request**: A client (like VS Code or Claude Desktop) sends a JSON-RPC request (`mcp.executeTypeScript`).
16
+ 2. **Transportation**: The request is received via `SocketTransport` (TCP/UDS/Pipe).
17
+ 3. **Dispatch**: `RequestController` validates the request and session tokens.
18
+ 4. **Tool Discovery**: `GatewayService` aggregates tools from all upstream MCP servers.
19
+ 5. **SDK Generation**: The `SdkService` generates a type-safe SDK (`tools.*`) based on discovered schemas.
20
+ 6. **Execution**:
21
+ - **Deno**: Spawns a Deno subprocess with limited permissions.
22
+ - **Browser-style (In-Process)**: Uses `isolated-vm` for high-speed JS logic.
23
+ - **Python**: Uses Pyodide in a worker thread.
24
+ 7. **Result**: Stdout/stderr and return values are captured and returned to the client.
25
+
26
+ ## IPC & Transport
27
+
28
+ Conduit supports multiple transports:
29
+ - **TCP**: Standard network sockets.
30
+ - **Unix Domain Sockets**: For local IPC.
31
+ - **Windows Named Pipes**: For local IPC on Windows.
32
+
33
+ ## Schema Caching
34
+
35
+ To optimize performance, upstreams are polled for tool schemas, which are cached with a TTL. This prevents repeated network calls during high-frequency execution loops.
@@ -0,0 +1,33 @@
1
+ # Code Mode Philosophy
2
+
3
+ Conduit is built for **Code Mode**.
4
+
5
+ ## What is Code Mode?
6
+
7
+ "Code Mode" is an architectural pattern for AI Agents where:
8
+ - **LLMs generate code**, not JSON tool calls.
9
+ - **Tools are libraries**, not RPC endpoints.
10
+ - **Execution is sandboxed**, not local.
11
+
12
+ Reference: [Cloudflare Code Mode](https://developers.cloudflare.com/agents/code-mode/)
13
+
14
+ ## Why Code Mode?
15
+
16
+ ### 1. Context Efficiency (98% Reduction)
17
+ Traditional "Tool Use" requires pasting typically huge JSON schemas for every available tool into the LLM system prompt.
18
+ In Code Mode, you paste **0 schemas**. The agent writes code to *discover* tools dynamically at runtime, or assumes standard SDK shapes.
19
+
20
+ ### 2. Composition & Logic
21
+ Agent logic (loops, conditionals, retries, variable transformations) happens **in the code**, not in the LLM's context window.
22
+ - **Old Way**: LLM -> Tool Call -> LLM -> Tool Call -> LLM -> Result
23
+ - **Code Mode**: LLM -> `for (item in items) { await tool(item) }` -> Result
24
+
25
+ ### 3. Safety
26
+ Because logic executes in a sandbox, you can enforce limits on loops, memory, and duration that are impossible to enforce on an LLM's token stream.
27
+
28
+ ## Implementation in Conduit
29
+
30
+ Conduit provides:
31
+ 1. **`executeTypeScript` / `executePython`**: The entry points.
32
+ 2. **`tools.*` SDK**: A dynamically generated client injected into the runtime.
33
+ 3. **Sandboxes**: Deno, Pyodide, and isolated-vm to run the code safely.
@@ -0,0 +1,52 @@
1
+ # Security & Isolation Guarantees
2
+
3
+ Conduit implements a defense-in-depth security model to ensure safe code execution.
4
+
5
+ ## Isolation Guarantees
6
+
7
+ Each execution:
8
+ - runs in a **fresh sandbox** (no state reuse).
9
+ - has strict **CPU, memory, output, and log limits**.
10
+ - cannot access **host credentials or filesystem** (unless explicitly allowed via tools).
11
+ - can only call **explicitly allowed tools**.
12
+ - is **forcibly terminated** on violation.
13
+
14
+ ## SSRF Protection
15
+
16
+ Conduit enforces strict Server-Side Request Forgery (SSRF) protections on upstreams:
17
+ - **Private IP ranges blocked** (unless explicitly allowed).
18
+ - **DNS rebinding prevented** by verifying IP resolution before connection.
19
+ - **IPv6-mapped IPv4** addresses are handled correctly.
20
+ - **HTTP Redirects** are visually disabled or strictly validated.
21
+
22
+ ## Secrets Management
23
+
24
+ - **Injection**: Secrets are never injected into user code as environment variables (unless via specific secure tool config).
25
+ - **Redaction**: Logs are automatically scrubbed for known secrets and PII patterns.
26
+
27
+ ## Authorization
28
+
29
+ - **Master Token**: Full access to all methods (set via `IPC_BEARER_TOKEN`).
30
+ - **Session Tokens**: Generated per-execution, restricted to `mcp.discoverTools` and `mcp.callTool` only.
31
+ - **Tool Allowlisting**: Per-request scope limits which tools code can discover/call (e.g., `["github.*"]`).
32
+
33
+ ## Runtime Security
34
+
35
+ - **Deno**: Uses OS-level sandbox permissions (`--allow-net`, `--allow-read` are restricted).
36
+ - **Pyodide**: Runs in a Worker Thread with no access to the main thread's DOM or context.
37
+ - **In-Process JS (isolated-vm)**: Uses V8 isolates for memory isolation but shares the host process.
38
+
39
+ ## Production Hardening Recommendations
40
+
41
+ While Conduit provides robust application-level sandboxing, `isolated-vm` and Deno subprocesses still share the host kernel. For **multi-tenant** or **hostile** workloads, you must implement defense-in-depth by wrapping Conduit itself.
42
+
43
+ ### Tiered Isolation Model
44
+
45
+ | Component | Protection Against | Vulnerable To |
46
+ |-----------|--------------------|---------------|
47
+ | **Conduit (Code)** | Logical errors, resource exhaustion, unauthorized tool use | Runtime/V8 escapes, Kernel exploits |
48
+ | **Container (Docker)** | Filesystem access, network enumeration | Kernel exploits, Container breakouts |
49
+ | **MicroVM (Firecracker/gVisor)** | Kernel exploits, complete system compromise | Hypervisor exploits (rare) |
50
+
51
+ **Recommendation:**
52
+ For production deployments executing untrusted code, deploy Conduit inside a **gVisor-backed container** or a **Firecracker MicroVM** (like AWS Fargate or Fly.io Machines). This prevents a V8/Deno escape from compromising the host infrastructure.
package/logo.png ADDED
Binary file
package/package.json ADDED
@@ -0,0 +1,74 @@
1
+ {
2
+ "name": "@mhingston5/conduit",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "A secure Code Mode execution substrate for MCP agents",
6
+ "main": "index.js",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "scripts": {
11
+ "test": "vitest run",
12
+ "test:watch": "vitest",
13
+ "build": "tsup"
14
+ },
15
+ "keywords": [
16
+ "mcp",
17
+ "agent",
18
+ "sandbox",
19
+ "code-execution",
20
+ "typescript",
21
+ "python",
22
+ "isolation"
23
+ ],
24
+ "author": "Mark Hingston",
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "https://github.com/mhingston/conduit.git"
29
+ },
30
+ "bugs": {
31
+ "url": "https://github.com/mhingston/conduit/issues"
32
+ },
33
+ "homepage": "https://github.com/mhingston/conduit#readme",
34
+ "packageManager": "pnpm@10.8.0",
35
+ "engines": {
36
+ "node": "24.0.0"
37
+ },
38
+ "dependencies": {
39
+ "@modelcontextprotocol/sdk": "^1.25.1",
40
+ "@opentelemetry/api": "^1.9.0",
41
+ "@opentelemetry/auto-instrumentations-node": "^0.67.3",
42
+ "@opentelemetry/exporter-prometheus": "^0.208.0",
43
+ "@opentelemetry/instrumentation-pino": "^0.55.1",
44
+ "@opentelemetry/resources": "^2.2.0",
45
+ "@opentelemetry/sdk-node": "^0.208.0",
46
+ "@opentelemetry/semantic-conventions": "^1.38.0",
47
+ "ajv": "^8.17.1",
48
+ "ajv-formats": "^3.0.1",
49
+ "axios": "^1.13.2",
50
+ "dotenv": "^17.2.3",
51
+ "fastify": "^5.6.2",
52
+ "isolated-vm": "^6.0.2",
53
+ "js-yaml": "^4.1.1",
54
+ "lru-cache": "^11.2.4",
55
+ "p-limit": "^7.2.0",
56
+ "pino": "^10.1.0",
57
+ "pyodide": "^0.29.0",
58
+ "uuid": "^13.0.0",
59
+ "zod": "^4.3.5"
60
+ },
61
+ "devDependencies": {
62
+ "@types/js-yaml": "^4.0.9",
63
+ "@types/node": "^25.0.3",
64
+ "@types/pino": "^7.0.5",
65
+ "@types/uuid": "^11.0.0",
66
+ "pino-pretty": "^13.1.3",
67
+ "ts-node": "^10.9.2",
68
+ "tsup": "^8.5.1",
69
+ "tsx": "^4.21.0",
70
+ "typescript": "^5.9.3",
71
+ "vitest": "^4.0.16",
72
+ "vitest-mock-extended": "^3.1.0"
73
+ }
74
+ }
@@ -0,0 +1,93 @@
1
+ // @ts-nocheck
2
+ // Deno Shim for Conduit - Code Mode SDK
3
+ const IPC_ADDRESS = '__CONDUIT_IPC_ADDRESS__';
4
+ const IPC_TOKEN = '__CONDUIT_IPC_TOKEN__';
5
+
6
+ async function sendIPCRequest(method: string, params: any) {
7
+ if (!IPC_ADDRESS) throw new Error('Conduit IPC address not configured');
8
+
9
+ let conn: any;
10
+ try {
11
+ if (IPC_ADDRESS.includes(':')) {
12
+ const lastColon = IPC_ADDRESS.lastIndexOf(':');
13
+ const hostname = IPC_ADDRESS.substring(0, lastColon);
14
+ const port = IPC_ADDRESS.substring(lastColon + 1);
15
+
16
+ // Normalize hostname for Deno connect
17
+ let targetHost = hostname.replace(/[\[\]]/g, '');
18
+ if (targetHost === '0.0.0.0' || targetHost === '::' || targetHost === '::1' || targetHost === '') {
19
+ targetHost = '127.0.0.1';
20
+ }
21
+
22
+ conn = await (Deno as any).connect({
23
+ hostname: targetHost,
24
+ port: Number(port)
25
+ });
26
+ } else {
27
+ conn = await (Deno as any).connect({ transport: 'unix', path: IPC_ADDRESS });
28
+ }
29
+ } catch (err: any) {
30
+ throw new Error(`Failed to connect to Conduit IPC (${IPC_ADDRESS}): ${err.message}`);
31
+ }
32
+
33
+ try {
34
+ const id = Math.random().toString(36).substring(7);
35
+ const request = {
36
+ jsonrpc: '2.0',
37
+ id,
38
+ method,
39
+ params: params || {},
40
+ auth: { bearerToken: IPC_TOKEN }
41
+ };
42
+
43
+ const encoder = new TextEncoder();
44
+ await conn.write(encoder.encode(JSON.stringify(request) + '\n'));
45
+
46
+ const decoder = new TextDecoder();
47
+ let buffer = '';
48
+ const chunk = new Uint8Array(2 * 1024 * 1024); // 2MB buffer for large tool returns
49
+
50
+ while (true) {
51
+ const n = await conn.read(chunk);
52
+ if (n === null) throw new Error('IPC connection closed by host before receiving response');
53
+
54
+ buffer += decoder.decode(chunk.subarray(0, n));
55
+ const lines = buffer.split('\n');
56
+ buffer = lines.pop() || ''; // Keep partial line
57
+
58
+ for (const line of lines) {
59
+ if (!line.trim()) continue;
60
+ try {
61
+ const response = JSON.parse(line);
62
+ if (response.id === id) {
63
+ if (response.error) {
64
+ const error = new Error(response.error.message);
65
+ (error as any).code = response.error.code;
66
+ (error as any).data = response.error.data;
67
+ throw error;
68
+ }
69
+ return response.result;
70
+ }
71
+ } catch (e: any) {
72
+ if (e.message.includes('JSON')) continue;
73
+ throw e;
74
+ }
75
+ }
76
+ }
77
+ } finally {
78
+ conn.close();
79
+ }
80
+ }
81
+
82
+ // Internal tool call function - used by generated SDK
83
+ const __internalCallTool = async (name: string, params: any) => {
84
+ return await sendIPCRequest('mcp.callTool', { name, arguments: params });
85
+ };
86
+
87
+ // Tool discovery - still available for dynamic scenarios
88
+ (globalThis as any).discoverMCPTools = async (options: any) => {
89
+ const result = await sendIPCRequest('mcp.discoverTools', options);
90
+ return result.tools || [];
91
+ };
92
+
93
+ // __CONDUIT_SDK_INJECTION__
@@ -0,0 +1,21 @@
1
+ # Python Shim for Conduit - Code Mode SDK
2
+ import asyncio
3
+
4
+ async def discover_mcp_tools(options=None):
5
+ """Discover available MCP tools from the gateway."""
6
+ # These functions are injected into the Python global scope by the executor
7
+ res = await discover_mcp_tools_js(options)
8
+ # Pyodide's JS proxy handles conversion broadly, but we might need to convert the tools list
9
+ if hasattr(res, 'to_py'):
10
+ data = res.to_py()
11
+ return data.get('tools', []) if isinstance(data, dict) else []
12
+ return []
13
+
14
+ async def _internal_call_tool(name, arguments):
15
+ """Internal tool call function - used by generated SDK."""
16
+ res = await call_mcp_tool_js(name, arguments)
17
+ if hasattr(res, 'to_py'):
18
+ return res.to_py()
19
+ return res
20
+
21
+ # __CONDUIT_SDK_INJECTION__