ServiceNow MCP

Use this integration to connect securely with a ServiceNow Model Context Protocol (MCP) server and access its tools in real time.

Case Management · ServiceNow MCP MCP

Details

IDServiceNow MCP
ProviderServiceNow
CategoryCase Management
From Version8.13.0
Docker Imagedemisto/mcp:1.0.0.10120494
Supported ModulesAttack Surface Management Exposure Management Agentix Cortex Cloud Cloud Runtime Security Cloud Posture Security XSIAM EDR

Connection settings

Parameter Name Type Required Default
ServiceNow Instance URL instance_url Short text Yes
MCP Server Name server_name Short text Yes sn_mcp_server_default
Client ID oauth_credentials Credentials Yes
Authorization code auth_code Credentials No
Redirect URI redirect_uri Short text No https://oproxy.demisto.ninja/authcode
Trust any certificate (not secure) insecure Boolean No

Commands (4)

An MCP server publishes no fixed command set: list-tools and call-tool are the protocol plumbing, and the tools they reach are discovered from the remote server when the instance connects. The pack cannot name them ahead of time, so neither can this page.

  • call-tool

    Calls a specific tool on the MCP server with optional input parameters.

  • list-tools

    Retrieves a list of available tools in the ServiceNow MCP server.

  • servicenow-mcp-auth-test

    Test the authentication configuration with the MCP server.

  • servicenow-mcp-generate-login-url

    Generate an authentication login URL.

import demistomock as demisto
from CommonServerPython import *
from MCPApiModule import *

import asyncio

from urllib.parse import unquote


SERVICENOW_AUTH_TYPE = AuthMethods.AUTHORIZATION_CODE.value
SERVICENOW_SCOPE = "mcp_server"
COMMAND_PREFIX = "servicenow-mcp"
SERVER_NAME = "ServiceNow MCP"
DEFAULT_MCP_SERVER_NAME = "sn_mcp_server_default"


def build_servicenow_urls(instance_url: str, server_name: str) -> tuple[str, str, str]:
    """Builds the ServiceNow MCP server URL and OAuth authorization/token endpoints from the instance URL.

    Args:
        instance_url: The full ServiceNow instance URL (e.g., 'https://dev12345.service-now.com').
        server_name: The name of the MCP server on the instance.

    Returns:
        A tuple of (base_url, authorization_endpoint, token_endpoint).
    """
    instance_url = instance_url.strip().rstrip("/")
    server_name = (server_name or DEFAULT_MCP_SERVER_NAME).strip()

    base_url = f"{instance_url}/sncapps/mcp-server/mcp/{server_name}"
    authorization_endpoint = f"{instance_url}/oauth_auth.do"
    token_endpoint = f"{instance_url}/oauth_token.do"
    return base_url, authorization_endpoint, token_endpoint


def validate_required_params(instance_url: str, client_id: str, client_secret: str) -> None:
    """Validates that required parameters are present.

    Args:
        instance_url: The full ServiceNow instance URL.
        client_id: The OAuth Client ID.
        client_secret: The OAuth Client Secret.
    """
    if not instance_url:
        raise ValueError("ServiceNow Instance URL must be provided (e.g., 'https://dev12345.service-now.com').")
    if not all((client_id, client_secret)):
        raise ValueError("Client ID and Client Secret are required for OAuth authentication.")


async def main() -> None:  # pragma: no cover
    params = demisto.params()
    args = demisto.args()
    command = demisto.command()

    client = None
    try:
        instance_url = params.get("instance_url", "")
        server_name = params.get("server_name", "")
        client_id = params.get("oauth_credentials", {}).get("identifier")
        client_secret = params.get("oauth_credentials", {}).get("password")
        auth_code = unquote(params.get("auth_code", {}).get("password") or "")
        redirect_uri = params.get("redirect_uri", "") or REDIRECT_URI
        verify: bool = not argToBoolean(params.get("insecure", False))

        validate_required_params(instance_url, client_id, client_secret)

        base_url, authorization_endpoint, token_endpoint = build_servicenow_urls(instance_url, server_name)

        client = Client(
            base_url=base_url,
            auth_type=SERVICENOW_AUTH_TYPE,
            command_prefix=COMMAND_PREFIX,
            client_id=client_id,
            client_secret=client_secret,
            auth_code=auth_code,
            token_endpoint=token_endpoint,
            scope=SERVICENOW_SCOPE,
            redirect_uri=redirect_uri,
            verify=verify,
        )
        demisto.debug(f"Command being called is {command}")

        if command == "test-module":
            raise DemistoException(
                "\nTest module is unavailable for this integration. "
                f"Please use the **!{COMMAND_PREFIX}-auth-test** command to test "
                "connectivity after setting the Authorization Code.",
            )

        elif command == "list-tools":
            result = await client.list_tools(SERVER_NAME)
            return_results(result)

        elif command == "call-tool":
            result = await client.call_tool(args["name"], args.get("arguments", ""))
            return_results(result)

        elif command == f"{COMMAND_PREFIX}-auth-test":
            result = await client.test_connection(auth_test=True)
            return_results(result)

        elif command == f"{COMMAND_PREFIX}-generate-login-url":
            result = await generate_login_url(
                client._oauth_handler,
                auth_type=SERVICENOW_AUTH_TYPE,
                authorization_endpoint=authorization_endpoint,
                redirect_uri=redirect_uri,
                troubleshooting_redirect=True,
            )
            return_results(result)

        else:
            raise NotImplementedError(f"Command {command} is not implemented")

    except Exception as eg:
        root_msg = extract_root_error_message(eg)
        return_error(f"Failed to execute {command} command.\nError:\n{root_msg}")

    finally:
        if client:
            demisto.debug(f"Closing client connection for {command}")
            await client.close()


""" ENTRY POINT """

if __name__ in ("__main__", "__builtin__", "builtins"):
    asyncio.run(main())