Skip to content

MCP server

A server that lets an AI client call the compiler itself. It ships inside the package, and the client launches it according to its configuration.

Open Tsukimi MCP from the TsukimiCode menu in Unity. Check the clients you use and press the main button, and the configuration of every checked client, the Skill, and the final check (a compile check run when work is reported as done) are written together.

The Tsukimi MCP window. All 8 clients are checked and marked ✓, Server is found, Skill is up to date, Final check is not installed, and the main button reads Set Up (8 clients)

LocationContents
ToolbarThe package version, and Refresh, which rereads the configuration files and updates the marks
Client rows8 rows. Each has a checkbox, the location of the configuration file, and a mark. The checkboxes are saved per project in UserSettings/TsukimiMcpClients.json. Until something is saved, Claude Code and any client whose configuration already has a tsukimi entry are checked
ServerWhether the bundled server DLL is found
SkillState of the instructions the AI reads (Skills)
Final checkState of the hook that checks compilation when work is reported as done. Claude Code only
Main buttonWrites the configuration of the checked clients, the Skill, and the final check together. The label changes with the state
MoreThe start command, the note in AGENTS.md, the configuration to paste by hand, and removal of the final check. Closed at first
Bottom rowLast check (the most recent result of the final check), and Open the guide, which opens the setup page
MarkMeaning
✓Installed and up to date
Empty circleNot installed yet
!Installed but out of date. Either an earlier version wrote it, or it points at a different server or project
✕Cannot be installed. Appears when the bundled server or the source files of the Skill cannot be found
RowsTextMeaning
ServerfoundThe bundled server is found
Servernot found · reinstall the package to restore itThe server DLL is not found. The main button cannot be pressed either. Reinstalling the package restores it
Skillup to date · shared by every clientUp to date. Every client reads the same Skill
Skillout of date · shared by every clientAn earlier version of the Skill is installed
Skillout of date (changed by hand) · shared by every clientAn earlier version of the Skill is installed, and some files were changed by hand after installation
Skillnot installed · shared by every clientNot installed
Skillsource not foundThe source files of the Skill are missing from the package
Final checkup to date · Claude Code onlyUp to date
Final checkout of date · Claude Code onlyIt points at a different server or project
Final checknot installed · Claude Code onlyNot installed
TextWhen it appearsNote under the button
Set Up (N clients)At least one of the checked clients, the Skill, and the final check is not installed yet or cannot be installedWrites the checked clients, the Skill and the final check. Restart your AI client afterwards.
Update (N clients)Everything is installed, and something is out of dateThe package was updated. Restart your AI clients afterwards.
Set Up AgainEverything is up to dateEverything is in place.
ItemDescription
NThe number of checked clients (client when it is 1)
What goes into the labelThe checked clients, the Skill, and the final check. The final check is included only when Claude Code is checked
What happens when pressedThe same for every label. Writes the configuration of the checked clients and the Skill, and also the final check if Claude Code is checked. The Skill is installed regardless of the checkboxes
Things already up to dateThese are rewritten too. Set Up Again is for bringing the way they are written in line with the current version
When it cannot be pressedWhen Server is not found
After pressingRestart the AI client. Clients read the configuration and the Skill only at startup
CaseTextWhat happens when you choose
The configuration file cannot be read as JSON... could not be read as JSON. Replace it with a file that holds only the tsukimi entry?Replace makes the file hold only the tsukimi entry. With Cancel, that client is not written
A file with the same name as one in the Skill exists with different contentsThese files already exist and differ. Replace them?, followed by the list of those filesReplace overwrites them. With Cancel, the Skill is not installed
.claude/settings.local.json cannot be read as JSON... could not be read as JSON, so it was left alone.The final check is not installed. The file is left as it is
foundThe bundled server is present
not foundThe server DLL is not found. The main button cannot be pressed and the mark is ✕. Reinstalling the package restores it
Start commandThe command the client runs appears under Start command in More

The configuration file and the key differ per client, so 8 variants are written out separately.

ClientConfiguration fileKeyFormatPath to the serverNotes
Claude Code.mcp.jsonmcpServersJSONPath relative to the project
GitHub Copilot CLI.mcp.jsonmcpServersJSONPath relative to the projectThe same file as Claude Code. It is launched from the project folder
Visual Studio.mcp.jsonserversJSONAbsolute paths (the project location is written too)A different key in the same file
VS Code.vscode/mcp.jsonserversJSONPath starting with ${workspaceFolder}
Cursor.cursor/mcp.jsonmcpServersJSONPath starting with ${workspaceFolder}
Roo Code.roo/mcp.jsonmcpServersJSONPath relative to the project
Gemini CLI.gemini/settings.jsonmcpServersJSONAbsolute paths (the project location is written too)The same file as its other settings
Codex CLI.codex/config.tomlmcp_serversTOMLAbsolute paths (the project location is written too)The project must be trusted separately
ItemDescription
Clients written with a relative path or ${workspaceFolder}Only the path to the server is written, not the project location. The server walks up from its own file and uses the first folder that contains both Assets and ProjectSettings as the project. So the same configuration starts the server after a clone to another machine or folder
Clients written with absolute pathsThe absolute paths of both the server and the project are written
When the package is placed outside the projectAbsolute paths are written for every client
How a client’s mark is decidedBy where the path in the configuration points. Even if it is written differently from what the window writes, it is ✓ as long as it points at the current server and this project
Absolute paths written by an earlier version of the windowEarlier versions wrote absolute paths for every client. If they point at the current server and project, ✓ appears and they are not rewritten automatically. To move to a relative path or ${workspaceFolder}, press the main button (Set Up Again when everything is ✓)

Open More and choose a client in the Paste by hand dropdown, and what to paste appears as it is.

{
"mcpServers": {
"tsukimi": {
"command": "dotnet",
"args": ["<package location relative to the project>/Server~/TsukimiCode.Mcp.dll"]
}
}
}
{
"servers": {
"tsukimi": {
"command": "dotnet",
"args": ["${workspaceFolder}/<package location relative to the project>/Server~/TsukimiCode.Mcp.dll"]
}
}
}
[mcp_servers.tsukimi]
command = "dotnet"
args = ["<package location>/Server~/TsukimiCode.Mcp.dll", "<project location>"]
ItemDescription
What appearsThe same as what the window writes. The paths hold the values for that project
The examples aboveIn order: Claude Code (relative path), VS Code (${workspaceFolder}, key servers), and Codex CLI (absolute paths, TOML)
The project location argumentPresent only for clients written with absolute paths. The server uses it to read the database of the runtime’s APIs generated for that project
If it is omittedThe server walks up from its own file to find the project. If the server is outside the project and cannot find it, APIs are not checked for existence
What it runsWhat happens
WhenWhen Unity loads scripts (at startup, or after the package is updated). Only when the recorded version of the Skill installed from the window is an earlier one; nothing happens for the same version
SkillRewrites the files that are still as they were installed (and untouched) (Skills)
Skill files changed by handLeft as they are, and named in a warning in the Console. To replace them, press the main button and choose Replace in the prompt about files with the same name
Client configurationRewrites only the entries where tsukimi points at a different server or a different project
Final checkRewritten only when it is installed and out of date
Projects with no record of the SkillNothing is rewritten. A Skill installed from a window older than 0.9.0 has no record, so reinstall it once with the main button
After rewritingOne line appears in the Console: Updated ... for TsukimiSharp <version>. Restart your AI client so that it reads them. Restart the client
When nothing needed rewritingIf the version differs from the one this project loaded last time, and the configuration of any client has a tsukimi entry, the Console shows the line TsukimiSharp <version> is loaded. If your AI client was already running, restart it, or reconnect its MCP servers, so that it uses this version. Restart the client, or reconnect its MCP servers

Open More under the card to see 4 fields that are not used day to day.

FieldButtonContents
Start commandCopyThe same start command that goes into the Claude Code configuration. When the package is inside the project, the path to the server is relative, so run it from the project folder when starting it by hand
Note in AGENTS.mdAddAdds a short note to AGENTS.md, which is always read (Skills)
Paste by handCopyWhat to paste into the configuration of the client chosen in the dropdown
Final checkRemoveRemoves the final check hook. Cannot be pressed when it is not installed

The window with More open. The Start command, Note in AGENTS.md, Paste by hand (with Claude Code chosen), and Final check fields are visible

The compile check when work is reported as done

Section titled “The compile check when work is reported as done”

Check Claude Code and press the main button, and a hook is registered in .claude/settings.local.json. When the AI is about to report that work is done, the hook compiles the T# sources changed in that session, once.

CaseWhat happens
Compilation failedHands back the diagnostics and asks for the work to continue
Only warnings appearedDoesn’t send it back
Compilation succeededSays nothing. The last result appears under Last check in the window
The check itself doesn’t runLets it through rather than stopping. A broken check must not keep blocking work
The same diagnostic twice in a rowLets it through. It has decided the problem cannot be fixed and stops
Which client this coversClaude Code only. The hook mechanism exists only there
Where it is writtenA configuration file not meant for sharing, because absolute paths go into it
Last resultIt appears under Last check at the bottom of the window. It reads not run yet if the check has never run
DeletionRemove under Final check in More deletes only this hook. Other settings in the same file are kept

There are seven.

ToolsDescription
pingCheck whether the server is running
inspectCompile source and return diagnostics and facts
testRun the methods marked with [TsukimiTest]
diagnosticsList of error numbers
specGenerate a description of this language
decompileTurn a compiled assembly into a readable form
profileReading the instruction and extern counts of the programs in the scene open in Unity

inspect and test are the core; ping checks the connection, diagnostics and spec interpret what inspect returned, and decompile is for examining a program that already exists.

Checks whether the server is running, and which version is running. It takes no arguments.

"tsukimi-mcp ok (version x.y.z; static-analysis MCP; liveness check)"

The version of the running server goes where x.y.z is. Use it right after registering, to tell whether the configuration is in effect.

When the server started before a package update is still running after it, tools other than ping do not run, and the following message comes back as an error (isError: true). (ping adds the same message after its line, separated by one space, and does not make it an error.)

The TsukimiSharp package was updated after this MCP server started (running x.y.z, installed x.y.z). Restart your AI client, or reconnect its MCP servers, to use the new version.

installed is the version of the updated package, and is left out when it cannot be read. Restarting the client, or reconnecting its MCP servers in the client, starts the updated server.

Compiles the source and returns the result as structured JSON.

ArgumentsDescription
sourceThe full text of one source file
fileThe file name used for diagnostic locations. <inline> when omitted
sourcesMultiple files. An array of {name, text}. Takes precedence over source
pathFiles in the Unity project, passed by path instead of by their text: one path or an array, relative to the project folder (such as Assets/Lamp/Lamp.cs). A .cs file is compiled together with the files Unity collects when it compiles that program (the files in the same folder and the folders below it, and the files in TsukimiShared folders, leaving out anything under a folder named Editor). A program asset (.asset) is treated as the .cs file it compiles, and a folder passes every .cs file below it. The files are read as saved on disk, so for a file with unsaved changes, pass its text as well. Text whose name matches a file read from path is used in place of that file
mochiChecks a MoCHI .mochi.xml file instead of .cs. See MoCHI inspect for the details
costWhether to measure instruction count and heap. Omitted, nothing is measured. Measuring runs the same optimization as shipping does, so most of this call’s time goes there

One source can declare only one concrete Behaviour, so pass several at once through sources when you want to check a shape like the one below.

  • Implementing an interface with a Behaviour
  • Splitting into a base Behaviour and a derived Behaviour
  • Calling a method on another Behaviour from one Behaviour
  • Receiving a component as a Behaviour type

Writing two in a single source and getting an error is a mistake in how you passed them, not something the language can’t do (pass them through sources and the results are split per Behaviour, landing in each element of programs rather than at the level above).

This is the result of passing the following source as source with cost set to true. Without cost, the two keys heap and cost are absent altogether.

using UnityEngine;
using Tsukimi;
public class Lamp : TsukimiBehaviour
{
[SerializeField] private Light target;
[UdonSynced] private bool on;
public override void Interact()
{
on = !on;
target.enabled = on;
RequestSerialization();
}
}
{
"schemaVersion": 1,
"compiles": true,
"diagnostics": [],
"facts": {
"heap": { "slots": 11, "limit": 1048576, "remaining": 1048565 },
"cost": {
"instructionCount": 12,
"staticExternCount": 3,
"nsPerExtern": 77,
"nsPerNonExtern": 5.4,
"isStraightLine": true
},
"entries": [ "Interact" ],
"recursiveMethods": [],
"loopCount": 0,
"methods": [
{
"name": "Interact", "isEntry": true, "isRecursive": false,
"params": 0, "locals": 1, "loops": 0, "externs": 3,
"entryName": "_interact"
}
],
"runtimeRisk": [],
"contract": {
"synced": [ { "name": "on", "type": "SystemBoolean", "sync": "none" } ],
"exportedFields": [],
"syncMode": "any"
},
"nullDerefRisks": [
{
"kind": "unassignedFieldDeref",
"severity": "warning",
"origin": "runtime",
"message": "The reference field 'target' (type UnityEngineLight) is shown in the Unity Inspector and is never assigned in code, so its value comes only from there. ...",
"method": "Interact",
"field": "target",
"type": "UnityEngineLight",
"deref": "UnityEngineLight.__set_enabled__SystemBoolean__SystemVoid"
}
]
},
"summary": { "total": 0, "bySeverity": {}, "byOrigin": {} },
"externDb": { "resolved": true, "unknownApiChecks": true, "externCount": 32898 }
}
What to look at
diagnostics empty, compiles trueThis source compiles
One entry in nullDerefRiskstarget is never assigned anywhere in the code; its value can only come from the Inspector. Forget to assign it and it stays null at runtime, and the assignment to target.enabled silently cuts the whole event short (Udon has no exception handling, so nothing appears in the log either)
nsPerExtern and nsPerNonExtern under costRoughly how long one extern call and one non-extern instruction take. The gap between the two shows that how many times you call an extern matters more than the instruction count itself

This is an example that uses a type that does not exist in Udon.

using System.Collections.Generic;
using UnityEngine;
using Tsukimi;
public class Bag : TsukimiBehaviour
{
private List<int> items;
public override void Interact()
{
items = new List<int>();
items.Add(1);
Debug.Log(items.Count);
}
}
{
"schemaVersion": 1,
"compiles": false,
"diagnostics": [
{
"code": "TUKI0102",
"severity": "error",
"message": "Variable type does not exist in Udon: field items has the type SystemCollectionsGenericList",
"explain": "This type does not exist in Udon (outside the extern database).",
"location": { "file": "Bag.cs", "startLine": 7, "startCol": 23,
"endLine": 7, "endCol": 23 },
"fix": "This type cannot be used here (it is outside the usable Udon extern set). ... For lists and dictionaries, use the VRChat data containers DataList / DataDictionary (VRC.SDK3.Data) - generic List<T> / Dictionary<K,V> are not usable.",
"witness": "SystemCollectionsGenericList",
"origin": "subset",
"path": null
},
{
"code": "TUKI0101",
"severity": "error",
"message": "Not exposed to Udon: SystemCollectionsGenericList.__ctor____SystemCollectionsGenericList",
"explain": "This API is not exposed to Udon.",
"location": { "file": "Bag.cs", "startLine": 11, "startCol": 17,
"endLine": 11, "endCol": 17 },
"fix": "This API is not exposed to Udon. Use an API that exists in the Udon extern set (see the `spec` tool, topic \"api\").",
"witness": "SystemCollectionsGenericList.__ctor____SystemCollectionsGenericList",
"origin": "subset",
"path": null
}
],
"facts": null,
"summary": {
"total": 4,
"bySeverity": { "error": 4 },
"byOrigin": { "subset": 4 }
},
"externDb": { "resolved": true, "unknownApiChecks": true, "externCount": 32898 }
}
What to look at
facts is nullThis is what you get when compiles is false. Nothing compiled, so neither heap usage nor cost can be measured. When facts is there but only heap and cost are missing, that’s a different matter: it means cost wasn’t passed
Two entries in diagnosticsOnly the first 2 of 4 are shown (the rest are the same kind of finding against List method calls). The overall count is in summary.total
witnessIt holds the actual evidence behind the decision to call it an error. Here that is the type name SystemCollectionsGenericList and the signature of the extern that wasn’t found, so you can see what was missing without unpacking the message
KeyDescription
schemaVersionThe version of this report’s shape. It goes up when the shape changes
compilesWhether it compiled all the way to Udon bytecode. Not a guarantee that it works in the runtime
diagnosticsAn array of errors and warnings. Holds the number, severity, location, how to fix it, and the origin category
summarydiagnostics counted by severity and by origin category
factsPresent only when it compiled. Null on an error
facts.heapThe number of heap slots used, and how many remain. limit is the maximum the runtime allows for the heap. Present only when cost was passed as true
facts.costInstruction count, extern call count, and the approximate time each one takes. Present only when cost was passed as true. Its absence means it wasn’t measured, not that there is no cost
facts.entriesThe names of the entry points the runtime calls
facts.methodsA per-method breakdown. Counts of local variables, loops, and externs
facts.recursiveMethodsThe names of the methods that may be entered again while they are still running, and so save their arguments and local variables around the call (Entering a method again while it runs)
facts.contractSynced fields, fields exposed outward, and the sync method of the behaviour as a whole. The method is a separate axis from the per-field sync
facts.runtimeRiskForms that compile but can halt at runtime
facts.nullDerefRisksPlaces where a reference that can be null is dereferenced directly
externDbWhether the database of runtime APIs could be read, and how many APIs it holds

The origin category attached to a diagnostic

Section titled “The origin category attached to a diagnostic”

Each element of diagnostics carries an origin, and its 4 categories change where the fix belongs (runtime isn’t in this table; it only appears on the facts.runtimeRisk and facts.nullDerefRisks side).

CategoryMeaning
subsetA form this language doesn’t accept. Rewriting the form makes it compile
environmentDoesn’t exist on the runtime side. Rewriting the form won’t make it compile
costIt converts, but the cost exceeds the limit
toolThe compiler or the analysis failed. The place to fix is not the code you wrote

tool alone is different in kind: it signals that the compiler failed rather than the code you wrote, so rewriting the code gives the same result.

Compiles the source and runs the methods marked with [TsukimiTest] without Unity.

It takes five arguments.

ArgumentsDescription
sourcesThe files to compile together. Same shape as inspect. Write tests in Name.Tests.cs and pass them along with what you want to check (see Testing for how)
pathThe same as for inspect. Passing a .cs file also reads its Name.Tests.cs. For a file with unsaved changes, pass its text in sources as well
projectPathThe location of the Unity project. Optional. Pass it and the same content is also written inside that project, appearing there when you return to Unity and reopen the window. path is also read from this project
fastWhether to run as plain C#. Omitted, it runs on the default path. It’s fast, so it suits checking while you’re still writing, but it answers a different question: it checks whether the rules you wrote are right, not whether the compiled form is right (Testing)
summaryWhen true, only the tests that did not pass are returned in cases. When omitted, all of them are returned. passed, failed, notRunnable and allPassed count every test, and the number of passed tests left out is in passedOmitted. The result written under projectPath keeps every test
{
"schemaVersion": 1,
"origin": "mcp",
"ranAt": "2026-08-13T05:57:52.7817272Z",
"passed": 2,
"failed": 1,
"notRunnable": 0,
"allPassed": false,
"cases": [
{
"name": "OneBumpAddsOne",
"source": "Counter.Tests.cs",
"outcome": "passed"
},
{
"name": "TwoBumpsMakeTwo",
"source": "Counter.Tests.cs",
"outcome": "passed"
},
{
"name": "DeliberatelyWrong",
"source": "Counter.Tests.cs",
"expected": "99",
"actual": "1",
"location": "32:9",
"outcome": "assertFailed"
}
]
}
KeyHow to read it
outcomeIt splits four ways. assertFailed is a check that didn’t hold, halted is a form that stops at the same place in the runtime, and notRunnable is something that couldn’t be run at all, which is not the same as a test failing (rewriting the code won’t change the result, so read detail first)
allPassedIt is also false when no test was found at all, and when even one test was not-runnable. Both are kept from looking green
originWhich path ran it, as a value. mcp is the default path, mcp-fast is the plain C# path, and editor is a run from the Unity window. Read this before reading a failure
tracePresent only when the test failed. Events recorded during the run are listed in the order they happened
passedOmittedPresent only when summary is passed as true. The number of passed tests left out of cases

Returns the list of error numbers (it takes no arguments). Use it to look up what a number returned by inspect means.

{
"code": "TUKI0101",
"defaultSeverity": "error",
"en": "This API is not exposed to Udon.",
"fixTemplate": "This API is not exposed to Udon. Use an API that exists in the Udon extern set ...",
"origin": "subset"
}

The above is one element of the array. Unlike the individual diagnostics inspect returns, it carries no position (this is a table defining the numbers themselves).

Returns documentation for this language as Markdown (topic offers 4 choices).

TopicDescriptionBasis
subsetRules for supported forms. For each error code, the conditions that trigger it and how to fix itGenerated from the diagnostic list. Its content changes when the compiler changes
apiThe list of type names the runtime holds. Being able to look a name up is not the same as that API being usable; run it through inspect to find outGenerated from the extern database. Same as above
pitfallsWhere the behaviour differs from plain C#. Where null comes from, forms where an event ends silently, and so onWritten by hand. Facts that cannot be generated from the compiler’s own definitions
builtinsThe surface this language itself has: attributes, base classes, how to write checks, the kernel surface. Not runtime APIs, so it doesn’t appear in apiGenerated from the type surface the compiler holds
(omitted)The overall map, and an index of the topicsIt also states whether the extern database could be read. If it couldn’t, the checks for unknown APIs and unknown types (TUKI0101 and TUKI0102) don’t run, so a form that errored in that state may have failed because the database was absent rather than because of how it was written
(an unknown topic)A message listing the available topics
  • compiles being true does not mean it works in the runtime. It only means it compiled all the way to bytecode
  • Empty runtimeRisk and nullDerefRisks do not mean it is safe. This detection is deliberately narrow: it follows only forms chained directly onto a call that can return null. Assign to a local variable once and the tracking stops there. Check component lookups and values taken from the runtime yourself, whatever the result says
  • When externDb.resolved is false, the checks for unknown APIs and unknown types haven’t run. In that state, forms that error only because the database couldn’t be read are mixed in
  • A diagnostic with info severity is not a reason to stop. It appears even when compiles is true

Turns a compiled Udon assembly into a readable form resembling C#. Use it to examine a program already placed in a world. It takes two arguments.

ArgumentsDescription
uasmThe assembly text
fileThe location of the assembly file. Read only when uasm is absent
{
"schemaVersion": 1,
"file": "Lamp.uasm",
"source": "public class Lamp\n{\n ...\n}",
"fidelity": {
"isOriginalSource": false,
"isCompileChecked": false,
"receiverIsInferred": true,
"note": "This is a readable rendering of the assembly you passed in. ..."
},
"externDb": { "resolved": true, "externCount": 32898 },
"warnings": [],
"facts": {
"heap": { "slots": 11, "limit": 1048576, "remaining": 1048565 },
"cost": { "instructionCount": 42, "staticExternCount": 6,
"nsPerExtern": 77, "nsPerNonExtern": 5.4 },
"entries": ["_interact"],
"externs": ["UnityEngineGameObject.__SetActive__SystemBoolean__SystemVoid"],
"loopCount": 0
}
}
KeyHow to read it
sourceThe readable result. It is not the original source. Local variable names, class names, and block structure are reconstructed from the assembly alone (the assembly doesn’t carry them)
fidelityThe nature of this tool. It isn’t a judgment per input, so the same value comes back every time. Read it before source
externDbTells you whether the receiver of each call was decided by consulting the database or inferred from the surrounding shape. Inference can be wrong, and a wrong result looks like ordinary code
warningsPlaces where the result can’t be trusted. receiverNotResolved marks a call where what came before the dot can’t be that call’s receiver; notRaisedToStatements marks lines left as stack operations. Empty doesn’t mean everything came out right
factsValues measured from the assembly you passed. heap is counted the same way as in inspect; cost is the instruction count and the number of static external calls
facts.entriesThe names of the entry points written in the assembly. Where the same key in inspect returns the C# spelling (Interact), this one returns the name the runtime calls (_interact)
facts.cost.isStraightLineAbsent. Loops are visible in an assembly but recursion isn’t, so loopCount counts only backward jumps
Source you wrote yourselfUse inspect. Feeding this tool’s output back into inspect is not an intended use
What it returnsThe instruction and extern counts of each program placed in the scene open in Unity. The counts are the ones Unity wrote to Library/Tsukimi/profile.json; this tool does not count again
When it is writtenWhen you choose TsukimiCode > Tsukimi Profiler from the menu, and when Unity finishes compiling a saved TsukimiSharp script (Profiler)
ArgumentsOnly program. Pass the name of a program (programs[].name) to get that one program only. Omit it to get every program in the scene
When there is no fileIt returns isError: true with a message telling you to choose the menu item or save a script
{
"schemaVersion": 1,
"writtenAt": "2026-10-11T08:12:34.5678901Z",
"scene": "SampleScene",
"tsukimiVersion": "0.9.0",
"programs": [
{
"name": "ReactiveLamp",
"asset": "Assets/ReactiveLamp.asset",
"tsukimiSharp": true,
"placed": 3,
"instructions": 395,
"externs": 45,
"codeSizeBytes": 2944,
"syncedCount": 0,
"events": [
{ "name": "_interact", "instructions": 129, "externs": 15, "perFrame": false, "measuredExterns": 7 },
{ "name": "_start", "instructions": 49, "externs": 7, "perFrame": false, "measuredExterns": 4 }
],
"stale": false
}
]
}
KeyHow to read it
writtenAt・scene・tsukimiVersionThe time the summary was written, the scene that was open then, and the package version
placedThe number of UdonBehaviours in the scene that use the program
instructions・externsThe instruction and extern counts of the whole program. They are counted the same way as in the Profiler
events[].instructions・events[].externsThe instructions and externs reachable from that entry point. The bodies of the methods it calls are not included
events[].perFrameWhether the event runs every frame
events[].measuredExternsPresent for TsukimiSharp programs only. The number of externs called when the entry point was run once with every field at its default value, including the calls made inside the methods it calls. With default values an early return on a condition is often taken, so this is not the count during actual play
events[].notMeasuredFor an entry point that could not be run, the reason is given instead of a number
stalePresent for TsukimiSharp programs only. true means the asset on disk changed to a different program after it was counted. Choose the menu item again to count it again
Unit of the countsEvery number is a count, not a time. Nothing comes from play mode

Calling ping returns the following single line.

"tsukimi-mcp ok (version x.y.z; static-analysis MCP; liveness check)"

The client has a list of the servers it is connected to as well.

The server list as the client sees it

Tools visible7 (ping, inspect, test, diagnostics, spec, decompile, profile)
When none are visibleEither the client was launched before the configuration was written, or it was launched outside the project

Run one short source through inspect and externDb comes back.

"externDb": { "resolved": true, "unknownApiChecks": true, "externCount": 32898 }
resolvedTrue means it could be read. While it is false, APIs that really exist are reported as missing
When it is falseWhen you have never once opened this project in Unity
externCountThe number of APIs read. It varies with the SDK version you installed, so your number differing from the one above is fine

Placing things in a scene, assigning references in the Inspector, and checking with Play all lie outside this server; to let an AI touch those too, use an MCP server that drives the Unity editor from outside alongside it.

Servers of that kind are published by third parties and are not included in this package (for MCP for Unity, put the following address into Add package from git URL in Unity’s package manager).

https://github.com/CoplayDev/unity-mcp.git?path=/MCPForUnity#main
SymptomCauseWhat to do
TsukimiCode doesn’t appear in the menuEither the package isn’t installed, or the project doesn’t compileRead Unity’s console. If there is a compile error, that comes first
The tsukimi tools don’t appear in the clientIt was launched before the configuration, or launched outside the projectRestart it from the project root. In the window, check that the mark of that client is ✓
Nothing changes after pressing the main buttonA running client reads its configuration only at startupRestart the client
The AI does not know the instructions even though the main button was pressedThe instructions that were written out are also read by the client only at startupRestart the client
The AI writes code without consulting the SkillThe instructions haven’t been loaded by the clientCheck in the window that the Skill row says up to date, press the main button, and then restart
Only Codex CLI can’t connectThe project isn’t trustedTrust it by that client’s procedure, then restart
Only GitHub Copilot CLI cannot connectThe path to the server in the configuration is relative to the project, and the client is launched from another folderLaunch it again from the project folder
Can’t connect after updating the packageThe location of the server written in the configuration changed with an update, and the automatic rewrite did not run (it does not run in projects with no record of a Skill installed from the window)Open the window, press the main button if any row is marked !, and restart the client
After updating from 0.8.1, the Configure, Install Skill, and Install Check buttons are goneIn 0.9.0 the window was rebuilt around a single main button. A Skill installed with 0.8.1 has no record, so it is not rewritten automaticallyCheck the clients you use and press the main button once (choose Replace if the prompt about files with the same name appears). From the next update on, it is rewritten automatically
The server does not start in a cloned copyThe 0.8.1 window wrote absolute paths into the configuration. In the original project they point at the current server and project, so ✓ appears and they are not rewritten automaticallyPress the main button in the original project (Set Up Again when everything is ✓) and the configuration is rewritten with a relative path or ${workspaceFolder}. Visual Studio, Gemini CLI, and Codex CLI keep absolute paths
After a package update, tools return The TsukimiSharp package was updated after this MCP server started …The client is still running the server it started before the update. When the server detects that its own files were updated, it returns this message instead of running the tool, so that it never runs old and new files togetherRestart the client, or reconnect its MCP servers in the client. It is not a fault in the code or the tool
After a package update, tools fail with Method not found or a similar errorThe server started before the update is version 0.9.0 or earlier, which does not detect updatesRestart the client, or reconnect its MCP servers in the client
The Server row says not foundThe bundled server DLL is not found. The main button cannot be pressed eitherInstall the package again
It keeps saying an API that should exist is missingThe database of runtime APIs hasn’t been generatedOpen this project once in Unity. This is the state whenever externDb.resolved is false
No way to tell whether the completion check is runningNothing appears when compilation succeedsLook at Last check at the bottom of the window. If the Final check row is out of date, check Claude Code and press the main button
The AI placed a file but nothing happens in UnityUnity doesn’t import a file placed from outside until focus returns to itClick the Unity window once
Nothing happens when you touch it in the sceneThe Inspector reference is emptyAssign it in the UdonBehaviour field. Udon has no exception handling, so nothing appears in the log

If none of the fixes above solves it, press Refresh in the window and check the marks from the top, starting with the first row that is not ✓.