Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Packs/ServiceNowMCP/.pack-ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

1 change: 1 addition & 0 deletions Packs/ServiceNowMCP/.secrets-ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://myinstance.service-now.com
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .secrets-ignore file should contain domain names, not full URLs. Please remove the https:// prefix.

Suggested change
https://myinstance.service-now.com
myinstance.service-now.com

90 changes: 90 additions & 0 deletions Packs/ServiceNowMCP/Integrations/ServiceNowMCP/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
Use this integration to connect securely with a ServiceNow Model Context Protocol (MCP) server and access its tools in real time.
This integration was integrated and tested with version xx of ServiceNow MCP.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please replace the placeholder version xx with the actual supported version of ServiceNow MCP, or use the latest version if a specific version is not applicable.


## Configure ServiceNow MCP in Cortex

| **Parameter** | **Description** | **Required** |
| --- | --- | --- |
| Server URL | The full MCP server URL for your ServiceNow instance. For example, https://<instance>.service-now.com/sncapps/mcp-server/mcp/<server-name>. | True |
| Client ID | The Client ID and Client Secret from the OAuth inbound integration configured on your ServiceNow instance. | True |
| Client Secret | | True |
| Authorization code | The authorization code obtained by running the \!servicenow-mcp-generate-login-url command. | |
| Redirect URI | The redirect URI configured in your ServiceNow OAuth inbound integration. Must match the Redirect URL set in ServiceNow. | |
| Trust any certificate (not secure) | | |

## Commands

You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

### list-tools

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

#### Base Command

`list-tools`

#### Input

| **Argument Name** | **Description** | **Required** |
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The input table is empty. It should be replaced with the standard text indicating no input arguments. Additionally, this command (and others in this file) is missing the standard #### Command example and #### Human Readable Output sections.

Please apply the suggestion below to fix the empty table (and remove the table separator on line 32), and then run the demisto-sdk generate-docs command to automatically generate the missing sections with proper formatting, examples, and context output.

Suggested change
| **Argument Name** | **Description** | **Required** |
There are no input arguments for this command.

To regenerate the documentation, run:

demisto-sdk generate-docs --insecure -e Packs/ServiceNowMCP/Integrations/ServiceNowMCP/command_examples.txt -i Packs/ServiceNowMCP/Integrations/ServiceNowMCP/ServiceNowMCP.yml

For more details, refer to the Command Examples - Integration Documentation guidelines.

| --- | --- | --- |

#### Context Output

There is no context output for this command.

### call-tool

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

#### Base Command

`call-tool`

#### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| name | The name of the tool to call. | Required |
| arguments | Parameters for the tool execution. | Optional |

#### Context Output

There is no context output for this command.

### servicenow-mcp-auth-test

***
Test the authentication configuration with the MCP server.

#### Base Command

`servicenow-mcp-auth-test`

#### Input

There are no input arguments for this command.

#### Context Output

There is no context output for this command.

### servicenow-mcp-generate-login-url

***
Generate an authentication login URL.

#### Base Command

`servicenow-mcp-generate-login-url`

#### Input

There are no input arguments for this command.

#### Context Output

There is no context output for this command.
104 changes: 104 additions & 0 deletions Packs/ServiceNowMCP/Integrations/ServiceNowMCP/ServiceNowMCP.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import demistomock as demisto
from CommonServerPython import *
from MCPApiModule import *

import asyncio


from urllib.parse import unquote, urlparse


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


def derive_oauth_endpoints(base_url: str) -> tuple[str, str]:
"""Derives the OAuth authorization and token endpoints from the ServiceNow MCP server URL.

ServiceNow OAuth endpoints follow the pattern:
- Authorization: https://<instance>.service-now.com/oauth_auth.do
- Token: https://<instance>.service-now.com/oauth_token.do
"""
parsed = urlparse(base_url)
origin = f"{parsed.scheme}://{parsed.netloc}"
return f"{origin}/oauth_auth.do", f"{origin}/oauth_token.do"


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

client = None
try:
base_url = params.get("base_url", "")
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))

authorization_endpoint, token_endpoint = derive_oauth_endpoints(base_url)

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 BaseException as eg:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use Exception instead of BaseException.

root_msg = extract_root_error_message(eg)
return_error(f"Failed to execute {command} command.\nError:\n{root_msg}")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add traceback logging for comprehensive error tracking.


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())
71 changes: 71 additions & 0 deletions Packs/ServiceNowMCP/Integrations/ServiceNowMCP/ServiceNowMCP.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
category: IT Services
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: The first key defined at the root level of the .yml file must always be name or display.

Please move name and display from lines 41-42 to the top of the file.

provider: ServiceNow
sectionorder:
- Connect
commonfields:
id: ServiceNow MCP
version: -1
configuration:
- name: base_url
section: Connect
display: Server URL
type: 0
required: true
additionalinfo: The full MCP server URL for your ServiceNow instance. For example, https://<instance>.service-now.com/sncapps/mcp-server/mcp/<server-name>.
- name: oauth_credentials
type: 9
display: Client ID
displaypassword: Client Secret
section: Connect
required: true
additionalinfo: The Client ID and Client Secret from the OAuth inbound integration configured on your ServiceNow instance.
- name: auth_code
type: 9
displaypassword: Authorization code
hiddenusername: true
section: Connect
additionalinfo: The authorization code obtained by running the !servicenow-mcp-generate-login-url command.
- name: redirect_uri
section: Connect
defaultvalue: https://oproxy.demisto.ninja/authcode
display: Redirect URI
type: 0
advanced: true
additionalinfo: The redirect URI configured in your ServiceNow OAuth inbound integration. Must match the Redirect URL set in ServiceNow.
- name: insecure
section: Connect
display: Trust any certificate (not secure)
type: 8
advanced: true
description: Use this integration to connect securely with a ServiceNow Model Context Protocol (MCP) server and access its tools in real time.
display: ServiceNow MCP
name: ServiceNow MCP
script:
commands:
- arguments: []
description: Retrieves a list of available tools in the ServiceNow MCP server.
name: list-tools
hidden: true
outputs: []
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can context outputs be defined for this command?

- arguments:
- name: name
description: The name of the tool to call.
required: true
- name: arguments
description: Parameters for the tool execution.
description: Calls a specific tool on the ServiceNow MCP server with optional input parameters.
name: call-tool
hidden: true
outputs: []
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can context outputs be defined for this command?

- description: Test the authentication configuration with the MCP server.
name: servicenow-mcp-auth-test
- description: Generate an authentication login URL.
name: servicenow-mcp-generate-login-url
script: '-'
type: python
subtype: python3
dockerimage: demisto/mcp:1.0.0.6978288
mcp: true
fromversion: 8.13.0
tests:
- No tests (auto formatted)
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
## ServiceNow MCP Server URL
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the initial header and add a brief purpose/scope section.

According to the Integration Description File guidelines, the description should begin with ## <Integration Name> and explain why the integration exists and its main use cases.

Suggested change
## ServiceNow MCP Server URL
## ServiceNow MCP
This integration connects securely with a ServiceNow Model Context Protocol (MCP) server, allowing you to access its tools in real time.
### Server URL


The Server URL follows the format: `https://<instance>.service-now.com/sncapps/mcp-server/mcp/<server-name>`

To connect to the preconfigured Quickstart Server, use: `https://<instance>.service-now.com/sncapps/mcp-server/mcp/sn_mcp_server_default`

Replace `<instance>` with your ServiceNow instance name.

## OAuth Setup

Before configuring this integration, you must create an OAuth inbound integration on your ServiceNow instance:

1. In ServiceNow, navigate to **All > MCP Server Console**.
2. From the **Configuration** tab, select **Servers**.
3. Select **Set up OAuth** from the banner, or navigate to **All > Machine Identity Console** and select the **Inbound integrations** tab.
4. Select **New integration** > **OAuth - Authorization code grant**.
5. Fill in the required fields:
- **Name**: Enter a name for the OAuth integration.
- **Redirect URLs**: Enter the Redirect URI configured in this integration instance (default: `https://oproxy.demisto.ninja/authcode`).
6. Under **Advanced options**, set **Token Format** to **JWT**.
7. Select **Save**.
8. Copy the generated **Client ID** and **Client Secret**.

## Authorization Code

To obtain the Authorization code, follow these steps:

1. Enter the **Server URL**, **Client ID**, and **Client Secret** in this integration instance and save.
2. Run the integration command `!servicenow-mcp-generate-login-url` from the Playground and follow its instructions.
3. Copy the generated Authorization code into the integration instance and save the integration instance.
4. Run the integration command `!servicenow-mcp-auth-test` from the Playground to verify that everything is configured correctly.
Loading
Loading