
# Use Shotstack in your own agent

If you're building your own agent, give it Shotstack as a tool. There are two ways.

## Connect the MCP server

If your agent framework supports MCP, connect it to `https://mcp.shotstack.io/` and pass your API key in an
`x-api-key` header. Your agent gets every Shotstack tool, including Studio previews, templates and AI generation. See
[MCP server](/agents/mcp-server) for the tools and how agents should use them.

Building in n8n? The Shotstack node works as a tool for n8n's AI Agent node. See
[Automation tools](/architecting-an-application/automation-tools#with-ai-agents).

## Define a render tool

Otherwise, describe one tool that takes an edit, load the
[agent guide](https://github.com/shotstack/shotstack-cli/blob/master/skills/shotstack/shared/agent-core.md) into the
system prompt, and call the Edit API when the model uses the tool. This example uses the Anthropic Python SDK. The same pattern
works with OpenAI function calling or any framework that supports tools.

```python
import os
import time

import anthropic
import requests

API = "https://api.shotstack.io/edit/stage"  # stage renders are free and watermarked
HEADERS = {"x-api-key": os.environ["SHOTSTACK_API_KEY"]}

# The guide the CLI skill and MCP server use. Fetching it each run picks up new authoring rules as they ship.
guide = requests.get(
    "https://raw.githubusercontent.com/shotstack/shotstack-cli/master/skills/shotstack/shared/agent-core.md"
).text

render_tool = {
    "name": "render_video",
    "description": "Render a Shotstack edit and return the URL of the finished video.",
    "input_schema": {
        "type": "object",
        "properties": {"edit": {"type": "object", "description": "A Shotstack Edit JSON with a timeline and output."}},
        "required": ["edit"],
    },
}


def render_video(edit):
    render_id = requests.post(f"{API}/render", json=edit, headers=HEADERS).json()["response"]["id"]
    while True:
        render = requests.get(f"{API}/render/{render_id}", headers=HEADERS).json()["response"]
        if render["status"] in ("done", "failed"):
            return render.get("url") or render.get("error", "Render failed")
        time.sleep(5)


client = anthropic.Anthropic()
messages = [{"role": "user", "content": "Make a 10-second video announcing our spring sale."}]

while True:
    reply = client.messages.create(
        model="claude-sonnet-5-5",
        max_tokens=8000,
        system=guide,
        tools=[render_tool],
        messages=messages,
    )
    messages.append({"role": "assistant", "content": reply.content})
    if reply.stop_reason != "tool_use":
        break
    messages.append({
        "role": "user",
        "content": [
            {"type": "tool_result", "tool_use_id": block.id, "content": render_video(block.input["edit"])}
            for block in reply.content
            if block.type == "tool_use"
        ],
    })

print(reply.content[-1].text)
```

Polling is the simplest way to wait for a render. In production, set a [webhook](/architecting-an-application/webhooks)
instead.

## Next steps

- Once the video is right, save it as a template so your app can render it without the agent. See
  [From draft to production](/agents/draft-to-production).
- Give the agent more tools for templates and AI generation, or use the MCP server, which has them already.
