Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Empty file added Packs/PanoraysMCP/.pack-ignore
Empty file.
5 changes: 5 additions & 0 deletions Packs/PanoraysMCP/.secrets-ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
https://mcp.panoraysapp.com/mcp
https://auth.panoraysapp.com/op/auth
https://auth.panoraysapp.com/op/token
https://panorays.com
oproxy.demisto.ninja/authcode
Binary file added Packs/PanoraysMCP/Author_image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
114 changes: 114 additions & 0 deletions Packs/PanoraysMCP/Integrations/PanoraysMCP/PanoraysMCP.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import demistomock as demisto
from CommonServerPython import *
from MCPApiModule import *

import asyncio

from urllib.parse import unquote


PANORAYS_MCP_URL = "https://mcp.panoraysapp.com/mcp"
PANORAYS_AUTHORIZATION_ENDPOINT = "https://auth.panoraysapp.com/op/auth"
PANORAYS_TOKEN_ENDPOINT = "https://auth.panoraysapp.com/op/token"
PANORAYS_SCOPE = "openid offline_access features permissions"
SUPPORTED_AUTH_TYPES = (AuthMethods.BEARER.value, AuthMethods.AUTHORIZATION_CODE.value)
COMMAND_PREFIX = "panorays-mcp"
SERVER_NAME = "Panorays Axis MCP"


def validate_required_params(auth_type: str, token: str, client_id: str, client_secret: str) -> None:
"""Validates that the parameters required by the selected authentication type are present.
Args:
auth_type: The selected authentication type.
token: The Panorays API token, used for Bearer authentication.
client_id: The OAuth Client ID, used for OAuth authentication.
client_secret: The OAuth Client Secret, used for OAuth authentication.
"""
if auth_type not in SUPPORTED_AUTH_TYPES:
raise ValueError(f"Unsupported authentication type: {auth_type}. Supported types: {', '.join(SUPPORTED_AUTH_TYPES)}.")
if auth_type == AuthMethods.BEARER and not token:

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 .value for Enum comparison to ensure consistency and prevent potential bugs.

raise ValueError("API Token is required for Bearer authentication.")
if auth_type == AuthMethods.AUTHORIZATION_CODE and not all((client_id, client_secret)):

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 .value for Enum comparison.

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:
auth_type = params.get("auth_type", "")

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.

Ensure the Python default value matches the YAML configuration.

token = params.get("token", {}).get("password", "")
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

validate_required_params(auth_type, token, client_id, client_secret)

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

if command == "test-module":
if auth_type == AuthMethods.AUTHORIZATION_CODE:

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 .value for Enum comparison.

raise DemistoException(
f"\nTest module is unavailable for this authentication type: {auth_type}.\n"
f"Please use the **!{COMMAND_PREFIX}-auth-test** command to test "
"connectivity after setting the Authorization Code.",
)
result = await client.test_connection()
return_results(result)

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=auth_type,
authorization_endpoint=PANORAYS_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.

  • Update exception handling to catch Exception and log the traceback.
  • Catch Exception instead of BaseException.

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())
75 changes: 75 additions & 0 deletions Packs/PanoraysMCP/Integrations/PanoraysMCP/PanoraysMCP.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Panorays Axis MCP
display: Panorays Axis MCP
description: Use this integration to connect securely with the Panorays Axis Model Context Protocol (MCP) server and access its tools in real time.

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 content-item-level description must use the active voice and describe what the item does (e.g., "Connects...").

Suggested change
description: Use this integration to connect securely with the Panorays Axis Model Context Protocol (MCP) server and access its tools in real time.
description: Connects securely with the Panorays Axis Model Context Protocol (MCP) server and accesses its tools in real time.

category: Vulnerability Management
provider: Panorays
sectionorder:
- Connect
commonfields:
id: Panorays Axis MCP
version: -1
configuration:
- name: auth_type
section: Connect
display: Authentication Type
type: 15
required: true
defaultvalue: Bearer
options:
- Bearer
- OAuth 2.0 Authorization Code
additionalinfo: Select the authentication method.

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.

Descriptions for parameters, arguments, context paths (outputs), and additionalinfo must start with "The " and use a descriptive form, not an active form.

Suggested change
additionalinfo: Select the authentication method.
additionalinfo: The authentication method.

- name: token
type: 9
displaypassword: API Token
hiddenusername: true
section: Connect
additionalinfo: The Panorays API token. Required for Bearer authentication.
- name: oauth_credentials
type: 9
display: Client ID
displaypassword: Client Secret
section: Connect
additionalinfo: The Client ID and Client Secret provided by Panorays support. Required for OAuth authentication.
- name: auth_code
type: 9
displaypassword: Authorization code
hiddenusername: true
section: Connect
additionalinfo: Authorization code returned after running the `!panorays-mcp-generate-login-url` command and authenticating. Required for OAuth authentication.

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.

Descriptions for parameters, arguments, context paths (outputs), and additionalinfo must start with "The ".

Suggested change
additionalinfo: Authorization code returned after running the `!panorays-mcp-generate-login-url` command and authenticating. Required for OAuth authentication.
additionalinfo: The authorization code returned after running the `!panorays-mcp-generate-login-url` command and authenticating. Required for OAuth authentication.

- name: redirect_uri
section: Connect
display: Redirect URI
type: 0
advanced: true
defaultvalue: https://oproxy.demisto.ninja/authcode
additionalinfo: The redirect URI registered on the Panorays OAuth client. Must match the URI configured by Panorays support.
script:
commands:
- arguments: []
description: Retrieves a list of available tools in the Panorays Axis MCP server.
name: list-tools
hidden: true
outputs: []
- arguments:
- name: name
description: The name of the tool to call.
required: true
- name: arguments
description: Parameters for the tool execution.

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.

Descriptions for parameters, arguments, context paths (outputs), and additionalinfo must start with "The ".

Suggested change
description: Parameters for the tool execution.
description: The parameters for the tool execution.

description: Calls a specific tool on the Panorays Axis MCP server with optional input parameters.
name: call-tool
hidden: true
outputs: []
- description: Test the authentication configuration with the MCP server.

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.

Command descriptions must use the active voice and describe what the command does (e.g., "Tests...").

Suggested change
- description: Test the authentication configuration with the MCP server.
- description: Tests the authentication configuration with the MCP server.

name: panorays-mcp-auth-test
- description: Generate an authentication login URL. Only available for OAuth authentication.

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.

Command descriptions must use the active voice and describe what the command does (e.g., "Generates...").

Suggested change
- description: Generate an authentication login URL. Only available for OAuth authentication.
- description: Generates an authentication login URL. Only available for OAuth authentication.

name: panorays-mcp-generate-login-url
script: '-'
type: python
subtype: python3
dockerimage: demisto/mcp:1.0.0.13526390
mcp: true
fromversion: 8.13.0
tests:
- No tests (auto formatted)
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
## Panorays Axis MCP

This integration connects securely with the Panorays Axis Model Context Protocol (MCP) server, allowing you to access its tools in real time.

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.

Move product overview to README


Select one of the following authentication types.

## Bearer

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 correct header hierarchy


1. Log in to your Panorays platform.
2. Navigate to **Settings → Integrations → Public API**.
3. Click **Generate API Key** and assign it a role.
4. Copy the token into the **API Token** parameter.
5. Save the integration instance and click **Test**.

## OAuth 2.0 Authorization Code

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 correct header hierarchy


### Prerequisites

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 correct header hierarchy


Contact Panorays support at **support@panorays.com** to create an OAuth client for Cortex. Ask for a client with:

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 correct Cortex branding


- The **Authorization Code** and **Refresh Token** grant types.
- The redirect URI `https://oproxy.demisto.ninja/authcode` (or your custom redirect URI).
- PKCE disabled.

Panorays support will provide a **Client ID** and **Client Secret**.

### Configuration

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 correct header hierarchy


1. Enter the **Client ID** and **Client Secret** provided by Panorays support.
2. Save the integration instance.
3. Run the command `!panorays-mcp-generate-login-url` from the Playground and follow the instructions to authenticate.

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.

Avoid command invocations in description

4. Copy the generated **Authorization code** into the integration instance and save.
5. Run the command `!panorays-mcp-auth-test` from the Playground to verify connectivity.

## Support

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 correct header hierarchy


For assistance, contact Panorays support at **support@panorays.com**.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading