Long-running tools
Tools that take minutes or hours, how they run as job steps, and how they report progress and stop.
Use AddLongRunningTool for anything that waits: farming, crafting a list, walking somewhere. A quick tool (AddTool) runs on the framework thread and must return at once; a long-running tool runs asynchronously, for as long as its work takes.
Long-running tools and jobs
A long-running tool is one tool. A job is a way to run several calls: XIV MCP works through them on its own, without the AI model. A long-running tool can be called either way:
- As a job step, the usual way, the tool can run for hours. The assistant (or your plugin, with
StartJob) puts it into a job, and the job waits until it is done before starting the next step. - Called directly, it works too, but only within the AI app's own time limit for a request, often a minute, which XIV MCP does not control. XIV MCP sends nothing while it waits, and when the app gives up, the call is cancelled.
- Cancelling comes from the job. Pausing or cancelling the job fires
call.Cancellation, and so does an app that aborts a direct call. - Progress goes to the job log, shown in
/xivmcp→ Jobs and inget_job. - Failing makes the job wait. The step becomes pending until the assistant retries, skips or changes it.
So write a long-running tool as if it were a job step: safe to stop at any moment, safe to run again, with a result the next step can use ({{farm.kills}}).
When the assistant should drive a task itself and when it should hand it to a job, with what each costs, is on Step by step or as a job. How players see jobs is described in Background jobs.
Example
Framework is Dalamud's IFramework service. StartFarming, BagsFull, Kills and StopFarmingSafely stand for your plugin's own code.
mcp.AddLongRunningTool(
new McpToolDefinition(
"myplugin_farm",
"Farms the current zone until the bags are full " +
"or 'minutes' have passed.")
{
Capabilities =
[McpCapabilities.MoveCharacter, McpCapabilities.Combat],
InputSchema = """
{
"type": "object",
"properties": {
"minutes": {
"type": "integer", "minimum": 1, "maximum": 600
}
}
}
""",
},
async call =>
{
var minutes = call.Args["minutes"]?.GetValue<int>() ?? 60;
var until = DateTime.UtcNow.AddMinutes(minutes);
await Framework.RunOnFrameworkThread(StartFarming);
try
{
while (DateTime.UtcNow < until
&& !await Framework.RunOnFrameworkThread(BagsFull))
{
// Throws when the job is paused or cancelled.
await Task.Delay(5000, call.Cancellation);
// Shown in the job log.
call.Progress($"{Kills} kills");
}
return new { kills = Kills };
}
finally
{
// Also runs on cancel.
await Framework.RunOnFrameworkThread(StopFarmingSafely);
}
});Rules
- Threads: the handler starts on the framework thread and continues on the thread pool after its first
await. UseFramework.RunOnFrameworkThreadfor game access after that. - Cancel safely: when
call.Cancellationfires, finish the fight or close the window, then return or throw. XIV MCP waits up to two minutes for you, then moves on without your result. - Progress:
call.Progress("Room 2 of 5")adds a line to the job log. It can be called from any thread, is cut at 300 characters, and is dropped when the tool was called directly rather than as a job step. Report milestones, not every frame. - Ending a cancelled call: let the
OperationCanceledExceptionfromTask.Delay(…, call.Cancellation)propagate, or throw it yourself. The client reports "Cancelled." - Pause and resume: when a paused job resumes, it runs the step again from the start, with the same arguments. Make tools safe to run again: prefer targets ("until 20 ore") over counts ("20 more").
- Failing (throwing) makes the job step pending: the job waits for the assistant to retry or change it. Say what is left: "Bags full after 120 kills; 3 Iron Ore still missing."
- One acting step at a time: while your tool runs as a job step, other calls that are not read-only are refused, so nothing collides with it. Read-only tools and XIV MCP's waiting steps (
wait,wait_until_arrived) are not blocked, and do not block others; they still follow the player's settings.