Skip to main content
Glama

get_login_link

Generate a clickable authentication link for Meta Ads to access and manage advertising campaigns on Facebook and Instagram platforms.

Instructions

Get a clickable login link for Meta Ads authentication.

NOTE: This method should only be used if you're using your own Facebook app.
If using Pipeboard authentication (recommended), set the PIPEBOARD_API_TOKEN
environment variable instead (token obtainable via https://pipeboard.co).

Args:
    access_token: Meta API access token (optional - will use cached token if not provided)

Returns:
    A clickable resource link for Meta authentication

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
access_tokenNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • Main handler function for the 'get_login_link' tool. Determines authentication mode based on environment variables and returns a JSON response with login URL or status message. Supports Pipeboard token auth, production OAuth, and local callback server.
    async def get_login_link(access_token: Optional[str] = None) -> str:
        """
        Get a clickable login link for Meta Ads authentication.
        
        NOTE: This method should only be used if you're using your own Facebook app.
        If using Pipeboard authentication (recommended), set the PIPEBOARD_API_TOKEN
        environment variable instead (token obtainable via https://pipeboard.co).
        
        Args:
            access_token: Meta API access token (optional - will use cached token if not provided)
        
        Returns:
            A clickable resource link for Meta authentication
        """
        # Check if we're using pipeboard authentication
        using_pipeboard = bool(os.environ.get("PIPEBOARD_API_TOKEN", ""))
        callback_server_disabled = bool(os.environ.get("META_ADS_DISABLE_CALLBACK_SERVER", ""))
        
        if using_pipeboard:
            # Pipeboard token-based authentication
            try:
                logger.info("Using Pipeboard token-based authentication")
                
                # If an access token was provided, this is likely a test - return success
                if access_token:
                    return json.dumps({
                        "message": "✅ Authentication Token Provided",
                        "status": "Using provided access token for authentication",
                        "token_info": f"Token preview: {access_token[:10]}...",
                        "authentication_method": "manual_token",
                        "ready_to_use": "You can now use all Meta Ads MCP tools and commands."
                    }, indent=2)
                
                # Check if Pipeboard token is working
                token = pipeboard_auth_manager.get_access_token()
                if token:
                    return json.dumps({
                        "message": "✅ Already Authenticated",
                        "status": "You're successfully authenticated with Meta Ads via Pipeboard!",
                        "token_info": f"Token preview: {token[:10]}...",
                        "authentication_method": "pipeboard_token",
                        "ready_to_use": "You can now use all Meta Ads MCP tools and commands."
                    }, indent=2)
                
                # Start Pipeboard auth flow
                auth_data = pipeboard_auth_manager.initiate_auth_flow()
                login_url = auth_data.get('loginUrl')
                
                if login_url:
                    return json.dumps({
                        "message": "🔗 Click to Authenticate",
                        "login_url": login_url,
                        "markdown_link": f"[🚀 Authenticate with Meta Ads]({login_url})",
                        "instructions": "Click the link above to complete authentication with Meta Ads.",
                        "authentication_method": "pipeboard_oauth",
                        "what_happens_next": "After clicking, you'll be redirected to Meta's authentication page. Once completed, your token will be automatically saved.",
                        "token_duration": "Your token will be valid for approximately 60 days."
                    }, indent=2)
                else:
                    return json.dumps({
                        "message": "❌ Authentication Error",
                        "error": "Could not generate authentication URL from Pipeboard",
                        "troubleshooting": [
                            "Check that your PIPEBOARD_API_TOKEN is valid",
                            "Ensure the Pipeboard service is accessible",
                            "Try again in a few moments"
                        ],
                        "authentication_method": "pipeboard_oauth_failed"
                    }, indent=2)
                    
            except Exception as e:
                logger.error(f"Error initiating Pipeboard auth flow: {e}")
                return json.dumps({
                    "message": "❌ Pipeboard Authentication Error",
                    "error": f"Failed to initiate Pipeboard authentication: {str(e)}",
                    "troubleshooting": [
                        "✅ Check that PIPEBOARD_API_TOKEN environment variable is set correctly",
                        "🌐 Verify that pipeboard.co is accessible from your network",
                        "🔄 Try refreshing your Pipeboard API token",
                        "⏰ Wait a moment and try again"
                    ],
                    "get_help": "Contact support if the issue persists",
                    "authentication_method": "pipeboard_error"
                }, indent=2)
        elif callback_server_disabled:
            # Production OAuth flow - use Pipeboard OAuth endpoints directly
            logger.info("Production OAuth flow - using Pipeboard OAuth endpoints")
            
            return json.dumps({
                "message": "🔐 Authentication Required",
                "instructions": "Please sign in to your Pipeboard account to authenticate with Meta Ads.",
                "sign_in_url": "https://pipeboard.co/auth/signin",
                "markdown_link": "[🚀 Sign in to Pipeboard](https://pipeboard.co/auth/signin)",
                "what_to_do": "Click the link above to sign in to your Pipeboard account and complete authentication.",
                "authentication_method": "production_oauth"
            }, indent=2)
        else:
            # Original Meta authentication flow (development/local)
            # Check if we have a cached token
            cached_token = auth_manager.get_access_token()
            token_status = "No token" if not cached_token else "Valid token"
            
            # If we already have a valid token and none was provided, just return success
            if cached_token and not access_token:
                logger.info("get_login_link called with existing valid token")
                return json.dumps({
                    "message": "✅ Already Authenticated", 
                    "status": "You're successfully authenticated with Meta Ads!",
                    "token_info": f"Token preview: {cached_token[:10]}...",
                    "created_at": auth_manager.token_info.created_at if hasattr(auth_manager, "token_info") else None,
                    "expires_in": auth_manager.token_info.expires_in if hasattr(auth_manager, "token_info") else None,
                    "authentication_method": "meta_oauth",
                    "ready_to_use": "You can now use all Meta Ads MCP tools and commands."
                }, indent=2)
            
            # IMPORTANT: Start the callback server first by calling our helper function
            # This ensures the server is ready before we provide the URL to the user
            logger.info("Starting callback server for authentication")
            try:
                port = start_callback_server()
                logger.info(f"Callback server started on port {port}")
                
                # Generate direct login URL
                auth_manager.redirect_uri = f"http://localhost:{port}/callback"  # Ensure port is set correctly
                logger.info(f"Setting redirect URI to {auth_manager.redirect_uri}")
                login_url = auth_manager.get_auth_url()
                logger.info(f"Generated login URL: {login_url}")
            except Exception as e:
                logger.error(f"Failed to start callback server: {e}")
                return json.dumps({
                    "message": "❌ Local Authentication Unavailable",
                    "error": "Cannot start local callback server for authentication",
                    "reason": str(e),
                    "solutions": [
                        "🌐 Use Pipeboard authentication: Set PIPEBOARD_API_TOKEN environment variable",
                        "🔑 Use direct token: Set META_ACCESS_TOKEN environment variable", 
                        "🔧 Check if another service is using the required ports"
                    ],
                    "authentication_method": "meta_oauth_disabled"
                }, indent=2)
            
            # Check if we can exchange for long-lived tokens
            token_exchange_supported = bool(META_APP_SECRET)
            token_duration = "60 days" if token_exchange_supported else "1-2 hours"
            
            # Return a special format that helps the LLM format the response properly
            response = {
                "message": "🔗 Click to Authenticate",
                "login_url": login_url,
                "markdown_link": f"[🚀 Authenticate with Meta Ads]({login_url})",
                "instructions": "Click the link above to authenticate with Meta Ads.",
                "server_info": f"Local callback server running on port {port}",
                "token_duration": f"Your token will be valid for approximately {token_duration}",
                "authentication_method": "meta_oauth",
                "what_happens_next": "After clicking, you'll be redirected to Meta's authentication page. Once completed, your token will be automatically saved.",
                "security_note": "This uses a secure local callback server for development purposes."
            }
            
            # Wait a moment to ensure the server is fully started
            await asyncio.sleep(1)
            
        return json.dumps(response, indent=2)
  • Conditional registration of the get_login_link function as an MCP tool using mcp_server.tool() decorator. ENABLE_LOGIN_LINK is set based on absence of META_ADS_DISABLE_LOGIN_LINK env var.
    if ENABLE_LOGIN_LINK:
        get_login_link = mcp_server.tool()(get_login_link)
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses that the tool returns a 'clickable resource link' and mentions optional token usage with caching behavior ('will use cached token if not provided'). However, it lacks details on authentication requirements, rate limits, error handling, or what the link actually does (e.g., redirects to OAuth flow).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured and concise. It starts with the core purpose, followed by a NOTE for usage guidelines, and then clearly labeled sections for Args and Returns. Each sentence adds value without redundancy, and the information is front-loaded for quick understanding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity (authentication-related), no annotations, and an output schema (which handles return values), the description is fairly complete. It covers purpose, usage guidelines, parameter semantics, and return type. However, it could improve by detailing behavioral aspects like authentication flow or error cases, but the output schema mitigates some gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It explains the single parameter 'access_token' as 'Meta API access token (optional - will use cached token if not provided)', adding meaning beyond the schema's title 'Access Token'. This clarifies its purpose, optionality, and caching behavior. With 0 parameters documented in the schema, the baseline is 4, and the description meets this by providing useful semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Get a clickable login link for Meta Ads authentication.' This specifies the verb ('Get'), resource ('clickable login link'), and domain ('Meta Ads authentication'). However, it doesn't explicitly differentiate from sibling tools, which are primarily about ad management rather than authentication.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit usage guidelines: 'This method should only be used if you're using your own Facebook app. If using Pipeboard authentication (recommended), set the PIPEBOARD_API_TOKEN environment variable instead.' It clearly states when to use this tool vs. an alternative approach, including a recommendation and a link for obtaining the alternative token.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/pipeboard-co/meta-ads-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server