MadgicxMCP Docs

Agentic Frameworks

Integrate your backend applications and AI agents with Madgicx MCP using OAuth 2.0 client credentials.

Agentic Frameworks

Agentic frameworks are server-side applications that can securely store credentials. Unlike browser-based OAuth flows, these integrations authenticate directly using a Client ID and Client Secret — no user interaction required after initial setup.

This is ideal for backend services, automated pipelines, and AI agent frameworks that need programmatic access to Madgicx MCP.

Getting Your Credentials

Copy your Client ID

Your Client ID is displayed in the Credentials section. Use the copy button to copy it.

Generate a Client Secret

Click the rotate icon next to the Client ID to generate a new Client Secret. Copy and store it securely — it will only be shown once.

Store your secret securely

The client secret is only displayed once at creation time. Store it in a secrets manager or environment variable — never commit it to source control.

Rotating the Client Secret

You can rotate your client secret at any time from the MCP Integration settings:

  1. Click the rotate icon next to your Client ID
  2. Confirm the rotation in the dialog — this will invalidate your current secret immediately
  3. Copy and deploy the new secret to all services that use it

Secret rotation is immediate

Rotating the secret invalidates the previous one instantly. Any services using the old secret will need to be updated, or they will fail to authenticate.

MCP Server URL

All agentic frameworks connect to:

https://mcp.madgicx.com/mcp

Environment Variables

All framework integrations below use the same environment variables. Create a .env file or set them in your environment:

MADGICX_CLIENT_ID=your_client_id_here
MADGICX_CLIENT_SECRET=your_client_secret_here
MADGICX_TOKEN_URL=https://mcp.madgicx.com/oauth/token
MADGICX_MCP_URL=https://mcp.madgicx.com/mcp

Auth Helper

All framework integrations use a shared MadgicxConfidentialClientAuth helper that handles the OAuth 2.0 client credentials flow, including automatic token refresh. Place this in your project as auth.py:

"""OAuth2 Confidential Client token manager for Madgicx MCP server."""
 
from __future__ import annotations
 
import logging
import os
import threading
import time
 
import requests
 
log = logging.getLogger("mcp_auth")
 
 
class MadgicxConfidentialClientAuth:
    """Thread-safe OAuth2 token manager using client_credentials grant.
 
    Token lifecycle:
      1. Valid access token  -> use it
      2. Access token expired + valid refresh token -> refresh
      3. Refresh token expired/rejected -> re-authenticate
    """
 
    def __init__(
        self,
        client_id: str | None = None,
        client_secret: str | None = None,
        token_url: str | None = None,
        scopes: str = "mcp:read mcp:write",
        expiry_buffer_seconds: int = 60,
    ):
        self.client_id = client_id or os.getenv("MADGICX_CLIENT_ID", "")
        self.client_secret = client_secret or os.getenv("MADGICX_CLIENT_SECRET", "")
        self.token_url = token_url or os.getenv("MADGICX_TOKEN_URL", "")
        self.scopes = scopes
        self.expiry_buffer = expiry_buffer_seconds
 
        self._access_token: str | None = None
        self._refresh_token: str | None = None
        self._access_token_expiry: float = 0
        self._refresh_token_expiry: float = 0
        self._lock = threading.Lock()
 
    @property
    def access_token(self) -> str:
        """Always returns a valid access token. Thread-safe."""
        with self._lock:
            now = time.time()
 
            if self._access_token and now < self._access_token_expiry - self.expiry_buffer:
                return self._access_token
 
            if self._refresh_token and now < self._refresh_token_expiry - self.expiry_buffer:
                self._do_refresh()
                return self._access_token
 
            self._do_client_credentials()
            return self._access_token
 
    @property
    def headers(self) -> dict[str, str]:
        return {"Authorization": f"Bearer {self.access_token}"}
 
    def _do_client_credentials(self) -> None:
        resp = requests.post(
            self.token_url,
            data={
                "grant_type": "client_credentials",
                "client_id": self.client_id,
                "client_secret": self.client_secret,
                "scope": self.scopes,
            },
        )
        resp.raise_for_status()
        self._store_tokens(resp.json())
 
    def _do_refresh(self) -> None:
        try:
            resp = requests.post(
                self.token_url,
                data={
                    "grant_type": "refresh_token",
                    "refresh_token": self._refresh_token,
                    "client_id": self.client_id,
                    "client_secret": self.client_secret,
                },
            )
            resp.raise_for_status()
            self._store_tokens(resp.json())
        except requests.HTTPError:
            self._do_client_credentials()
 
    def _store_tokens(self, token_response: dict) -> None:
        now = time.time()
        self._access_token = token_response["access_token"]
        self._access_token_expiry = now + token_response.get("expires_in", 3600)
 
        if "refresh_token" in token_response:
            self._refresh_token = token_response["refresh_token"]
            self._refresh_token_expiry = now + token_response.get(
                "refresh_token_expires_in", 1_209_600
            )

This class:

  • Reads credentials from environment variables (or accepts them as constructor arguments)
  • Automatically obtains tokens via the client_credentials grant
  • Refreshes expired access tokens using the refresh token
  • Falls back to a full re-authentication if the refresh token is also expired
  • Is thread-safe for use in concurrent applications

Framework Integrations

On this page