CoolFace
Apppublic

veten/OpenAPI2MCP

sourceHugging Faceupdated 1y agoView on Hugging Face
0likes
app.py214 linesDownload Raw Back to root
1import gradio as gr2import httpx3import json4from huggingface_hub import HfApi5import random6import re7 8def find_endpoints(openapi_spec_url, api_base_url, paths, methods):9    print(f"Finding endpoints for {openapi_spec_url} with methods {methods}")10    if openapi_spec_url.startswith(("http://", "https://")):11        response = httpx.get(openapi_spec_url)12        response.raise_for_status()13        content = response.text14    else:15        raise gr.Error("Invalid URL for OpenAPI spec")16 17    try:18        spec = json.loads(content)19    except json.JSONDecodeError as e:20        raise gr.Error("Invalid JSON for OpenAPI spec")21 22    api_paths = spec.get("paths", {})23    if not api_paths:24        raise gr.Error("No valid paths found in the OpenAPI specification")25 26    valid_api_paths = []27    for path, path_item in api_paths.items():28        for method, operation in path_item.items():29            if methods and method.lower() not in [m.lower() for m in methods]:30                continue31            if not paths:32                valid_api_paths.append({33                    "path": path,34                    "method": method.upper(),35                })36            else:37                for path_regex in paths.split(","):38                    if re.match(path_regex, path):39                        valid_api_paths.append({40                            "path": path,41                            "method": method.upper(),42                        })43                        break44 45    return gr.JSON(valid_api_paths, label=f"๐Ÿ” {len(valid_api_paths)} endpoints found")46 47def update_bottom(oauth_token: gr.OAuthToken | None):48    if oauth_token:49        return "Click the ๐Ÿš€ Create button to create a new MCP Space", gr.Button(interactive=True)50    else:51        return gr.skip()52 53gradio_app_code = """54import os55import gradio as gr56 57gr.load_openapi(58    openapi_spec=\"{}\",59    base_url=\"{}\",60    paths={},61    methods={},62    auth_token=os.getenv("OPENAPI_AUTH_TOKEN")63).launch(mcp_server=True)64"""65 66readme_code = """67---68title: OpenAPI MCP Server69sdk: gradio70sdk_version: 5.38.271app_file: app.py72pinned: false73tags:74 - openapi2mcp75---76 77Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference78"""79 80requirements_code = """81https://gradio-pypi-previews.s3.amazonaws.com/86331cf36187d17a6d3ce26b01f28ea8dd5cbe35/gradio-5.38.2-py3-none-any.whl82"""83 84def create_hf_space(token, space_name, space_public, app_code, auth_token):85    """86    Create a new Hugging Face Space with optional app.py file87    88    Args:89        token (str): Your Hugging Face API token90        space_name (str): The name of the space to create91        space_public (bool): Whether the space should be public92        app_code (str): String content for the app.py file93        auth_token (str | None): The auth token to include in the API requests94 95    Returns:96        SpaceInfo: Information about the created space97    """98    99    api = HfApi(token=token)100    user_info = api.whoami()101    username = user_info["name"]102    space_name = space_name or f"my-mcp-space-{random.randint(100000, 999999)}" 103    space_id = f"{username}/{space_name}"104    105    try:106        gr.Info(f"Creating space {space_id}...", duration=20)107        space_info = api.create_repo(108            repo_id=space_id,109            repo_type="space",110            private=not space_public,111            space_sdk="gradio"112        )113        api.upload_file(114            path_or_fileobj=app_code.encode('utf-8'),115            path_in_repo="app.py",116            repo_id=space_id,117            repo_type="space",118            commit_message="Add app.py"119        )120        api.upload_file(121            path_or_fileobj=readme_code.encode('utf-8'),122            path_in_repo="README.md",123            repo_id=space_id,124            repo_type="space",125            commit_message="Add README.md"126        )127        api.upload_file(128            path_or_fileobj=requirements_code.encode('utf-8'),129            path_in_repo="requirements.txt",130            repo_id=space_id,131            repo_type="space",132            commit_message="Add requirements.txt"133        )134        if auth_token:135            api.add_space_secret(136                repo_id=space_id,137                key="OPENAPI_AUTH_TOKEN",138                value=auth_token139            )140 141        space_url = f"https://huggingface.co/spaces/{space_id}"142        gr.Success(f"๐Ÿš€ Your space will be available at: <a href='{space_url}' target='_blank'>{space_url} โคด</a>", duration=None)        143        return space_info144        145    except Exception as e:146        gr.Error(f"โŒ Error creating space: {str(e)}")147 148 149def launch_mcp_server(openapi_spec_url, api_base_url, paths, methods, auth_token, space_name_box, space_public_box, oauth_token: gr.OAuthToken | None):150    if oauth_token:151        if not paths:152            paths = None153        else:154            paths = f"[\"{paths}\"]"155        create_hf_space(156            oauth_token.token, 157            space_name_box,158            space_public_box,159            gradio_app_code.format(160                openapi_spec_url,161                api_base_url,162                paths,163                methods,164            ),165            auth_token166        )167    else:168        pass169 170with gr.Blocks(theme="ocean") as demo:171    gr.Markdown("## OpenAPI โžช MCP")172    gr.Markdown("""173    This is a tool that converts an OpenAPI spec to a MCP server that you can launch as a Space and then use with any MCP Client (e.g. ChatGPT, Claude, Cursor, Cline).174    """)175    with gr.Row():176        with gr.Column():177            openapi_spec_url = gr.Textbox(label="OpenAPI Spec URL", value="https://petstore3.swagger.io/api/v3/openapi.json")178            api_base_url = gr.Textbox(label="API Base URL", value="https://petstore3.swagger.io/api/v3/")179            methods = gr.CheckboxGroup(label="Methods", choices=["GET", "POST", "PUT", "DELETE"], value=["GET", "POST", "PUT", "DELETE"])180            with gr.Accordion("Optional Settings", open=False):181                paths = gr.Textbox(label="Regex to filter paths by", placeholder=".*user.*", info="Only include API endpoints that match this regex")182                auth_token = gr.Textbox(label="Auth token to include in API requests", info="This will be sent to the API endpoints as a Bearer token", type="password")183            find_endpoints_button = gr.Button("๐Ÿ” Find Endpoints")184        with gr.Column():185            endpoints = gr.JSON(label="๐Ÿ” endpoints found", value=[], max_height=400)186            message = gr.Markdown("_Note:_ you must be signed in through your Hugging Face account to create the MCP Space")187            space_name_box = gr.Textbox(show_label=False, placeholder="Optional space name (e.g. my-mcp-space)")188            space_public_box = gr.Checkbox(label="Make Space public", value=True)189            with gr.Row():190                login_button = gr.LoginButton()191                launch_button = gr.Button("๐Ÿš€ Create MCP Space", variant="primary", interactive=False)192 193        gr.on(194            [demo.load, find_endpoints_button.click],195            find_endpoints,196            inputs=[openapi_spec_url, api_base_url, paths, methods],197            outputs=endpoints,198        )199 200        gr.on(201            [demo.load],202            update_bottom,203            inputs=None,204            outputs=[message, launch_button]205        )206 207        gr.on(208            [launch_button.click],209            launch_mcp_server,210            inputs=[openapi_spec_url, api_base_url, paths, methods, auth_token, space_name_box, space_public_box],211            outputs=None212        )213 214demo.launch()