<@ULVA73B9P> are there docs/guidelines for how to ...
# ask-marvin
a
@Marvin are there docs/guidelines for how to integrate prefect tasks inside fastmcp? specifically, I'm interested in knowing how to kick off a long running prefect deployment from an mcp task that supports long-running/progress, and then report incremental prefect flow progress to the mcp client. How can I report progress/status? I can think of two options - one is to poll the flow run status and progress artifacts, and the other is to subscribe to events on the flow run and emit them from the flow. Are there any considerations to keep in mind if the mcp worker process dies? Could it resubmit the prefect deployment?
m
thought for 149.5 seconds
Yes — there’s some relevant Prefect support here, but not a single “FastMCP integration guide” for exactly this pattern. What does exist: - Prefect MCP server docs: Use the Prefect MCP server - Prefect events concepts: Event triggers - Prefect Python deployment docs: Deploy via Python A few important caveats: - The Prefect MCP server is primarily for read/inspect/debug use, not as the mechanism to create runs. - If your FastMCP server wants to start a long-running Prefect deployment, the clean pattern is to call the Prefect Python client directly from your MCP tool/task code. Recommended pattern 1. MCP tool receives request 2. MCP tool calls
create_flow_run_from_deployment(...)
3. Return the Prefect
flow_run_id
to the MCP client immediately 4. Stream status/progress updates to the MCP client by either: - subscribing to
FlowRunSubscriber
, or - polling flow run state + progress artifacts 5. On reconnect/retry, use a stable
idempotency_key
so you don’t create duplicate flow runs The relevant Prefect APIs are real/available in 3.x: -
FlowRunSubscriber(flow_run_id, straggler_timeout=3, reconnection_attempts=10)
-
DeploymentAsyncClient.create_flow_run_from_deployment(..., idempotency_key=..., tags=..., job_variables=...)
-
prefect.artifacts.create_progress_artifact(...)
-
prefect.artifacts.update_progress_artifact(...)
How to kick off the deployment safely Use the async client and always set an
idempotency_key
derived from the MCP operation/request ID.
Copy code
python
from prefect import get_client

async def start_prefect_run(deployment_id, parameters, request_id):
    async with get_client() as client:
        flow_run = await client.create_flow_run_from_deployment(
            deployment_id=deployment_id,
            parameters=parameters,
            idempotency_key=f"mcp:{request_id}",
            tags=["mcp"],
        )
        return flow_run
If your MCP process dies and retries the same request with the same
idempotency_key
, Prefect should return the existing run instead of creating a new one. That’s the main safeguard against accidental resubmission. Polling vs subscribing I’d think about it this way: Option 1: Poll state + progress artifacts - Simpler and more robust operationally - Easier if the MCP client already has a “check status” / “resume task” pattern - Good if you want the MCP task to survive temporary disconnects A common flow-side pattern is: - create one progress artifact once - update it as work advances - MCP side polls: -
read_flow_run(...)
for state - artifacts for latest progress value / description Prefect has first-class progress artifact helpers:
Copy code
python
from prefect.artifacts import create_progress_artifact, update_progress_artifact

artifact_id = create_progress_artifact(
    progress=0.0,
    key="mcp-progress",
    description="Starting work"
)

update_progress_artifact(
    artifact_id=artifact_id,
    progress=25.0,
    description="Finished step 1 of 4"
)
This is probably the easiest way to expose user-friendly incremental progress from a flow to an MCP client. Option 2: Subscribe to flow-run events/logs - Better for near-real-time streaming - Lower latency than polling - More moving parts: websocket/subscription lifecycle, reconnect handling, client backpressure Prefect exposes
FlowRunSubscriber
for this:
Copy code
python
from prefect.events.subscribers import FlowRunSubscriber

async def stream_prefect_updates(flow_run_id):
    async with FlowRunSubscriber(flow_run_id=flow_run_id) as subscriber:
        async for item in subscriber:
            yield item
This is attractive if your MCP long-running task protocol wants continuous live updates. My recommendation - Use events/logs subscription for live UX
- Also write progress artifacts from the flow as a durable progress checkpoint That hybrid approach gives you: - real-time updates when everything is healthy - resumable/latest-known progress if the MCP process or client disconnects How to report progress/status to the MCP client Best practice is to separate state from progress: - State/status: - Prefect flow run state:
Scheduled
,
Pending
,
Running
,
Completed
,
Failed
,
Cancelled
, etc. - Progress: - a progress artifact (
0-100
) - optional descriptive text (“loaded dataset”, “processed 3/10 partitions”) - Detail stream: - logs and/or emitted events So for an MCP client, I’d model updates like:
Copy code
text
status = Running
progress = 42
message = "Processed 21/50 files"
flow_run_id = ...
Then on terminal state:
Copy code
text
status = Completed
progress = 100
message = "Run finished successfully"
Should you use Prefect events emitted from the flow? Possibly, but I would not make custom events your only progress channel. Why: - Events are great for observability/automation/richer signaling - But for “current progress”, artifacts are a better fit because they represent latest durable state - Events are append-only signals; progress is naturally “latest value” So: - use artifacts for current progress - use events/logs for live feed / richer lifecycle updates If the MCP worker/server dies Important point: once the flow run has been created, it is managed by Prefect. The MCP process is not the owner of execution. So if your MCP process dies: - the Prefect flow run continues independently - if it was submitted to a work pool, a worker can still pick it up / keep running it - your MCP layer just loses its in-memory subscription state What you need for recovery: - persist the mapping
mcp_request_id -> prefect_flow_run_id
- use a stable
idempotency_key
- on restart: - first look up the known
flow_run_id
- if missing, retry submission with same
idempotency_key
- then resume monitoring via polling or subscription Could it resubmit the deployment? Yes, if you implement it naively. If the MCP process crashes after submitting but before persisting the
flow_run_id
, then on restart it may try again. To avoid duplicate runs: 1. Generate stable
idempotency_key
from the MCP request/task ID 2. Persist that request ID externally if possible 3. Treat Prefect as the source of truth for run existence That makes retries safe. Operational considerations / gotchas A few things to keep in mind: - Don’t rely on only an in-memory websocket subscription - if the MCP process dies, you lose the stream - back it with polling/artifact reads - Progress artifacts are durable, but not a full event history - great for current progress - not enough if you need every transition - Logs can be a good lightweight progress stream too - especially if you already emit structured log messages from the flow - Use tags/labels on MCP-triggered runs - for example
tags=["mcp", "customer-facing"]
- makes them easier to find/debug - Think about idempotency scope carefully - same request should reuse same key - different user actions should get different keys - Return
flow_run_id
to the MCP client as early as possible
- that gives the client something durable to reconnect to Practical architecture I’d suggest For FastMCP specifically, I’d implement it like this: - Start tool - submits deployment with
idempotency_key
- returns: -
flow_run_id
- initial state - maybe a status endpoint/handle in your MCP abstraction - Progress stream - primary: subscribe with
FlowRunSubscriber
- fallback: poll
read_flow_run
+ latest progress artifact - Recovery - if server restarts, resume from
flow_run_id
- if
flow_run_id
was never saved, retry same
idempotency_key
- Flow code - update one progress artifact throughout the run - optionally log milestone messages
- optionally emit custom events if you need richer semantic milestones If you want, I can sketch a concrete FastMCP example with: - one MCP tool that starts a deployment - one MCP long-running/progress handler that streams Prefect updates - flow code that publishes progress artifacts cleanly
n
hey alastair have you seen the tasks paradigm in MCP?
a
oh hai nate 🙂
a
still a mcp newbie. I'll read it, thanks
the best that claude has told me so far is to do https://gofastmcp.com/clients/tasks#background-tasks and then poll prefect for deployment/flow completion status (more or less what I asked marvin)
n
yep! so what i sent is some of the philosophy and guts motivating the Background Tasks UX fastmcp exposes
a
and so I'm not 100% if this is something that I invent from scratch myself, or use part of what fastmcp provides, or if there's a magic "run this prefect and it takes care of everything"
I think the prefect mcp isn't what we're after - we need a bit more control in our custom mcp, with some domain rules - we're not after just "run this deployment"
n
the prefect MCP (intentionally) doesn't even do mutations 🙂 its read only and comes with a skill on doing mutations w the CLI or SDK but yea starting without a opinionated 3rd party MCP makes sense, using skills i think is always good to codify workflows for agents in a more portable way. there's some fun stuff of ours in flight around the "takes care of everything" but also some existing stuff here (incrementally deferring decisions to agents) my question would be, how do you want to define the work that should happen? like in what format?
it sounds like maybe you're thinking that • you have some python functions decorated as tasks • you call them from tools on your own MCP server impl is that right?
a
yeah, that's more or less the pattern. we have a handful of deployments and want to be able to call them. but our mcp server impl does more than just trigger prefect flows (e.g. "get data related to project x", "identify gaps in the project and choose a relevant deployment to trigger to fill in the gap depending on its nature")
well, I guess that second one is more of an llm instruction, we're still working out the details
a
for us, we kind of understand "trigger a prefect deployment" to be an implementation detail of our mcp as a whole, the whole thing could work just as well if we did the work inline (not that we would), or if it was celery, or something else
mmm
n
^ proxying is good for the BespokeMcpServer | PrefectMcpServer use case
a
you mentioned that the prefect mcp is readonly? but that it still might be good for getting status of a flow run?
where do you see the benefit of proxying to the prefect mcp vs just polling for completion state through the api? (which I guess we need anyway to actually execute the deployment??)
n
eg GTM writes GTMMcpServer that has salesforce tools but proxies PrefectMcpServer so it can read state from a prefect server via its tools without independently defining them
a
right, so there's a value there in being able to just say "you already have access to "prefect__read flow run status", just use that"
n
yep. if you don't like our definition of that tool and don't need the other offerings, you can always just reimplement that on your bespoke mcp and not proxy ours
a
in your experience do you see the cli skill being robust enough to work all the time?
I guess I'm just skeptical of using a 100 line markdown file instead of just calling
prefect_api.execute_deployment(n)
🤣
I guess we could modify it to use the readonly parts of the mcp but our own custom code to actually trigger things
n
yes! depends on the LLM driving of course but we have largely client-agnostic evals that pass consistently
a
great, that's useful
n
if you identify cases where you expect it to be able to do something where it fails, an issue/PR to add an eval would always be useful!
a
I think we need to go back and make sure we have a clear design for the tasks that we want to have available, and see if it makes sense to just defer to the prefect mcp to get deployment/flow status updates, or if it makes sense to make something custom that better reflects our workflow
👍 1
n
the skills are more for guiding actions across MCPs or very idiosyncratic stuff that's not in the JSON schema for an MCP (or stuff entirely unrelated to MCP). atomic stuff should ideally be grokkable from the tool schema if the MCP server is well implemented
a
great, thanks for the suggestions anyway. I think the prefect mcp + marvin's initial suggestions especially around idempotency + progress reporting is a good start for us to prototype something
👍 1