Skip to the page

LiveKit Agents

Give a LiveKit voice agent live web search. It asks SpecStream mid conversation, gets one answer with the pages that print it, and speaks it back. Connect over MCP in a few lines, or call the Search API from a function tool.

SpecStream for LiveKit AgentsAgent frameworks & builders

What you need

  • Python and LiveKit Agents 1.8 or newer, with a voice pipeline or realtime model that supports tool calls.
  • A SpecStream account. New accounts start with $10 of credit, no card. Create one.
  • A SpecStream API key with a spending limit.
  1. 1. Create an API key

    In your SpecStream workspace, open Agents & API, choose API keys, then Create API key, and set a spending limit. Keep the key in the environment the agent server runs in:

    Terminal
    export SPECSTREAM_API_KEY="YOUR_SPECSTREAM_API_KEY"
  2. 2. Install the MCP extra

    LiveKit Agents reaches MCP servers through its optional mcp dependencies:

    Terminal
    uv add "livekit-agents[mcp]~=1.8"
  3. 3. Add SpecStream as an MCP toolset

    Wrap SpecStream's server in mcp.MCPToolset and pass it in the agent's tools. MCPServerHTTP sends the key as a header, and the address ends in /mcp, so LiveKit picks Streamable HTTP on its own. allowed_tools keeps the agent to search_web and read_pages, the two tools a spoken turn needs:

    agent.py
    import os
    from livekit.agents import Agent, AgentServer, AgentSession, JobContext, cli, inference, mcp
    specstream = mcp.MCPToolset(
    id="specstream",
    mcp_server=mcp.MCPServerHTTP(
    "https://api.specstream.ai/mcp",
    headers={"Authorization": f"Bearer {os.environ['SPECSTREAM_API_KEY']}"},
    allowed_tools=["search_web", "read_pages"],
    ),
    )
    server = AgentServer()
    @server.rtc_session()
    async def entrypoint(ctx: JobContext):
    session = AgentSession(
    vad=inference.VAD(),
    stt=inference.STT("deepgram/nova-3", language="multi"),
    llm=inference.LLM("google/gemma-4-31b-it"),
    tts=inference.TTS("cartesia/sonic-3", voice="9626c31c-bec5-4cca-baa8-f8ba9e84c8bc"),
    )
    agent = Agent(
    instructions=(
    "You are a voice assistant. For anything recent or factual, call search_web "
    "with the question in plain words. Say the answer in one or two sentences "
    "and name the site it came from. Call read_pages only when the user asks "
    "what a page says."
    ),
    tools=[specstream],
    )
    await session.start(agent=agent, room=ctx.room)
    if __name__ == "__main__":
    cli.run_app(server)
  4. 4. Run it and ask

    Start the agent with uv run agent.py dev, join the room from the LiveKit Agents Playground, and ask a question about this week:

    Spoken to the agent
    Who won the Nobel Prize in Chemistry this year, and for what?

What comes back

search_web takes {"q": "<the question>"}. The reply holds answer, the value as the pages print it, with the page it was read from, and sources, the results read in rank order with their url, title, site and snippet. When no page prints a value that answers the question, answer is null and the sources are still there, so the agent can say what it found instead of guessing.

read_pages takes {"urls": ["<url>", ...]} and returns each page's text as Markdown, for a follow up such as "what does that article say about prices".

Or call the Search API from a function tool

If you would rather not run an MCP client, wrap the Search API in a @function_tool. The call is async, so the event loop keeps the audio moving while it waits, and a failed search returns a sentence the agent can speak instead of raising. Install httpx and pass search_web in the agent's tools:

Keep spoken answers short

A search answers in a few seconds. Tell the agent in its instructions to say a short line such as "Let me check" before it calls the tool, and to read back the answer and one source, not the whole list. Quoted phrases and site: in the question hold on every result, which helps when the user names a source.

Cost

Each search is one Search API call at $5 per 1,000 searches of up to 10 results, from your balance, with no quote and no approval. A search that returns no results costs nothing. Each page read_pages reads is $0.80 per 1,000 pages, and a page with no text is not charged. The reply's price_usd says what each call cost. Search API

Limits on the key

The key's spending limit holds on every call the agent makes, so a long session or a loop cannot spend past it. Give the agent server its own key, and revoke it in Agents & API to stop it at once. Every search is kept in your account's history with its answer and sources.

Remove

Take the toolset or the function tool out of the agent's tools, and revoke the key in Agents & API. Every tool on the server is described in the agent guide. Questions go to [email protected].

More

SpecStream for LiveKit Agents covers what it does in LiveKit Agents on one page. Every other tool has its guide in Connect your tools. You see the most a request can cost before it starts, and the matches are paid from your balance. Billing has the details. For help, email [email protected].