/**
* IRCAM Amplify MCP Server
*
* MCP server enabling LLMs to use IRCAM Amplify audio processing APIs.
*/
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
ListToolsRequestSchema,
CallToolRequestSchema,
ErrorCode,
McpError,
} from '@modelcontextprotocol/sdk/types.js';
import { hasApiKey } from './utils/auth.js';
import { formatToolError, toMCPError } from './utils/errors.js';
// Import tool handlers
import { analyzeMusicTool, handleAnalyzeMusic } from './tools/analyze-music.js';
import { separateStemsTool, handleSeparateStems } from './tools/separate-stems.js';
import { detectAiMusicTool, handleDetectAiMusic } from './tools/detect-ai-music.js';
import { analyzeLoudnessTool, handleAnalyzeLoudness } from './tools/analyze-loudness.js';
import { checkJobStatusTool, handleCheckJobStatus } from './tools/check-job-status.js';
/**
* Server metadata
*/
const SERVER_INFO = {
name: 'ircam-amplify-mcp',
version: '1.0.0',
};
/**
* All available tools
*/
const TOOLS = [
analyzeMusicTool,
separateStemsTool,
detectAiMusicTool,
analyzeLoudnessTool,
checkJobStatusTool,
];
/**
* Tool name to handler mapping
*/
const TOOL_HANDLERS: Record<string, (args: Record<string, unknown>) => Promise<unknown>> = {
analyze_music: handleAnalyzeMusic,
separate_stems: handleSeparateStems,
detect_ai_music: handleDetectAiMusic,
analyze_loudness: handleAnalyzeLoudness,
check_job_status: handleCheckJobStatus,
};
/**
* Create and configure the MCP server
*/
function createServer(): Server {
const server = new Server(SERVER_INFO, {
capabilities: {
tools: {},
},
});
// Handle list tools request
server.setRequestHandler(ListToolsRequestSchema, () => {
return { tools: TOOLS };
});
// Handle tool call request
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
// Check if tool exists
const handler = TOOL_HANDLERS[name];
if (!handler) {
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
}
// Check API key before executing any tool
if (!hasApiKey()) {
const error = toMCPError({
code: 'MISSING_API_KEY',
message: 'Missing API key. Set IRCAM_AMPLIFY_API_KEY environment variable.',
suggestion: 'Get your API key from https://app.ircamamplify.io',
});
return formatToolError(error);
}
try {
// Execute tool handler
const result = await handler(args || {});
// Return success response
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
};
} catch (error) {
// Return error response
return formatToolError(toMCPError(error));
}
});
return server;
}
/**
* Main entry point
*/
async function main(): Promise<void> {
const server = createServer();
const transport = new StdioServerTransport();
await server.connect(transport);
// Handle graceful shutdown
process.on('SIGINT', () => {
void server.close().then(() => process.exit(0));
});
process.on('SIGTERM', () => {
void server.close().then(() => process.exit(0));
});
}
// Run the server
main().catch((error) => {
console.error('Failed to start MCP server:', error);
process.exit(1);
});