Spaces:
Running
Running
File size: 7,160 Bytes
7476735 3a7c6fc 7476735 3a7c6fc 7476735 3a7c6fc 7476735 3a7c6fc 7476735 9b7940f 7476735 3754af6 7476735 0e3672c 3a7c6fc 7476735 3a7c6fc 7476735 3a7c6fc 7476735 9b7940f 7476735 3a7c6fc 7476735 3a7c6fc 7476735 0e3672c 3a7c6fc 9b7940f 7476735 0e3672c 7476735 9b7940f 3754af6 7476735 3a7c6fc 7476735 9b7940f 0e3672c 7476735 0e3672c 7476735 3a7c6fc 7476735 3a7c6fc 7476735 3a7c6fc 7476735 0e3672c 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 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
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={},
auth_token={}
).launch(mcp_server=True)
"""
readme_code = """
---
title: OpenAPI MCP Server
sdk: gradio
sdk_version: 5.38.2
app_file: app.py
pinned: false
tags:
- openapi2mcp
---
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
"""
requirements_code = """
https://gradio-pypi-previews.s3.amazonaws.com/86331cf36187d17a6d3ce26b01f28ea8dd5cbe35/gradio-5.38.2-py3-none-any.whl
"""
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"
)
api.upload_file(
path_or_fileobj=readme_code.encode('utf-8'),
path_in_repo="README.md",
repo_id=space_id,
repo_type="space",
commit_message="Add README.md"
)
api.upload_file(
path_or_fileobj=requirements_code.encode('utf-8'),
path_in_repo="requirements.txt",
repo_id=space_id,
repo_type="space",
commit_message="Add requirements.txt"
)
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, auth_token, space_name_box, oauth_token: gr.OAuthToken | None):
if oauth_token:
if not paths:
paths = None
else:
paths = f"[\"{paths}\"]"
if not auth_token:
auth_token = None
else:
auth_token = f"[\"{auth_token}\"]"
create_hf_space(
oauth_token.token,
space_name_box,
gradio_app_code.format(
openapi_spec_url,
api_base_url,
paths,
methods,
auth_token
)
)
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"])
with gr.Accordion("Optional Settings", open=False):
paths = gr.Textbox(label="Regex to filter paths by", placeholder=".*user.*", info="Only include API endpoints that match this regex")
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")
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, auth_token, space_name_box],
outputs=None
)
demo.launch() |