v2.0.1: Add /qwenclaw slash commands for Qwen Code CLI

This commit is contained in:
AI Agent
2026-02-26 21:18:00 +04:00
Unverified
parent 69cf7e8a05
commit c2a97e0995
5 changed files with 1388 additions and 5 deletions

200
src/mcp-server.js Normal file
View File

@@ -0,0 +1,200 @@
#!/usr/bin/env node
/**
* QwenClaw MCP Server
*
* Provides QwenClaw functionality as MCP tools for Qwen Code CLI
*
* Usage:
* In Qwen Code, type: /qwenclaw <command>
* Commands: start, status, send, skills, help
*/
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { spawn } from 'child_process';
import { join } from 'path';
const QWENCLAW_DIR = join(process.cwd());
// Tool definitions
const TOOLS = [
{
name: 'qwenclaw_start',
description: 'Start QwenClaw daemon',
inputSchema: {
type: 'object',
properties: {
web: {
type: 'boolean',
description: 'Enable web dashboard',
default: false,
},
},
},
},
{
name: 'qwenclaw_status',
description: 'Check QwenClaw daemon status',
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'qwenclaw_send',
description: 'Send message to QwenClaw daemon',
inputSchema: {
type: 'object',
properties: {
message: {
type: 'string',
description: 'Message to send',
},
},
required: ['message'],
},
},
{
name: 'qwenclaw_skills',
description: 'List all available QwenClaw skills',
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'qwenclaw_help',
description: 'Show QwenClaw help information',
inputSchema: {
type: 'object',
properties: {},
},
},
];
// Create MCP server
const server = new Server(
{
name: 'qwenclaw',
version: '2.0.0',
},
{
capabilities: {
tools: {},
},
}
);
// Handle tool listing
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: TOOLS,
};
});
// Handle tool execution
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args = {} } = request.params;
try {
switch (name) {
case 'qwenclaw_start': {
const web = args.web || false;
const result = await runCommand('start', web ? ['--web'] : []);
return {
content: [{ type: 'text', text: result }],
};
}
case 'qwenclaw_status': {
const result = await runCommand('status', []);
return {
content: [{ type: 'text', text: result }],
};
}
case 'qwenclaw_send': {
const message = args.message;
if (!message) {
return {
content: [{ type: 'text', text: 'Error: message is required' }],
isError: true,
};
}
const result = await runCommand('send', [message]);
return {
content: [{ type: 'text', text: result }],
};
}
case 'qwenclaw_skills': {
const result = await runCommand('skills', []);
return {
content: [{ type: 'text', text: result }],
};
}
case 'qwenclaw_help': {
const result = await runCommand('help', []);
return {
content: [{ type: 'text', text: result }],
};
}
default:
return {
content: [{ type: 'text', text: `Unknown tool: ${name}` }],
isError: true,
};
}
} catch (error) {
return {
content: [{ type: 'text', text: `Error: ${error.message}` }],
isError: true,
};
}
});
// Run QwenClaw command
async function runCommand(command, args = []) {
return new Promise((resolve, reject) => {
const proc = spawn('node', [join(QWENCLAW_DIR, 'bin', 'qwenclaw.js'), command, ...args], {
stdio: ['pipe', 'pipe', 'pipe'],
});
let output = '';
let error = '';
proc.stdout.on('data', (data) => {
output += data.toString();
});
proc.stderr.on('data', (data) => {
error += data.toString();
});
proc.on('close', (code) => {
if (code === 0) {
resolve(output.trim());
} else {
reject(new Error(error || `Command failed with code ${code}`));
}
});
});
}
// Start server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('QwenClaw MCP server running on stdio');
}
main().catch((error) => {
console.error('Fatal error:', error);
process.exit(1);
});