Connect to MCP clients
Botverse uses the Model Context Protocol (MCP) with Streamable HTTP transport. Any MCP-compatible client can connect — Claude Desktop, Cursor, Continue.dev, or a custom agent.
https://botverse.cloud/mcp — works with any client that supports Streamable HTTP transport.Claude.ai (web — recommended)
The fastest way to connect. Works in any browser — no software to install, no config files. Uses a short-lived connector token so your API key never appears in a URL.
Step 1 — generate your connector URL
Go to botverse.cloud/dashboard/api-keys and click Generate connector URL. This creates a 24-hour token and gives you a ready-to-paste URL in the format:
https://botverse.cloud/mcp?token=bv_sess_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Step 2 — add the connector in claude.ai
Go to claude.ai and open Customize → Connectors → +.
Paste the URL you generated in Step 1. Leave OAuth fields blank. Click Add. Claude will connect and list all Botverse tools under Tool permissions.
Token expiry and reconnection
When a connector token expires (after 24 hours), claude.ai will show a connection error for Botverse tools. To reconnect: go to your dashboard, click Regenerate URL, then update the URL in your claude.ai connector settings. The whole flow takes about 30 seconds.
Claude Desktop
Claude Desktop supports MCP via a config file. Setup differs slightly between Mac and Windows.
Locate your config file
macOS / Linux
Add the mcpServers entry to your config file:
{
"mcpServers": {
"botverse": {
"url": "https://botverse.cloud/mcp",
"headers": {
"X-API-Key": "bv_live_YOUR_KEY_HERE"
}
}
}
}Quit and relaunch Claude Desktop. In a new conversation, type: What tools do you have from Botverse? — Claude will list all five Botverse tools.
Windows
Windows Claude Desktop does not support the url config format directly. Use a small local bridge script instead — it starts instantly and proxies MCP messages to Botverse over HTTPS.
Step 1 — Install Node.js if you haven't already: nodejs.org. Version 18 or later required.
Step 2 — Create the bridge script. Save the following as C:\botverse-bridge.mjs, replacing bv_live_YOUR_KEY_HERE with your API key. The key goes in a header — not a URL — so it stays out of logs and history.
import { createInterface } from "readline";
const API_KEY = "bv_live_YOUR_KEY_HERE";
const MCP_URL = "https://botverse.cloud/mcp";
const TOOLS = [
{ name: "get_upload_url", description: "Get a presigned S3 PUT URL to upload a source video or audio file.", inputSchema: { type: "object", properties: { filename: { type: "string" }, content_type: { type: "string" } }, required: ["filename", "content_type"] } },
{ name: "transcode_video", description: "Submit a video transcode job. Returns a job_id — poll get_job_status until complete.", inputSchema: { type: "object", properties: { object_key: { type: "string" }, output_format: { type: "string", enum: ["webm", "mov_prores", "mp3", "gif"] } }, required: ["object_key", "output_format"] } },
{ name: "get_job_status", description: "Poll the status of a transcode job. Call every 5 seconds until complete or failed.", inputSchema: { type: "object", properties: { job_id: { type: "string" } }, required: ["job_id"] } },
{ name: "get_download_url", description: "Get a presigned download URL for a completed job. URL expires in 24 hours.", inputSchema: { type: "object", properties: { job_id: { type: "string" } }, required: ["job_id"] } },
{ name: "get_wallet_balance", description: "Check your prepaid wallet balance.", inputSchema: { type: "object", properties: {}, required: [] } },
];
const rl = createInterface({ input: process.stdin, terminal: false });
rl.on("line", async (line) => {
const trimmed = line.trim();
if (!trimmed) return;
let body;
try { body = JSON.parse(trimmed); } catch { return; }
const { method, id } = body;
if (method === "initialize") {
process.stdout.write(JSON.stringify({ jsonrpc: "2.0", id, result: { protocolVersion: "2024-11-05", capabilities: { tools: {} }, serverInfo: { name: "Botverse", version: "1.0.0" } } }) + "\n");
return;
}
if (method === "tools/list") {
process.stdout.write(JSON.stringify({ jsonrpc: "2.0", id, result: { tools: TOOLS } }) + "\n");
return;
}
if (method?.startsWith("notifications/")) return;
try {
const res = await fetch(MCP_URL, { method: "POST", headers: { "Content-Type": "application/json", "X-API-Key": API_KEY }, body: trimmed });
if (res.status === 204) return;
process.stdout.write(await res.text() + "\n");
} catch (e) {
process.stdout.write(JSON.stringify({ jsonrpc: "2.0", id: id ?? null, error: { code: -32603, message: e.message } }) + "\n");
}
});Step 3 — Add to your Claude Desktop config:
{
"mcpServers": {
"botverse": {
"command": "C:\\Program Files\\nodejs\\node.exe",
"args": ["C:\\botverse-bridge.mjs"]
}
}
}C:\Program Files\nodejs\node.exe, find the correct path by running where node in a terminal and update the command value accordingly.Quit and relaunch Claude Desktop. Ask: What tools do you have from Botverse?
Test your first encode
Try a real job. Paste this into a Claude conversation:
I have a video at /Users/me/Desktop/keynote.mp4. Please transcode it to WebM format using Botverse, then give me the download URL.
Claude will call get_upload_url, upload the file, call transcode_video, poll for completion, and return a download link.
What is my Botverse wallet balance?Cursor
Cursor supports MCP in agent mode via the same config format as Claude Desktop (macOS).
{
"mcpServers": {
"botverse": {
"url": "https://botverse.cloud/mcp",
"headers": {
"X-API-Key": "bv_live_YOUR_KEY_HERE"
}
}
}
}After restarting Cursor, open Agent mode (Cmd/Ctrl + Shift + L). Botverse tools will be available to the agent when relevant to your request.
Continue.dev
Add Botverse as an MCP provider in your Continue config:
{
"experimental": {
"modelContextProtocolServers": [
{
"transport": {
"type": "streamableHttp",
"url": "https://botverse.cloud/mcp",
"headers": {
"X-API-Key": "bv_live_YOUR_KEY_HERE"
}
}
}
]
}
}OpenAI / ChatGPT
OpenAI Assistants API (function calling)
OpenAI does not support MCP natively. Define Botverse tools as OpenAI function definitions and proxy the calls to the Botverse MCP endpoint.
{
"name": "transcode_video",
"description": "Submit a video transcode job on Botverse. Source must first be uploaded via get_upload_url. Returns a job_id to poll with get_job_status.",
"parameters": {
"type": "object",
"properties": {
"object_key": {
"type": "string",
"description": "S3 object key from get_upload_url response"
},
"output_format": {
"type": "string",
"enum": ["webm", "mov_prores", "mp3", "gif"],
"description": "Target output format"
}
},
"required": ["object_key", "output_format"]
}
}Proxy function call to Botverse
When OpenAI calls a function, forward it to the Botverse MCP endpoint:
async function callBotverseTool(toolName: string, args: Record<string, unknown>) {
const res = await fetch("https://botverse.cloud/mcp", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": process.env.BOTVERSE_API_KEY!,
},
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "tools/call",
params: { name: toolName, arguments: args },
}),
});
const data = await res.json();
return JSON.parse(data.result.content[0].text);
}ChatGPT Plugins / GPT Actions
Build a thin REST wrapper around the Botverse MCP tools and expose it as an OpenAPI spec. Each Botverse tool becomes one API endpoint. GPT Actions call your wrapper, which calls Botverse. A full OpenAPI spec is available in the API reference.
Custom agents (bare HTTP)
Botverse uses standard JSON-RPC 2.0 over HTTP POST. Any HTTP client can call it — no MCP library required.
Tool discovery
curl -X POST https://botverse.cloud/mcp \
-H "Content-Type: application/json" \
-H "X-API-Key: bv_live_YOUR_KEY" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'Python example
import httpx, json, time
BOTVERSE_URL = "https://botverse.cloud/mcp"
BOTVERSE_KEY = "bv_live_YOUR_KEY"
def call_tool(name: str, arguments: dict) -> dict:
response = httpx.post(
BOTVERSE_URL,
headers={"Content-Type": "application/json", "X-API-Key": BOTVERSE_KEY},
json={"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {"name": name, "arguments": arguments}},
timeout=35,
)
result = response.json()
if "error" in result:
raise RuntimeError(result["error"]["message"])
return json.loads(result["result"]["content"][0]["text"])
# Get upload URL
upload = call_tool("get_upload_url", {"filename": "video.mp4", "content_type": "video/mp4"})
print(upload["upload_url"]) # PUT your file here
# Submit transcode
job = call_tool("transcode_video", {"object_key": upload["object_key"], "output_format": "webm"})
# Poll for completion
while True:
status = call_tool("get_job_status", {"job_id": job["job_id"]})
if status["status"] == "complete": break
if status["status"] == "failed": raise RuntimeError(status.get("error", "Job failed"))
time.sleep(5)
# Get download URL
dl = call_tool("get_download_url", {"job_id": job["job_id"]})
print(dl["download_url"])TypeScript / Node.js example
const BASE = "https://botverse.cloud/mcp";
const KEY = process.env.BOTVERSE_API_KEY!;
async function callTool<T>(name: string, args: Record<string, unknown>): Promise<T> {
const res = await fetch(BASE, {
method: "POST",
headers: { "Content-Type": "application/json", "X-API-Key": KEY },
body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/call",
params: { name, arguments: args } }),
});
const data = await res.json();
if (data.error) throw new Error(data.error.message);
return JSON.parse(data.result.content[0].text) as T;
}
async function pollUntilComplete(jobId: string, intervalMs = 5000) {
for (;;) {
const s = await callTool<{ status: string }>("get_job_status", { job_id: jobId });
if (s.status === "complete") return s;
if (s.status === "failed") throw new Error("Job failed");
await new Promise(r => setTimeout(r, intervalMs));
}
}