computer-volume-control-mcp
Version:
Model Context Protocol Server via Cross-Platform (Mac, Windows & Linux) Computer Audio Control
254 lines (236 loc) • 10.1 kB
JavaScript
const { exec } = require('child_process');
const { promisify } = require('util');
const readline = require('readline');
const execAsync = promisify(exec);
// Import Audio Control Functions
const {
getCurrentVolume,
setVolume,
getMuteStatus,
mute,
unmute,
increaseVolume,
decreaseVolume
} = require('./index.js');
// Create Readline Interface for Stdin/Stdout Communication
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
// Handle Incoming Messages
rl.on('line', async (line) => {
try {
const message = JSON.parse(line);
if (message.method === 'initialize') {
const response = {
jsonrpc: '2.0',
id: message.id,
result: {
protocolVersion: '2024-11-05',
capabilities: {
tools: {}
},
serverInfo: {
name: 'computer-volume-control-mcp',
version: '1.0.0'
}
}
};
console.log(JSON.stringify(response));
}
else if (message.method === 'tools/list') {
const response = {
jsonrpc: '2.0',
id: message.id,
result: {
tools: [
{
name: 'get_current_volume',
description: 'Get the current computer system volume level as a percentage between 0 and 100',
inputSchema: {
type: 'object',
properties: {},
required: []
}
},
{
name: 'set_volume',
description: 'Set the computer system volume level to a specific percentage between 0 and 100',
inputSchema: {
type: 'object',
properties: {
volume: {
type: 'number',
description: 'Volume level as a percentage (0-100)',
minimum: 0,
maximum: 100
}
},
required: ['volume']
}
},
{
name: 'get_mute_status',
description: 'Check if the computer system is currently muted',
inputSchema: {
type: 'object',
properties: {},
required: []
}
},
{
name: 'mute_system',
description: 'Mute the computer system audio',
inputSchema: {
type: 'object',
properties: {},
required: []
}
},
{
name: 'unmute_system',
description: 'Unmute the computer system audio',
inputSchema: {
type: 'object',
properties: {},
required: []
}
},
{
name: 'increase_volume',
description: 'Increase the computer system volume level by 10%',
inputSchema: {
type: 'object',
properties: {},
required: []
}
},
{
name: 'decrease_volume',
description: 'Decrease the computer system volume level by 10%',
inputSchema: {
type: 'object',
properties: {},
required: []
}
}
]
}
};
console.log(JSON.stringify(response));
}
else if (message.method === 'tools/call') {
const { name, arguments: args } = message.params;
let result;
let structuredData = {};
let isError = false;
try {
switch (name) {
case 'get_current_volume':
const volume = await getCurrentVolume();
result = `Current system volume is ${volume}%`;
structuredData = { volume: volume, unit: 'percentage' };
break;
case 'set_volume':
const { volume: newVolume } = args;
if (typeof newVolume !== 'number' || newVolume < 0 || newVolume > 100) {
throw new Error('Volume must be a number between 0 and 100');
}
await setVolume(newVolume);
result = `Volume set to ${newVolume}%`;
structuredData = { volume: newVolume, unit: 'percentage', action: 'set' };
break;
case 'get_mute_status':
const isMuted = await getMuteStatus();
result = `System is ${isMuted ? 'muted' : 'not muted'}`;
structuredData = { muted: isMuted };
break;
case 'mute_system':
await mute();
result = 'System has been muted';
structuredData = { muted: true, action: 'mute' };
break;
case 'unmute_system':
await unmute();
result = 'System has been unmuted';
structuredData = { muted: false, action: 'unmute' };
break;
case 'increase_volume':
const currentVol = await getCurrentVolume();
await increaseVolume();
const newVol = await getCurrentVolume();
result = `Volume increased from ${currentVol}% to ${newVol}%`;
structuredData = {
previousVolume: currentVol,
newVolume: newVol,
change: newVol - currentVol,
action: 'increase',
unit: 'percentage'
};
break;
case 'decrease_volume':
const currentVol2 = await getCurrentVolume();
await decreaseVolume();
const newVol2 = await getCurrentVolume();
result = `Volume decreased from ${currentVol2}% to ${newVol2}%`;
structuredData = {
previousVolume: currentVol2,
newVolume: newVol2,
change: newVol2 - currentVol2,
action: 'decrease',
unit: 'percentage'
};
break;
default:
throw new Error(`Unknown tool: ${name}`);
}
const response = {
jsonrpc: '2.0',
id: message.id,
result: {
content: [
{
type: 'text',
text: result
}
],
structuredContent: structuredData,
isError: isError
}
};
console.log(JSON.stringify(response));
} catch (error) {
const errorResponse = {
jsonrpc: '2.0',
id: message.id,
result: {
content: [
{
type: 'text',
text: `Error: ${error.message}`
}
],
structuredContent: { error: error.message, errorCode: -32603 },
isError: true
}
};
console.log(JSON.stringify(errorResponse));
}
}
else {
// Handle Other Methods
const response = {
jsonrpc: '2.0',
id: message.id,
result: {}
};
console.log(JSON.stringify(response));
}
} catch (error) {
// Log Errors to stderr to avoid Interfering with MCP protocol
process.stderr.write(`Error processing message: ${error.message}\n`);
}
});
// MCP Server Started - Ready to Receive Messages