OpenAI Integration
Advanced
#MCP#OpenAI#API#ChatGPT#Integration

How to Use Zulk MCP as a Tool in OpenAI

Integrate Zulk's Model Context Protocol server with OpenAI's API and ChatGPT to add URL shortening capabilities to your AI applications.

By Zulk Team
15 min read
January 5, 2025

How to Use Zulk MCP as a Tool in OpenAI

This guide demonstrates how to integrate Zulk's Model Context Protocol (MCP) server with OpenAI's API and tools ecosystem, enabling URL shortening capabilities in your AI applications.

Overview

By integrating Zulk MCP with OpenAI, you can:

  • Add URL shortening to ChatGPT conversations
  • Build AI applications with link management features
  • Create automated workflows that include URL shortening
  • Enhance your AI tools with analytics and link tracking

Prerequisites

  • OpenAI API access and API key
  • Zulk account with API credentials
  • Node.js or Python development environment
  • Basic understanding of OpenAI's function calling

Setup

Step 1: Install Dependencies

For Node.js:

npm install openai @zulk/mcp-client

For Python:

pip install openai zulk-mcp-client

Step 2: Configure Environment Variables

Create a .env file with your credentials:

OPENAI_API_KEY=your-openai-api-key
ZULK_API_KEY=your-zulk-api-key
ZULK_BASE_URL=https://zu.lk

Implementation

Node.js Implementation

import OpenAI from 'openai';
import { ZulkMCPClient } from '@zulk/mcp-client';

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

const zulkClient = new ZulkMCPClient({
  apiKey: process.env.ZULK_API_KEY,
  baseUrl: process.env.ZULK_BASE_URL,
});

// Define Zulk tools for OpenAI
const zulkTools = [
  {
    type: "function",
    function: {
      name: "shorten_url",
      description: "Shorten a long URL using Zulk",
      parameters: {
        type: "object",
        properties: {
          url: {
            type: "string",
            description: "The URL to shorten"
          },
          customSlug: {
            type: "string",
            description: "Optional custom slug for the short URL"
          }
        },
        required: ["url"]
      }
    }
  },
  {
    type: "function",
    function: {
      name: "get_link_analytics",
      description: "Get analytics for a shortened link",
      parameters: {
        type: "object",
        properties: {
          shortUrl: {
            type: "string",
            description: "The short URL to get analytics for"
          }
        },
        required: ["shortUrl"]
      }
    }
  }
];

// Function to handle tool calls
async function handleToolCall(toolCall) {
  const { name, arguments: args } = toolCall.function;
  
  switch (name) {
    case 'shorten_url':
      const parsedArgs = JSON.parse(args);
      return await zulkClient.shortenUrl(parsedArgs.url, parsedArgs.customSlug);
      
    case 'get_link_analytics':
      const analyticsArgs = JSON.parse(args);
      return await zulkClient.getAnalytics(analyticsArgs.shortUrl);
      
    default:
      throw new Error(`Unknown tool: ${name}`);
  }
}

// Main chat function
async function chatWithZulkIntegration(userMessage) {
  const response = await openai.chat.completions.create({
    model: "gpt-4",
    messages: [
      {
        role: "system",
        content: "You are a helpful assistant with access to URL shortening tools via Zulk. Use these tools when users ask to shorten URLs or get link analytics."
      },
      {
        role: "user",
        content: userMessage
      }
    ],
    tools: zulkTools,
    tool_choice: "auto"
  });

  const message = response.choices[0].message;
  
  if (message.tool_calls) {
    // Handle tool calls
    const toolResults = await Promise.all(
      message.tool_calls.map(async (toolCall) => {
        const result = await handleToolCall(toolCall);
        return {
          tool_call_id: toolCall.id,
          role: "tool",
          content: JSON.stringify(result)
        };
      })
    );

    // Get final response with tool results
    const finalResponse = await openai.chat.completions.create({
      model: "gpt-4",
      messages: [
        {
          role: "system",
          content: "You are a helpful assistant with access to URL shortening tools via Zulk."
        },
        {
          role: "user",
          content: userMessage
        },
        message,
        ...toolResults
      ]
    });

    return finalResponse.choices[0].message.content;
  }

  return message.content;
}

// Example usage
async function example() {
  const result = await chatWithZulkIntegration(
    "Please shorten this URL: https://example.com/very/long/url/path/to/resource"
  );
  console.log(result);
}

Python Implementation

import openai
import json
import os
from zulk_mcp_client import ZulkMCPClient

# Initialize clients
openai.api_key = os.getenv('OPENAI_API_KEY')
zulk_client = ZulkMCPClient(
    api_key=os.getenv('ZULK_API_KEY'),
    base_url=os.getenv('ZULK_BASE_URL')
)

# Define tools
zulk_tools = [
    {
        "type": "function",
        "function": {
            "name": "shorten_url",
            "description": "Shorten a long URL using Zulk",
            "parameters": {
                "type": "object",
                "properties": {
                    "url": {"type": "string", "description": "The URL to shorten"},
                    "custom_slug": {"type": "string", "description": "Optional custom slug"}
                },
                "required": ["url"]
            }
        }
    }
]

def handle_tool_call(tool_call):
    name = tool_call.function.name
    args = json.loads(tool_call.function.arguments)
    
    if name == "shorten_url":
        return zulk_client.shorten_url(args["url"], args.get("custom_slug"))
    else:
        raise ValueError(f"Unknown tool: {name}")

def chat_with_zulk(user_message):
    response = openai.ChatCompletion.create(
        model="gpt-4",
        messages=[
            {"role": "system", "content": "You are a helpful assistant with URL shortening capabilities."},
            {"role": "user", "content": user_message}
        ],
        tools=zulk_tools,
        tool_choice="auto"
    )
    
    message = response.choices[0].message
    
    if message.tool_calls:
        # Handle tool calls and get final response
        tool_results = []
        for tool_call in message.tool_calls:
            result = handle_tool_call(tool_call)
            tool_results.append({
                "tool_call_id": tool_call.id,
                "role": "tool",
                "content": json.dumps(result)
            })
        
        # Get final response
        final_response = openai.ChatCompletion.create(
            model="gpt-4",
            messages=[
                {"role": "system", "content": "You are a helpful assistant with URL shortening capabilities."},
                {"role": "user", "content": user_message},
                message,
                *tool_results
            ]
        )
        
        return final_response.choices[0].message.content
    
    return message.content

Advanced Features

Batch URL Processing

const batchShortenTool = {
  type: "function",
  function: {
    name: "batch_shorten_urls",
    description: "Shorten multiple URLs at once",
    parameters: {
      type: "object",
      properties: {
        urls: {
          type: "array",
          items: { type: "string" },
          description: "Array of URLs to shorten"
        }
      },
      required: ["urls"]
    }
  }
};

async function batchShortenUrls(urls) {
  const results = await Promise.all(
    urls.map(url => zulkClient.shortenUrl(url))
  );
  return results;
}

Link Analytics Integration

const analyticsTools = [
  {
    type: "function",
    function: {
      name: "get_comprehensive_analytics",
      description: "Get detailed analytics for a link including geographic data",
      parameters: {
        type: "object",
        properties: {
          shortUrl: { type: "string", description: "The short URL" },
          timeRange: { 
            type: "string", 
            enum: ["24h", "7d", "30d", "90d"],
            description: "Time range for analytics"
          }
        },
        required: ["shortUrl"]
      }
    }
  }
];

Error Handling

async function handleToolCallWithErrorHandling(toolCall) {
  try {
    return await handleToolCall(toolCall);
  } catch (error) {
    if (error.code === 'RATE_LIMIT_EXCEEDED') {
      return { error: "Rate limit exceeded. Please try again later." };
    } else if (error.code === 'INVALID_URL') {
      return { error: "The provided URL is invalid." };
    } else {
      return { error: "An unexpected error occurred." };
    }
  }
}

Best Practices

1. Rate Limiting

Implement proper rate limiting to respect API quotas:

const rateLimiter = new RateLimiter({
  tokensPerInterval: 100,
  interval: 'hour'
});

await rateLimiter.removeTokens(1);

2. Caching

Cache shortened URLs to avoid duplicate API calls:

const urlCache = new Map();

async function cachedShortenUrl(url) {
  if (urlCache.has(url)) {
    return urlCache.get(url);
  }
  
  const result = await zulkClient.shortenUrl(url);
  urlCache.set(url, result);
  return result;
}

3. Input Validation

Always validate URLs before processing:

function isValidUrl(string) {
  try {
    new URL(string);
    return true;
  } catch (_) {
    return false;
  }
}

Deployment Considerations

Environment Variables

Ensure all sensitive credentials are stored securely:

# Production environment
OPENAI_API_KEY=sk-...
ZULK_API_KEY=zulk_...
ZULK_BASE_URL=https://zu.lk
NODE_ENV=production

Monitoring

Implement logging and monitoring:

import winston from 'winston';

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.File({ filename: 'zulk-integration.log' })
  ]
});

// Log tool usage
logger.info('URL shortened', { 
  originalUrl: url, 
  shortUrl: result.shortUrl,
  timestamp: new Date().toISOString()
});

Troubleshooting

Common Issues

Authentication Errors: Verify your API keys are correct and have the necessary permissions.

Rate Limiting: Implement exponential backoff and respect rate limits.

Invalid URLs: Add proper URL validation before making API calls.

Network Issues: Implement retry logic with exponential backoff.

Next Steps

Need help with your integration? Contact our developer support team!