Skip to content

a2a

A2A interface and remote agent configuration definitions.

A2AConfig models MADA's own A2A identity for a2a.self when MADA is run as an A2A server. RemoteA2AAgentConfig models remote agents under a2a.agents that the orchestrator can call as tools.

A2AConfig dataclass

Configuration for the Agent-to-Agent HTTP interface.

Attributes:

Name Type Description
name str

Public agent name advertised in the A2A agent card.

description str

Public agent description advertised in the A2A agent card.

version str

Public agent version advertised in the A2A agent card.

url str

Externally reachable A2A endpoint URL. When omitted, the runtime host and port are used to build a local URL for the agent card.

card_path str

Optional path to a standalone A2A agent card JSON file. When provided, the A2A interface serves this card and overrides its url field with the runtime public URL.

skills list[dict[str, Any]]

Optional skill entries to expose in the A2A agent card. When omitted, skills are derived from configured MADA agents.

Source code in src/mada/core/config/a2a.py
@dataclass
class A2AConfig:
    """
    Configuration for the Agent-to-Agent HTTP interface.

    Attributes:
        name: Public agent name advertised in the A2A agent card.
        description: Public agent description advertised in the A2A agent card.
        version: Public agent version advertised in the A2A agent card.
        url: Externally reachable A2A endpoint URL. When omitted, the runtime
            host and port are used to build a local URL for the agent card.
        card_path: Optional path to a standalone A2A agent card JSON file.
            When provided, the A2A interface serves this card and overrides its
            `url` field with the runtime public URL.
        skills: Optional skill entries to expose in the A2A agent card. When
            omitted, skills are derived from configured MADA agents.
    """

    name: str = "MADA"
    description: str = "MADA multi-agent orchestration service"
    version: str = "0.2.0"
    url: str = ""
    card_path: str = ""
    skills: list[dict[str, Any]] = field(default_factory=list)
    card_path_base: InitVar[str | Path | None] = None

    def __post_init__(self, card_path_base: str | Path | None) -> None:
        """
        Normalize fields and validate generated-card skill entries.
        """
        self.name = expand_env_vars(self.name or "").strip() or "MADA"
        self.description = (
            expand_env_vars(self.description or "").strip()
            or "MADA multi-agent orchestration service"
        )
        self.version = expand_env_vars(self.version or "").strip() or "0.2.0"
        self.url = expand_env_vars(self.url or "").strip()
        self.card_path = expand_env_vars(self.card_path or "").strip()
        if self.card_path and card_path_base:
            resolved_card_path = Path(self.card_path)
            if not resolved_card_path.is_absolute():
                self.card_path = str(
                    (Path(card_path_base) / resolved_card_path).resolve()
                )

        if self.skills is None:
            self.skills = []
        if not isinstance(self.skills, list):
            raise ValueError("'a2a.self.skills' must be a list")
        for skill in self.skills:
            if not isinstance(skill, dict):
                raise ValueError("'a2a.self.skills' must contain only objects")

__post_init__(card_path_base)

Normalize fields and validate generated-card skill entries.

Source code in src/mada/core/config/a2a.py
def __post_init__(self, card_path_base: str | Path | None) -> None:
    """
    Normalize fields and validate generated-card skill entries.
    """
    self.name = expand_env_vars(self.name or "").strip() or "MADA"
    self.description = (
        expand_env_vars(self.description or "").strip()
        or "MADA multi-agent orchestration service"
    )
    self.version = expand_env_vars(self.version or "").strip() or "0.2.0"
    self.url = expand_env_vars(self.url or "").strip()
    self.card_path = expand_env_vars(self.card_path or "").strip()
    if self.card_path and card_path_base:
        resolved_card_path = Path(self.card_path)
        if not resolved_card_path.is_absolute():
            self.card_path = str(
                (Path(card_path_base) / resolved_card_path).resolve()
            )

    if self.skills is None:
        self.skills = []
    if not isinstance(self.skills, list):
        raise ValueError("'a2a.self.skills' must be a list")
    for skill in self.skills:
        if not isinstance(skill, dict):
            raise ValueError("'a2a.self.skills' must contain only objects")

RemoteA2AAgentConfig dataclass

Configuration for a remote A2A agent that MADA can delegate work to.

Attributes:

Name Type Description
url str

JSON-RPC endpoint for the remote A2A agent.

card_url str

Optional explicit URL for the remote A2A agent card. When omitted, MADA discovers the card from standard paths derived from url.

timeout float

HTTP timeout in seconds for calls to this remote agent.

api_key str

Optional API key sent as x-api-key.

headers dict[str, str]

Optional additional HTTP headers.

Source code in src/mada/core/config/a2a.py
@dataclass
class RemoteA2AAgentConfig:
    """
    Configuration for a remote A2A agent that MADA can delegate work to.

    Attributes:
        url: JSON-RPC endpoint for the remote A2A agent.
        card_url: Optional explicit URL for the remote A2A agent card. When
            omitted, MADA discovers the card from standard paths derived from
            `url`.
        timeout: HTTP timeout in seconds for calls to this remote agent.
        api_key: Optional API key sent as `x-api-key`.
        headers: Optional additional HTTP headers.
    """

    url: str
    card_url: str = ""
    timeout: float = 180.0
    api_key: str = ""
    headers: dict[str, str] = field(default_factory=dict)

    def __post_init__(self) -> None:
        """
        Normalize fields and validate required remote-agent settings.
        """
        self.url = expand_env_vars(self.url or "").strip()
        if not self.url:
            raise ValueError("'a2a.agents.<name>.url' must not be empty")

        self.card_url = expand_env_vars(self.card_url or "").strip()
        self.api_key = expand_env_vars(self.api_key or "").strip()

        if not isinstance(self.headers, dict):
            raise ValueError("'a2a.agents.<name>.headers' must be an object")

        expanded_headers = {}
        for key, value in self.headers.items():
            expanded_headers[str(key)] = expand_env_vars(str(value))
        self.headers = expanded_headers

__post_init__()

Normalize fields and validate required remote-agent settings.

Source code in src/mada/core/config/a2a.py
def __post_init__(self) -> None:
    """
    Normalize fields and validate required remote-agent settings.
    """
    self.url = expand_env_vars(self.url or "").strip()
    if not self.url:
        raise ValueError("'a2a.agents.<name>.url' must not be empty")

    self.card_url = expand_env_vars(self.card_url or "").strip()
    self.api_key = expand_env_vars(self.api_key or "").strip()

    if not isinstance(self.headers, dict):
        raise ValueError("'a2a.agents.<name>.headers' must be an object")

    expanded_headers = {}
    for key, value in self.headers.items():
        expanded_headers[str(key)] = expand_env_vars(str(value))
    self.headers = expanded_headers

load_a2a_agents_config(config_dict)

Load remote A2A agent definitions from a dictionary.

Source code in src/mada/core/config/a2a.py
def load_a2a_agents_config(
    config_dict: dict[str, Any] | None,
) -> dict[str, RemoteA2AAgentConfig]:
    """
    Load remote A2A agent definitions from a dictionary.
    """
    if config_dict is None:
        return {}

    if not isinstance(config_dict, dict):
        raise ValueError("'a2a.agents' must be an object")

    agents = {}
    for name, agent_config in config_dict.items():
        if not isinstance(agent_config, dict):
            raise ValueError("'a2a.agents' values must be objects")
        clean_name = str(name).strip()
        if not clean_name:
            raise ValueError("'a2a.agents' must not contain empty names")
        agents[clean_name] = RemoteA2AAgentConfig(**agent_config)

    return agents

load_a2a_config(config_dict, card_path_base=None)

Load self A2A configuration from a dictionary.

Parameters:

Name Type Description Default
config_dict dict[str, Any] | None

Serialized A2A settings, or None.

required

Returns:

Type Description
A2AConfig

A validated A2A configuration object.

Source code in src/mada/core/config/a2a.py
def load_a2a_config(
    config_dict: dict[str, Any] | None,
    card_path_base: str | Path | None = None,
) -> A2AConfig:
    """
    Load self A2A configuration from a dictionary.

    Args:
        config_dict: Serialized A2A settings, or `None`.

    Returns:
        A validated A2A configuration object.
    """
    if config_dict is None:
        return A2AConfig(card_path_base=card_path_base)

    if not isinstance(config_dict, dict):
        raise ValueError("'a2a.self' must be an object")

    return A2AConfig(**config_dict, card_path_base=card_path_base)