Connect your agent (MCP)
Keytween runs a remote Model Context Protocol server. Add it to your coding agent and the agent can generate images and video, check prices and your balance, read the prompting guides and manage what it made, all through tool calls.
| Endpoint | https://keytween.com/mcp |
| Transport | Streamable HTTP (stateless; no session to keep alive) |
| Authentication | Authorization: Bearer <your API key> on every request |
| Protocol versions | 2026-07-28, and the 2025 revisions for older clients |
1. Get an API key #
- Sign in and open Account.
- Create a key under API keys. Keys start with
sk_test_and are shown once. API keys unlock after your first credit purchase. - Put the key in an environment variable so it stays out of files you commit:
export KEYTWEEN_API_KEY="sk_test_..."A key acts as you and spends your credits. Revoke it on the Account page if it leaks.
2. Add the server #
Claude Code #
Project scope, shared with your team through .mcp.json in the project root:
{
"mcpServers": {
"keytween": {
"type": "http",
"url": "https://keytween.com/mcp",
"headers": {
"Authorization": "Bearer ${KEYTWEEN_API_KEY}"
}
}
}
}Or from the command line:
claude mcp add --transport http --scope project keytween https://keytween.com/mcp \
--header "Authorization: Bearer $KEYTWEEN_API_KEY"${VAR}and${VAR:-default}are expanded inurlandheaders.- Use
--scope userto make it available in every project instead. - Check the connection with
/mcpinside a session orclaude mcp list. - Prompts appear as slash commands, for example
/mcp__keytween__storyboard.
Cursor #
.cursor/mcp.json in the project, or ~/.cursor/mcp.json for every project:
{
"mcpServers": {
"keytween": {
"url": "https://keytween.com/mcp",
"headers": { "Authorization": "Bearer ${env:KEYTWEEN_API_KEY}" }
}
}
}Cursor expands ${env:NAME}. The Cursor CLI reads the same files; agent mcp list shows the connection.
VS Code with GitHub Copilot #
.vscode/mcp.json (note the root key is servers). VS Code asks for the key once and stores it securely:
{
"inputs": [
{ "type": "promptString", "id": "keytween-key", "description": "Keytween API key", "password": true }
],
"servers": {
"keytween": {
"type": "http",
"url": "https://keytween.com/mcp",
"headers": { "Authorization": "Bearer ${input:keytween-key}" }
}
}
}Run MCP: List Servers from the command palette to start it and see its output.
GitHub Copilot CLI #
copilot mcp add --transport http --header "Authorization: Bearer $KEYTWEEN_API_KEY" keytween https://keytween.com/mcpThis writes ~/.copilot/mcp-config.json. A project can also carry .mcp.json or .github/mcp.json in the Claude Code format above. Check with /mcp show keytween.
OpenAI Codex #
~/.codex/config.toml (shared by the CLI and the IDE extension):
[mcp_servers.keytween]
url = "https://keytween.com/mcp"
bearer_token_env_var = "KEYTWEEN_API_KEY"
tool_timeout_sec = 120Or codex mcp add keytween --url https://keytween.com/mcp --bearer-token-env-var KEYTWEEN_API_KEY. Codex ends tool calls after 60 seconds by default, which is enough for the default waits here; tool_timeout_sec gives longer waits room. Check with /mcp.
Gemini CLI #
~/.gemini/settings.json, or .gemini/settings.json in the project. Use httpUrl (plain url means the older SSE transport):
{
"mcpServers": {
"keytween": {
"httpUrl": "https://keytween.com/mcp",
"headers": { "Authorization": "Bearer sk_test_..." }
}
}
}Or gemini mcp add --transport http -H "Authorization: Bearer $KEYTWEEN_API_KEY" keytween https://keytween.com/mcp. Check with /mcp.
Windsurf #
~/.config/devin/mcp_config.json (macOS and Linux) or %APPDATA%\devin\mcp_config.json (Windows); older installs use ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"keytween": {
"serverUrl": "https://keytween.com/mcp",
"headers": { "Authorization": "Bearer ${env:KEYTWEEN_API_KEY}" }
}
}
}Cline #
Open the MCP Servers panel, choose Remote Servers, pick Streamable HTTP and enter the URL; or edit the config (~/.cline/mcp.json for the CLI):
{
"mcpServers": {
"keytween": {
"type": "streamableHttp",
"url": "https://keytween.com/mcp",
"headers": { "Authorization": "Bearer sk_test_..." }
}
}
}Zed #
settings.json (zed: open settings file), under context_servers:
{
"context_servers": {
"keytween": {
"url": "https://keytween.com/mcp",
"headers": { "Authorization": "Bearer sk_test_..." }
}
}
}Keep the Authorization header: without it Zed starts an OAuth sign-in, which this server does not use.
OpenCode #
opencode.json in the project, or ~/.config/opencode/opencode.json:
{
"mcp": {
"keytween": {
"type": "remote",
"url": "https://keytween.com/mcp",
"enabled": true,
"oauth": false,
"headers": { "Authorization": "Bearer {env:KEYTWEEN_API_KEY}" }
}
}
}Set "oauth": false so OpenCode sends the header instead of starting an OAuth flow. Check with opencode mcp list.
Kilo Code #
kilo.jsonc in the project, or ~/.config/kilo/kilo.jsonc:
{
"mcp": {
"keytween": {
"type": "remote",
"url": "https://keytween.com/mcp",
"headers": { "Authorization": "Bearer {env:KEYTWEEN_API_KEY}" },
"enabled": true,
"timeout": 120000
}
}
}Kilo Code's default timeout for remote servers is 15 seconds, so set timeout (milliseconds) as shown.
Amp #
.amp/settings.json in the workspace, or ~/.config/amp/settings.json:
{
"amp.mcpServers": {
"keytween": {
"url": "https://keytween.com/mcp",
"headers": { "Authorization": "Bearer ${KEYTWEEN_API_KEY}" }
}
}
}Workspace servers wait for amp mcp approve keytween. Check with amp mcp doctor.
Goose #
~/.config/goose/config.yaml:
extensions:
keytween:
type: streamable_http
name: keytween
enabled: true
uri: "https://keytween.com/mcp"
headers:
Authorization: "Bearer sk_test_..."
timeout: 300Or run goose configure, choose Add Extension, then Remote Extension (Streamable HTTP).
Kiro #
.kiro/settings/mcp.json in the workspace, or ~/.kiro/settings/mcp.json:
{
"mcpServers": {
"keytween": {
"url": "https://keytween.com/mcp",
"headers": { "Authorization": "Bearer ${KEYTWEEN_API_KEY}" }
}
}
}Kiro only expands environment variables you have approved: add KEYTWEEN_API_KEY under the Mcp Approved Env Vars setting.
JetBrains Junie #
.junie/mcp/mcp.json in the project, or ~/.junie/mcp/mcp.json:
{
"mcpServers": {
"keytween": {
"url": "https://keytween.com/mcp",
"headers": { "Authorization": "Bearer sk_test_..." }
}
}
}Factory Droid #
droid mcp add keytween https://keytween.com/mcp --type http --header "Authorization: Bearer $KEYTWEEN_API_KEY"Continue #
A file in .continue/mcpServers/, or the mcpServers block of config.yaml. MCP tools are available in agent mode:
mcpServers:
- name: keytween
type: streamable-http
url: https://keytween.com/mcp
requestOptions:
headers:
Authorization: "Bearer ${{ secrets.KEYTWEEN_API_KEY }}"Claude Desktop, JetBrains AI Assistant and other stdio-only clients #
Clients that can only launch local servers, or that cannot send a custom header to a remote one, reach the server through the mcp-remote bridge:
{
"mcpServers": {
"keytween": {
"command": "npx",
"args": ["mcp-remote", "https://keytween.com/mcp", "--header", "Authorization:${AUTH_HEADER}"],
"env": { "AUTH_HEADER": "Bearer sk_test_..." }
}
}
}In Claude Desktop this goes in claude_desktop_config.json (Settings, Developer, Edit Config). Claude Desktop can also add the server as a custom connector: Customize, Connectors, Add custom connector, enter https://keytween.com/mcp, choose No sign in, and add a request header named Authorization with the value Bearer sk_test_....
Anything else #
Any client that speaks MCP over Streamable HTTP works. It needs three things: the URL https://keytween.com/mcp, the HTTP transport (sometimes called http, streamable-http or remote), and the header Authorization: Bearer <key>. The server does not use OAuth, so turn OAuth discovery off if your client offers the choice.
3. Check that it works #
Ask the agent: "Use Keytween to check my credit balance." It should call get_account and report your credits.
From a terminal, without any agent:
curl -s https://keytween.com/mcp \
-H "Authorization: Bearer $KEYTWEEN_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'Timeouts #
Generations are queued, and a video takes two to three minutes to render. The tools are built so that no single call has to stay open that long:
- A generate call waits up to
wait_seconds(45 by default) and then returns the job, finished or not. wait_for_jobwaits again, up totimeout_seconds, and can be called as often as needed.- While a call is open the server streams progress and keep-alive frames, so proxies do not drop it.
The defaults stay under the 60-second tool timeout that several clients apply. If your client allows longer calls you can pass up to 300 seconds and finish a video in one call:
| Client | Default tool timeout | Setting |
|---|---|---|
| Claude Code | very long; calls with no progress for 5 minutes are stopped | MCP_TOOL_TIMEOUT, or "timeout" per server (ms) |
| OpenAI Codex | 60 s | tool_timeout_sec |
| Gemini CLI | 10 minutes | "timeout" per server (ms) |
| Kilo Code | 15 s | "timeout" per server (ms) |
| Goose | 300 s | timeout (seconds) |
What the agent gets #
- Tools for generating, editing, waiting, managing sequences, pricing and account status. See the MCP tool reference.
- Guides as MCP resources (
keytween://guides/<topic>) and through theget_guidetool, so the agent can read the prompting guides before it writes a prompt. - Prompts (slash commands in clients that support them) for storyboarding a multi-shot video and for drafting image and video prompts.
- Previews: finished images and videos come back with a small picture the model can look at, and a download link it can save with
curl.
Troubleshooting #
| Symptom | Cause and fix |
|---|---|
401 with invalid_api_key |
The key is wrong or revoked. An unexpanded ${...} variable also ends up here: check that the variable is set in the environment the agent runs in. |
401 with unauthenticated |
No Authorization header arrived. Some clients drop headers unless the transport type is set to HTTP explicitly. |
| The client opens a browser to sign in | It is trying OAuth. Disable OAuth for this server or make sure the header is configured. |
| Tool calls time out | Lower wait_seconds / timeout_seconds, or raise the client's tool timeout (table above). The job keeps running either way; find it with list_jobs. |
402 insufficient_credits |
Buy credits at https://keytween.com/buy. |
429 too_many_jobs |
Wait for a running generation to finish; get_account shows the limit. |