Skip to main content

Lightfielder Viewport | MCP Server

The Viewport app exposes its full scripting API as a Model Context Protocol (MCP) server, allowing AI coding assistants and other MCP clients to control the Viewport programmatically.


Architecture​

┌────────────────────────────────────────────────────────────┐
│ Viewport App │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ ScriptingServer (TCP JSON-RPC, port 9876) │ │
│ │ Routes lf.* commands to the active scene │ │
│ └─────────────────────┬───────────────────────────────┘ │
└────────────────────────┼──────────────────────────────────┘
│ TCP 127.0.0.1:9876
┌────────────────────────▼──────────────────────────────────┐
│ Extras/mcp_server.py (Python MCP server) │
│ Translates MCP tool calls → JSON-RPC to Viewport app │
│ stdio transport for opencode / Claude Desktop etc. │
└────────────────────────────────────────────────────────────┘

Quick Start​

1. Launch the Viewport App​

The app automatically starts the JSON-RPC server on port 9876.

MCP Server: listening on port 9876

Visible in the app's console output.

2. Install Dependencies​

pip install mcp

3. Connect with MCP​

Using opencode​

Add to your opencode.json:

{
"mcpServers": {
"viewport": {
"command": "python3",
"args": ["/path/to/Viewport/Extras/mcp_server.py"]
}
}
}

Using Claude Desktop​

Add to your Claude Desktop config:

{
"mcpServers": {
"viewport": {
"command": "python3",
"args": ["/path/to/Viewport/Extras/mcp_server.py"]
}
}
}

Using any MCP client​

python3 /path/to/Viewport/Extras/mcp_server.py

4. Interactive Test Mode​

If the mcp library is not installed, mcp_server.py falls back to a direct TCP test mode where you can send JSON-RPC commands manually:

$ python3 Extras/mcp_server.py
MCP library not installed. Running in test mode.
Connected to Viewport app at 127.0.0.1:9876

> {"method":"new_scene","params":[],"id":1}
{
"jsonrpc": "2.0",
"result": true,
"id": 1
}
> {"method":"create_primitive","params":["cube"],"id":2}
{
"jsonrpc": "2.0",
"result": true,
"id": 2
}

Available MCP Tools​

Scene / File​

ToolDescriptionParameters
new_sceneCreate an empty scene(none)
open_sceneOpen a scene filepath: string
save_sceneSave current scene(none)
save_scene_asSave to new pathpath: string
revert_sceneRevert to saved(none)
import_fileImport a reference filepath: string

Create Objects​

ToolDescriptionParameters
create_cameraAdd a camera(none)
create_locatorAdd a locator(none)
create_groupAdd an empty group(none)
create_referenceAdd a reference container(none)
create_audioAdd an audio container(none)
create_noteAdd a note(none)
create_primitiveAdd a mesh primitivetype: cube | cone | sphere | cylinder | pyramid | torus
create_lightAdd a lighttype: ambient | area | directional | dome | point | spot | sphere | tube

Selection​

ToolDescriptionParameters
select_allSelect everything(none)
deselect_allClear selection(none)
select_by_nameSelect by partial name matchname: string
select_by_idSelect by exact IDid: string
get_selectedGet details of selected objects(none)

Edit​

ToolDescriptionParameters
undoUndo last action(none)
redoRedo last undone action(none)
cutCut selected(none)
copyCopy selected(none)
pastePaste from clipboard(none)
delete_selectedDelete selected objects(none)
duplicate_selectedDuplicate selected objects(none)
group_selectedGroup selected(none)
ungroup_selectedUngroup selected group(none)

Transform​

ToolDescriptionParameters
set_transformSet object transformid, position[3], rotation[3], scale[3]
get_transformGet object transform as JSONid: string
set_parentReparent an objectchild_id, parent_id (empty to detach)
rename_objectRename an objectid, name

Viewport​

ToolDescriptionParameters
frame_allFrame all objects(none)
go_homeReset camera to home(none)
set_camera_modeSwitch camera modemode: orbit | fps
set_shadingSet shading modemode: shaded | boundingBox | points | wireframe | none
set_interactionSet interaction modemode: selection | transform

Display Toggles​

ToolDescription
show_gridToggle grid
show_verticesToggle vertex display
show_normalsToggle normal display
show_edgesToggle edge wireframe
show_xrayToggle X-Ray
show_hudToggle HUD overlay
show_fpsToggle FPS counter
show_detailsToggle detail info
show_distanceToggle distance display
show_renderToggle render info
show_selectedToggle selected info
show_camera_viewToggle camera view info
show_polygonsToggle polygon count
show_camera_locatorsToggle camera icons
show_light_locatorsToggle light icons
show_locator_iconsToggle locator icons
show_skyboxToggle skybox

Each takes a single parameter on: boolean.

Windows​

ToolDescription
open_outlinerOpen Outliner window
open_attributesOpen Attributes window
open_history_stackOpen History Stack
close_outlinerClose Outliner
close_attributesClose Attributes
close_history_stackClose History Stack

Layouts​

ToolDescriptionParameters
save_layoutSave window layoutname: string
load_layoutLoad window layoutname: string
list_layoutsList saved layouts(none)

Tabs​

ToolDescription
new_tabOpen new scene in OS tab
close_tabClose current tab

Scripts & Examples​

ToolDescriptionParameters
run_scriptRun a script filepath: string
list_scriptsList available scripts(none)
open_scripts_folderOpen Scripts folder(none)
open_exampleOpen an example scenename: string
list_examplesList available examples(none)
open_examples_folderOpen Examples folder(none)

History​

ToolDescriptionParameters
clear_undoClear undo history(none)
save_undoSave undo events to filepath: string
load_undoLoad undo events from filepath: string

Example Usage (openocode / MCP Client)​

Basic Scene Setup​

Tool: new_scene
Tool: create_light type="directional"
Tool: create_primitive type="cube"
Tool: frame_all

Building and Exporting​

Tool: new_scene
Tool: create_light type="directional"
Tool: create_primitive type="cube"
Tool: get_selected → [{"id":"obj_3","name":"Cube",...}]
Tool: set_transform id="obj_3", position=[2,0,0], rotation=[0,0,0], scale=[1,1,1]
Tool: save_scene_as path="/Users/me/output.jsonc"

Scene Inspection​

Tool: open_scene path="/Users/me/scene.jsonc"
Tool: get_selected → [...]
Tool: select_by_name name="Camera"
Tool: get_selected → [{"type":"camera",...}]
Tool: get_transform id="obj_1" → {"position":[0,2,6],...}

Duplicating and Grouping​

Tool: select_all
Tool: duplicate_selected
Tool: group_selected

Layout Management​

Tool: save_layout name="my_workspace"
Tool: close_attributes
Tool: close_outliner
Tool: load_layout name="my_workspace"

Configuration​

Changing the Port​

Set the port via environment variable or UserDefaults:

# Environment variable (Python MCP server)
VIEWPORT_MCP_PORT=9877 python3 Extras/mcp_server.py

# UserDefaults (Viewport app)
defaults write com.Lightfielder.Viewport MCPPort 9877

Network​

  • The TCP server binds to 127.0.0.1 only (localhost).
  • Firewall-friendly with no incoming connections from the network.
  • Transport: raw TCP with newline-delimited JSON.

JSON-RPC Wire Format​

Request:

{"jsonrpc":"2.0","method":"frame_all","params":[],"id":1}

Success response:

{"jsonrpc":"2.0","result":true,"id":1}

Error response:

{"jsonrpc":"2.0","error":{"code":-1,"message":"Object not found"},"id":1}

Data response:

{"jsonrpc":"2.0","result":[{"id":"obj_3","name":"Cube"}],"id":1}

Troubleshooting​

"Cannot connect to Viewport app"

  • Ensure the Viewport app is running.
  • Check the port: lsof -i :9876
  • Verify no firewall is blocking localhost connections.

"Method not found"

  • Check the tool name matches exactly (case-sensitive, snake_case).
  • Update mcp_server.py if the app has been updated with new functions.

"Operation failed"

  • The action could not be completed so check the Viewport app's console output for details.
  • Common causes: no active scene, no object selected, invalid object ID.