@mhingston5/conduit 1.1.0 → 1.1.1

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.
package/README.md CHANGED
@@ -175,6 +175,21 @@ By default, Conduit runs in **Permissive Mode** to allow easy exploration.
175
175
  - permissive mode for exploration
176
176
  - strict mode for production agents
177
177
 
178
+ ## Code Mode Prompting Guide
179
+
180
+ To get the most out of Conduit, you should guide your LLM (agent) to prefer multi-tool scripts over individual tool calls.
181
+
182
+ **Recommended System Prompt Additions:**
183
+ > You are equipped with a "Code Mode" execution environment via Conduit.
184
+ >
185
+ > - **Prefer `mcp.executeTypeScript`**: Use this for any task requiring multiple steps, data transformation, or logical branching.
186
+ > - **Use `tools.*` SDK**: Within your scripts, access all upstream tools via the `tools` namespace (e.g., `await tools.github.create_issue(...)`).
187
+ > - **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.
188
+ > - **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.
189
+
190
+ Example of a high-efficiency prompt:
191
+ *"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."*
192
+
178
193
  ---
179
194
 
180
195
  ## Design Principles
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhingston5/conduit",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "type": "module",
5
5
  "description": "A secure Code Mode execution substrate for MCP agents",
6
6
  "main": "index.js",
@@ -10,6 +10,66 @@ import { PolicyService, ToolIdentifier } from '../core/policy.service.js';
10
10
  import { Ajv } from 'ajv';
11
11
  import addFormats from 'ajv-formats';
12
12
 
13
+ const BUILT_IN_TOOLS: ToolSchema[] = [
14
+ {
15
+ name: 'mcp.executeTypeScript',
16
+ description: 'Executes TypeScript code in a secure sandbox with access to `tools.*` SDK.',
17
+ inputSchema: {
18
+ type: 'object',
19
+ properties: {
20
+ code: {
21
+ type: 'string',
22
+ description: 'The TypeScript code to execute.'
23
+ },
24
+ allowedTools: {
25
+ type: 'array',
26
+ items: { type: 'string' },
27
+ description: 'Optional list of tools the script is allowed to call (e.g. ["github.*"]).'
28
+ }
29
+ },
30
+ required: ['code']
31
+ }
32
+ },
33
+ {
34
+ name: 'mcp.executePython',
35
+ description: 'Executes Python code in a secure sandbox with access to `tools.*` SDK.',
36
+ inputSchema: {
37
+ type: 'object',
38
+ properties: {
39
+ code: {
40
+ type: 'string',
41
+ description: 'The Python code to execute.'
42
+ },
43
+ allowedTools: {
44
+ type: 'array',
45
+ items: { type: 'string' },
46
+ description: 'Optional list of tools the script is allowed to call (e.g. ["github.*"]).'
47
+ }
48
+ },
49
+ required: ['code']
50
+ }
51
+ },
52
+ {
53
+ name: 'mcp.executeIsolate',
54
+ description: 'Executes JavaScript code in a high-speed V8 isolate (no Deno/Node APIs).',
55
+ inputSchema: {
56
+ type: 'object',
57
+ properties: {
58
+ code: {
59
+ type: 'string',
60
+ description: 'The JavaScript code to execute.'
61
+ },
62
+ allowedTools: {
63
+ type: 'array',
64
+ items: { type: 'string' },
65
+ description: 'Optional list of tools the script is allowed to call.'
66
+ }
67
+ },
68
+ required: ['code']
69
+ }
70
+ }
71
+ ];
72
+
13
73
  export class GatewayService {
14
74
  private logger: Logger;
15
75
  private clients: Map<string, UpstreamClient> = new Map();
@@ -110,8 +170,13 @@ export class GatewayService {
110
170
  }
111
171
 
112
172
  const parsed = this.policyService.parseToolName(toolId);
173
+ const toolName = parsed.name; // Use a new variable for the un-namespaced name
174
+
175
+ // Check for built-in tools
176
+ const builtIn = BUILT_IN_TOOLS.find(t => t.name === toolId); // Compare with the full toolId
177
+ if (builtIn) return builtIn;
178
+
113
179
  const upstreamId = parsed.namespace;
114
- const toolName = parsed.name;
115
180
 
116
181
  // Ensure we have schemas for this upstream
117
182
  if (!this.schemaCache.get(upstreamId)) {
@@ -132,7 +197,7 @@ export class GatewayService {
132
197
  }
133
198
 
134
199
  async discoverTools(context: ExecutionContext): Promise<ToolSchema[]> {
135
- const allTools: ToolSchema[] = [];
200
+ const allTools: ToolSchema[] = [...BUILT_IN_TOOLS];
136
201
 
137
202
  for (const [id, client] of this.clients.entries()) {
138
203
  let tools = this.schemaCache.get(id);
@@ -31,11 +31,21 @@ describe('GatewayService', () => {
31
31
  });
32
32
 
33
33
  const tools = await gateway.discoverTools(context);
34
- expect(tools).toHaveLength(2);
34
+ expect(tools.length).toBeGreaterThanOrEqual(3);
35
+ expect(tools.find(t => t.name === 'mcp.executeTypeScript')).toBeDefined();
36
+ expect(tools.find(t => t.name === 'mcp.executePython')).toBeDefined();
37
+ expect(tools.find(t => t.name === 'mcp.executeIsolate')).toBeDefined();
35
38
  expect(tools.find(t => t.name === 'u1__t1')).toBeDefined();
36
39
  expect(tools.find(t => t.name === 'u2__t2')).toBeDefined();
37
40
  });
38
41
 
42
+ it('should return schema for built-in tools', async () => {
43
+ const schema = await gateway.getToolSchema('mcp.executeTypeScript', context);
44
+ expect(schema).toBeDefined();
45
+ expect(schema?.name).toBe('mcp.executeTypeScript');
46
+ expect(schema?.inputSchema.required).toContain('code');
47
+ });
48
+
39
49
  it('should route tool calls to correct upstream', async () => {
40
50
  gateway.registerUpstream({ id: 'u1', url: 'http://u1' });
41
51