# -*- coding: utf-8 -*-
"""Location: ./mcpgateway/routers/toolops_router.py
Copyright 2025
SPDX-License-Identifier: Apache-2.0
Authors: Jay Bandlamudi
Toolops Router Module
This module provides FastAPI endpoints for managing Toolops functionalities
.It supports tool test case generation , tool meta-data enrichment and tool
test case execution with an agent.
The module handles API endpoints created for several toolops features.
"""
# Standard
from typing import Any, Dict, List
# Third-Party
from fastapi import APIRouter, Depends, HTTPException, Query, status
import orjson
from pydantic import BaseModel, Field
from sqlalchemy.orm import Session
# First-Party
from mcpgateway.main import get_db
from mcpgateway.middleware.rbac import get_current_user_with_permissions, require_permission
from mcpgateway.services.logging_service import LoggingService
from mcpgateway.services.tool_service import ToolService
from mcpgateway.toolops.toolops_altk_service import enrich_tool, execute_tool_nl_test_cases, validation_generate_test_cases
# Initialize router
toolops_router = APIRouter(prefix="/toolops", tags=["Toolops"])
# Initialize services
tool_service = ToolService()
# Logging
logging_service = LoggingService()
logger = logging_service.get_logger(__name__)
# ---------- Utility ----------
class ToolNLTestInput(BaseModel):
"""
Toolops test input format to run NL test cases of a tool using agent
Args:
tool_id : Unique Tool ID
tool_nl_test_cases: List of natural language test cases for testing MCP tool with the agent
Returns:
This class defines tool NL test input format and returns nothing.
"""
tool_id: str | None = Field(default=None, title="Tool ID", max_length=300)
tool_nl_test_cases: list | None = Field(default=None, title="List of natural language test cases for testing MCP tool with the agent")
# ---------- ROUTES ----------
# First-Party
# Toolops APIs - Generating test cases , Tool enrichment #
@toolops_router.post("/validation/generate_testcases")
@require_permission("admin.system_config")
async def generate_testcases_for_tool(
tool_id: str = Query(None, description="Tool ID"),
number_of_test_cases: int = Query(2, description="Maximum number of tool test cases"),
number_of_nl_variations: int = Query(1, description="Number of NL utterance variations per test case"),
mode: str = Query("generate", description="Three modes: 'generate' for test case generation, 'query' for obtaining test cases from DB , 'status' to check test generation status"),
db: Session = Depends(get_db),
_user=Depends(get_current_user_with_permissions),
) -> List[Dict]:
"""
Generate test cases for a tool
This endpoint handles the automated test case generation for a tool by accepting
a tool id . The `require_auth` dependency ensures that
the user is authenticated before proceeding.
Args:
tool_id: Tool ID in context forge.
number_of_test_cases: Number of test cases to generate for the given tools (optional)
number_of_nl_variations: Number of Natural language variations(parapharses) per test case (optional)
mode: Three supported modes - 'generate' for test case generation, 'query' for obtaining test cases from DB , 'status' to check test generation status
db: DB session to connect with database
Returns:
List: A list of test cases generated for the tool , each test case is dictionary object
Raises:
HTTPException: If the request body contains invalid JSON, a 400 Bad Request error is raised.
"""
try:
# logger.debug(f"Authenticated user {user} is initializing the protocol.")
test_cases = await validation_generate_test_cases(tool_id, tool_service, db, number_of_test_cases, number_of_nl_variations, mode)
return test_cases
except orjson.JSONDecodeError:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Invalid JSON in request body",
)
@toolops_router.post("/validation/execute_tool_nl_testcases")
@require_permission("admin.system_config")
async def execute_tool_nl_testcases(tool_nl_test_input: ToolNLTestInput, db: Session = Depends(get_db), _user=Depends(get_current_user_with_permissions)) -> List:
"""
Execute test cases for a tool
This endpoint handles the automated test case generation for a tool by accepting
a tool id . The `require_auth` dependency ensures that
the user is authenticated before proceeding.
Args:
tool_nl_test_input: NL test case format input to run test cases with agent , it contains\
- tool_id: Tool ID in context forge\
- tool_nl_test_cases: List of natural language test cases (utteances) for testing MCP tool with the agent
db: DB session to connect with database
Returns:
List: A list of tool outputs after agent execution for the provided tool nl test cases
Raises:
HTTPException: If the request body contains invalid JSON, a 400 Bad Request error is raised.
"""
try:
# logger.debug(f"Authenticated user {user} is initializing the protocol.")
tool_id = tool_nl_test_input.tool_id
tool_nl_test_cases = tool_nl_test_input.tool_nl_test_cases
tool_nl_test_cases_output = await execute_tool_nl_test_cases(tool_id, tool_nl_test_cases, tool_service, db)
return tool_nl_test_cases_output
except orjson.JSONDecodeError:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Invalid JSON in request body",
)
@toolops_router.post("/enrichment/enrich_tool")
@require_permission("admin.system_config")
async def enrich_a_tool(tool_id: str = Query(None, description="Tool ID"), db: Session = Depends(get_db), _user=Depends(get_current_user_with_permissions)) -> dict[str, Any]:
"""
Enriches an input tool
Args:
tool_id: Unique Tool ID MCP-CF.
db: The database session used to interact with the data store.
Returns:
result: A dict having the keys "tool_id", "tool_name", "original_desc" and "enriched_desc" with their corresponding values
Raises:
HTTPException: If the request body contains invalid JSON, a 400 Bad Request error is raised.
"""
try:
logger.info("Running tool enrichment for Tool - " + tool_id)
enriched_tool_description, tool_schema = await enrich_tool(tool_id, tool_service, db)
result: dict[str, Any] = {}
result["tool_id"] = tool_id
result["tool_name"] = tool_schema.name
result["original_desc"] = tool_schema.description
result["enriched_desc"] = enriched_tool_description
# logger.info ("result: "+ json.dumps(result, indent=4, sort_keys=False))
return result
except Exception as e:
logger.info("Error in tool enrichment for Tool - " + str(e))
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Invalid JSON in request body" + str(e),
) from e