Skip to main content
Glama

scripts

Destructive

Manage GDScript files in Godot projects: create templates, read, write, attach to scene nodes, list, and delete scripts.

Instructions

GDScript file CRUD.

Actions (required params -> optional):

  • create (script_path -> extends="Node", content, project_path): generate template

  • read (script_path -> project_path)

  • write (script_path, content -> project_path): replace entire file

  • attach (script_path, scene_path, node_name -> project_path): link to scene node

  • list (-> project_path)

  • delete (script_path -> project_path)

script_path: relative to project root (e.g., "scripts/player.gd").

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actionYesAction to perform
project_pathNoPath to Godot project directory
script_pathNoPath to GDScript file
extendsNoBase class for create (default: Node)
contentNoScript content (for create/write)
scene_pathNoScene file path (for attach)
node_nameNoTarget node name (for attach)

Implementation Reference

  • Main handler function for the 'scripts' tool. Dispatches to action-specific functions (create, read, write, attach, list, delete).
    export async function handleScripts(action: string, args: Record<string, unknown>, config: GodotConfig) {
      const baseDir = config.projectPath || process.cwd()
      // Validate args.project_path against the trusted baseDir to prevent path traversal vulnerabilities
      const projectPath = args.project_path ? safeResolve(baseDir, args.project_path as string) : config.projectPath
    
      if (!projectPath && action !== 'list') {
        // List handles missing projectPath internally, but others need it for safeResolve base
        // Though list also throws if missing. Let's rely on standard checks inside but ensure projectPath is available for resolution.
        // Actually, all actions check projectPath. We can resolve it early.
      }
    
      // Helper to resolve path securely
      const resolvePath = (path: string) => {
        if (!projectPath) {
          // Should be caught by action-specific checks, but fallback for safety
          throw new GodotMCPError('No project path specified', 'INVALID_ARGS', 'Provide project_path argument.')
        }
        return safeResolve(projectPath, path)
      }
    
      switch (action) {
        case 'create':
          return createScript(args, resolvePath)
        case 'read':
          return readScript(args, resolvePath)
        case 'write':
          return writeScript(args, resolvePath)
        case 'attach':
          return attachScript(args, resolvePath)
        case 'list':
          return listScripts(baseDir, projectPath ?? undefined)
        case 'delete':
          return deleteScript(args, resolvePath)
        default:
          throwUnknownAction(action, ['create', 'read', 'write', 'attach', 'list', 'delete'])
      }
    }
  • Input/output schema definition for the 'scripts' tool, including description, annotations, and input properties.
    {
      name: 'scripts',
      description:
        'GDScript file CRUD.\n\nActions (required params -> optional):\n- create (script_path -> extends="Node", content, project_path): generate template\n- read (script_path -> project_path)\n- write (script_path, content -> project_path): replace entire file\n- attach (script_path, scene_path, node_name -> project_path): link to scene node\n- list (-> project_path)\n- delete (script_path -> project_path)\n\nscript_path: relative to project root (e.g., "scripts/player.gd").',
      annotations: createAnnotations('Scripts', { destructive: true }),
      inputSchema: {
        type: 'object' as const,
        properties: {
          action: {
            type: 'string',
            enum: ['create', 'read', 'write', 'attach', 'list', 'delete'],
            description: 'Action to perform',
          },
          project_path: { type: 'string', description: 'Path to Godot project directory' },
          script_path: { type: 'string', description: 'Path to GDScript file' },
          extends: { type: 'string', description: 'Base class for create (default: Node)' },
          content: { type: 'string', description: 'Script content (for create/write)' },
          scene_path: { type: 'string', description: 'Scene file path (for attach)' },
          node_name: { type: 'string', description: 'Target node name (for attach)' },
        },
        required: ['action'],
      },
    },
  • Registration of all tools with the MCP server. The 'scripts' handler is mapped in TOOL_HANDLERS at line 493 and the schema is included in P0_TOOLS (lines 134-156).
    export function registerTools(server: Server, config: GodotConfig): void {
      server.setRequestHandler(ListToolsRequestSchema, async () => ({
        tools: TOOLS,
      }))
    
      server.setRequestHandler(CallToolRequestSchema, async (request) => {
        const { name, arguments: args = {} } = request.params
    
        try {
          let result: { content: Array<{ type: string; text: string }>; isError?: boolean }
          if (name === 'help') {
            result = await handleHelp(
              (args.action as string) || (args.tool_name as string),
              args as Record<string, unknown>,
            )
          } else {
            const handler = TOOL_HANDLERS[name]
            if (!handler) {
              const validTools = TOOLS.map((t) => t.name)
              const closest = findClosestMatch(name, validTools)
              const suggestion = closest ? ` Did you mean '${closest}'?` : ''
              throw new GodotMCPError(
                `Unknown tool: ${name}.${suggestion}`,
                'INVALID_ACTION',
                `Available tools: ${validTools.join(', ')}`,
              )
            }
            result = await handler(args.action as string, args as Record<string, unknown>, config)
          }
          return wrapToolResult(name, result)
        } catch (error) {
          return formatError(error)
        }
      })
    }
  • Import of the handleScripts function from the composite scripts module.
    import { handleScripts } from './composite/scripts.js'
  • Helper for creating a new GDScript file with optional template content.
    async function createScript(args: Record<string, unknown>, resolvePath: (path: string) => string) {
      const scriptPath = args.script_path as string
      if (!scriptPath)
        throw new GodotMCPError('No script_path specified', 'INVALID_ARGS', 'Provide script_path (e.g., "player.gd").')
      const extendsType = (args.extends as string) || 'Node'
      const content = (args.content as string) || getTemplate(extendsType)
    
      const fullPath = resolvePath(scriptPath)
      if (await pathExists(fullPath)) {
        throw new GodotMCPError(
          `Script already exists: ${scriptPath}`,
          'SCRIPT_ERROR',
          'Use write action to modify existing scripts.',
        )
      }
    
      await mkdir(dirname(fullPath), { recursive: true })
      await writeFile(fullPath, content, 'utf-8')
      return formatSuccess(`Created script: ${scriptPath}\nExtends: ${extendsType}`)
    }
Behavior3/5

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

Annotations already indicate destructiveHint=true and readOnlyHint=false. The description adds context that write 'replace entire file' and attach 'link to scene node', but lacks details on authentication requirements, error handling, or side effects beyond the listed actions. This provides moderate behavioral insight.

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

Conciseness4/5

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

The description is concise, using a structured list that is easy to scan. It front-loads the purpose and clearly separates actions. However, the use of arrows and parentheses might be slightly confusing for new users, slightly reducing clarity.

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

Completeness3/5

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

Given the tool's complexity (7 parameters, 6 actions) and lack of output schema, the description provides basic action definitions but omits details like return values, error scenarios, or the fact that project_path is often required. It is minimally adequate but leaves gaps for an AI agent to handle correctly.

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

Parameters4/5

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

With 100% schema description coverage, the baseline is 3. The description goes further by grouping parameters per action (e.g., create requires script_path, optional extends, content, project_path) and explaining each action's effect (e.g., 'generate template'). This adds meaningful usage context beyond the schema.

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

Purpose4/5

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

The description clearly states 'GDScript file CRUD' and enumerates specific actions (create, read, write, attach, list, delete), making the tool's purpose unambiguous. It distinguishes itself from sibling tools which cover different domains (animation, audio, etc.), so no confusion.

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?

The description does not provide guidance on when to use this tool versus alternatives. While sibling tools are distinct, there is no explicit advice on prerequisite conditions (e.g., project path must exist) or when to prefer one action over another for a given task.

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/n24q02m/better-godot-mcp'

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