GitHub MCP

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

Utilities · GitHub MCP MCP

Details

IDGitHub MCP
ProviderMicrosoft
CategoryUtilities
From Version8.13.0
Docker Imagedemisto/mcp:1.0.0.10325753
Supported ModulesAgentix Cloud Runtime Security Cloud Posture Security XSIAM EDR Cortex Cloud

Enabled Toolsets (21 options)

If no toolsets are selected, GitHub's default toolsets 'context', 'repos', 'issues', 'pull_requests', and 'users' will be enabled.

context actions code_security dependabot discussions gists git issues labels notifications orgs projects pull_requests repos secret_protection security_advisories stargazers users copilot copilot_spaces github_support_docs_search

Connection settings

Parameter Name Type Required Default
Personal Access Token token Credentials Yes
Enabled Toolsets enabled_toolsets Multi select No
Enable Read-Only Tools readonly Boolean No

Commands (2)

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 GitHub MCP server with optional input parameters.

  • list-tools

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

import pytest
from pytest_mock import MockerFixture


from GitHubMCP import main

from unittest.mock import AsyncMock


class TestGitHubMCPMain:
    """Test class for GitHubMCP main function."""

    @pytest.mark.asyncio
    async def test_main_test_module_success(self, mocker: MockerFixture):
        """
        Given: A test-module command with valid parameters and successful client connection.
        When: The main function is called with test-module command.
        Then: The client test_connection method is called and results are returned successfully.
        """

        # Mock demisto functions
        mock_params = mocker.patch("GitHubMCP.demisto.params")
        mock_args = mocker.patch("GitHubMCP.demisto.args")
        mock_command = mocker.patch("GitHubMCP.demisto.command")
        mocker.patch("GitHubMCP.demisto.debug")
        mock_return_results = mocker.patch("GitHubMCP.return_results")
        mock_arg_to_list = mocker.patch("GitHubMCP.argToList")
        mock_arg_to_boolean = mocker.patch("GitHubMCP.argToBoolean")

        # Mock Client class
        mock_client_class = mocker.patch("GitHubMCP.Client")
        mock_client_instance = AsyncMock()
        mock_client_class.return_value = mock_client_instance
        mock_client_instance.test_connection.return_value = "Connection successful"

        # Set up test data
        mock_params.return_value = {
            "token": {"password": "test-token"},
            "enabled_toolsets": "toolset1,toolset2",
            "readonly": "true",
        }
        mock_args.return_value = {}
        mock_command.return_value = "test-module"
        mock_arg_to_list.return_value = ["toolset1", "toolset2"]
        mock_arg_to_boolean.return_value = True

        # Execute
        await main()

        # Verify
        mock_client_class.assert_called_once()
        mock_client_instance.test_connection.assert_called_once()
        mock_return_results.assert_called_once_with("Connection successful")

    @pytest.mark.asyncio
    async def test_main_list_tools_success(self, mocker: MockerFixture):
        """
        Given: A list-tools command with valid parameters.
        When: The main function is called with list-tools command.
        Then: The client list_tools method is called and tools are returned successfully.
        """

        # Mock demisto functions
        mock_params = mocker.patch("GitHubMCP.demisto.params")
        mock_args = mocker.patch("GitHubMCP.demisto.args")
        mock_command = mocker.patch("GitHubMCP.demisto.command")
        mocker.patch("GitHubMCP.demisto.debug")
        mock_return_results = mocker.patch("GitHubMCP.return_results")
        mock_arg_to_list = mocker.patch("GitHubMCP.argToList")
        mock_arg_to_boolean = mocker.patch("GitHubMCP.argToBoolean")

        # Mock Client class
        mock_client_class = mocker.patch("GitHubMCP.Client")
        mock_client_instance = AsyncMock()
        mock_client_class.return_value = mock_client_instance
        mock_client_instance.list_tools.return_value = {"tools": ["tool1", "tool2"]}

        # Set up test data
        mock_params.return_value = {"token": {"password": "test-token"}, "enabled_toolsets": "toolset1", "readonly": "false"}
        mock_args.return_value = {}
        mock_command.return_value = "list-tools"
        mock_arg_to_list.return_value = ["toolset1"]
        mock_arg_to_boolean.return_value = False

        # Execute
        await main()

        # Verify
        mock_client_instance.list_tools.assert_called_once()
        mock_return_results.assert_called_once_with({"tools": ["tool1", "tool2"]})

    @pytest.mark.asyncio
    async def test_main_call_tool_with_arguments(self, mocker: MockerFixture):
        """
        Given: A call-tool command with tool name and arguments provided.
        When: The main function is called with call-tool command.
        Then: The client call_tool method is called with the correct parameters and result is returned.
        """

        # Mock demisto functions
        mock_params = mocker.patch("GitHubMCP.demisto.params")
        mock_args = mocker.patch("GitHubMCP.demisto.args")
        mock_command = mocker.patch("GitHubMCP.demisto.command")
        mocker.patch("GitHubMCP.demisto.debug")
        mock_return_results = mocker.patch("GitHubMCP.return_results")
        mock_arg_to_list = mocker.patch("GitHubMCP.argToList")
        mock_arg_to_boolean = mocker.patch("GitHubMCP.argToBoolean")

        # Mock Client class
        mock_client_class = mocker.patch("GitHubMCP.Client")
        mock_client_instance = AsyncMock()
        mock_client_class.return_value = mock_client_instance
        mock_client_instance.call_tool.return_value = {"result": "tool executed"}

        # Set up test data
        mock_params.return_value = {"token": {"password": "test-token"}, "enabled_toolsets": "", "readonly": "false"}
        mock_args.return_value = {"name": "test-tool", "arguments": '{"param1": "value1"}'}
        mock_command.return_value = "call-tool"
        mock_arg_to_list.return_value = []
        mock_arg_to_boolean.return_value = False

        # Execute
        await main()

        # Verify
        mock_client_instance.call_tool.assert_called_once_with("test-tool", '{"param1": "value1"}')
        mock_return_results.assert_called_once_with({"result": "tool executed"})

    @pytest.mark.asyncio
    async def test_main_call_tool_without_arguments(self, mocker: MockerFixture):
        """
        Given: A call-tool command with tool name but no arguments provided.
        When: The main function is called with call-tool command.
        Then: The client call_tool method is called with empty arguments and result is returned.
        """

        # Mock demisto functions
        mock_params = mocker.patch("GitHubMCP.demisto.params")
        mock_args = mocker.patch("GitHubMCP.demisto.args")
        mock_command = mocker.patch("GitHubMCP.demisto.command")
        mocker.patch("GitHubMCP.demisto.debug")
        mocker.patch("GitHubMCP.return_results")
        mock_arg_to_list = mocker.patch("GitHubMCP.argToList")
        mock_arg_to_boolean = mocker.patch("GitHubMCP.argToBoolean")

        # Mock Client class
        mock_client_class = mocker.patch("GitHubMCP.Client")
        mock_client_instance = AsyncMock()
        mock_client_class.return_value = mock_client_instance
        mock_client_instance.call_tool.return_value = {"result": "tool executed"}

        # Set up test data
        mock_params.return_value = {"token": {"password": "test-token"}, "enabled_toolsets": "", "readonly": "false"}
        mock_args.return_value = {"name": "test-tool"}
        mock_command.return_value = "call-tool"
        mock_arg_to_list.return_value = []
        mock_arg_to_boolean.return_value = False

        # Execute
        await main()

        # Verify
        mock_client_instance.call_tool.assert_called_once_with("test-tool", "")

    @pytest.mark.asyncio
    async def test_main_unknown_command(self, mocker: MockerFixture):
        """
        Given: An unknown command that is not implemented.
        When: The main function is called with the unknown command.
        Then: A NotImplementedError is raised and return_error is called with appropriate message.
        """

        # Mock demisto functions
        mock_params = mocker.patch("GitHubMCP.demisto.params")
        mock_args = mocker.patch("GitHubMCP.demisto.args")
        mock_command = mocker.patch("GitHubMCP.demisto.command")
        mocker.patch("GitHubMCP.demisto.debug")
        mock_return_error = mocker.patch("GitHubMCP.return_error")
        mock_arg_to_list = mocker.patch("GitHubMCP.argToList")
        mock_arg_to_boolean = mocker.patch("GitHubMCP.argToBoolean")

        # Mock Client class
        mock_client_class = mocker.patch("GitHubMCP.Client")
        mock_client_instance = AsyncMock()
        mock_client_class.return_value = mock_client_instance

        # Mock extract_root_error_message
        mock_extract_error = mocker.patch("GitHubMCP.extract_root_error_message")
        mock_extract_error.return_value = "Command unknown-command is not implemented"

        # Set up test data
        mock_params.return_value = {"token": {"password": "test-token"}, "enabled_toolsets": "", "readonly": "false"}
        mock_args.return_value = {}
        mock_command.return_value = "unknown-command"
        mock_arg_to_list.return_value = []
        mock_arg_to_boolean.return_value = False

        # Execute
        await main()

        # Verify
        mock_return_error.assert_called_once_with(
            "Failed to execute unknown-command command.\nError:\nCommand unknown-command is not implemented"
        )

    @pytest.mark.asyncio
    async def test_main_client_exception(self, mocker: MockerFixture):
        """
        Given: A test-module command where the client raises an exception.
        When: The main function is called and client test_connection fails.
        Then: The exception is caught and return_error is called with formatted error message.
        """

        # Mock demisto functions
        mock_params = mocker.patch("GitHubMCP.demisto.params")
        mock_args = mocker.patch("GitHubMCP.demisto.args")
        mock_command = mocker.patch("GitHubMCP.demisto.command")
        mocker.patch("GitHubMCP.demisto.debug")
        mock_return_error = mocker.patch("GitHubMCP.return_error")
        mock_arg_to_list = mocker.patch("GitHubMCP.argToList")
        mock_arg_to_boolean = mocker.patch("GitHubMCP.argToBoolean")

        # Mock Client class
        mock_client_class = mocker.patch("GitHubMCP.Client")
        mock_client_instance = AsyncMock()
        mock_client_class.return_value = mock_client_instance
        mock_client_instance.test_connection.side_effect = Exception("Connection failed")

        # Mock extract_root_error_message
        mock_extract_error = mocker.patch("GitHubMCP.extract_root_error_message")
        mock_extract_error.return_value = "Connection failed"

        # Set up test data
        mock_params.return_value = {"token": {"password": "test-token"}, "enabled_toolsets": "", "readonly": "false"}
        mock_args.return_value = {}
        mock_command.return_value = "test-module"
        mock_arg_to_list.return_value = []
        mock_arg_to_boolean.return_value = False

        # Execute
        await main()

        # Verify
        mock_return_error.assert_called_once_with("Failed to execute test-module command.\nError:\nConnection failed")