import gradio as gr from fastmcp import FastMCP import logging import requests from datetime import datetime logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s") logger = logging.getLogger(__name__) mcp = FastMCP("Jobicy Remote Jobs Agent") # Remaining filter options COMPANY_INDUSTRIES = [ ("", ""), ("Business Development", "business"), ("Content & Editorial", "copywriting"), ("Creative & Design", "design-multimedia"), ("Customer Success", "supporting"), ("Data Science & Analytics", "data-science"), ("DevOps & Infrastructure", "admin"), ("Finance & Accounting", "accounting-finance"), ("HR & Recruiting", "hr"), ("Legal & Compliance", "legal"), ("Marketing & Sales", "marketing"), ("Product & Operations", "management"), ("Programming", "dev"), ("Sales", "seller"), ("SEO", "seo"), ("Social Media Marketing", "smm"), ("Software Engineering", "engineering"), ("Technical Support", "technical-support"), ("Web & App Design", "web-app-design"), ] COUNTRY_CHOICES = [ "", "APAC", "EMEA", "LATAM", "Argentina", "Australia", "Austria", "Belgium", "Brazil", "Bulgaria", "Canada", "China", "Costa Rica", "Croatia", "Cyprus", "Czechia", "Denmark", "Estonia", "Europe", "Finland", "France", "Germany", "Greece", "Hungary", "Ireland", "Israel", "Italy", "Japan", "Latvia", "Lithuania", "Mexico", "Netherlands", "New Zealand", "Norway", "Philippines", "Poland", "Portugal", "Romania", "Singapore", "Slovakia", "Slovenia", "South Korea", "Spain", "Sweden", "Switzerland", "Thailand", "Türkiye", "UAE", "UK", "USA", "Vietnam" ] @mcp.tool(name="search_jobs") def search_jobs_tool(industry: str = "", country: str = "", keyword: str = "", limit: int = 20) -> dict: """ Search remote jobs via Jobicy API, supports filters. Args: industry (str): Company industry filter. country (str): Region filter (e.g., usa, canada, ...). keyword (str): Free-form keyword tag. limit (int): Number of results (1–50). Returns: dict: {"jobs": [...]} or {"error": "..." } """ base = "https://jobicy.com/api/v2/remote-jobs" params = {"count": max(1, min(limit, 50))} if industry: params["industry"] = industry.lower().replace(" & ", "-").replace(" ", "-") if country and country.lower() != "anywhere": params["geo"] = country.lower() if keyword: params["tag"] = keyword.strip() logger.info(f"Requesting Jobicy API with params: {params}") try: resp = requests.get(base, params=params, headers={"User-Agent": "Mozilla/5.0"}, timeout=10) resp.raise_for_status() jobs_raw = resp.json().get("jobs", []) except Exception as e: return {"error": f"Fetch error: {e}"} def fmt(j): posted = j.get("pubDate", "")[:10] sal_min = j.get("annualSalaryMin") sal_max = j.get("annualSalaryMax") cur = j.get("salaryCurrency", "") salary = f"{sal_min}–{sal_max} {cur}".strip() if sal_min or sal_max else "Not specified" return { "title": j.get("jobTitle", "No Title"), "company": j.get("companyName", ""), "location": j.get("jobGeo", ""), "url": j.get("url", "#"), "pubDate": posted, "salary": salary } sorted_jobs = sorted(jobs_raw, key=lambda x: x.get("pubDate", ""), reverse=True)[:params["count"]] return {"jobs": [fmt(j) for j in sorted_jobs]} def search_jobs_ui(industry, country, keyword, limit): res = search_jobs_tool(industry=industry, country=country, keyword=keyword, limit=limit) if "error" in res: return f"❌ {res['error']}" if not res["jobs"]: return "No jobs found with these filters." md = "# Remote Jobs Results\n\n" for i, j in enumerate(res["jobs"], 1): md += ( f"### {i}. {j['title']}\n\n" f"**Company:** {j['company']}\n\n" f"**Location:** {j['location']}\n\n" f"**Salary:** {j['salary']}\n\n" f"**Posted On:** {j['pubDate']}\n\n" f"[Apply Here]({j['url']})\n\n---\n\n" ) return md app = gr.Interface( fn=search_jobs_ui, inputs=[ gr.Dropdown(label="Company Industry (optional) (Empty = All)", choices=COMPANY_INDUSTRIES, value=""), gr.Dropdown(label="Country / Region (optional) (Empty = Anywhere)", choices=COUNTRY_CHOICES, value=""), gr.Textbox(label="Keyword / Tag (optional)", placeholder="e.g., python, data, web"), gr.Slider(minimum=1, maximum=50, value=20, step=1, label="Number of Results"), ], outputs=gr.Markdown(), title="Jobicy Remote Job Search", description="Search remote jobs by industry, region, and keyword. Results sorted by most recent.", theme="huggingface" ) if __name__ == "__main__": app.launch(mcp_server=True)