MCP server by JupiterBroadcasting
Auphonic MCP Server
Production-ready HTTP Model Context Protocol server for Auphonic audio processing.
Overview
HTTP-based MCP server implementing Streamable HTTP transport (spec 2025-03-26) to expose Auphonic API capabilities to AI agents like OpenClaw, OpenCode, and other MCP clients.
Key Features:
- ✅ Full MCP compliance (protocol 2025-03-26)
- ✅ Session management with secure UUIDs
- ✅ Comprehensive error handling
- ✅ Input validation
- ✅ Production state tracking
- ✅ Health monitoring
Quick Start
# Install Babashka
brew install borkdude/brew/babashka # macOS
# OR
curl -sLO https://raw.githubusercontent.com/babashka/babashka/master/install
chmod +x install && ./install # Linux
# Set environment variables
export AUPHONIC_API_KEY="your-api-key"
export AUPHONIC_PRESET_LUP="preset-uuid"
export AUPHONIC_PRESET_LAUNCH="preset-uuid"
# Run server
chmod +x auphonic-mcp-server.clj
./auphonic-mcp-server.clj 3003
Server runs on http://localhost:3003 with endpoint /mcp.
Configuration
Environment Variables
| Variable | Required | Description |
|----------|----------|-------------|
| AUPHONIC_API_KEY | Yes | API key from https://auphonic.com/account |
| AUPHONIC_PRESET_LUP | Yes* | Preset UUID for LUP show |
| AUPHONIC_PRESET_LAUNCH | Yes* | Preset UUID for Launch show |
*Required if uploading files for that show.
Getting Credentials:
- API Key: https://auphonic.com/account
- Preset UUIDs: https://auphonic.com/presets → click preset → copy UUID from URL
Show Configuration
Pre-configured shows:
- LUP: Types:
bootleg,adfree,main - Launch: Types:
bootleg,main
Add more shows by editing show-types in server file.
MCP Capabilities
Tools (6)
-
upload_audio - Upload and start processing
{ "show": "lup", "type": "bootleg", "file_path": "/absolute/path/to/file.mp3", "title": "Optional title", "subtitle": "Optional subtitle", "summary": "Optional summary" } -
check_status - Get production status
{ "production_uuid": "abc123..." } -
list_productions - List productions with filtering
{ "limit": 20, "offset": 0, "status": 3 } -
download_output - Download processed file
{ "production_uuid": "abc123...", "output_path": "/path/to/save", "format": "mp3" } -
delete_production - Delete a production
{ "production_uuid": "abc123..." } -
list_presets - List available presets
{}
Resources (3)
auphonic://config- Server configuration and show settingsauphonic://presets- All available presetsauphonic://production/{uuid}- Specific production details
Prompts (3)
upload_and_process- Guided upload workflowanalyze_production- Production analysischeck_recent_uploads- Recent uploads status
Protocol
Streamable HTTP Transport
Initialize Session:
curl -X POST http://localhost:3003/mcp \
-H "Accept: application/json, text/event-stream" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"clientInfo": {"name": "my-client", "version": "1.0"},
"capabilities": {}
}
}'
Response includes Mcp-Session-Id header. Use this in all subsequent requests:
curl -X POST http://localhost:3003/mcp \
-H "Mcp-Session-Id: {session-id}" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}'
Terminate Session:
curl -X DELETE http://localhost:3003/mcp \
-H "Mcp-Session-Id: {session-id}"
Session Management
- Server assigns UUID on initialization
- Client must include
Mcp-Session-Idheader on all requests after init - Session required for all methods except
initialize - Missing session ID → 400 Bad Request
- Invalid session ID → 404 Not Found
Error Handling
JSON-RPC Errors:
-32700: Parse error (malformed JSON)-32601: Method not found-32602: Invalid params-32603: Internal error-32000: Application error (validation, API errors)
HTTP Status Codes:
200 OK: Success400 Bad Request: Missing session, malformed request404 Not Found: Invalid session ID415 Unsupported Media Type: Wrong Content-Type500 Internal Server Error: Server error
Testing
Run Test Suite
# Start server on port 3001
./auphonic-mcp-server.clj 3001 &
# Run tests
bb test-runner.clj
Tests cover:
- Protocol compliance
- Session management
- Input validation
- Error handling
- Tool functionality
- Resource access
- Concurrent requests
Manual Testing
Health Check:
curl http://localhost:3003/health
Initialize:
curl -X POST http://localhost:3003/mcp \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","clientInfo":{"name":"test","version":"1.0"},"capabilities":{}}}'
List Tools:
curl -X POST http://localhost:3003/mcp \
-H "Mcp-Session-Id: YOUR_SESSION_ID" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
Integration Examples
OpenClaw / OpenCode
Configure in your agent's MCP settings:
{
"mcpServers": {
"auphonic": {
"url": "http://localhost:3003/mcp",
"env": {
"AUPHONIC_API_KEY": "your-key",
"AUPHONIC_PRESET_LUP": "preset-uuid",
"AUPHONIC_PRESET_LAUNCH": "preset-uuid"
}
}
}
}
Custom Client
import requests
# Initialize
response = requests.post('http://localhost:3003/mcp',
headers={
'Accept': 'application/json',
'Content-Type': 'application/json'
},
json={
'jsonrpc': '2.0',
'id': 1,
'method': 'initialize',
'params': {
'protocolVersion': '2025-03-26',
'clientInfo': {'name': 'my-client', 'version': '1.0'},
'capabilities': {}
}
})
session_id = response.headers['Mcp-Session-Id']
# Use tools
response = requests.post('http://localhost:3003/mcp',
headers={
'Mcp-Session-Id': session_id,
'Content-Type': 'application/json'
},
json={
'jsonrpc': '2.0',
'id': 2,
'method': 'tools/call',
'params': {
'name': 'list_presets',
'arguments': {}
}
})
Production Deployment
Systemd Service
[Unit]
Description=Auphonic MCP Server
After=network.target
[Service]
Type=simple
User=auphonic-mcp
Group=auphonic-mcp
WorkingDirectory=/opt/auphonic-mcp
EnvironmentFile=/etc/auphonic-mcp/secrets
ExecStart=/usr/local/bin/bb /opt/auphonic-mcp/auphonic-mcp-server.clj 3003
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
Note: Store API keys in EnvironmentFile, not inline Environment= values.
Docker
FROM babashka/babashka:latest
WORKDIR /app
COPY auphonic-mcp-server.clj .
ENV AUPHONIC_API_KEY=""
ENV AUPHONIC_PRESET_LUP=""
ENV AUPHONIC_PRESET_LAUNCH=""
EXPOSE 3003
CMD ["bb", "auphonic-mcp-server.clj", "3003"]
docker build -t auphonic-mcp .
docker run -p 3003:3003 \
-e AUPHONIC_API_KEY="your-key" \
-e AUPHONIC_PRESET_LUP="preset-uuid" \
-e AUPHONIC_PRESET_LAUNCH="preset-uuid" \
auphonic-mcp
Reverse Proxy (nginx)
server {
listen 80;
server_name auphonic-mcp.example.com;
location /mcp {
proxy_pass http://localhost:3003/mcp;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /health {
proxy_pass http://localhost:3003/health;
}
}
NixOS Module
Import the module from flake inputs and configure:
{ config, pkgs, ... }:
let
secretsFile = "/etc/nixos/secrets/auphonic-mcp.env";
in {
imports = [ inputs.auphonic-mcp.nixosModules.default ];
services.auphonic-mcp = {
enable = true;
port = 3003;
openFirewall = true;
environmentFile = secretsFile;
};
}
Create secrets file (/etc/nixos/secrets/auphonic-mcp.env):
AUPHONIC_API_KEY=your-api-key
AUPHONIC_PRESET_LUP=preset-uuid
AUPHONIC_PRESET_LAUNCH=preset-uuid
Home Manager Module
{ inputs, pkgs, ... }:
{
imports = [ inputs.auphonic-mcp.homeManagerModules.default ];
programs.auphonic-mcp = {
enable = true;
apiKeyFile = "/home/user/.config/auphonic-mcp/api-key";
presets = {
lup = "preset-uuid";
launch = "preset-uuid";
};
};
}
Security
Best Practices
- ✅ Store API keys in environment variables only
- ✅ Use HTTPS in production (reverse proxy)
- ✅ Implement rate limiting at reverse proxy
- ✅ Validate all user inputs
- ✅ Use absolute file paths only
- ✅ Restrict server to localhost if not needed remotely
- ✅ Implement authentication at reverse proxy level
- ✅ Monitor /health endpoint
- ✅ Set secure session IDs (UUIDs)
- ✅ Validate Origin header (DNS rebinding protection)
Input Validation
Server validates:
- Required fields present
- Show names from whitelist
- Episode types match show
- File paths exist
- UUIDs are valid
Invalid inputs return clear error messages.
Architecture
┌─────────────┐
│ MCP Client │
│ (Agent) │
└──────┬──────┘
│ HTTP POST /mcp
│ (JSON-RPC 2.0)
↓
┌──────────────────────┐
│ Auphonic MCP Server │
│ ┌──────────────────┐ │
│ │ Session Manager │ │
│ ├──────────────────┤ │
│ │ JSON-RPC Handler │ │
│ ├──────────────────┤ │
│ │ Tool Handlers │ │
│ │ Resource Handlers│ │
│ │ Prompt Handlers │ │
│ ├──────────────────┤ │
│ │ Validation Layer │ │
│ ├──────────────────┤ │
│ │ HTTP Client │ │
│ └──────────────────┘ │
└──────────┬───────────┘
│ HTTPS
↓
┌──────────────┐
│ Auphonic API │
└──────────────┘
Development
Code Structure
;; Configuration - Constants and defaults
;; State Management - Session and production tracking
;; Environment & Validation - Input validation helpers
;; HTTP Client - Auphonic API wrapper
;; Tool Implementations - MCP tool functions
;; Resource Handlers - MCP resource functions
;; Prompt Generators - MCP prompt functions
;; Protocol Handlers - MCP method handlers
;; JSON-RPC Handler - Protocol logic
;; HTTP Server - Transport layer
;; Main - Entry point
Design Principles
- Simple, direct functions - No unnecessary abstractions
- Explicit validation - Validate at boundaries
- Clear error messages - Help users understand issues
- Idiomatic Babashka - Use fs, http-client properly
- Production-ready - Error handling, logging, monitoring
Adding Tools
;; 1. Implement tool function
(defn tool-my-new-tool [{:keys [arg1 arg2]}]
(if-let [error (validate-required-fields ...)]
{:error (:error error)}
;; Implementation
{:content [{:type "text" :text "Result"}]}))
;; 2. Add to handle-tools-list
{:name "my_new_tool"
:description "What it does"
:inputSchema {:type "object"
:properties {:arg1 {:type "string"}}
:required ["arg1"]}}
;; 3. Add to handle-tools-call
"my_new_tool" (tool-my-new-tool arguments)
Troubleshooting
Server won't start
# Check Babashka installed
bb --version
# Check port available
lsof -i :3003
# Check environment variables
env | grep AUPHONIC
API errors
# Test API key
curl -H "Authorization: Bearer $AUPHONIC_API_KEY" \
https://auphonic.com/api/info.json
# Check preset exists
curl -H "Authorization: Bearer $AUPHONIC_API_KEY" \
https://auphonic.com/api/preset/$AUPHONIC_PRESET_LUP.json
Session errors
- Sessions expire when server restarts
- Sessions require initialization before use
- Check session ID in headers matches server's
Upload fails
- Use absolute paths:
/Users/you/file.mp3not~/file.mp3 - Verify file exists:
ls -lh /path/to/file.mp3 - Check file is readable
- Ensure enough disk space on Auphonic account
Performance
- Startup time: ~50ms (Babashka native)
- Memory: ~30MB (Babashka process)
- Concurrent sessions: Tested with 100+
- Request latency: <10ms (excluding Auphonic API)
Limitations
- Max file size: Depends on Auphonic account plan
- Processing time: Typically 1-5 min per hour of audio
- No streaming support for large file uploads
- Session state lost on server restart
Resources
- MCP Specification: https://spec.modelcontextprotocol.io/
- Auphonic API: https://auphonic.com/help/api/
- Babashka: https://babashka.org/
License
MIT