Skip to main content
Glama

execute_background_script

Execute server-side JavaScript in ServiceNow using Background Scripts to run custom code, automate processes, and interact with instance data within specified application scopes.

Instructions

Execute server-side JavaScript in ServiceNow using Background Scripts. ⚠️ SANDBOX ONLY - executes arbitrary code. πŸ›‘οΈ Auto-truncates large outputs. πŸ“ Use {{file:path}} for large scripts.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
scriptYesThe server-side JavaScript code to execute (e.g., gs.print("Hello");). Maximum 50,000 characters. Supports {{file:...}} placeholders to load content from local files.
scopeYesThe application scope (e.g., "global" or specific app scope). Required.
timeout_msNoOptional timeout in milliseconds (default: 60000, range: 1000-300000)
include_htmlNoInclude HTML output in response (default: true). Set to false for text-only mode to reduce response size.
response_modeNoResponse verbosity: full (all data), minimal (essential only), compact (summarized). Default: full

Implementation Reference

  • MCP CallToolRequest handler specifically for 'execute_background_script': initializes client check, extracts and validates parameters (script, scope, etc.), resolves file placeholders, executes via client.executeScript, applies overflow prevention, formats JSON response, handles all errors.
    if (request.params.name === 'execute_background_script') {
      try {
        // Check if client was initialized successfully
        if (!client) {
          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify({
                  success: false,
                  error: {
                    code: 'INITIALIZATION_ERROR',
                    message: 'ServiceNow client failed to initialize',
                    details:
                      initError instanceof Error ? initError.message : 'Unknown error',
                  },
                } as ServiceNowErrorResponse),
              },
            ],
            isError: true,
          };
        }
    
        // Extract parameters from tool arguments
        const args = request.params.arguments as Record<string, unknown> | undefined;
        const script = args?.script as string | undefined;
        const scope = args?.scope as string | undefined;
        const timeoutMs = args?.timeout_ms as number | undefined;
        const includeHtml = args?.include_html as boolean | undefined;
        const responseMode = args?.response_mode as string | undefined;
    
        // Validate required parameters
        if (!script) {
          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify({
                  success: false,
                  error: {
                    code: ERROR_CODES.MISSING_PARAMETER,
                    message: 'Required parameter "script" is missing',
                    details: 'Please provide the JavaScript code to execute',
                  },
                } as ServiceNowErrorResponse),
              },
            ],
            isError: true,
          };
        }
    
        if (!scope) {
          return {
            content: [
              {
                type: 'text',
                text: JSON.stringify({
                  success: false,
                  error: {
                    code: ERROR_CODES.MISSING_PARAMETER,
                    message: 'Required parameter "scope" is missing',
                    details: 'Please provide the application scope (e.g., "global")',
                  },
                } as ServiceNowErrorResponse),
              },
            ],
            isError: true,
          };
        }
    
        // Resolve file placeholders in the request
        let resolvedScript = script;
        let resolvedScope = scope;
        
        try {
          const scriptResolution = resolveFilePlaceholders(script);
          resolvedScript = scriptResolution.data;
          
          if (scope) {
            const scopeResolution = resolveFilePlaceholders(scope);
            resolvedScope = scopeResolution.data;
          }
        } catch (error) {
          if (error instanceof FilePlaceholderError) {
            return {
              content: [
                {
                  type: 'text',
                  text: JSON.stringify({
                    success: false,
                    error: {
                      code: 'FILE_PLACEHOLDER_ERROR',
                      message: 'Failed to resolve file placeholder',
                      details: `${error.placeholder}: ${error.message}`,
                    },
                  } as ServiceNowErrorResponse),
                },
              ],
              isError: true,
            };
          }
          
          // Re-throw unknown errors
          throw error;
        }
    
        // Execute the script
        const result = await client.executeScript({
          script: resolvedScript,
          scope: resolvedScope,
          timeoutMs,
          include_html: includeHtml,
          response_mode: responseMode as any,
        });
    
        // Apply global context overflow prevention
        const { response: protectedResult, monitoring } = globalContextOverflowPrevention.monitorResponse(result, 'execute_background_script', responseMode);
    
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify(protectedResult, null, 2),
            },
          ],
        };
    
      } catch (error) {
        const errorResponse: ServiceNowErrorResponse = {
          success: false,
          error: {
            code: 'UNKNOWN_ERROR',
            message: 'An unexpected error occurred',
          },
        };
    
        if (error instanceof ServiceNowScriptError) {
          errorResponse.error.code = error.code;
          errorResponse.error.message = error.message;
          errorResponse.error.details = `HTTP Status: ${error.statusCode || 'N/A'}`;
        } else if (error instanceof Error) {
          errorResponse.error.message = error.message;
          errorResponse.error.details = 'Check ServiceNow instance connectivity and credentials';
        }
    
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify(errorResponse),
            },
          ],
          isError: true,
        };
      }
    }
  • Tool schema definition in ListToolsRequest handler: specifies name, detailed description, and inputSchema with properties, types, descriptions, and required fields for the execute_background_script tool.
      name: 'execute_background_script',
      description:
        'Execute server-side JavaScript in ServiceNow using Background Scripts. ⚠️ SANDBOX ONLY - executes arbitrary code. πŸ›‘οΈ Auto-truncates large outputs. πŸ“ Use {{file:path}} for large scripts.',
      inputSchema: {
        type: 'object',
        properties: {
          script: {
            type: 'string',
            description:
              'The server-side JavaScript code to execute (e.g., gs.print("Hello");). Maximum 50,000 characters. Supports {{file:...}} placeholders to load content from local files.',
          },
          scope: {
            type: 'string',
            description:
              'The application scope (e.g., "global" or specific app scope). Required.',
          },
          timeout_ms: {
            type: 'number',
            description:
              'Optional timeout in milliseconds (default: 60000, range: 1000-300000)',
          },
          include_html: {
            type: 'boolean',
            description:
              'Include HTML output in response (default: true). Set to false for text-only mode to reduce response size.',
          },
          response_mode: {
            type: 'string',
            enum: ['full', 'minimal', 'compact'],
            description:
              'Response verbosity: full (all data), minimal (essential only), compact (summarized). Default: full',
          },
        },
        required: ['script', 'scope'],
      },
    },
  • src/index.ts:583-790 (registration)
    Registration of all MCP tools via setRequestHandler(ListToolsRequestSchema), listing 'execute_background_script' with its schema and description.
    server.setRequestHandler(ListToolsRequestSchema, async () => {
      return {
        tools: [
          {
            name: 'execute_background_script',
            description:
              'Execute server-side JavaScript in ServiceNow using Background Scripts. ⚠️ SANDBOX ONLY - executes arbitrary code. πŸ›‘οΈ Auto-truncates large outputs. πŸ“ Use {{file:path}} for large scripts.',
            inputSchema: {
              type: 'object',
              properties: {
                script: {
                  type: 'string',
                  description:
                    'The server-side JavaScript code to execute (e.g., gs.print("Hello");). Maximum 50,000 characters. Supports {{file:...}} placeholders to load content from local files.',
                },
                scope: {
                  type: 'string',
                  description:
                    'The application scope (e.g., "global" or specific app scope). Required.',
                },
                timeout_ms: {
                  type: 'number',
                  description:
                    'Optional timeout in milliseconds (default: 60000, range: 1000-300000)',
                },
                include_html: {
                  type: 'boolean',
                  description:
                    'Include HTML output in response (default: true). Set to false for text-only mode to reduce response size.',
                },
                response_mode: {
                  type: 'string',
                  enum: ['full', 'minimal', 'compact'],
                  description:
                    'Response verbosity: full (all data), minimal (essential only), compact (summarized). Default: full',
                },
              },
              required: ['script', 'scope'],
            },
          },
          {
            name: 'execute_table_operation',
            description:
              'CRUD operations on ServiceNow tables via Table API. Supports GET/POST/PUT/PATCH/DELETE with query syntax and batch operations. ⚠️ SANDBOX ONLY - reads/modifies data. πŸ›‘οΈ Auto-limits large results. Use pagination for big datasets. πŸ“ Use {{file:path}} for large data.',
            inputSchema: {
              type: 'object',
              properties: {
                operation: {
                  type: 'string',
                  enum: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
                  description: 'The operation to perform on the table. Required.',
                },
                table: {
                  type: 'string',
                  description: 'The ServiceNow table name (e.g., "incident", "sys_user"). Required.',
                },
                sys_id: {
                  type: 'string',
                  description: 'System ID for single record operations (GET, PUT, PATCH, DELETE).',
                },
                sys_ids: {
                  type: 'array',
                  items: { type: 'string' },
                  description: 'Array of system IDs for batch operations.',
                },
                query: {
                  type: 'string',
                  description: 'ServiceNow encoded query string (e.g., "active=true^priority=1").',
                },
                fields: {
                  type: 'string',
                  description: 'Comma-separated list of fields to return.',
                },
                limit: {
                  type: 'number',
                  description: 'Maximum number of records to return (default: 1000).',
                },
                offset: {
                  type: 'number',
                  description: 'Number of records to skip for pagination.',
                },
                display_value: {
                  type: 'string',
                  enum: ['true', 'false', 'all'],
                  description: 'Return display values for reference fields.',
                },
                exclude_reference_link: {
                  type: 'boolean',
                  description: 'Exclude reference link fields from response.',
                },
                data: {
                  type: 'object',
                  description: 'Record data for POST/PUT/PATCH operations. Can be single object or array for batch operations. Supports {{file:...}} placeholders to load content from local files.',
                },
                batch: {
                  type: 'boolean',
                  description: 'Enable batch mode for multiple record operations.',
                },
                validate_fields: {
                  type: 'boolean',
                  description: 'Enable field validation warnings to catch typos and invalid field names. Default: true (validation enabled by default).',
                },
                context_overflow_prevention: {
                  type: 'boolean',
                  description: 'Enable context overflow prevention to limit large result sets. Default: true. Set to false to disable automatic truncation (use with caution).',
                },
                strict_fields: {
                  type: 'boolean',
                  description: 'Strict field filtering - only return requested fields and strip large fields (script, html, css) unless explicitly requested. Default: false.',
                },
                response_mode: {
                  type: 'string',
                  enum: ['full', 'minimal', 'compact'],
                  description: 'Response verbosity: full (all data), minimal (essential only), compact (summarized). Default: full',
                },
              },
              required: ['operation', 'table'],
            },
          },
          {
            name: 'execute_updateset_operation',
            description:
              'Manage ServiceNow update sets with lifecycle operations, XML reassignment, and working set tracking. ⚠️ SANDBOX ONLY - modifies update sets. πŸ›‘οΈ Auto-limits large results. Use pagination for big datasets. πŸ“ Use {{file:path}} for large data.',
            inputSchema: {
              type: 'object',
              properties: {
                operation: {
                  type: 'string',
                  enum: ['create', 'set_working', 'show_working', 'clear_working', 'insert', 'update', 'rehome', 'contents', 'recent', 'list', 'info', 'complete', 'reopen', 'delete', 'diff_default'],
                  description: 'The update set operation to perform. Required.',
                },
                name: {
                  type: 'string',
                  description: 'Update set name (required for create operation).',
                },
                description: {
                  type: 'string',
                  description: 'Update set description (optional for create operation).',
                },
                scope: {
                  type: 'string',
                  description: 'Update set scope (optional, defaults to configured scope).',
                },
                set_as_working: {
                  type: 'boolean',
                  description: 'Set the created update set as working set (for create operation).',
                },
                update_set_sys_id: {
                  type: 'string',
                  description: 'Update set sys_id for operations that require it.',
                },
                table: {
                  type: 'string',
                  description: 'Table name for insert/update operations.',
                },
                sys_id: {
                  type: 'string',
                  description: 'Record sys_id for update operations.',
                },
                data: {
                  type: 'object',
                  description: 'Record data for insert/update operations. Can be single object or array for batch operations. Supports {{file:...}} placeholders to load content from local files.',
                },
                batch: {
                  type: 'boolean',
                  description: 'Enable batch mode for multiple record operations.',
                },
                xml_sys_ids: {
                  type: 'array',
                  items: { type: 'string' },
                  description: 'Array of XML sys_ids for rehome operations.',
                },
                query: {
                  type: 'string',
                  description: 'ServiceNow encoded query string for rehome operations.',
                },
                force: {
                  type: 'boolean',
                  description: 'Force reassignment even if XML is not in Default update set.',
                },
                limit: {
                  type: 'number',
                  description: 'Maximum number of records to return for list/recent operations.',
                },
                offset: {
                  type: 'number',
                  description: 'Number of records to skip for pagination.',
                },
                filters: {
                  type: 'object',
                  description: 'Filters for list operations (scope, state, created_by, sys_created_on).',
                },
                response_mode: {
                  type: 'string',
                  enum: ['full', 'minimal', 'compact'],
                  description: 'Response verbosity: full (all data), minimal (essential only), compact (summarized). Default: full',
                },
                quiet: {
                  type: 'boolean',
                  description: 'Compact acknowledgment for update operations to avoid RESPONSE_TOO_LARGE errors. Default: false.',
                },
              },
              required: ['operation'],
            },
          },
        ],
      };
    });
  • Core helper method ServiceNowBackgroundScriptClient.executeScript(): performs full flow of authenticating UI session, fetching/parsing background script form, posting script execution with retry on session timeout, parsing HTML/text output, returning structured ScriptExecutionResult.
    async executeScript(request: ScriptExecutionRequest): Promise<ScriptExecutionResult> {
      const startTime = Date.now();
    
      try {
    
        // Validate input
        this.validateScriptRequest(request);
    
        // Step 1: Establish UI session via form login
        await this.establishUISession();
    
        // Step 2: GET the background script page and parse form data
        const pageResponse = await this.getBackgroundScriptPage();
        const { actionUrl, formData } = this.parseFormData(pageResponse.html, request.script, request.scope);
    
        // Step 3: POST the script execution request with retry logic
        let executionResponse = await this.postScriptExecution({
          actionUrl,
          formData,
          timeoutMs: request.timeoutMs || this.clientConfig.timeoutMs,
        });
    
        // Log telemetry (expert specification)
        const cookieNames = this.getCookieHeader(actionUrl).split(';').map(c => c.split('=')[0]).filter(c => c).join(',');
    
        // Check for session timeout and retry if needed
        let retry = false;
        if (this.hasSessionTimeout(executionResponse.body)) {
          retry = true;
          
          // Get fresh page and parse form data
          const freshPageResponse = await this.getBackgroundScriptPage();
          const { actionUrl: freshActionUrl, formData: freshFormData } = this.parseFormData(freshPageResponse.html, request.script, request.scope);
          
          // Retry POST with fresh form data
          executionResponse = await this.postScriptExecution({
            actionUrl: freshActionUrl,
            formData: freshFormData,
            timeoutMs: request.timeoutMs || this.clientConfig.timeoutMs,
          });
          
        }
    
        // Step 3: Parse the response
        const parsedOutput = parseScriptOutput(executionResponse.body);
        const executionTime = Date.now() - startTime;
        
        // Log pre blocks telemetry
        const preBlocks = (executionResponse.body.match(/<pre[^>]*>/gi) || []).length;
    
        // Handle response_mode shortcuts and include_html parameter for text-only mode
        const shouldIncludeHtml = request.include_html !== false && request.response_mode !== 'minimal';
        
        if (!shouldIncludeHtml) {
          return {
            success: true,
            output: {
              text: parsedOutput.text,
            },
            metadata: {
              executionTime,
              htmlSize: 0,
              timestamp: new Date().toISOString(),
              scope: request.scope,
            },
          };
        }
    
        return {
          success: true,
          output: {
            html: parsedOutput.html,
            text: parsedOutput.text,
          },
          metadata: {
            executionTime,
            htmlSize: parsedOutput.html.length,
            timestamp: new Date().toISOString(),
            scope: request.scope,
          },
        };
    
      } catch (error) {
        if (error instanceof ServiceNowScriptError) {
          throw error;
        }
        
        throw new ServiceNowScriptError(
          ERROR_CODES.SCRIPT_EXECUTION_ERROR,
          undefined,
          `Script execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`
        );
      }
    }

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/ClearSkye/SkyeNet-MCP-ACE'

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