swaywm-mcp
Version:
Swaywm MCP service
115 lines • 3.87 kB
JavaScript
import logger from "./logger.js";
import { McpServer, ResourceTemplate, } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { exec } from "child_process";
import { promisify } from "util";
import { find } from "./sway-querier.js";
const swaymsgBin = process.env.SWAYMSG_BIN || "swaymsg";
const execAsync = promisify(exec);
// Create an MCP server
const server = new McpServer({
name: "SwayWM MCP",
// NOTE: Update ../package.json version when changing this
version: '0.0.2',
});
// Helper function to execute swaymsg commands
async function swaymsg(command) {
logger.debug(`Executing swaymsg command: ${command}`);
// Fix issue with sway socket: swaymsg --raw -t get_tree
try {
// Use the swaymsgBin variable to execute the command
const { stdout } = await execAsync(`${swaymsgBin} --raw ${command}`);
return JSON.parse(stdout);
}
catch (error) {
logger.error(`Error executing swaymsg ${command}:`, error);
console.error(`Error executing swaymsg ${command}:`, error);
throw error;
}
}
// Get all workspaces
server.tool("workspaces", "Get all workspaces", {}, async () => {
const workspaces = await swaymsg("-t get_workspaces");
return {
content: [{ type: "text", text: JSON.stringify(workspaces, null, 2) }],
};
});
// Get all outputs (monitors)
server.tool("outputs", "Get all outputs", {}, async () => {
const outputs = await swaymsg("-t get_outputs");
return {
content: [{ type: "text", text: JSON.stringify(outputs, null, 2) }],
};
});
// Get all windows
server.tool("windows", "Get all windows", {}, async () => {
const tree = await swaymsg("-t get_tree");
return {
content: [{ type: "text", text: JSON.stringify(tree, null, 2) }],
};
});
// Get focused window
server.tool("focused", "Get focused window", {}, async () => {
const tree = await swaymsg("-t get_tree");
const focused = find(tree, (node) => {
return node.focused;
});
return {
content: [{ type: "text", text: JSON.stringify(focused[0], null, 2) }],
};
});
// Get input devices
server.tool("inputs", "Get all input devices", {}, async () => {
const inputs = await swaymsg("-t get_inputs");
return {
content: [{ type: "text", text: JSON.stringify(inputs, null, 2) }],
};
});
// Execute a sway command
server.tool("execute", "Execute a sway command", {
command: z.string()
.describe("The sway command to execute")
.default(""),
}, async ({ command }) => {
try {
await swaymsg(command);
return {
content: [{ type: "text", text: `Successfully executed: ${command}` }],
};
}
catch (error) {
return {
content: [{ type: "text", text: `Error executing command: ${error}` }],
};
}
});
// Add a dynamic workspace resource
server.resource("workspace", new ResourceTemplate("workspace://{name}", { list: undefined }), async (uri, { name }) => {
const workspaces = await swaymsg("-t get_workspaces");
const workspace = workspaces.find((w) => w.name === name);
if (!workspace) {
return {
contents: [
{
uri: uri.href,
text: `Workspace "${name}" not found`,
},
],
};
}
return {
contents: [
{
uri: uri.href,
text: JSON.stringify(workspace, null, 2),
},
],
};
});
logger.info("SwayWM MCP server started");
// Start receiving messages on stdin and sending messages on stdout
const transport = new StdioServerTransport();
await server.connect(transport);
//# sourceMappingURL=main.js.map