Skip to content
Open
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
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.
3 changes: 3 additions & 0 deletions Packs/PanoraysMCP/CONTRIBUTORS.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[
"David Limkys"
]
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.value and not token:
raise ValueError("API Token is required for Bearer authentication.")
if auth_type == AuthMethods.AUTHORIZATION_CODE.value and 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:
auth_type = params.get("auth_type") or AuthMethods.BEARER.value
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.value:
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: Connects securely with the Panorays Axis Model Context Protocol (MCP) server and accesses its tools in real time.
category: Data Enrichment & Threat Intelligence
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: 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: 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: 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: Tests the authentication configuration with the MCP server.
name: panorays-mcp-auth-test
- 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

**Before you start:** Panorays Axis MCP is a commercial product. Contact your Panorays Admin to enable it for your Panorays account; until it is enabled, tool discovery and the integration's tools do not work.

Select one of the following authentication types.

### Bearer

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

#### Prerequisites

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

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

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