Skip to main content
Glama
miyamamoto

JVLink MCP Server

by miyamamoto

execute_template_query

Generate and execute SQL queries from templates with custom parameters to retrieve Japanese horse racing data.

Instructions

テンプレートからSQLを生成して実行

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
template_nameYes
paramsYes

Implementation Reference

  • The MCP tool handler function for 'execute_template_query'. It receives a template_name and parameters, calls render_template() to generate SQL, executes it via DatabaseConnection, and returns results (up to 100 rows).
    @mcp.tool()
    def execute_template_query(template_name: str, **params) -> dict:
        """テンプレートからSQLを生成して実行"""
        try:
            sql, query_params = render_template(template_name, **params)
            with DatabaseConnection() as db:
                result_df = db.execute_safe_query(sql, params=query_params)
                return {
                    "success": True,
                    "template": template_name,
                    "parameters": params,
                    "generated_sql": sql,
                    "query_params": list(query_params),
                    "rows": len(result_df),
                    "columns": result_df.columns.tolist(),
                    "data": result_df.head(100).to_dict(orient="records"),
                    "note": "max 100 rows" if len(result_df) > 100 else None
                }
        except ValueError as e:
            return {"success": False, "error": str(e), "hint": "Use list_query_templates to see available templates"}
        except Exception as e:
            return {"success": False, "error": str(e)}
  • The @mcp.tool() decorator registers 'execute_template_query' as an MCP tool with FastMCP.
    @mcp.tool()
    def execute_template_query(template_name: str, **params) -> dict:
  • The render_template() function that generates SQL and parameters from a named template. Called by the handler to produce the parameterized SQL query.
    def render_template(template_name: str, **params) -> Tuple[str, tuple]:
        """テンプレートにパラメータを適用してSQLとパラメータタプルを生成
    
        Args:
            template_name: テンプレート名
            **params: パラメータ(テンプレートで定義されたもの)
    
        Returns:
            (SQL文字列, パラメータタプル) のタプル
    
        Raises:
            ValueError: テンプレートが存在しない、または必須パラメータが不足している場合
    
        Examples:
            >>> sql, query_params = render_template('favorite_win_rate', ninki=1, venue='東京')
            >>> sql, query_params = render_template('jockey_stats', jockey_name='武豊', limit=10)
        """
        if template_name not in QUERY_TEMPLATES:
            raise ValueError(
                f"テンプレート '{template_name}' が見つかりません。"
                f"利用可能なテンプレート: {list(QUERY_TEMPLATES.keys())}"
            )
    
        template = QUERY_TEMPLATES[template_name]
        template_params = template["parameters"]
        sql_template = template["sql"]
    
        # 必須パラメータのチェック
        for param_name, param_info in template_params.items():
            if param_info.get("required", False) and param_name not in params:
                raise ValueError(
                    f"必須パラメータ '{param_name}' が指定されていません。"
                    f"説明: {param_info.get('description', 'なし')}"
                )
    
        # パラメータを整形して格納
        formatted_params = {}
        query_params = []  # プレースホルダに対応するパラメータリスト
    
        for key, value in params.items():
            if value is None:
                continue
    
            # 人気順位の変換(INTEGER型)
            if key == "ninki":
                formatted_params[key] = "?"
                query_params.append(_to_int(value))
    
            # 競馬場名の変換
            elif key == "venue":
                formatted_params["venue_condition"] = "AND JyoCD = ?"
                query_params.append(_zero_pad_code(_venue_to_code(value)))
    
            # グレードの変換
            elif key == "grade":
                formatted_params["grade_condition"] = "AND r.GradeCD = ?"
                query_params.append(_grade_to_code(value))
    
            # 年の条件(INTEGER型)
            elif key == "year":
                # テンプレートSQL内に {year} プレースホルダがある場合は直接埋め込み
                if "{year}" in sql_template:
                    formatted_params["year"] = "?"
                    query_params.append(_to_int(value))
                else:
                    formatted_params["year_condition"] = "AND Year = ?"
                    query_params.append(_to_int(value))
    
            elif key == "year_from":
                formatted_params["year_condition"] = "AND Year >= ?"
                query_params.append(_to_int(value))
    
            # 騎手名の条件 - パラメータ化クエリ
            elif key == "jockey_name":
                formatted_params["jockey_condition"] = "AND KisyuRyakusyo LIKE ?"
                query_params.append('%' + str(value) + '%')
    
            # レース名の条件 - パラメータ化クエリ
            elif key == "race_name":
                # race_searchテンプレートではSQL内に既に LIKE ? があるので
                # formatted_paramsには入れずquery_paramsにだけ追加(先頭に挿入)
                query_params.insert(0, '%' + str(value) + '%')
    
            # 国内限定フラグ
            elif key == "domestic_only":
                if value:
                    formatted_params["domestic_condition"] = "AND CAST(r.JyoCD AS INTEGER) BETWEEN 1 AND 10"
                else:
                    formatted_params["domestic_condition"] = ""
    
            # 種牡馬名の条件 - パラメータ化クエリ
            elif key == "sire_name":
                formatted_params["sire_condition"] = "AND u.Ketto3InfoBamei1 LIKE ?"
                query_params.append('%' + str(value) + '%')
    
            # 距離の条件(INTEGER型)
            elif key == "kyori":
                formatted_params["kyori_condition"] = "AND Kyori = ?"
                query_params.append(_to_int(value))
    
            # 馬名 - パラメータ化クエリ(テンプレートSQL内の LIKE '%{horse_name}%' を置換)
            elif key == "horse_name":
                formatted_params[key] = "?"
                # horse_nameはテンプレート内で '%{horse_name}%' として使われるので
                # プレースホルダ置換後に処理する(下記の後処理で対応)
                query_params.append('%' + str(value) + '%')
    
            # 競馬場コード
            elif key == "jyo_cd":
                formatted_params[key] = "?"
                query_params.append(_zero_pad_code(value))
    
            # 数値として使われるパラメータ
            elif key in ("kaiji", "nichiji", "race_num"):
                formatted_params[key] = "?"
                query_params.append(_to_int(value))
    
            # 月日パラメータ(MMDD形式、数字のみ許可)
            elif key == "month_day":
                if not str(value).strip().isdigit():
                    raise ValueError(f"month_day に不正な値が指定されました: {value!r}")
                formatted_params[key] = "?"
                query_params.append(str(value).strip())
    
            # limit等の数値パラメータ
            elif key == "limit":
                formatted_params[key] = "?"
                query_params.append(_to_int(value))
    
            # その他はそのまま
            else:
                formatted_params[key] = value
    
        # デフォルト値の設定
        for param_name, param_info in template_params.items():
            if param_name not in formatted_params and "default" in param_info:
                default_val = param_info["default"]
                # bool型のデフォルト(domestic_only等)は条件文字列として処理
                if param_info.get("type") == "bool":
                    if param_name == "domestic_only" and default_val:
                        formatted_params["domestic_condition"] = "AND CAST(r.JyoCD AS INTEGER) BETWEEN 1 AND 10"
                else:
                    formatted_params[param_name] = "?"
                    query_params.append(default_val)
    
        # 条件が指定されていない場合は空文字に
        condition_keys = [
            "venue_condition", "year_condition", "jockey_condition",
            "sire_condition", "kyori_condition", "grade_condition",
            "domestic_condition"
        ]
        for cond_key in condition_keys:
            if cond_key not in formatted_params:
                formatted_params[cond_key] = ""
    
        # テンプレートに適用
        try:
            sql = sql_template.format(**formatted_params)
        except KeyError as e:
            raise ValueError(f"テンプレートに必要なパラメータが不足しています: {e}")
    
        # race_result等で '{field}' が '?' になった場合、クォートを除去
        sql = sql.replace("'?'", "?")
    
        # 余分な空白行を削除
        sql_lines = [line for line in sql.split("\n") if line.strip()]
        sql = "\n".join(sql_lines)
    
        return sql, tuple(query_params)
  • The QUERY_TEMPLATES dictionary defining all available templates (e.g., favorite_win_rate, jockey_stats, race_result) with their parameters and SQL patterns.
    QUERY_TEMPLATES = {
        "favorite_win_rate": {
            "description": "人気別勝率を計算",
            "parameters": {
                "ninki": {
                    "type": "int",
                    "description": "人気順位(1-18)",
                    "required": True,
                },
                "venue": {
                    "type": "str",
                    "description": "競馬場名(札幌、函館、福島、新潟、東京、中山、中京、京都、阪神、小倉)",
                    "required": False,
                },
                "year_from": {
                    "type": "str",
                    "description": "集計開始年(YYYY形式)",
                    "required": False,
                },
            },
            "sql": """
    SELECT
        COUNT(*) as total_races,
        SUM(CASE WHEN KakuteiJyuni = 1 THEN 1 ELSE 0 END) as wins,
        SUM(CASE WHEN KakuteiJyuni <= 3 THEN 1 ELSE 0 END) as top3,
        ROUND(100.0 * SUM(CASE WHEN KakuteiJyuni = 1 THEN 1 ELSE 0 END) / COUNT(*), 1) as win_rate,
        ROUND(100.0 * SUM(CASE WHEN KakuteiJyuni <= 3 THEN 1 ELSE 0 END) / COUNT(*), 1) as top3_rate
    FROM NL_SE
    WHERE Ninki = {ninki}
      {venue_condition}
      {year_condition}
      AND KakuteiJyuni IS NOT NULL
      AND KakuteiJyuni > 0
    """,
        },
        "jockey_stats": {
            "description": "騎手成績を集計",
            "parameters": {
                "jockey_name": {
                    "type": "str",
                    "description": "騎手名(部分一致可)",
                    "required": False,
                },
                "year": {
                    "type": "str",
                    "description": "対象年(YYYY形式)",
                    "required": False,
                },
                "limit": {
                    "type": "int",
                    "description": "表示件数",
                    "required": False,
                    "default": 20,
                },
            },
            "sql": """
    SELECT
        KisyuRyakusyo as jockey_name,
        COUNT(*) as total_rides,
        SUM(CASE WHEN KakuteiJyuni = 1 THEN 1 ELSE 0 END) as wins,
        SUM(CASE WHEN KakuteiJyuni <= 2 THEN 1 ELSE 0 END) as top2,
        SUM(CASE WHEN KakuteiJyuni <= 3 THEN 1 ELSE 0 END) as top3,
        ROUND(100.0 * SUM(CASE WHEN KakuteiJyuni = 1 THEN 1 ELSE 0 END) / COUNT(*), 1) as win_rate,
        ROUND(100.0 * SUM(CASE WHEN KakuteiJyuni <= 3 THEN 1 ELSE 0 END) / COUNT(*), 1) as top3_rate
    FROM NL_SE
    WHERE KakuteiJyuni IS NOT NULL
      AND KakuteiJyuni > 0
      {jockey_condition}
      {year_condition}
    GROUP BY KisyuRyakusyo
    ORDER BY wins DESC, win_rate DESC
    LIMIT {limit}
    """,
        },
        "frame_stats": {
            "description": "枠番別成績を集計",
            "parameters": {
                "venue": {
                    "type": "str",
                    "description": "競馬場名",
                    "required": False,
                },
                "kyori": {
                    "type": "str",
                    "description": "距離(メートル単位、例:1600)",
                    "required": False,
                },
            },
            "sql": """
    SELECT
        Wakuban as frame_number,
        COUNT(*) as total_runs,
        SUM(CASE WHEN KakuteiJyuni = 1 THEN 1 ELSE 0 END) as wins,
        SUM(CASE WHEN KakuteiJyuni <= 3 THEN 1 ELSE 0 END) as top3,
        ROUND(100.0 * SUM(CASE WHEN KakuteiJyuni = 1 THEN 1 ELSE 0 END) / COUNT(*), 1) as win_rate,
        ROUND(100.0 * SUM(CASE WHEN KakuteiJyuni <= 3 THEN 1 ELSE 0 END) / COUNT(*), 1) as top3_rate
    FROM NL_SE
    WHERE KakuteiJyuni IS NOT NULL
      AND KakuteiJyuni > 0
      {venue_condition}
      {kyori_condition}
    GROUP BY Wakuban
    ORDER BY Wakuban
    """,
        },
        "race_result": {
            "description": "レース結果を取得(レース情報とJOIN)",
            "parameters": {
                "year": {
                    "type": "str",
                    "description": "開催年(YYYY形式)",
                    "required": True,
                },
                "month_day": {
                    "type": "str",
                    "description": "開催月日(MMDD形式)",
                    "required": True,
                },
                "jyo_cd": {
                    "type": "str",
                    "description": "競馬場コード(01-10)",
                    "required": True,
                },
                "kaiji": {
                    "type": "str",
                    "description": "開催回次",
                    "required": True,
                },
                "nichiji": {
                    "type": "str",
                    "description": "開催日次",
                    "required": True,
                },
                "race_num": {
                    "type": "str",
                    "description": "レース番号(1-12)",
                    "required": True,
                },
            },
            "sql": """
    SELECT
        r.Hondai as race_name,
        r.GradeCD as grade,
        r.Kyori as distance,
        r.TrackCD as track_code,
        s.KakuteiJyuni as finish_position,
        s.Wakuban as frame_number,
        s.Umaban as horse_number,
        s.Bamei as horse_name,
        s.KisyuRyakusyo as jockey_name,
        s.Ninki as popularity,
        s.Odds as odds,
        s.Time as time,
        s.HaronTimeL3 as last_3f,
        s.BaTaijyu as weight
    FROM NL_RA r
    JOIN NL_SE s
      ON r.Year = s.Year
      AND r.MonthDay = s.MonthDay
      AND r.JyoCD = s.JyoCD
      AND r.Kaiji = s.Kaiji
      AND r.Nichiji = s.Nichiji
      AND r.RaceNum = s.RaceNum
    WHERE r.Year = {year}
      AND r.MonthDay = '{month_day}'
      AND r.JyoCD = '{jyo_cd}'
      AND r.Kaiji = {kaiji}
      AND r.Nichiji = {nichiji}
      AND r.RaceNum = {race_num}
    ORDER BY CAST(s.KakuteiJyuni AS INTEGER)
    """,
        },
        "grade_race_list": {
            "description": "重賞レース一覧を取得",
            "parameters": {
                "grade": {
                    "type": "str",
                    "description": "グレード(G1、G2、G3、リステッド)",
                    "required": False,
                },
                "year": {
                    "type": "str",
                    "description": "対象年(YYYY形式)",
                    "required": False,
                },
                "venue": {
                    "type": "str",
                    "description": "競馬場名",
                    "required": False,
                },
                "limit": {
                    "type": "int",
                    "description": "表示件数",
                    "required": False,
                    "default": 50,
                },
            },
            "sql": """
    SELECT
        r.Year as year,
        r.MonthDay as month_day,
        r.JyoCD as venue_code,
        r.Hondai as race_name,
        r.GradeCD as grade,
        r.Kyori as distance,
        r.TrackCD as track_code,
        r.SyussoTosu as horse_count
    FROM NL_RA r
    WHERE r.GradeCD IN ('A', 'B', 'C', 'D')
      {grade_condition}
      {year_condition}
      {venue_condition}
    ORDER BY r.Year DESC, r.MonthDay DESC
    LIMIT {limit}
    """,
        },
        "horse_pedigree": {
            "description": "馬の血統情報を取得",
            "parameters": {
                "horse_name": {
                    "type": "str",
                    "description": "馬名(部分一致可)",
                    "required": True,
                },
            },
            "sql": """
    SELECT
        u.Bamei as horse_name,
        u.KettoNum as ketto_num,
        u.SexCD as sex_code,
        u.BirthDate as birth_date,
        u.Ketto3InfoBamei1 as sire,
        u.Ketto3InfoBamei2 as dam,
        u.Ketto3InfoBamei5 as broodmare_sire,
        u.SanchiName as birthplace,
        u.BreederName as breeder,
        u.BanusiName as owner
    FROM NL_UM u
    WHERE u.Bamei LIKE {horse_name}
    ORDER BY u.Bamei
    LIMIT 20
    """,
        },
        "sire_stats": {
            "description": "種牡馬別成績を集計",
            "parameters": {
                "sire_name": {
                    "type": "str",
                    "description": "種牡馬名(部分一致可)",
                    "required": False,
                },
                "year": {
                    "type": "str",
                    "description": "対象年(YYYY形式)",
                    "required": False,
                },
                "limit": {
                    "type": "int",
                    "description": "表示件数",
                    "required": False,
                    "default": 20,
                },
            },
            "sql": """
    SELECT
        u.Ketto3InfoBamei1 as sire_name,
        COUNT(*) as total_runs,
        SUM(CASE WHEN s.KakuteiJyuni = 1 THEN 1 ELSE 0 END) as wins,
        SUM(CASE WHEN s.KakuteiJyuni <= 3 THEN 1 ELSE 0 END) as top3,
        ROUND(100.0 * SUM(CASE WHEN s.KakuteiJyuni = 1 THEN 1 ELSE 0 END) / COUNT(*), 1) as win_rate,
        ROUND(100.0 * SUM(CASE WHEN s.KakuteiJyuni <= 3 THEN 1 ELSE 0 END) / COUNT(*), 1) as top3_rate
    FROM NL_SE s
    JOIN NL_UM u ON s.KettoNum = u.KettoNum
    WHERE s.KakuteiJyuni IS NOT NULL
      AND s.KakuteiJyuni > 0
      AND u.Ketto3InfoBamei1 IS NOT NULL
      AND LENGTH(u.Ketto3InfoBamei1) > 0
      {sire_condition}
      {year_condition}
    GROUP BY u.Ketto3InfoBamei1
    HAVING COUNT(*) >= 10
    ORDER BY wins DESC, win_rate DESC
    LIMIT {limit}
    """,
        },
        # === NAR(地方競馬)テンプレート ===
        "nar_favorite_win_rate": {
            "description": "NAR地方競馬の人気別勝率を計算",
            "parameters": {
                "ninki": {"type": "int", "description": "人気順位(1-18)", "required": True},
                "venue": {"type": "str", "description": "地方競馬場名(大井、船橋、川崎、浦和、名古屋、園田等)", "required": False},
                "year_from": {"type": "str", "description": "集計開始年(YYYY形式)", "required": False},
            },
            "sql": """
    SELECT
        COUNT(*) as total_races,
        SUM(CASE WHEN KakuteiJyuni = 1 THEN 1 ELSE 0 END) as wins,
        SUM(CASE WHEN KakuteiJyuni <= 3 THEN 1 ELSE 0 END) as top3,
        ROUND(100.0 * SUM(CASE WHEN KakuteiJyuni = 1 THEN 1 ELSE 0 END) / COUNT(*), 1) as win_rate,
        ROUND(100.0 * SUM(CASE WHEN KakuteiJyuni <= 3 THEN 1 ELSE 0 END) / COUNT(*), 1) as top3_rate
    FROM NL_SE_NAR
    WHERE Ninki = {ninki}
      {venue_condition}
      {year_condition}
      AND KakuteiJyuni IS NOT NULL
      AND KakuteiJyuni > 0
    """,
        },
        "nar_jockey_stats": {
            "description": "NAR地方競馬の騎手成績を集計",
            "parameters": {
                "jockey_name": {"type": "str", "description": "騎手名(部分一致可)", "required": False},
                "year": {"type": "str", "description": "対象年(YYYY形式)", "required": False},
                "limit": {"type": "int", "description": "表示件数", "required": False, "default": 20},
            },
            "sql": """
    SELECT
        KisyuRyakusyo as jockey_name,
        COUNT(*) as total_rides,
        SUM(CASE WHEN KakuteiJyuni = 1 THEN 1 ELSE 0 END) as wins,
        SUM(CASE WHEN KakuteiJyuni <= 3 THEN 1 ELSE 0 END) as top3,
        ROUND(100.0 * SUM(CASE WHEN KakuteiJyuni = 1 THEN 1 ELSE 0 END) / COUNT(*), 1) as win_rate,
        ROUND(100.0 * SUM(CASE WHEN KakuteiJyuni <= 3 THEN 1 ELSE 0 END) / COUNT(*), 1) as top3_rate
    FROM NL_SE_NAR
    WHERE KakuteiJyuni IS NOT NULL AND KakuteiJyuni > 0
      {jockey_condition}
      {year_condition}
    GROUP BY KisyuRyakusyo
    ORDER BY wins DESC, win_rate DESC
    LIMIT {limit}
    """,
        },
        "nar_venue_stats": {
            "description": "NAR地方競馬場別の1番人気成績を集計",
            "parameters": {
                "year_from": {"type": "str", "description": "集計開始年", "required": False},
            },
            "sql": """
    SELECT
        JyoCD as venue_code,
        COUNT(*) as total_races,
        SUM(CASE WHEN KakuteiJyuni = 1 THEN 1 ELSE 0 END) as wins,
        ROUND(100.0 * SUM(CASE WHEN KakuteiJyuni = 1 THEN 1 ELSE 0 END) / COUNT(*), 1) as win_rate
    FROM NL_SE_NAR
    WHERE Ninki = 1 AND KakuteiJyuni IS NOT NULL AND KakuteiJyuni > 0
      {year_condition}
    GROUP BY JyoCD
    ORDER BY win_rate DESC
    """,
        },
        "race_search": {
            "description": "レース名で検索(国内限定オプション付き)",
            "parameters": {
                "race_name": {
                    "type": "str",
                    "description": "レース名(部分一致、例: ダービー)",
                    "required": True,
                },
                "year_from": {
                    "type": "str",
                    "description": "集計開始年(YYYY形式)",
                    "required": False,
                },
                "domestic_only": {
                    "type": "bool",
                    "description": "国内(JRA)レースのみに限定する(JyoCD 01-10)。デフォルトtrue",
                    "required": False,
                    "default": True,
                },
                "limit": {
                    "type": "int",
                    "description": "表示件数",
                    "required": False,
                    "default": 50,
                },
            },
            "sql": """
    SELECT
        r.Year as year,
        r.MonthDay as month_day,
        r.JyoCD as venue_code,
        r.Hondai as race_name,
        r.GradeCD as grade,
        r.Kyori as distance,
        r.TrackCD as track_code,
        r.SyussoTosu as horse_count
    FROM NL_RA r
    WHERE r.Hondai LIKE ?
      {domestic_condition}
      {year_condition}
    ORDER BY r.Year DESC, r.MonthDay DESC
    LIMIT {limit}
    """,
        },
        "track_condition_stats": {
            "description": "馬場状態別成績を分析(特定の馬)",
            "parameters": {
                "horse_name": {
                    "type": "str",
                    "description": "馬名(部分一致可)",
                    "required": True,
                },
            },
            "sql": """
    SELECT
        s.Bamei as horse_name,
        r.TrackCD as track_code,
        COUNT(*) as total_runs,
        SUM(CASE WHEN s.KakuteiJyuni = 1 THEN 1 ELSE 0 END) as wins,
        SUM(CASE WHEN s.KakuteiJyuni <= 3 THEN 1 ELSE 0 END) as top3,
        ROUND(100.0 * SUM(CASE WHEN s.KakuteiJyuni = 1 THEN 1 ELSE 0 END) / COUNT(*), 1) as win_rate
    FROM NL_SE s
    JOIN NL_RA r
      ON s.Year = r.Year
      AND s.MonthDay = r.MonthDay
      AND s.JyoCD = r.JyoCD
      AND s.Kaiji = r.Kaiji
      AND s.Nichiji = r.Nichiji
      AND s.RaceNum = r.RaceNum
    WHERE s.Bamei LIKE {horse_name}
      AND s.KakuteiJyuni IS NOT NULL
      AND s.KakuteiJyuni > 0
    GROUP BY s.Bamei, r.TrackCD
    ORDER BY total_runs DESC
    """,
        },
    }
  • The list_query_templates tool returns available templates and shows usage format 'execute_template_query(template_name, **params)', serving as the schema hint.
    @mcp.tool()
    def list_query_templates() -> dict:
        """利用可能なクエリテンプレート一覧を取得"""
        templates = get_templates_list()
        return {
            "templates": templates,
            "total": len(templates),
            "usage": "execute_template_query(template_name, **params)"
        }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description must disclose behavioral traits. It only says 'generate and execute', implying potential write operations, but no warnings about destructive effects, authentication needs, or side effects are given.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single short sentence, which is concise, but it sacrifices informative value. It provides no structure or additional detail, making it minimally adequate.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness1/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (executing SQL), the description is severely incomplete. It lacks parameter details, output specification, and behavioral context, leaving significant gaps for safe and correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 0% description coverage, and the description adds no meaning to the parameters. 'template_name' and 'params' are unexplained, leaving the agent to guess their format or role.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states the tool generates and executes SQL from a template, but it does not clarify what 'template' means or how it relates to sibling tools like get_sql_generation_prompt or validate_sql_query. The purpose is vaguely clear but lacks specificity.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use this tool versus alternatives. It does not mention prerequisites, context, or exclusions, leaving the agent to infer usage from the name and siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/miyamamoto/jvlink-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server