Spaces:
Running
Running
File size: 4,963 Bytes
7476735 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
import gradio as gr
import httpx
import json
from huggingface_hub import HfApi
import random
def find_endpoints(openapi_spec_url, api_base_url, methods):
print(f"Finding endpoints for {openapi_spec_url} with methods {methods}")
if openapi_spec_url.startswith(("http://", "https://")):
response = httpx.get(openapi_spec_url)
response.raise_for_status()
content = response.text
else:
raise gr.Error("Invalid URL for OpenAPI spec")
try:
spec = json.loads(content)
except json.JSONDecodeError as e:
raise gr.Error("Invalid JSON for OpenAPI spec")
api_paths = spec.get("paths", {})
if not api_paths:
raise gr.Error("No valid paths found in the OpenAPI specification")
valid_api_paths = []
for path, path_item in api_paths.items():
for method, operation in path_item.items():
if methods and method.lower() not in [m.lower() for m in methods]:
continue
valid_api_paths.append({
"path": path,
"method": method.upper(),
})
return gr.JSON(valid_api_paths, label=f"π {len(valid_api_paths)} endpoints found")
def update_bottom(oauth_token: gr.OAuthToken | None):
if oauth_token:
return "Click the π Launch button to create a new MCP Space", gr.Button(interactive=True)
else:
return gr.skip()
gradio_app_code = """
import gradio as gr
gr.load_openapi(
openapi_spec=\"{}\",
base_url=\"{}\",
methods={},
).launch(mcp_server=True)
"""
def create_hf_space(token, app_code):
"""
Create a new Hugging Face Space with optional app.py file
Args:
token (str): Your Hugging Face API token
app_code (str): String content for the app.py file
Returns:
SpaceInfo: Information about the created space
"""
api = HfApi(token=token)
user_info = api.whoami()
username = user_info["name"]
space_name = f"{username}/openapi-to-mcp-{random.randint(100000, 999999)}"
try:
gr.Info("Creating space...")
space_info = api.create_repo(
repo_id=space_name,
repo_type="space",
private=False,
space_sdk="gradio"
)
print(f"Space created: {space_info}")
api.upload_file(
path_or_fileobj=app_code.encode('utf-8'),
path_in_repo="app.py",
repo_id=space_name,
repo_type="space",
commit_message="Add app.py"
)
print(f"App.py uploaded to {space_name}")
space_url = f"https://huggingface.co/spaces/{space_name}"
gr.Success(f"π Your space is available at: <a href='{space_url}' target='_blank'>{space_url}</a>")
return space_info
except Exception as e:
gr.Error(f"β Error creating space: {str(e)}")
def launch_mcp_server(openapi_spec_url, api_base_url, methods, oauth_token: gr.OAuthToken | None):
if oauth_token:
create_hf_space(
oauth_token.token,
gradio_app_code.format(
openapi_spec_url,
api_base_url,
methods
)
)
else:
pass
with gr.Blocks(theme="ocean") as demo:
gr.Markdown("## OpenAPI βͺ MCP")
gr.Markdown("""
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).
""")
with gr.Row():
with gr.Column():
openapi_spec_url = gr.Textbox(label="OpenAPI Spec URL", value="https://petstore3.swagger.io/api/v3/openapi.json")
api_base_url = gr.Textbox(label="API Base URL", value="https://petstore3.swagger.io/api/v3/")
methods = gr.CheckboxGroup(label="Methods", choices=["GET", "POST", "PUT", "DELETE"], value=["GET", "POST", "PUT", "DELETE"])
find_endpoints_button = gr.Button("π Find Endpoints")
with gr.Column():
endpoints = gr.JSON(label="π endpoints found", value=[], max_height=400)
message = gr.Markdown("_Note:_ you must be signed in through your Hugging Face account to launch the MCP Server")
with gr.Row():
login_button = gr.LoginButton()
launch_button = gr.Button("π Launch MCP Server", variant="primary", interactive=False)
gr.on(
[demo.load, find_endpoints_button.click],
find_endpoints,
inputs=[openapi_spec_url, api_base_url, methods],
outputs=endpoints,
)
gr.on(
[demo.load],
update_bottom,
inputs=None,
outputs=[message, launch_button]
)
gr.on(
[launch_button.click],
launch_mcp_server,
inputs=[openapi_spec_url, api_base_url, methods],
outputs=None
)
demo.launch() |