#!/usr/bin/env python3
"""Example MCP client for the Agentic Security stdio server.

The default command lists the tools exposed by ``agentic_security.mcp.main``.
If the Agentic Security HTTP app is running, pass ``--call`` to invoke one of
the no-argument HTTP-backed tools through MCP.
"""

from __future__ import annotations

import argparse
import asyncio
import json
import os
import sys
from typing import Any

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

NO_ARGUMENT_TOOLS = {"get_data_config", "get_spec_templates", "stop_scan"}


def _build_server_params(agentic_security_url: str | None) -> StdioServerParameters:
    env = os.environ.copy()
    if agentic_security_url:
        env["AGENTIC_SECURITY_URL"] = agentic_security_url

    return StdioServerParameters(
        command=sys.executable,
        args=["-m", "agentic_security.mcp.main"],
        env=env,
    )


def _jsonable(value: Any) -> Any:
    if hasattr(value, "model_dump"):
        return value.model_dump(mode="json")
    if isinstance(value, (list, tuple)):
        return [_jsonable(item) for item in value]
    if isinstance(value, dict):
        return {key: _jsonable(item) for key, item in value.items()}
    return value


async def run_client(agentic_security_url: str | None, call_tool: str | None) -> None:
    server_params = _build_server_params(agentic_security_url)

    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            tools = await session.list_tools()
            tool_names = [tool.name for tool in tools.tools]

            print("Available Agentic Security MCP tools:")
            for tool in tools.tools:
                description_lines = (tool.description or "").strip().splitlines()
                description = (
                    description_lines[0] if description_lines else "No description"
                )
                print(f"- {tool.name}: {description}")

            if not call_tool:
                return

            if call_tool not in tool_names:
                raise ValueError(
                    f"Unknown tool {call_tool!r}. Available tools: {', '.join(tool_names)}"
                )
            if call_tool not in NO_ARGUMENT_TOOLS:
                raise ValueError(
                    f"{call_tool!r} requires arguments. This example only calls "
                    f"no-argument tools: {', '.join(sorted(NO_ARGUMENT_TOOLS))}"
                )

            result = await session.call_tool(call_tool, arguments={})
            print()
            print(f"{call_tool} result:")
            print(json.dumps(_jsonable(result), indent=2))


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="List Agentic Security MCP tools and optionally call one.",
    )
    parser.add_argument(
        "--agentic-security-url",
        default=None,
        help=(
            "Agentic Security HTTP app URL. Defaults to AGENTIC_SECURITY_URL "
            "or http://0.0.0.0:8718 in the server."
        ),
    )
    parser.add_argument(
        "--call",
        choices=sorted(NO_ARGUMENT_TOOLS),
        help="Optional no-argument MCP tool to call after listing tools.",
    )
    return parser.parse_args()


if __name__ == "__main__":
    args = parse_args()
    asyncio.run(run_client(args.agentic_security_url, args.call))
