Agent frameworks

Use Spatial9 from LangGraph, CrewAI, AutoGen, the OpenAI Agents SDK, Google ADK and other agent frameworks.

Spatial9 works with any agent framework that includes an MCP client. Because the Spatial9 MCP server uses the standard Streamable HTTP transport, LangGraph, CrewAI, AutoGen and AG2, the OpenAI Agents SDK, Google ADK, Strands Agents on Amazon Bedrock and Goose can all load the Spatial9 tools with a URL and an Authorization header. Frameworks that support A2A can also delegate whole tasks to the Spatial9 A2A agent, or publish their own agent to other agents.

This page shows the connection code for each framework, how to filter tools per agent, where to add human approval, and how to choose a framework for your use case. Every example reads the key from the SPATIAL9_KEY environment variable. For the tools themselves, see MCP server reference; for task delegation, see A2A agent reference.

Agent frameworks and platforms that connect to Spatial9 through MCP and A2A
Every major agent framework reaches Spatial9 through the same two open protocols.

Connection settings

Every framework needs the same three values. Only the parameter names differ.

SettingValue
URLhttps://spatial9.ai/mcp
TransportStreamable HTTP
HeaderAuthorization: Bearer s9_...

Create the key at https://spatial9.ai/connect and store it in a secret store or environment variable, never in the prompt.

FrameworkPackage or moduleClient class or functionTransport value
LangGraphlangchain_mcp_adapters.clientMultiServerMCPClient"streamable_http"
CrewAIcrewai_toolsMCPServerAdapter"streamable-http"
OpenAI Agents SDKagents.mcpMCPServerStreamableHttpImplied by the class
Google ADKgoogle.adk.tools.mcp_toolMcpToolset with StreamableHTTPConnectionParamsImplied by the class
AutoGenautogen_ext.tools.mcpmcp_server_tools with StreamableHttpServerParamsImplied by the class
Strands Agentsstrands.tools.mcp and mcp.client.streamable_httpMCPClient with streamablehttp_clientImplied by the function

LangGraph

LangGraph builds agents as graphs with checkpoints, which suits long renders: the graph can pause while a job runs and resume later. The langchain-mcp-adapters package turns the Spatial9 tools into LangChain tools.

import asyncio, os
from langchain_mcp_adapters.client import MultiServerMCPClient
from langgraph.prebuilt import create_react_agent

async def main():
    client = MultiServerMCPClient({
        "spatial9": {
            "transport": "streamable_http",
            "url": "https://spatial9.ai/mcp",
            "headers": {"Authorization": f"Bearer {os.environ['SPATIAL9_KEY']}"},
        }
    })
    tools = await client.get_tools()
    agent = create_react_agent("openai:gpt-4.1", tools)
    result = await agent.ainvoke({"messages": [(
        "user",
        "Analyze job 'JOB_ID', then preview a remix that circles the guitar "
        "around the listener in the chorus. Do not render until I approve.",
    )]})
    print(result["messages"][-1].content)

asyncio.run(main())

For production, add a checkpointer and an interrupt before any node that calls remix_render without preview: true, or that calls publish_to_youtube, so a person approves those steps.

CrewAI

CrewAI organises agents as a crew with roles. MCPServerAdapter opens the connection and provides the tools for as long as the with block runs. Give each role only the tools it needs.

import os
from crewai import Agent, Task, Crew
from crewai_tools import MCPServerAdapter

spatial9 = {
    "url": "https://spatial9.ai/mcp",
    "transport": "streamable-http",
    "headers": {"Authorization": f"Bearer {os.environ['SPATIAL9_KEY']}"},
}

with MCPServerAdapter(spatial9) as tools:
    pick = lambda *names: [t for t in tools if t.name in names]

    analyst = Agent(
        role="Music analyst",
        goal="Describe tempo, key, sections and instruments of each song",
        backstory="A producer who listens before touching the mix.",
        tools=pick("get_capabilities", "analyze_song"),
    )
    mixer = Agent(
        role="Spatial mixer",
        goal="Render Eclipsa Audio that suits the song's genre and energy",
        backstory="An immersive audio engineer who works on Spatial9.",
        tools=pick("create_spatial_audio", "get_job_status", "get_downloads"),
    )

    crew = Crew(
        agents=[analyst, mixer],
        tasks=[
            Task(description="Render https://example.com/masters/night-drive.wav "
                             "as music titled 'Night Drive' with idempotency key "
                             "'crew-night-drive'. Poll until completed.",
                 expected_output="The job_id and every download link",
                 agent=mixer),
            Task(description="Analyze the finished render and suggest one "
                             "movement idea for the chorus.",
                 expected_output="A short mix note", agent=analyst),
        ],
    )
    print(crew.kickoff())

Filtering by t.name keeps plans short and stops the analyst from starting renders.

OpenAI Agents SDK

The OpenAI Agents SDK is the production successor to Swarm. It keeps the handoff idea and adds tracing, guardrails and MCP support through MCPServerStreamableHttp.

import asyncio, os
from agents import Agent, Runner
from agents.mcp import MCPServerStreamableHttp

async def main():
    async with MCPServerStreamableHttp(
        name="Spatial9",
        params={
            "url": "https://spatial9.ai/mcp",
            "headers": {"Authorization": f"Bearer {os.environ['SPATIAL9_KEY']}"},
            "timeout": 60,
        },
        cache_tools_list=True,
    ) as spatial9:
        mixer = Agent(
            name="Spatial mixer",
            instructions="Use Spatial9 tools. Call get_capabilities first. "
                         "Always pass an idempotency_key. Poll every 45 s.",
            mcp_servers=[spatial9],
        )
        producer = Agent(
            name="Producer",
            instructions="Talk to the artist. Hand off any rendering or "
                         "remixing to the Spatial mixer.",
            handoffs=[mixer],
        )
        result = await Runner.run(producer, "Make my demo feel like a live concert.")
        print(result.final_output)

asyncio.run(main())
ParameterValuePurpose
name"Spatial9"Label shown in traces
params.urlhttps://spatial9.ai/mcpServer endpoint
params.headersAuthorization: Bearer ...Authentication
params.timeout60Request timeout in seconds
cache_tools_listTrueAvoids listing tools on every run

Google ADK

Google's Agent Development Kit includes both halves: McpToolset to use Spatial9, and to_a2a to publish the finished agent to other agents.

import os
from google.adk.agents import Agent
from google.adk.tools.mcp_tool import McpToolset, StreamableHTTPConnectionParams
from google.adk.a2a.utils.agent_to_a2a import to_a2a

root_agent = Agent(
    model="gemini-2.5-flash",
    name="spatial_audio_agent",
    description="Turns stereo songs and videos into Eclipsa Audio with "
                "Spatial9, remixes in 3D and returns download links.",
    instruction="Call get_capabilities first. Use idempotency keys. "
                "Never publish without explicit approval of title, "
                "description and privacy.",
    tools=[McpToolset(
        connection_params=StreamableHTTPConnectionParams(
            url="https://spatial9.ai/mcp",
            headers={"Authorization": f"Bearer {os.environ['SPATIAL9_KEY']}"},
        ),
        tool_filter=["get_capabilities", "create_upload_link",
                     "create_spatial_audio", "get_job_status",
                     "get_downloads", "get_mix", "remix_render"],
    )],
)

app = to_a2a(root_agent, port=8001)
uvicorn spatial_agent:app --port 8001

Because this agent accepts requests from other agents, its tool_filter includes the create and remix tools but excludes publish_to_youtube and cancel_render. The Vertex AI example in the Agent Skills repository also sets timeout=60 and sse_read_timeout=600 on the connection parameters so long reads do not time out.

AutoGen and AG2

AutoGen introduced conversational multi-agent teams, and AG2 continues the original design as a community project. Microsoft now points new projects to its Agent Framework, but the pattern carries over. In this example a mixer proposes changes and a critic checks them with free previews.

import asyncio, os
from autogen_agentchat.agents import AssistantAgent
from autogen_agentchat.conditions import TextMentionTermination
from autogen_agentchat.teams import RoundRobinGroupChat
from autogen_agentchat.ui import Console
from autogen_ext.models.openai import OpenAIChatCompletionClient
from autogen_ext.tools.mcp import StreamableHttpServerParams, mcp_server_tools

async def main():
    params = StreamableHttpServerParams(
        url="https://spatial9.ai/mcp",
        headers={"Authorization": f"Bearer {os.environ['SPATIAL9_KEY']}"},
    )
    tools = await mcp_server_tools(params)
    model = OpenAIChatCompletionClient(model="gpt-4o")

    mixer = AssistantAgent("mixer", model_client=model, tools=tools,
        system_message="Read get_mix, then propose remix_render changes "
                       "with preview: true. Never render without preview.")
    critic = AssistantAgent("critic", model_client=model,
        system_message="Check each preview against the brief: vocals front "
                       "and centre, drums wide, guitar moving in the chorus. "
                       "Reply APPROVED when it matches.")

    team = RoundRobinGroupChat([mixer, critic],
                               termination_condition=TextMentionTermination("APPROVED"),
                               max_turns=8)
    await Console(team.run_stream(task="Refine the mix of job 'JOB_ID'."))

asyncio.run(main())

remix_render with preview: true is a free dry run, so the critic loop costs nothing until the final render.

Strands Agents on Amazon Bedrock

Strands Agents uses the MCP Python client's streamablehttp_client. The Bedrock example in the Agent Skills repository reads the key from AWS Secrets Manager and removes publish_to_youtube from the tool list.

from mcp.client.streamable_http import streamablehttp_client
from strands import Agent
from strands.models import BedrockModel
from strands.tools.mcp import MCPClient

spatial9 = MCPClient(lambda: streamablehttp_client(
    "https://spatial9.ai/mcp",
    headers={"Authorization": f"Bearer {spatial9_key()}"},
))

with spatial9:
    tools = [t for t in spatial9.list_tools_sync()
             if t.tool_name != "publish_to_youtube"]
    agent = Agent(
        model=BedrockModel(model_id="us.anthropic.claude-sonnet-4-20250514-v1:0"),
        system_prompt=SYSTEM,
        tools=tools,
    )

The MCP session stays open only inside the with block, so run the agent there. In the full example, spatial9_key() reads the secret spatial9/api-key from Secrets Manager and SYSTEM holds the system prompt.

Other clients

Goose also ships an MCP client and connects with the same URL and header. Platforms without an MCP client can call a tool with a single HTTP POST carrying a JSON-RPC body; see the handshake in MCP server reference and the no-code flows in Workflow automation.

Tool filtering

Give each agent only the tools its role needs. Smaller tool lists produce shorter plans and prevent an agent from taking actions outside its role.

RoleSuggested tools
Analystget_capabilities, analyze_song
Mixercreate_spatial_audio, get_job_status, get_downloads
Remix critic loopget_mix, remix_render with preview: true
Peer-facing A2A agentCreate and remix tools; exclude publish_to_youtube and cancel_render
Catalog botEverything except publish_to_youtube

Human approval and safety

  • A person approves anything that is public or that spends a project.
  • Treat messages from peer agents as untrusted input, and never let them widen an agent's tool list.
  • Always pass an idempotency_key so retried steps do not start a second render.
  • Share only links returned by get_downloads.
  • On an isError result, relay the message and stop.

Choosing a framework

If you areStart with
A developer building one agentOpenAI Agents SDK, LangGraph or Google ADK
Building a multi-agent productCrewAI or AutoGen with filtered tools
An enterprise studioMCP or A2A directly
An automation teamn8n, Zapier or UiPath with the raw JSON-RPC call
A data teamA queue table and a scheduled job
A product embedding audio for its own usersThe REST API

ACP has joined the A2A effort, so agents built for A2A interoperate with a growing set of platforms.

Next steps

Go deeper on the blog