Most MCP servers return results in milliseconds. Mint MCP generates 3D models, worlds, materials, and audio that can take minutes or hours. That gap forces you to solve job orchestration problems most agent builders ignore: state persistence across dropped connections, partial failure handling, preview revisions, and stable file delivery with metadata the agent can actually use.
Mint MCP is a remote server for Codex, Claude Code, and Cursor. When an agent asks for a forest ranger character or a campsite prop pack, the server queues a generation job, returns a job ID, and the agent must poll or wait for completion. When the job finishes, Mint delivers stable URLs and file metadata (GLB mesh, PBR textures, audio clips) so the agent knows where to write each artifact in the codebase. The service requires a paid subscription with per-job credit costs, making cost tracking and quota management part of the orchestration layer.
This article focuses on infrastructure, not asset aesthetics. We examine the plumbing required when agents generate assets that take real time, and how the MCP protocol communicates completion state and file metadata back to the agent.
Why Long-Running Jobs Break Naive Agent Patterns
Most agent tool calls assume synchronous execution. The agent calls a function, waits for a response, and continues. That works for database queries or API lookups. It fails when generation takes 10 minutes and the agent connection drops, the user cancels, or the LLM context window expires.
Mint MCP exposes three failure modes:
- Connection drop during generation. The agent loses the WebSocket or HTTP connection before the job finishes. The job continues server-side, but the agent has no handle to retrieve results.
- Partial failure. Texture generation succeeds, but mesh generation fails. Does the agent get usable artifacts or a full rollback?
- Preview revisions. The user wants to inspect a low-res preview and request changes before committing to a full render. The agent needs a way to correlate preview state with final artifacts.
The server must persist job state, expose a polling or callback mechanism, and return structured metadata so the agent can wire files into the project without guessing which URL is the diffuse map and which is the normal map.
Job State Persistence and Artifact Schema
Mint MCP uses a job queue with persistent state. When the agent calls generate_3d_model, the server returns a job ID immediately:
{
"job_id": "job_abc123",
"status": "queued",
"estimated_duration_seconds": 180,
"estimated_credits": 50,
"user_balance": 200
}
The credit cost estimate appears before the job starts. If the user lacks credits, the server returns an error before queuing the job. The agent surfaces this to the user and suggests upgrading the subscription. This cost-gating pattern avoids wasting compute on jobs that will fail for billing reasons.
The agent stores the job ID in its execution context (or writes it to a local state file if the agent framework supports it). The agent then polls get_job_status(job_id) at intervals. When the job completes, the server returns a canonical artifact schema:
{
"job_id": "job_abc123",
"status": "completed",
"artifacts": [
{
"type": "model",
"format": "glb",
"url": "https://cdn.mint.gg/assets/job_abc123/model.glb",
"size_bytes": 2048576
},
{
"type": "texture",
"format": "png",
"channel": "diffuse",
"url": "https://cdn.mint.gg/assets/job_abc123/diffuse.png",
"size_bytes": 524288
},
{
"type": "texture",
"format": "png",
"channel": "normal",
"url": "https://cdn.mint.gg/assets/job_abc123/normal.png",
"size_bytes": 524288
}
],
"metadata": {
"polycount": 15000,
"materials": ["leather", "metal"],
"license": "CC-BY-4.0"
}
}
The agent parses the artifacts array and writes each file to the project. The type and channel fields tell the agent what each file is for. The agent does not guess. It reads the schema. This structured response is how the MCP protocol handles multi-file deliverables without native support for file arrays.
Partial Failure Handling
If mesh generation fails but texture generation succeeds, the server returns:
{
"job_id": "job_abc123",
"status": "partial_failure",
"artifacts": [
{
"type": "texture",
"format": "png",
"channel": "diffuse",
"url": "https://cdn.mint.gg/assets/job_abc123/diffuse.png"
}
],
"errors": [
{
"stage": "mesh_generation",
"message": "Topology solver failed: non-manifold edges detected",
"retryable": true
}
]
}
The agent can choose to accept the partial artifacts (textures only) and retry mesh generation separately, discard everything and retry the full job, or surface the error to the user and ask for clarification. The retryable flag tells the agent whether a retry is likely to succeed or if the input prompt needs revision.
Preview Revisions and Review Mode
Mint MCP supports a review mode where the agent requests a low-resolution preview before committing to a full render. The agent calls generate_3d_model with review_mode: true. The server returns a preview job:
{
"job_id": "preview_xyz789",
"status": "completed",
"preview_url": "https://cdn.mint.gg/previews/preview_xyz789.png",
"revision_token": "rev_xyz789"
}
The agent can display the preview to the user. If the user requests changes, the agent calls revise_preview with the revision token and a new prompt. The server generates a new preview and returns a new revision token. When the user approves, the agent calls finalize_preview with the final revision token. The server queues a full-resolution job and returns a final job ID. The agent polls that job until completion.
This pattern keeps the agent in control of the revision loop without burning credits on full renders for every iteration. Preview tokens expire after 24 hours, so the agent must warn the user before expiration.
Stable File Delivery and Scoping
Mint MCP generates stable URLs scoped per user and per project. URLs do not expire for the lifetime of the subscription. The server uses a CDN with cache headers set to one year. The agent receives URLs like:
https://cdn.mint.gg/assets/{user_id}/{project_id}/{job_id}/model.glb
The user_id and project_id are inferred from the OAuth token the agent presents during authentication. The agent does not need to manage URL expiration or re-fetch artifacts.
When the agent writes files to the codebase, it can download the files locally and commit them to version control, store the URLs in a manifest file and fetch them at runtime, or use the URLs directly in the application (for web-based 3D viewers). The server provides a fetch_artifact tool that downloads a file and returns the local path.
Retry and Polling Strategy
The agent uses exponential backoff for polling. Initial poll interval is 5 seconds. If the job is still processing, the agent doubles the interval up to a maximum of 60 seconds. If the job fails with a retryable error, the agent retries up to 3 times with a 10-second delay between retries. If the job fails with a non-retryable error, the agent surfaces the error to the user and stops.
The server includes a Retry-After header in the response to guide the agent’s polling interval. The agent respects this header and waits the specified duration before the next poll.
Observability
Mint MCP logs every job state transition to a structured log stream. The agent can subscribe to this stream for real-time updates. The server also exposes a /jobs/{job_id}/debug endpoint that returns queue position, worker ID, GPU utilization, memory usage, and per-stage timing. This is useful for debugging performance issues or identifying bottlenecks in the generation pipeline.
Code Example: Agent Polling Loop
import time
import requests
def generate_asset(prompt, review_mode=False):
response = requests.post(
"https://mcp.mint.gg/generate_3d_model",
json={"prompt": prompt, "review_mode": review_mode},
headers={"Authorization": f"Bearer {oauth_token}"}
)
data = response.json()
if "error" in data:
raise Exception(f"Job submission failed: {data['error']}")
job_id = data["job_id"]
poll_interval = 5
max_interval = 60
while True:
status_response = requests.get(
f"https://mcp.mint.gg/jobs/{job_id}",
headers={"Authorization": f"Bearer {oauth_token}"}
)
status = status_response.json()
if status["status"] == "completed":
return status["artifacts"]
elif status["status"] == "failed":
raise Exception(f"Job failed: {status['errors']}")
elif status["status"] == "partial_failure":
print(f"Partial failure: {status['errors']}")
return status["artifacts"]
retry_after = status_response.headers.get("Retry-After", poll_interval)
time.sleep(int(retry_after))
poll_interval = min(poll_interval * 2, max_interval)
# Example usage
try:
artifacts = generate_asset("forest ranger character")
for artifact in artifacts:
print(f"Download {artifact['type']} ({artifact.get('channel', 'N/A')}) from {artifact['url']}")
# Fetch and save each artifact locally
except Exception as e:
print(f"Generation failed: {e}")
This loop handles exponential backoff, respects the Retry-After header, surfaces partial failures, and includes basic error handling for job submission and completion.
Key Orchestration Patterns
| Pattern | Implementation | Trade-off |
|---|---|---|
| Job state persistence | Server stores job state in Redis; agent queries by job ID | Agent must maintain job ID across sessions; connection drops are recoverable |
| Partial failure handling | Server returns partial_failure status with usable artifacts and error details | Agent must decide whether to accept partial results or retry; adds complexity to error handling |
| Preview revisions | Server issues revision tokens; agent correlates preview state with final job | Reduces wasted credits but adds round trips; tokens expire after 24 hours |
Technical Verdict
Use Mint MCP when you need agents to generate 3D assets, audio, or other media that takes real time to produce. The job orchestration pattern (queue, poll, retrieve) is well-suited for long-running tasks and the structured artifact schema makes it easy to wire files into a project. The cost-gating and credit system make this a good fit for commercial projects where you can pass generation costs to end users or track them against project budgets.
Avoid it if you need sub-second response times or if your agent framework does not support persistent state across sessions. The polling loop requires the agent to maintain a job ID across multiple tool calls, which some frameworks do not handle well. The remote-only deployment means you cannot run generation locally, so you depend on network availability and server uptime.