flutter3d_mcp 1.0.0-rc.2
flutter3d_mcp: ^1.0.0-rc.2 copied to clipboard
MCP servers for flutter3d over stdio: a level editor and a model editor an agent can drive, the project server, and the kit every flutter3d server is built on.
1.0.0-rc.2 #
-
Breaking: the three servers say the version they are.
editorMcpVersion,modelMcpVersionandprojectMcpVersionare'1.0.0-rc.2', the pubspec's, where they said'1.0.0-rc.1'; a client that compared one with a literal reads the new number. -
Breaking:
command.runholds a plugin's command to what its own tool is held to. It ran any command the editor knew, so an agent drove the commands of a plugin that never asked for thetoolspermission, and a command its plugin said nothing about ran undercommand.run'swritesalthough its own tool is offered as destructive. Now a plugin withouttoolskeeps its commands in the editor, and a destructive plugin command is refused there and run through its own tool, whose hints make the host ask first. Built-in and application commands run as before. -
Breaking:
editorMcpSchemaVersionis'1.3.0'andmodelMcpSchemaVersion'1.2.0'. The level editor's server grew a tool since rc.1 (render.graph) and the modeller's a field (occlusionAffects, whichmaterial.setFieldtakes), so the schema each announces moves by a minor, and a host that cached a tool list against the old number knows to read it again. Code that compared either constant with its old value reads the newer number. -
material.setFieldnamesocclusionAffectsamong its fields:both,directorindirect, which light the material's occlusion map darkens. -
Breaking:
CommandTargetis a class. It was a record typedef whose optional fields showed it had grown once already; it is afinal classwith the same fields, each optional, and==. -
Breaking:
ModelSession.importtakessettings:, where it tookoptions:. A parameter or a field that holds a…Settingsis namedsettings, as every other one is, where some weretuning,configoroptions: the same value under one name.dart fixrenames the arguments and the fields. -
Breaking:
PlaySession.disposeisclose.dispose()is synchronous, as Flutter's is, and an end that has to be waited for isFuture<void> close(): aFuturefromdisposewas left unawaited by every caller that wrote it in a widget's owndispose.dart fixrenames the calls and the overrides. -
Breaking:
ToolTableServer.shutdownisToolTableServer.close. A server ends withclose, as a connection does; it stops answering and closes the channel as before.dart fixrenames the calls. -
render.graphin the level editor's server. The running game's last frame graph: the passes that ran with the resource versions they read and wrote, the ones left out with why, as JSON and as a Mermaid flowchart. Published under the name it is written with, so no alias promises a name no release had. -
Breaking:
editorMcpSchemaVersionis'1.3.0'.render.graphis a new tool, so the schemaflutter3d.editorannounces moves a minor past the 1.2.0 that 1.0.0-rc.1 published; code that compared the constant with'1.2.0'reads the new one. -
Breaking:
modelMcpSchemaVersionis'1.2.0'.material.setFieldtakesocclusionAffects, an addition to the modelling server's tools, so the schemaflutter3d.modelannounces moves a minor past the 1.1.0 that 1.0.0-rc.1 published; code that compared the constant with'1.1.0'reads the new one. -
A plugin's editor command reaches an agent only with the
toolspermission, and is never safer than it says.shareCommandsoffers a command as a tool of its own only when its plugin declaresPluginPermission.tools, asMcpTools.addToolholds a plugin's own tools to, and carries the command's hints, a command that gave none offered as destructive. -
Breaking: results that were records are final classes.
GameAsk,PieceReportandProjectRootanswered or held a record, which can never gain a field. Each answers a final class now, with the record's field names (a positional$1has a name of its own),==andhashCode. A field read compiles as before; a destructuring pattern names the class, andflutter3d_build:migraterewrites the$1reads. -
Breaking:
LevelCamerais a final class, where it was a record typedef a minor could never add a field to. It keepsfromandat, with==andhashCode; a record literal names the class. -
tools/listoffers each tool once, under its current name. The old names of renamed tools (209 here:render,addBrush,capture_drawand the rest) still answer when called, until 2.0, through the same brake, argument check and watcher as before; they are no longer listed, so an agent stops reading every renamed tool twice into its context, and a prompt cannot learn a name that is already on its way out. The snapshot keeps each one as analiasline, so dropping one is still a break the schema rule sees. -
The tools' contract is the plugin API's.
McpTools,McpToolRegistry,ProjectTool,ProjectToolRun,ToolCall,SessionToolCall,ToolSpec,ToolHintsandToolResultare declared inpackage:flutter3d_plugin_api/tools.dart;kit.dartandproject_tools.dartre-export them, so every import and every type is the one it was. -
Breaking: a tool's body takes one call object.
ProjectToolRun, whatMcpTools.addTooltakes, is a function of aToolCall(new: theargumentsand the publishedname), andOfferedTool.runof aSessionToolCall(new: the same with thesession), where they took the arguments' map and the session as parameters;OfferedTool.runOn(new) runs a tool outside a server. A minor can hand a tool progress, cancellation or the project's root as members of the call; a parameter added to the function would break every tool written against 1.0. -
Breaking: the application's tools may not take an area of the engine as their namespace.
addTool(tool, run, namespace: 'game')is refused, aslevelor any ofPluginManifest.reservedAreasandf3dare: the servers' own tools there would shadow the application's. Name them after the application. -
Breaking:
Answeris a class, andPictureAnsweris gone into it.Answer(did:, says:, png:)has the record'sdidandsaysand the picture a drawing tool hands back. A record never gains a field, which is why a second answer type existed at all; every tool a plugin writes returns this one, so it can carry more in a minor. -
The modeller's tools take American spellings (schema 1.1.0).
paint.strokeandpaint.vertexColortakecolorand a sample'scenter, andobject.setOrigintakesboundsCenter; the British words are still read, so no agent breaks.light.addtakes anarealight. -
Breaking:
ToolNametakes its hints by name.ToolName('level.save', hints: ToolHints.destroys): an optional positional argument could never have a named one beside it. -
A plugin's tools are published under its namespace.
McpTools.addToolanddeclareSchemaVersionfile a plugin's tools underPluginManifest.namespace, so the editor half of a package (wind.editor) offerswind.gustbeside the runtime half's tools, and one schema version covers them; a plugin naming another namespace is refused with aPluginException.shareCommandsoffers a plugin's editor command under the same name. The editor server's schema version is 1.2.0. -
A plugin's editor command is a tool of its own.
shareCommands(new, ineditor.dart) offers every command a plugin added toEditorPiecesas a project tool,<plugin id>.<name>, its argument hints as its input schema, kept in step as plugins are switched on and off;serveEditorMcpdoes it for the plugins it installs. -
The editor server lists what the plugins brought and runs their importers.
plugin.listnames their commands, hints, gizmos, importers and asset-browser entries;asset.importruns an importer on a file inside the project and writes only inside it. -
An experiment is edited beside the level.
experiment.open,experiment.list,experiment.edit,experiment.undoandexperiment.saveopen anf3d.experimentinside the project, make oneExperimentEditat a time with the document reader's refusals as answers, and write it back. The editor server's schema version is 1.1.0. -
Breaking: every file tool reads and writes inside one directory.
ProjectRoot.resolve(new, inkit.dart, withPathOutsideRootExceptionunderResourceException) takes each path a tool is handed — the modeller'sproject.save,project.export,project.import,project.journal, the editor'slevel.save,capture.open,render.saveCapture— and refuses one that leaves the project by.., an absolute path elsewhere or a link.ModelSession,EditorSessiontakeroot:; left out, it is the nearest directory above the document with apubspec.yaml, or the document's own. A save under another spelling of a generated level is refused like the plain one. -
Breaking: the loopback transport takes its token in the header only.
Authorization: Bearer <token>; a?token=query is refused. The token is compared in constant time, a body overLoopbackMcpServer.defaultMaxBodyBytes(64 MiB,maxBodyBytes:onstart) is answered413, andwriteMcpSessionFilewrites the file0600on macOS and Linux. -
play.startrefuses a device id a shell would read. On Windows the id is an argument tocmd.exe; one outsideisFlutterDeviceIdis refused before a run is made. -
The editor server draws its level through
flutter3d_level_scene, whereLevelScenelives since it leftflutter3d_editor_core. -
McpToolRegistryis declared here, the slotMcpToolsfills; it was a marker influtter3d_plugin_api. -
Breaking: a call watcher is handed one
AnsweredCall.ToolTableServer.onCallandonProjectCall,ModelMcpServer(onCall:)andModelHttpServer.start(onToolCall:)take anAnsweredCall(tool name, arguments, answer, elapsed) where they took four arguments, so a feed keeps working when a call says more.model.dartre-exports it andPictureAnswer. -
Breaking:
ToolContentis anabstract base class, no longersealed, so an exhaustiveswitchover it needs a default. It gainsToolAudio,ToolResource,ToolResourceLink,ToolOtherContentandToolContent.fromJson; content of a kind this build does not know is kept asToolOtherContentinstead of becoming an emptyToolText. -
McpTools.declareSchemaVersionis honoured whenever it is called, and returns aRegistration. Tools already added get the version and a running server offers them again; through a plugin's view the declaration is withdrawn with the plugin. -
Every editor tool declares an
outputSchema(editorAnswerSchema) and answersstructuredContent{did, says, selection, hasPicture}.render.saveCaptureandplay.keepTapeare marked destructive: they write over a file. -
The servers' schema versions start at 1.0.0 with the first stable release (editor, model, project).
-
The stdio servers exit with the command's contract codes: 2 for usage and 1 for a document they cannot open, not 64 and 66; a project that will not open throws a
ProjectFormatException. -
New: one package for what was three.
flutter3d_mcp_kit,flutter3d_editor_mcp,flutter3d_model_mcpare libraries of this package now:kit.dart,editor.dart,model.dart, each with the API its package had, andflutter3d_mcp.dartexports them all.dart run flutter3d_build:migratemoves a project's dependencies and imports; the packages' own histories are indoc/changelogs/. -
The commands keep their names:
dart run flutter3d_mcp:editor_mcp,:model_mcpand:project_mcp, and each server announces the name and schema version it did. The skills areflutter3d-mcp-editor-*andflutter3d-mcp-model-*.
kit.dart, from flutter3d_mcp_kit 1.0.0-rc.1 #
-
Breaking: tools and answers are flutter3d's own types. A tool is a
ToolSpec(name, description, JSON Schema input and output,ToolHints,_meta) and an answer aToolResult(ToolTextandToolImagecontent,structuredContent,isError). The MCP library underneath is pre-1.0, and none of its types is in a signature any more:OfferedTool.toolisOfferedTool.spec,ProjectTool.toolisProjectTool.spec,ProjectToolRunandonProjectCallspeakToolResult,toResult,resultOfandpictureResultOfanswerToolResult,refuseArgumentstakes aToolSpec, andOfferedPrompt.promptis gone (the server builds the prompt itself).ToolTableServerholds the protocol server instead of extending it, so it no longer hasMCPServer's members;done,shutdown,serverInfoandofferedSpecsare what a caller needs. -
One naming scheme,
area.verb, with the old names kept. A server takesnames:— each tool's written name to aToolName, the name it is published under and its hints — and keeps the written name answering as an alias until 2.0.ToolName.patternis the rule; the area may be camel-cased like any other word (textureGraph.addNode), which the modelling server's names need to start at all. -
Every server says what its tools do and which schema it speaks. Each tool carries
ToolHints(read-only, destructive, idempotent, open world) as the protocol's annotations and its schema version in_meta(flutter3d/schemaVersion); theinitializeresult carries it in_metatoo, and every server answersflutter3d.schemawith its own version and each plugin namespace's. A structured answer comes from a tool that declared itsoutputSchema. -
A plugin asks for the
toolspermission to add a tool.McpTools.addToolrefuses a plugin whose manifest does not listPluginPermission.tools, with aPluginExceptionnaming it, so a person installing a plugin sees that it talks to agents.McpTools.declareSchemaVersiongives a namespace's own schema version, andschema_snapshot --plugin package:<package>#<Plugin>intool/apisnapshots a plugin's tools to itsapi/<package>.plugin.mcp. -
ProjectMcpServerannounces itself asflutter3d.project, the scheme every server follows now (flutter3d.editor,flutter3d.sim,flutter3d.diagnostics,flutter3d.model,flutter3d.plugins). Schema 1.1.0. -
1.0.0 is a promise: strict semver from there. This release candidate already keeps it. A patch fixes bugs and breaks nothing, a minor adds, and a break waits for a major. The whole public API is stable, with no experimental exceptions, and is held to the snapshot in
api/. A deprecated name stays until the next major and for at least six months, and says what replaces it. CONTRIBUTING.md has the rules, and SUPPORT.md says which releases get fixes and on which platforms. -
The project server starts from the command line, as
dart run flutter3d_mcp_kit:project_mcp.project_tools.dartexportsMcpToolsalone, withoutdart:io, so an application built for the browser can fill the registry too. -
A server announces its schema version, and a renamed tool keeps its old name.
ToolTableServertakes an optionalschemaVersion, sent in theinitializeresult'sserverInfobesideversion, so a host can tell whether the tool list it cached still holds; it moves only when the tools do. And an optionalaliases, old name to new: the old name stays intools/listwith the new tool's schema and a description that opens by saying it is deprecated and what to call instead, and a call to it runs the new tool through the same brake, argument check and watcher. An alias that names no tool, or shadows one, is refused when the server is built. Both are additions; every server built on this passes the first, and no tool has been renamed. The tools themselves are held toapi/<package>.mcpin each server's package — see "Tools for agents are a contract too" in CONTRIBUTING.md. -
A plugin brings its own tools, and every server of the project offers them.
McpToolsfills the plugin API'sMcpToolRegistryslot: a plugin'sinstallcallshost.registry<McpTools>().addTool(tool, run), and the tool is published as<plugin id>.<name>, so two plugins'resets do not meet. The application adds its own under a namespace it names. A name that is not letters, digits,_and-, or one already added, is refused with the owner's name, and switching a plugin off withdraws its tools.ToolTableServertakes the registry as an optionalprojectToolsand offers it after its own tools, through the same brake and argument check, withonProjectCallas its watcher. It keeps the list in step while it runs and tells the client when it changes. A project tool named like one of the server's own is not offered, andshadowedProjectToolssays which.ProjectMcpServeroffers the registry alone, for a project that runs no other server; its own surface is empty and is snapshotted inapi/flutter3d_mcp_kit.mcp. The plugins' tools are snapshotted and versioned by the packages that bring them. All of it is an addition. The package now depends onflutter3d_plugin_api, which is plain Dart with no dependencies.
Moves with the stack to 1.0.0, whose flutter3d_hardware gives
PassEncoder.draw a window of the bound indices and every PassEncoder
setAlphaToCoverage. Nothing in this package changed.
Its flutter3d_* dependencies ask for ^1.0.0.
editor.dart, from flutter3d_editor_mcp 1.0.0-rc.1 #
-
Breaking: American spelling in identifiers, as Flutter and Dart use.
removeBehaviourisremoveBehavior,setBehaviourissetBehavior. Only the Dart names changed: a file keeps the keys it was written with, anddart fixcarries the renames. -
Tools are named
area.verb, and the old names still answer.brush.add,selection.move,prefab.place,render.passes,play.start:editorToolNameslists each with what it does to the level (read-only, writes, destructive), andaddBrush,moveBy,play_statusand the rest stay aliases until 2.0. The server announces itself asflutter3d.editor, schema 1.2.0. -
command.runreaches every command the editor knows, a plugin's included. It takes a command's name and its arguments, and reads it through the session'sEditorPieces(EditorSession.pieces, filled by the pluginsserveEditorMcpinstalls), so a plugin'sboats.sinkis called the waymoveByis. -
Breaking:
EditorSession.runtakes anyDocumentCommand, a plugin's too, and tools areToolSpecs (seeflutter3d_mcp_kit): theTooltype of the MCP library is in no signature. -
1.0.0 is a promise: strict semver from there. This release candidate already keeps it. A patch fixes bugs and breaks nothing, a minor adds, and a break waits for a major. The whole public API is stable, with no experimental exceptions, and is held to the snapshot in
api/. A deprecated name stays until the next major and for at least six months, and says what replaces it. CONTRIBUTING.md has the rules, and SUPPORT.md says which releases get fixes and on which platforms. -
Captures saved and opened, memory and debug views listed.
render_capture_savewrites the running game's frame to a capture file,capture_openandcapture_drawread one back with a picture of its last pass,render_memoryreports what the renderer holds, andrender_debug_viewslists the viewsscreenshotand the renderer take. -
Prefab tools for agents.
createPrefab,placePrefab,setOverride,applyOverrides,revertOverrides,unpackPrefabandsetPrefabFieldare the editor's prefab commands;prefabslists the templates with the paths their overrides take;selecttakesalsoto pick several things. All additions: the schema version is 1.1.0. -
Breaking:
editorMcpSchemaVersionis'1.1.0', as the tools above require. Code that compared it with'1.0.0'should compare versions. -
The editor's server offers a project's plugin tools.
serveEditorMcp(arguments, plugins:)installs the plugins into anMcpToolsand hands it to the server asprojectTools.bin/editor_mcp.dartis that call with no plugins; a project that wants its plugins' tools calls it from its ownbin/with itsinstalledPlugins. -
The project's plugin tools are offered beside the server's own.
EditorMcpServertakes an optionalprojectTools, the project'sMcpToolsfromflutter3d_mcp_kit, andonProjectCallto watch calls to them. Each plugin tool is listed as<plugin id>.<name>after the server's own, and the list follows plugins as they are switched on and off. A server built without it offers exactly whatapi/flutter3d_editor_mcp.mcplists, so the schema version does not move. An addition. -
The tools are a contract too. Their names and input schemas are written down in
api/flutter3d_editor_mcp.mcpand held to the same semver as the Dart API: a tool removed or renamed without an alias, or a new required argument, waits for a major. The server announceseditorMcpSchemaVersion(1.0.0) asschemaVersionin itsinitializeresult, and it moves only when the tools do. CONTRIBUTING.md has the rules. -
play_buildsays whether the game compiles without running it. It runsflutter buildin the project above the level, for this computer's desktop or a named target, debug unlessreleaseis given, and answers a failure with the lines that carry an error rather than the whole log. It is refused whileplayruns the game, since both would write into the samebuilddirectory. -
play_send_levelhands the running game the level as it stands. Unsaved changes go with it and the file on disk is left alone, so an agent can try a change in the game before keeping it, or put the level back after a hot restart. -
play_eventshears what the running game says about itself. A level loaded, the player died or came back, a pickup taken, the way out reached: whatever the game posts withpostToolEvent, in order, each with a sequence number, kind, time and data. An agent passes back thenextit was given and sees nothing twice and skips nothing, through aplay_stopand aplayas well;kindsnarrows it, andmissedsays when more was posted than was kept before it asked. -
generate_levelreplaces the open level with one made from a seed and rules. -
screenshottakes adebugView, which draws each surface as one of its numbers. -
The frame the running game drew, for an agent.
render_*tools sit over the game'sext.flutter3d.render.*. Among them isrender_pick, which answers which draws painted a pixel.play_keep_tapekeeps the run the game recorded intest/tapes/.
-
setCutsceneandremoveCutscene. An agent writes a level's cutscene from nothing — camera keys, subtitles, fades, signals and actor cues in one document — and is told every problem with it, and where, before anything changes. -
An agent writes behaviour trees.
setBehaviorandremoveBehavior, the first describing every composite, leaf and consideration a tree may use and refusing one that does not read with each problem;listnames the level's trees andvalidatereports an entity running a tree the level does not have. -
An agent can play the level it is editing.
playruns the game the level belongs to throughflutter3d_editor_play, the editor's own Play, and waits until it is up or has failed;play_status,play_swap,play_stopandplay_devicesfollow it. While it runs,savesends the level to the game, which takes it without starting over. -
EditorSession.savereturns aFuture, for that send.EditorSession(play:)takes aPlaySessionof the caller's making.
Its flutter3d_* dependencies ask for ^1.0.0.
model.dart, from flutter3d_model_mcp 1.0.0-rc.1 #
-
Breaking: one suffix for settings, Settings, and Descriptor in the HAL.
ImportOptionsisImportSettings. Every settings class isfinalwith aconstconstructor and acopyWithover every field; a nullable field is reset withcopyWith(clearX: true).dart fixcarries the renames. -
Breaking:
ModelSession.makeGameReadyisprepareForGame. The MCP tool keeps its name;dart fixcarries the Dart call. -
Tools are named
area.verb, and the old names still answer.object.addPrimitive,mesh.extrude,selection.facing,material.setField:modelToolNameslists every one with what it does to the project, and the command names (addPrimitive,extrude), whichhistory.batchstill takes inside its list, stay aliases until 2.0. The server announces itself asflutter3d.model, schema 1.1.0. -
Every tool declares the shape of its structured answer.
modelAnswerSchema(did,says,ids,selection) is each tool'soutputSchema, so a host can validate what it reads. -
Breaking: tools are
ToolSpecs and answersToolResults (seeflutter3d_mcp_kit); this package re-exports them, so a host adding its own tools needs no import of the MCP library. -
1.0.0 is a promise: strict semver from there. This release candidate already keeps it. A patch fixes bugs and breaks nothing, a minor adds, and a break waits for a major. The whole public API is stable, with no experimental exceptions, and is held to the snapshot in
api/. A deprecated name stays until the next major and for at least six months, and says what replaces it. CONTRIBUTING.md has the rules, and SUPPORT.md says which releases get fixes and on which platforms. -
The modeller's server takes the project's tools.
serveModelMcp(arguments, projectTools:)is whatbin/model_mcp.dartruns, and a project's ownbin/passes the registry its plugins filled. -
The project's plugin tools are offered beside the server's own.
ModelMcpServertakes an optionalprojectTools, the project'sMcpToolsfromflutter3d_mcp_kit, andonProjectCallto watch calls to them. Each plugin tool is listed as<plugin id>.<name>after the server's own and afterextraTools, and the list follows plugins as they are switched on and off. A server built without it offers exactly whatapi/flutter3d_model_mcp.mcplists, so the schema version does not move. An addition. -
The tools are a contract too. Their names and input schemas — as the server offers them, with the target arguments every selection command gains — are written down in
api/flutter3d_model_mcp.mcpand held to the same semver as the Dart API: a tool removed or renamed without an alias, or a new required argument, waits for a major. The server announcesmodelMcpSchemaVersion(1.0.0) asschemaVersionin itsinitializeresult, and it moves only when the tools do; tools a GUI host adds throughextraToolsare the host's and not part of it. CONTRIBUTING.md has the rules.
setAnimationGraph and removeAnimationGraph. An agent sets a
character's graph by name over the project's clips, with the whole shape
described in the tool, and is told where a wrong one is wrong.
Its flutter3d_* dependencies ask for ^1.0.0.