Purl MCP Server
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| get_projectA | Get the current Purl project structure from the live editor. Returns cells, objects, and settings. |
| list_objectsA | List all objects in the current project or a specific cell. Returns names, types, tags, and key properties. |
| get_objectA | Get full details of a single object — all properties, dynamics config, states, children, scripts. Use this when you need to inspect or debug a specific object. |
| get_scriptB | Get the script code for an object or cell in the current project. |
| search_scriptsA | Search every script in the project (all cell-script tabs and all object-level scripts, templates included) for a substring. Returns one entry per matching line with target/scriptName/lineNumber/line so the result is directly actionable. Pass contextLines: N to also return the N lines above and below each match — usually enough to skip a follow-up get_script call. Use this whenever you need to answer "where is X used / set / played / spawned / destroyed / handled" before making changes — the only reliable way to enumerate distributed Purl logic. |
| read_project_scriptsA | Dump every script in the project (cell scripts + object scripts, all tabs) in one call. Use this for whole-project audits, refactors, or "find every place X is wired" questions where you need the surrounding code, not just matching lines (use search_scripts when you only need matching lines). Returns a flat array of {target, scriptName, code, lineCount}, sorted scene-order. Skips empty scripts by default. Soft byte cap (default 50000) bounds the response — if exceeded, returns what fits plus a truncation marker; refine via cellName or targets. |
| get_script_historyA | Get the MCP edit history of a specific script — all past versions written via update_script, most recent last. Use this to recover code that was accidentally wiped by a previous edit. Each entry shows the timestamp, the user prompt that triggered the edit, and the full code snapshot. |
| validate_scriptA | Validate Purl DSL script syntax using the full parser. Returns detailed error messages with line/column numbers, or confirms valid syntax with a summary of detected events and actions. |
| dsl_referenceA | Get reference documentation for the Purl DSL scripting language. Query by category (events, actions, functions, variables, operators, properties, transitions, concepts) or get the full syntax reference. The "concepts" category covers object variables, component child access, message parameters, spawn parameters, and variable scopes. |
| update_scriptA | Full-replace a script: writes the supplied code as the new content. Use for genuine rewrites or to create a new script slot. For incremental edits to an existing script, prefer edit_script — its anchor matching catches stale baselines that update_script would silently overwrite. If you must full-replace an existing script, pass expectedVersion (from get_script or read_project_scripts) so a stale write fails loudly instead of stomping concurrent changes. |
| edit_scriptA | Edit an existing script via a list of find/replace anchors — the safe way to change part of a script without overwriting unrelated lines. Each edit's "old" string must match exactly once in the current content (or set replaceAll: true to replace every occurrence). Edits are applied sequentially in the order supplied; each later edit operates on the result of the previous. Atomic: if any anchor fails to match (zero or multiple), the whole call is rejected with line numbers — nothing is written. Use this for targeted changes; use update_script only for full rewrites or brand-new scripts. Stale baselines fail loudly because the anchor either matches today's content (safe) or doesn't (rejected). |
| set_propertyA | Set properties on an object. Merges the given properties into the object. Use for position (x, y), size (width, height), visibility, tags, content (for text), dynamics settings, etc. For nested-shape properties (arrays/maps) the call is guarded: |
| add_objectA | Add a new object (prime or component) to a cell. Optionally adds the object as a child of an existing component via parentName. Returns the created object summary. |
| remove_objectA | Remove an object from a cell. If the object is a component, its children are also removed. |
| move_objectA | Reparent an existing object within the same cell. Use |
| update_cellC | Set cell-level properties like gravity, wind, windAngle, size, or label. |
| get_statesA | Get presets/states for a component. Returns child list, preset names with per-child property overrides, reference snapshot, and state groups. Only works on components. |
| clone_objectA | Deep-clone an object (with all children, presets, states, scripts) into the same or a different cell. Generates new unique IDs and renames children to avoid name collisions. Optionally lands the clone as a child of an existing component via parentName. |
| bulk_cloneA | Deep-clone one source object into many copies in a single call — the batch counterpart to clone_object. Names come from either an explicit |
| bulk_set_propertyA | Set properties on multiple objects in a single call. Useful for mass-editing children of a component (e.g., changing colors). Each entry specifies an object name and properties to set. Same nested-write guards as set_property apply per entry: pass |
| push_valueA | Append a value to an array at a nested path. Additive — only the target array is touched; siblings and unrelated entries stay intact. Errors if the target isn't an array. Use this instead of |
| set_value_at_pathA | Set a single nested value at the given path. Auto-creates intermediate objects/arrays where needed. Siblings stay intact. Use this instead of |
| remove_value_at_pathA | Remove a single value at the given path. For arrays, removes the element at the bracket index and shifts subsequent elements down. For maps, deletes the keyed entry. Errors if the path doesn't exist (no silent no-ops). |
| get_debug_logsA | Read recent debug log entries from the running play session. Useful for verifying what the engine saw after a test action (input received? error fired? audio playing?). Only entries for currently-enabled domains exist in the buffer — call set_debug_domains first to enable categories. |
| set_debug_domainsA | Enable a specific set of debug chips on the running play session. Replaces the current set (pass empty array to disable all). Valid domains: collision, movement, follow, dodge, physics, zone, camera, mask, input, audio, errors, log. |
| clear_debug_logsA | Empty the debug log buffer. Use before triggering a test action so the subsequent get_debug_logs call only contains entries from that action. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 26 tools
Most tools target distinct resources/actions (e.g., get_object vs list_objects vs get_script), but some overlap exists: get_states duplicates part of get_object, and edit_script/update_script both modify scripts. Descriptions are detailed enough to guide selection, though the boundary between set_property, set_value_at_path, and push_value could confuse an agent at first.
Tool names mostly follow a clear verb_noun pattern (get_, set_, add_, remove_, move_, update_, clone_, bulk_). Minor deviations like 'dsl_reference' (noun phrase) and the path-specific names (set_value_at_path, remove_value_at_path) are still readable and consistent in style. Overall predictable, with slight irregularity.
26 tools is on the heavy side, but the server covers a broad domain (project structure, object lifecycle, scripting, debugging, batch operations). The count feels justified, though the many variations (bulk_*, *_at_path, push_value) inflate the total and could be consolidated without losing clarity.
The tool surface covers the main workflows: object CRUD (add/remove/get/list/clone/move), script management (read/search/edit/update/validate/history), property mutation (set/bulk/path-specific), and debugging (logs/domains). Missing operations like cell creation/deletion or renaming are minor gaps; overall the domain is well covered.