mirror of
https://github.com/Skyvern-AI/skyvern.git
synced 2025-09-15 17:59:42 +00:00
skyvern run server, skyvern run mcp (#2072)
This commit is contained in:
parent
d168da4653
commit
c7e62f45d3
3 changed files with 85 additions and 33 deletions
4
skyvern/__main__.py
Normal file
4
skyvern/__main__.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
from skyvern.cli.commands import app
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app()
|
|
@ -1,3 +1,4 @@
|
||||||
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
|
@ -6,11 +7,35 @@ import time
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import typer
|
import typer
|
||||||
|
import uvicorn
|
||||||
from click import Choice
|
from click import Choice
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
from mcp.server.fastmcp import FastMCP
|
||||||
|
|
||||||
|
from skyvern.agent import SkyvernAgent
|
||||||
|
from skyvern.config import settings
|
||||||
|
from skyvern.schemas.runs import RunEngine
|
||||||
from skyvern.utils import detect_os, get_windows_appdata_roaming, migrate_db
|
from skyvern.utils import detect_os, get_windows_appdata_roaming, migrate_db
|
||||||
|
|
||||||
|
mcp = FastMCP("Skyvern")
|
||||||
|
skyvern_agent = SkyvernAgent(
|
||||||
|
base_url=settings.SKYVERN_BASE_URL,
|
||||||
|
api_key=settings.SKYVERN_API_KEY,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
async def skyvern_run_task(prompt: str, url: str) -> str:
|
||||||
|
"""Browse the internet using a browser to achieve a user goal.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
prompt: brief description of what the user wants to accomplish
|
||||||
|
url: the target website for the user goal
|
||||||
|
"""
|
||||||
|
res = await skyvern_agent.run_task(prompt=prompt, url=url, engine=RunEngine.skyvern_v1)
|
||||||
|
return res.model_dump()["output"]
|
||||||
|
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
app = typer.Typer()
|
app = typer.Typer()
|
||||||
|
@ -115,18 +140,54 @@ def setup_postgresql() -> None:
|
||||||
print("Database and user created successfully.")
|
print("Database and user created successfully.")
|
||||||
|
|
||||||
|
|
||||||
|
async def _setup_local_organization() -> str:
|
||||||
|
"""
|
||||||
|
Returns the API key for the local organization generated
|
||||||
|
"""
|
||||||
|
from skyvern.forge import app
|
||||||
|
from skyvern.forge.sdk.core import security
|
||||||
|
from skyvern.forge.sdk.db.enums import OrganizationAuthTokenType
|
||||||
|
from skyvern.forge.sdk.services.org_auth_token_service import API_KEY_LIFETIME
|
||||||
|
|
||||||
|
organization = await app.DATABASE.get_organization_by_domain("skyvern.local")
|
||||||
|
if not organization:
|
||||||
|
organization = await app.DATABASE.create_organization(
|
||||||
|
organization_name="Skyvern-local",
|
||||||
|
domain="skyvern.local",
|
||||||
|
max_steps_per_run=10,
|
||||||
|
max_retries_per_step=3,
|
||||||
|
)
|
||||||
|
api_key = security.create_access_token(
|
||||||
|
organization.organization_id,
|
||||||
|
expires_delta=API_KEY_LIFETIME,
|
||||||
|
)
|
||||||
|
# generate OrganizationAutoToken
|
||||||
|
await app.DATABASE.create_org_auth_token(
|
||||||
|
organization_id=organization.organization_id,
|
||||||
|
token=api_key,
|
||||||
|
token_type=OrganizationAuthTokenType.api,
|
||||||
|
)
|
||||||
|
org_auth_token = await app.DATABASE.get_valid_org_auth_token(
|
||||||
|
organization_id=organization.organization_id,
|
||||||
|
token_type=OrganizationAuthTokenType.api,
|
||||||
|
)
|
||||||
|
return org_auth_token.token
|
||||||
|
|
||||||
|
|
||||||
@app.command(name="init")
|
@app.command(name="init")
|
||||||
def init(
|
def init(
|
||||||
openai_api_key: str = typer.Option(..., help="The OpenAI API key"),
|
openai_api_key: str = typer.Option(..., help="The OpenAI API key"),
|
||||||
log_level: str = typer.Option("CRITICAL", help="The log level"),
|
log_level: str = typer.Option("INFO", help="The log level"),
|
||||||
) -> None:
|
) -> None:
|
||||||
setup_postgresql()
|
setup_postgresql()
|
||||||
|
api_key = asyncio.run(_setup_local_organization())
|
||||||
# Generate .env file
|
# Generate .env file
|
||||||
with open(".env", "w") as env_file:
|
with open(".env", "w") as env_file:
|
||||||
env_file.write("ENABLE_OPENAI=true\n")
|
env_file.write("ENABLE_OPENAI=true\n")
|
||||||
env_file.write(f"OPENAI_API_KEY={openai_api_key}\n")
|
env_file.write(f"OPENAI_API_KEY={openai_api_key}\n")
|
||||||
env_file.write(f"LOG_LEVEL={log_level}\n")
|
env_file.write(f"LOG_LEVEL={log_level}\n")
|
||||||
env_file.write("ARTIFACT_STORAGE_PATH=./artifacts\n")
|
env_file.write("ARTIFACT_STORAGE_PATH=./artifacts\n")
|
||||||
|
env_file.write(f"SKYVERN_API_KEY={api_key}\n")
|
||||||
print(".env file created with the parameters provided.")
|
print(".env file created with the parameters provided.")
|
||||||
|
|
||||||
|
|
||||||
|
@ -332,8 +393,8 @@ def get_command_config(host_system: str, command: str, target: str, env_vars: st
|
||||||
raise Exception(f"Unsupported host system: {host_system}")
|
raise Exception(f"Unsupported host system: {host_system}")
|
||||||
|
|
||||||
|
|
||||||
@run_app.command(name="mcp")
|
@run_app.command(name="setupmcp")
|
||||||
def run_mcp() -> None:
|
def setup_mcp() -> None:
|
||||||
"""Configure MCP for different Skyvern deployments."""
|
"""Configure MCP for different Skyvern deployments."""
|
||||||
host_system = detect_os()
|
host_system = detect_os()
|
||||||
|
|
||||||
|
@ -432,3 +493,20 @@ def setup_cursor_config(host_system: str, command: str, target: str, env_vars: s
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error configuring Cursor: {e}")
|
print(f"Error configuring Cursor: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@run_app.command(name="server")
|
||||||
|
def run_server() -> None:
|
||||||
|
port = int(os.environ.get("PORT", 8000))
|
||||||
|
uvicorn.run(
|
||||||
|
"skyvern.forge.api_app:app",
|
||||||
|
host="0.0.0.0",
|
||||||
|
port=port,
|
||||||
|
log_level="info",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@run_app.command(name="mcp")
|
||||||
|
def run_mcp() -> None:
|
||||||
|
"""Run the MCP server."""
|
||||||
|
mcp.run(transport="stdio")
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
import os
|
|
||||||
|
|
||||||
from mcp.server.fastmcp import FastMCP
|
|
||||||
|
|
||||||
from skyvern.agent import SkyvernAgent
|
|
||||||
|
|
||||||
mcp = FastMCP("Skyvern")
|
|
||||||
|
|
||||||
if "SKYVERN_MCP_CLOUD_URL" in os.environ and "SKYVERN_MCP_API_KEY" in os.environ:
|
|
||||||
skyvern_agent = SkyvernAgent(
|
|
||||||
base_url=os.environ.get("SKYVERN_MCP_CLOUD_URL"), api_key=os.environ.get("SKYVERN_MCP_API_KEY")
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
skyvern_agent = SkyvernAgent()
|
|
||||||
|
|
||||||
|
|
||||||
@mcp.tool()
|
|
||||||
async def skyvern_run_task(prompt: str, url: str) -> str:
|
|
||||||
"""Browse the internet using a browser to achieve a user goal.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
prompt: brief description of what the user wants to accomplish
|
|
||||||
url: the target website for the user goal
|
|
||||||
"""
|
|
||||||
res = await skyvern_agent.run_task(prompt=prompt, url=url)
|
|
||||||
return res.model_dump()["output"]
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
mcp.run(transport="stdio")
|
|
Loading…
Add table
Add a link
Reference in a new issue