Skip to main content

Use VieNeu from the OpenAI API

If you build your own app on OpenAI models, you can hand the model the VieNeu tools directly: the model decides when to search voices and synthesize, and OpenAI calls https://api.vieneu.io/mcp for you.

You need: an OpenAI API key and a VieNeu API key (vn_sk_..., from the Developer page). Keep both in environment variables:

export OPENAI_API_KEY=sk-...
export VIENEU_API_KEY=vn_sk_...
Just want audio from code?

If your code already knows the text and the voice, you do not need MCP or an LLM at all — call the OpenAI-compatible endpoint directly with the OpenAI SDK. MCP is for letting the model decide.

Responses API​

The Responses API has a built-in remote MCP tool. Pass your VieNeu key in authorization; OpenAI sends it to VieNeu as a Bearer token, which VieNeu accepts.

import os
from openai import OpenAI

client = OpenAI()
resp = client.responses.create(
model="gpt-5", # any current model that supports tools
tools=[{
"type": "mcp",
"server_label": "vieneu",
"server_url": "https://api.vieneu.io/mcp",
"authorization": os.environ["VIENEU_API_KEY"],
"allowed_tools": ["list_voices", "text_to_speech", "get_speech_status", "get_token_balance"],
"require_approval": "never",
}],
input="Tìm một giọng nữ miền Bắc rồi đọc câu: Xin chào, đây là VieNeu. Trả về link tải.",
)
print(resp.output_text)
import OpenAI from "openai";

const client = new OpenAI();
const resp = await client.responses.create({
model: "gpt-5",
tools: [{
type: "mcp",
server_label: "vieneu",
server_url: "https://api.vieneu.io/mcp",
authorization: process.env.VIENEU_API_KEY,
allowed_tools: ["list_voices", "text_to_speech", "get_speech_status", "get_token_balance"],
require_approval: "never",
}],
input: "Tìm một giọng nữ miền Bắc rồi đọc câu: Xin chào, đây là VieNeu. Trả về link tải.",
});
console.log(resp.output_text);
  • require_approval: the default asks for approval before every tool call (the response then contains mcp_approval_request items you must answer). "never" lets the model spend your VieNeu tokens without asking — keep allowed_tools tight, or require approval for text_to_speech only: "require_approval": {"always": {"tool_names": ["text_to_speech"]}}.
  • The key is not stored by OpenAI, so send it with every request.
  • The audio link is in the tool result and usually in the model's answer; the mcp_call items in resp.output hold the raw tool results.

OpenAI Agents SDK (Python)​

Let OpenAI call VieNeu for you (hosted tool):

import os
from agents import Agent, HostedMCPTool, Runner

agent = Agent(
name="Narrator",
instructions="You narrate Vietnamese text with VieNeu and return the audio link.",
tools=[HostedMCPTool(tool_config={
"type": "mcp",
"server_label": "vieneu",
"server_url": "https://api.vieneu.io/mcp",
"authorization": os.environ["VIENEU_API_KEY"],
"require_approval": "never",
})],
)
result = Runner.run_sync(agent, "Đọc câu 'Chào buổi sáng' bằng giọng Thu Trang.")
print(result.final_output)

Or connect from your own process (your code calls VieNeu, with any header you choose):

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

async def main():
async with MCPServerStreamableHttp(
name="vieneu",
params={
"url": "https://api.vieneu.io/mcp",
"headers": {"X-API-Key": os.environ["VIENEU_API_KEY"]},
"timeout": 60,
},
cache_tools_list=True,
) as vieneu:
agent = Agent(name="Narrator", mcp_servers=[vieneu])
result = await Runner.run(agent, "Đọc câu 'Chào buổi sáng' bằng giọng Thu Trang.")
print(result.final_output)

asyncio.run(main())

Set timeout generously: text_to_speech waits for the audio (a few seconds for short text, up to about 50 seconds for long text).

Costs​

Two bills: OpenAI charges for the model's tokens, VieNeu charges your plan for each synthesis (per character, minimum 50). list_voices, list_emotion_tags, get_speech_status and get_token_balance are free on the VieNeu side.