@@ -700,6 +700,24 @@ def _get_version_description(pack_format: int) -> str:
700700 },
701701 "required" : ["action" ]
702702 }
703+ ),
704+ Tool (
705+ name = "validate_function" ,
706+ description = "Validate a Minecraft function file (.mcfunction) using Spyglass API to check command syntax correctness." ,
707+ inputSchema = {
708+ "type" : "object" ,
709+ "properties" : {
710+ "function_path" : {
711+ "type" : "string" ,
712+ "description" : "Path to the .mcfunction file to validate"
713+ },
714+ "version" : {
715+ "type" : "string" ,
716+ "description" : "Minecraft version to validate against (e.g., '1.21', '1.20.4')"
717+ }
718+ },
719+ "required" : ["function_path" , "version" ]
720+ }
703721 )
704722]
705723
@@ -1247,6 +1265,7 @@ def handle_misode_get_recipes(version: str, recipe_type: str = "all", search: st
12471265 return {"success" : False , "error" : str (e )}
12481266
12491267
1268+ < << << << HEAD
12501269def get_minecraft_directory (minecraft_dir : str = None ) -> Path :
12511270 """Get the Minecraft directory path based on OS"""
12521271 if minecraft_dir :
@@ -1632,6 +1651,105 @@ def handle_launcher_clear_minecraft_logs(launcher_type: str, instance_name: str)
16321651 "error" : f"Error clearing logs: { str (e )} " ,
16331652 "launcher_type" : launcher_type ,
16341653 "instance_name" : instance_name
1654+ == == == =
1655+ def handle_validate_function (function_path : str , version : str ) -> dict :
1656+ """
1657+ Validate a Minecraft function file using Spyglass API.
1658+
1659+ Reads the .mcfunction file and validates each command against
1660+ the command syntax tree from Spyglass API.
1661+ """
1662+ import os
1663+
1664+ try :
1665+ # Check if file exists
1666+ if not os .path .exists (function_path ):
1667+ return {
1668+ "success" : False ,
1669+ "error" : f"File not found: { function_path } "
1670+ }
1671+
1672+ # Check if file has correct extension
1673+ if not function_path .endswith ('.mcfunction' ):
1674+ return {
1675+ "success" : False ,
1676+ "error" : "File must have .mcfunction extension"
1677+ }
1678+
1679+ # Read the function file
1680+ with open (function_path , 'r' , encoding = 'utf-8' ) as f :
1681+ lines = f .readlines ()
1682+
1683+ # Get available commands from Spyglass
1684+ try :
1685+ available_commands = spyglass .get_command_names (version )
1686+ except Exception as e :
1687+ return {
1688+ "success" : False ,
1689+ "error" : f"Failed to fetch command data from Spyglass API: { str (e )} "
1690+ }
1691+
1692+ # Validate each line
1693+ errors = []
1694+ warnings = []
1695+ valid_commands = []
1696+
1697+ for line_num , line in enumerate (lines , 1 ):
1698+ # Strip whitespace and check if line is empty or comment
1699+ stripped = line .strip ()
1700+
1701+ if not stripped or stripped .startswith ('#' ):
1702+ # Comments and empty lines are valid
1703+ continue
1704+
1705+ # Extract the command (first word)
1706+ parts = stripped .split ()
1707+ if not parts :
1708+ continue
1709+
1710+ command_name = parts [0 ].lstrip ('/' )
1711+
1712+ # Check if command exists in the version
1713+ if command_name not in available_commands :
1714+ errors .append ({
1715+ "line" : line_num ,
1716+ "content" : stripped ,
1717+ "type" : "unknown_command" ,
1718+ "message" : f"Unknown command: '{ command_name } '"
1719+ })
1720+ else :
1721+ # Command exists - basic validation passed
1722+ valid_commands .append ({
1723+ "line" : line_num ,
1724+ "command" : command_name ,
1725+ "content" : stripped
1726+ })
1727+
1728+ # Build result
1729+ result = {
1730+ "success" : True ,
1731+ "file" : function_path ,
1732+ "version" : version ,
1733+ "total_lines" : len (lines ),
1734+ "validated_commands" : len (valid_commands ),
1735+ "errors" : errors ,
1736+ "warnings" : warnings ,
1737+ "is_valid" : len (errors ) == 0
1738+ }
1739+
1740+ # Add summary message
1741+ if len (errors ) == 0 :
1742+ result ["message" ] = f"✓ All { len (valid_commands )} commands are valid for Minecraft { version } "
1743+ else :
1744+ result ["message" ] = f"✗ Found { len (errors )} error(s) in function file"
1745+
1746+ return result
1747+
1748+ except Exception as e :
1749+ return {
1750+ "success" : False ,
1751+ "error" : f"Error validating function: { str (e )} "
1752+ >> > >> >> copilot / add - validate - function - command
16351753 }
16361754
16371755
@@ -1729,6 +1847,7 @@ async def call_tool(name: str, arguments: dict) -> list[TextContent]:
17291847 recipe_type = arguments .get ("recipe_type" , "all" ),
17301848 search = arguments .get ("search" )
17311849 )
1850+ << << << < HEAD
17321851 # Minecraft logs tools
17331852 elif name == "get_minecraft_logs" :
17341853 result = handle_get_minecraft_logs (
@@ -1760,6 +1879,12 @@ async def call_tool(name: str, arguments: dict) -> list[TextContent]:
17601879 result = handle_launcher_clear_minecraft_logs (
17611880 launcher_type = arguments ["launcher_type" ],
17621881 instance_name = arguments ["instance_name" ]
1882+ == == == =
1883+ elif name == "validate_function" :
1884+ result = handle_validate_function (
1885+ function_path = arguments ["function_path" ],
1886+ version = arguments ["version" ]
1887+ >> > >> >> copilot / add - validate - function - command
17631888 )
17641889 else :
17651890 raise ValueError (f"Unknown tool: { name } " )
0 commit comments