Skip to main content
Glama
portel-dev

NCP - Natural Context Provider

by portel-dev

code

Execute TypeScript code with automatic tool discovery and parameter mapping using semantic understanding of user intent.

Instructions

Execute TypeScript code with automatic tool discovery and parameter mapping.

PRIMARY METHOD - ncp.do(intent, params): Single-call execution with embedding-based param matching. No need to know exact tool names or param schemas!

ncp.do("send email", { recipient: "john@example.com", // Auto-maps to "to" title: "Meeting", // Auto-maps to "subject" message: "Let's meet" // Auto-maps to "body" })

Returns on success: { success: true, tool, result, paramMappings } Returns on failure: { success: false, tool, schema, hint }

  • schema shows actual params needed

  • hint suggests corrections

  • Retry with correct params!

FALLBACK - Direct namespace calls (when you know exact tools):

  • ncp.find("query"): Returns Tool[] with { toolName, schema, confidence }

  • namespace.tool(): Direct call e.g., gmail.send_email({ to, subject, body })

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
codeYesTypeScript code. Use ncp.do("intent", { params }) for automatic tool discovery and param mapping.
timeoutNoTimeout in ms (default: 30000, max: 300000)

Implementation Reference

  • Main handler for the 'code:run' tool - executes TypeScript code with access to all MCPs as namespaces. Validates parameters, calls orchestrator.executeCode(), and returns results with logs and runId.
    private async executeRun(parameters: any): Promise<InternalToolResult> {
      if (!this.orchestrator) {
        return {
          success: false,
          error: 'Code execution not yet initialized'
        };
      }
    
      // Diagnostic logging to help debug parameter issues
      console.error('[code:run] Tool called with parameters:', {
        rawType: typeof parameters,
        isNull: parameters === null,
        isUndefined: parameters === undefined,
        keys: parameters ? Object.keys(parameters) : [],
        codeType: typeof parameters?.code,
        codeLength: parameters?.code?.length,
        codePreview: typeof parameters?.code === 'string' ? parameters.code.substring(0, 100) : 'N/A'
      });
    
      const { code, timeout } = parameters;
    
      if (!code || typeof code !== 'string') {
        console.error('[code:run] Validation failed:', {
          code,
          codeType: typeof code,
          allParams: JSON.stringify(parameters)
        });
        return {
          success: false,
          error: `code parameter is required and must be a string. Received: ${typeof code}`
        };
      }
    
      try {
        const result = await this.orchestrator.executeCode(code, timeout || 30000);
    
        if (result.error) {
          return {
            success: false,
            error: result.error,
            content: result.logs ? `Logs:\n${result.logs.join('\n')}` : undefined
          };
        }
    
        return {
          success: true,
          content: JSON.stringify({
            result: result.result,
            logs: result.logs,
            runId: result.runId
          }, null, 2)
        };
      } catch (error: any) {
        return {
          success: false,
          error: error.message,
          content: error.stack
        };
      }
    }
  • Core code execution logic with multiple sandbox strategies: IsolatedVM (V8 isolate), Subprocess (process isolation), Worker Thread (with bindings support), and VM fallback. Includes package approval, audit logging, and state management.
    async executeCode(code: string, timeout: number = 30000): Promise<CodeExecutionResult> {
      const startTime = Date.now();
      const runId = generateRunId();
      const stateLog = new StateLog(runId);
      const auditLogger = getAuditLogger();
      const approvalManager = getPackageApprovalManager();
    
      // Initialize state log for this execution (enables code:save-as-photon)
      try {
        await stateLog.init();
        await stateLog.writeStart('code', { code });
        logger.debug(`Code execution started with run ID: ${runId}`);
      } catch (error: any) {
        logger.debug(`Could not initialize state log: ${error.message}`);
      }
    
      // Phase 6: Check for non-whitelisted packages and elicit approval
      // This happens BEFORE execution starts
      let temporaryApprovals: string[] = [];
      try {
        temporaryApprovals = await this.checkPackageApproval(code);
      } catch (error: any) {
        // Package approval failed - return as error result
        try {
          await stateLog.writeError(error.message, error.stack);
        } catch (logError) {
          logger.debug(`Could not log error to state log: ${logError}`);
        }
        return {
          result: null,
          logs: [`[ERROR] ${error.message}`],
          error: error.message,
          runId,
        };
      }
    
      // Phase 5: Log code execution start
      await auditLogger.logCodeExecutionStart(code, { mcpName: 'code-mode' });
    
      // Get effective whitelist (built-in + temporarily approved)
      const effectiveWhitelist = approvalManager.getEffectiveWhitelist();
    
      try {
        // Try IsolatedVMSandbox first (most secure - true V8 Isolate)
        if (IsolatedVMSandbox.isAvailable()) {
          try {
            const result = await this.executeWithIsolatedVM(code, timeout);
    
            // Phase 5: Log success
            const duration = Date.now() - startTime;
            await auditLogger.logCodeExecutionSuccess(code, result.result, duration, {
              mcpName: 'code-mode',
              userId: 'isolated-vm'
            });
    
            // Log to state log and include runId in response
            try {
              await stateLog.writeReturn(result.result);
            } catch (logError) {
              logger.debug(`Could not log return to state log: ${logError}`);
            }
    
            return { ...result, runId };
          } catch (isolatedVMError: any) {
            logger.warn(`IsolatedVM execution failed: ${isolatedVMError.message}, falling back to Subprocess`);
          }
        }
    
        // Try SubprocessSandbox (second most secure - true process isolation)
        try {
          const result = await this.executeWithSubprocess(code, timeout);
    
          // Phase 5: Log success
          const duration = Date.now() - startTime;
          await auditLogger.logCodeExecutionSuccess(code, result.result, duration, {
            mcpName: 'code-mode',
            userId: 'subprocess'
          });
    
          // Log to state log and include runId in response
          try {
            await stateLog.writeReturn(result.result);
          } catch (logError) {
            logger.debug(`Could not log return to state log: ${logError}`);
          }
    
          return { ...result, runId };
        } catch (subprocessError: any) {
          logger.warn(`Subprocess execution failed: ${subprocessError.message}, falling back to Worker Thread`);
    
          // Fallback to Worker Thread (third most secure)
          try {
            const result = await this.executeWithWorkerThread(code, timeout);
    
            const duration = Date.now() - startTime;
            await auditLogger.logCodeExecutionSuccess(code, result.result, duration, {
              mcpName: 'code-mode',
              userId: 'worker-fallback'
            });
    
            // Log to state log and include runId in response
            try {
              await stateLog.writeReturn(result.result);
            } catch (logError) {
              logger.debug(`Could not log return to state log: ${logError}`);
            }
    
            return { ...result, runId };
          } catch (workerError: any) {
            logger.warn(`Worker Thread execution failed: ${workerError.message}, falling back to VM`);
    
            // Final fallback to VM module (least secure but stable)
            try {
              const result = await this.executeWithVM(code, timeout);
    
              const duration = Date.now() - startTime;
              await auditLogger.logCodeExecutionSuccess(code, result.result, duration, {
                mcpName: 'code-mode',
                userId: 'vm-fallback'
              });
    
              // Log to state log and include runId in response
              try {
                await stateLog.writeReturn(result.result);
              } catch (logError) {
                logger.debug(`Could not log return to state log: ${logError}`);
              }
    
              return { ...result, runId };
            } catch (vmError: any) {
              logger.error(`[VM Execution Error Details]`, {
                message: vmError.message,
                stack: vmError.stack,
                name: vmError.name,
                code: code.substring(0, 100)
              });
              await auditLogger.logCodeExecutionError(code, vmError.message, { mcpName: 'code-mode' });
    
              // Log error to state log
              try {
                await stateLog.writeError(vmError.message, vmError.stack);
              } catch (logError) {
                logger.debug(`Could not log error to state log: ${logError}`);
              }
    
              throw vmError;
            }
          }
        }
      } catch (error: any) {
        // Final error handler - ensure runId is included in error response
        return {
          result: null,
          logs: [`[ERROR] ${error.message}`],
          error: error.message,
          runId,
        };
      }
    }
  • Tool definitions and input/output schemas for the 'code' MCP including 'run', 'list-runs', 'get-run', and 'save-as-photon' tools with their parameter validation schemas.
      tools: InternalTool[] = [
        {
          name: 'run',
          description: `Execute TypeScript code with access to all MCPs as namespaces.
    
    ORCHESTRATION POWERHOUSE - Schedule code that calls multiple MCPs!
    
    EXAMPLES:
      // Single MCP call
      const result = await gmail.list_messages({ query: "is:unread" });
    
      // Orchestrate multiple MCPs
      const emails = await gmail.list_messages({ ... });
      const contacts = await gmail.get_contacts({});
      await slack.send_message({
        channel: "alerts",
        text: \`Found \${emails.length} emails from \${contacts.length} contacts\`
      });
    
      // Schedule code execution
      await schedule.create({
        name: "daily-automation",
        schedule: "0 6 * * *",
        tool: "code:run",
        parameters: {
          code: "... your code here ..."
        }
      });
    
    All MCPs available as namespaces: gmail, github, slack, stripe, schedule, analytics, mcp, etc.`,
          inputSchema: {
            type: 'object',
            properties: {
              code: {
                type: 'string',
                description: 'TypeScript code. Access MCPs as namespaces (e.g., await gmail.send_email({...})). Last expression or return value is result.'
              },
              timeout: {
                type: 'number',
                description: 'Timeout in ms (default: 30000, max: 300000)'
              }
            },
            required: ['code']
          }
        },
        {
          name: 'list-runs',
          description: 'List recent code execution runs for potential save-as-photon conversion',
          inputSchema: {
            type: 'object',
            properties: {
              limit: {
                type: 'number',
                description: 'Maximum number of runs to list (default: 10)'
              }
            }
          }
        },
        {
          name: 'get-run',
          description: 'Get details of a specific code execution run including full JSONL log',
          inputSchema: {
            type: 'object',
            properties: {
              runId: {
                type: 'string',
                description: 'The run ID from a previous code execution'
              }
            },
            required: ['runId']
          }
        },
        {
          name: 'save-as-photon',
          description: 'Convert a successful code execution into a reusable Photon (.photon.ts file)',
          inputSchema: {
            type: 'object',
            properties: {
              runId: {
                type: 'string',
                description: 'The run ID of the code execution to convert'
              },
              photonName: {
                type: 'string',
                description: 'Name for the new Photon (will be kebab-case, e.g., my-tool)'
              },
              description: {
                type: 'string',
                description: 'Description of what this Photon does'
              }
            },
            required: ['runId', 'photonName', 'description']
          }
        }
      ];
  • Registration of CodeMCP instance in the InternalMCPManager constructor. The code MCP is instantiated and registered alongside other internal MCPs.
    this.codeMCP = new CodeMCP();
    this.registerInternalMCP(this.codeMCP);
  • Helper handlers for code execution management: listRuns() lists recent executions, getRun() retrieves execution details including JSONL logs, enabling workflow tracking and save-as-photon conversion.
    private async listRuns(parameters: any): Promise<InternalToolResult> {
      try {
        const limit = parameters?.limit || 10;
        const runs = await listRuns();
    
        // Return only the most recent ones up to limit
        const recentRuns = runs.slice(0, limit);
    
        return {
          success: true,
          content: JSON.stringify({
            runs: recentRuns.map((run: WorkflowRun) => ({
              runId: run.runId,
              startedAt: run.startedAt,
              completedAt: run.completedAt,
              status: run.status
            }))
          }, null, 2)
        };
      } catch (error: any) {
        return {
          success: false,
          error: error.message
        };
      }
    }
    
    /**
     * Get details of a specific code execution run
     */
    private async getRun(parameters: any): Promise<InternalToolResult> {
      try {
        const { runId } = parameters;
        if (!runId || typeof runId !== 'string') {
          return {
            success: false,
            error: 'runId parameter is required'
          };
        }
    
        const runInfo = await getRunInfo(runId);
        if (!runInfo) {
          return {
            success: false,
            error: `Run ${runId} not found`
          };
        }
    
        return {
          success: true,
          content: JSON.stringify({
            runId: runInfo.runId,
            tool: runInfo.tool,
            params: runInfo.params,
            startedAt: runInfo.startedAt,
            completedAt: runInfo.completedAt,
            status: runInfo.status
          }, null, 2)
        };
      } catch (error: any) {
        return {
          success: false,
          error: error.message
        };
      }
    }
Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/portel-dev/ncp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server