Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ dependencies = [
"urllib3>=2.0.0",
"openpyxl>=3.1.0",
"fastmcp>=3.0.2",
"httpx>=0.27.0",
]

[project.urls]
Expand Down
1 change: 1 addition & 0 deletions qualytics/cli/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ def auth_status():
ssl_label = "[green]enabled[/green]" if ssl_verify else "[yellow]disabled[/yellow]"

print(f"[bold]{host}[/bold]")
print(f" URL: {url}")
print(f" Status: {status_icon}")
print(f" Token: {masked_token}")
if expiry_line:
Expand Down
43 changes: 40 additions & 3 deletions qualytics/cli/mcp_cmd.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
"""CLI command to start the Qualytics MCP server."""

import httpx
import typer
from fastmcp.client import Client
from fastmcp.client.transports import StreamableHttpTransport
from fastmcp.server import create_proxy

from . import add_suggestion_callback
from ..config import load_config, CONFIG_PATH
from ..mcp.server import auth_status

mcp_app = typer.Typer(name="mcp", help="Start an MCP server for LLM integrations")
add_suggestion_callback(mcp_app, "mcp")
Expand Down Expand Up @@ -30,6 +36,10 @@ def mcp_serve(
):
"""Start the Qualytics MCP server for Claude Code, Cursor, and other LLM tools.

Proxies the full Qualytics MCP tool set from the remote deployment over a
local stdio transport, combining the platform's native tool surface with
easy connectivity for desktop LLM clients.

STDIO transport (default) is used by Claude Code and Cursor.
Streamable-HTTP transport is available for network-accessible deployments.

Expand All @@ -44,9 +54,36 @@ def mcp_serve(
}
}
"""
from ..mcp.server import mcp
config = load_config()
if config is None:
raise typer.BadParameter(
f"Not authenticated. Run 'qualytics auth login' or "
f"'qualytics auth init'. Config expected at {CONFIG_PATH}",
param_hint="authentication",
)

url = config.get("url", "").rstrip("/")
token = config.get("token", "")
ssl_verify = config.get("ssl_verify", True)

if not url or not token:
raise typer.BadParameter(
f"Config at {CONFIG_PATH} is missing 'url' or 'token'. "
f"Run 'qualytics auth login' to re-authenticate.",
param_hint="authentication",
)

remote_transport = StreamableHttpTransport(
url=f"{url}/mcp",
auth=token,
httpx_client_factory=lambda **kwargs: httpx.AsyncClient(
verify=ssl_verify, **kwargs
),
)
proxy = create_proxy(Client(remote_transport), name="Qualytics")
proxy.add_tool(auth_status)

if transport in ("streamable-http", "http", "sse"):
mcp.run(transport="streamable-http", host=host, port=port)
proxy.run(transport="streamable-http", host=host, port=port)
else:
mcp.run(transport="stdio")
proxy.run(transport="stdio")
Loading
Loading