Spaces:
Running
Running
File size: 5,829 Bytes
7476735 3a7c6fc 7476735 3a7c6fc 7476735 3a7c6fc 7476735 3a7c6fc 7476735 9b7940f 7476735 3a7c6fc 7476735 3a7c6fc 7476735 3a7c6fc 7476735 9b7940f 7476735 3a7c6fc 7476735 3a7c6fc 7476735 3a7c6fc 9b7940f 7476735 3a7c6fc 7476735 9b7940f 7476735 3a7c6fc 7476735 9b7940f 7476735 9b7940f 7476735 3a7c6fc 7476735 3a7c6fc 7476735 3a7c6fc 7476735 3a7c6fc 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 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
import gradio as gr
import httpx
import json
from huggingface_hub import HfApi
import random
import re
def find_endpoints(openapi_spec_url, api_base_url, paths, 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
if not paths:
valid_api_paths.append({
"path": path,
"method": method.upper(),
})
else:
for path_regex in paths.split(","):
if re.match(path_regex, path):
valid_api_paths.append({
"path": path,
"method": method.upper(),
})
break
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 π Create 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=\"{}\",
paths={},
methods={},
).launch(mcp_server=True)
"""
def create_hf_space(token, space_name, app_code):
"""
Create a new Hugging Face Space with optional app.py file
Args:
token (str): Your Hugging Face API token
space_name (str): The name of the space to create
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 = space_name or f"my-mcp-space-{random.randint(100000, 999999)}"
space_id = f"{username}/{space_name}"
try:
gr.Info(f"Creating space {space_id}...", duration=20)
space_info = api.create_repo(
repo_id=space_id,
repo_type="space",
private=False,
space_sdk="gradio"
)
api.upload_file(
path_or_fileobj=app_code.encode('utf-8'),
path_in_repo="app.py",
repo_id=space_id,
repo_type="space",
commit_message="Add app.py"
)
space_url = f"https://huggingface.co/spaces/{space_id}"
gr.Success(f"π Your space will be available at: <a href='{space_url}' target='_blank'>{space_url} ‴</a>", duration=None)
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, paths, methods, space_name_box, oauth_token: gr.OAuthToken | None):
if oauth_token:
if not paths:
paths = None
else:
paths = f"[\"{paths}\"]"
create_hf_space(
oauth_token.token,
space_name_box,
gradio_app_code.format(
openapi_spec_url,
api_base_url,
paths,
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/")
paths = gr.Textbox(label="Optional regex to filter paths by", placeholder=".*user.*")
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 create the MCP Space")
space_name_box = gr.Textbox(show_label=False, placeholder="Optional space name (e.g. my-mcp-space)")
with gr.Row():
login_button = gr.LoginButton()
launch_button = gr.Button("π Create MCP Space", variant="primary", interactive=False)
gr.on(
[demo.load, find_endpoints_button.click],
find_endpoints,
inputs=[openapi_spec_url, api_base_url, paths, 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, paths, methods, space_name_box],
outputs=None
)
demo.launch() |