mcp-server-commands 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +74 -0
- package/build/index.js +158 -0
- package/package.json +27 -0
package/README.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# mcp-server-commands MCP Server
|
|
2
|
+
|
|
3
|
+
An MCP server to run commands and includ the output in chat history.
|
|
4
|
+
|
|
5
|
+
## Tools
|
|
6
|
+
|
|
7
|
+
- `run_command` - run a command, i.e. `hostname` or `ls -al` or `echo "hello world"` etc
|
|
8
|
+
- Returns STDOUT and STDERR as text
|
|
9
|
+
- for LLMs to request tool use and get back the command output, i.e. Claude Desktop app
|
|
10
|
+
|
|
11
|
+
## Prompts
|
|
12
|
+
|
|
13
|
+
- `include_command_output` - include the output of a command in the chat history
|
|
14
|
+
- for users to include relevant commands in chat history, i.e. via `Zed`'s slash commands
|
|
15
|
+
|
|
16
|
+
## Development
|
|
17
|
+
|
|
18
|
+
Install dependencies:
|
|
19
|
+
```bash
|
|
20
|
+
npm install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Build the server:
|
|
24
|
+
```bash
|
|
25
|
+
npm run build
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
For development with auto-rebuild:
|
|
29
|
+
```bash
|
|
30
|
+
npm run watch
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
To use with Claude Desktop, add the server config:
|
|
36
|
+
|
|
37
|
+
On MacOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
38
|
+
On Windows: `%APPDATA%/Claude/claude_desktop_config.json`
|
|
39
|
+
|
|
40
|
+
### Use the published npm package
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{
|
|
44
|
+
"mcpServers": {
|
|
45
|
+
"mcp-server-commands": {
|
|
46
|
+
"command": "npx",
|
|
47
|
+
"args": ["mcp-server-commands"]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Use a local build (repo checkout)
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"mcpServers": {
|
|
58
|
+
"mcp-server-commands": {
|
|
59
|
+
// works b/c of shebang in index.js
|
|
60
|
+
"command": "/path/to/mcp-server-commands/build/index.js"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Debugging
|
|
67
|
+
|
|
68
|
+
Since MCP servers communicate over stdio, debugging can be challenging. We recommend using the [MCP Inspector](https://github.com/modelcontextprotocol/inspector), which is available as a package script:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
npm run inspector
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The Inspector will provide a URL to access debugging tools in your browser.
|
package/build/index.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { exec } from "node:child_process";
|
|
6
|
+
import { promisify } from "node:util";
|
|
7
|
+
const execAsync = promisify(exec);
|
|
8
|
+
const server = new Server({
|
|
9
|
+
name: "mcp-server-commands",
|
|
10
|
+
version: "0.1.0",
|
|
11
|
+
}, {
|
|
12
|
+
capabilities: {
|
|
13
|
+
//resources: {},
|
|
14
|
+
tools: {},
|
|
15
|
+
prompts: {},
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
19
|
+
return {
|
|
20
|
+
tools: [
|
|
21
|
+
{
|
|
22
|
+
name: "run_command",
|
|
23
|
+
inputSchema: {
|
|
24
|
+
type: "object",
|
|
25
|
+
properties: {
|
|
26
|
+
command: {
|
|
27
|
+
type: "string",
|
|
28
|
+
description: "Command to run",
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
required: ["command"],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
38
|
+
switch (request.params.name) {
|
|
39
|
+
case "run_command": {
|
|
40
|
+
const command = String(request.params.arguments?.command);
|
|
41
|
+
if (!command) {
|
|
42
|
+
throw new Error("Command is required");
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const { stdout, stderr } = await execAsync(command);
|
|
46
|
+
return {
|
|
47
|
+
toolResult: {
|
|
48
|
+
content: [
|
|
49
|
+
{
|
|
50
|
+
type: "text",
|
|
51
|
+
text: stdout,
|
|
52
|
+
name: "STDOUT",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
type: "text",
|
|
56
|
+
text: stderr,
|
|
57
|
+
name: "STDERR",
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
const { message, stdout, stderr } = error;
|
|
65
|
+
return {
|
|
66
|
+
toolResult: {
|
|
67
|
+
content: [
|
|
68
|
+
{
|
|
69
|
+
// most of the time this is gonna match stderr, TODO do I want/need both error and stderr?
|
|
70
|
+
type: "text",
|
|
71
|
+
text: message,
|
|
72
|
+
name: "ERROR",
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
type: "text",
|
|
76
|
+
text: stderr || "",
|
|
77
|
+
name: "STDERR",
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
// keep STDOUT b/c there might be some useful output before the failure
|
|
81
|
+
type: "text",
|
|
82
|
+
text: stdout || "",
|
|
83
|
+
name: "STDOUT",
|
|
84
|
+
},
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
default:
|
|
91
|
+
throw new Error("Unknown tool");
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
95
|
+
return {
|
|
96
|
+
prompts: [
|
|
97
|
+
{
|
|
98
|
+
name: "include_command_output",
|
|
99
|
+
description: "Include command output in the prompt. Instead of a tool call, the user decides what commands are relevant.",
|
|
100
|
+
arguments: [
|
|
101
|
+
{
|
|
102
|
+
name: "command",
|
|
103
|
+
required: true,
|
|
104
|
+
},
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
};
|
|
109
|
+
});
|
|
110
|
+
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
111
|
+
if (request.params.name !== "include_command_output") {
|
|
112
|
+
throw new Error("Unknown prompt");
|
|
113
|
+
}
|
|
114
|
+
const command = String(request.params.arguments?.command);
|
|
115
|
+
if (!command) {
|
|
116
|
+
throw new Error("Command is required");
|
|
117
|
+
}
|
|
118
|
+
const { stdout, stderr } = await execAsync(command);
|
|
119
|
+
// let error bubble up, errors look good in zed /prompts (i.e. command not found)
|
|
120
|
+
const messages = [
|
|
121
|
+
{
|
|
122
|
+
role: "user",
|
|
123
|
+
content: {
|
|
124
|
+
type: "text",
|
|
125
|
+
text: "I ran the following command, if there is any output it will be shown below:\n" +
|
|
126
|
+
command,
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
];
|
|
130
|
+
if (stdout) {
|
|
131
|
+
messages.push({
|
|
132
|
+
role: "user",
|
|
133
|
+
content: {
|
|
134
|
+
type: "text",
|
|
135
|
+
text: "STDOUT:\n" + stdout,
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
if (stderr) {
|
|
140
|
+
messages.push({
|
|
141
|
+
role: "user",
|
|
142
|
+
content: {
|
|
143
|
+
type: "text",
|
|
144
|
+
text: "STDERR:\n" + stderr,
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return { messages };
|
|
149
|
+
});
|
|
150
|
+
async function main() {
|
|
151
|
+
console.log("Starting server...");
|
|
152
|
+
const transport = new StdioServerTransport();
|
|
153
|
+
await server.connect(transport);
|
|
154
|
+
}
|
|
155
|
+
main().catch((error) => {
|
|
156
|
+
console.error("Server error:", error);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mcp-server-commands",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "An MCP server to run arbitrary commands",
|
|
5
|
+
"private": false,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mcp-server-commands": "./build/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"build"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"clean": "rm -rf build",
|
|
15
|
+
"build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
|
|
16
|
+
"prepare": "npm run build",
|
|
17
|
+
"watch": "tsc --watch",
|
|
18
|
+
"inspector": "npx @modelcontextprotocol/inspector build/index.js"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@modelcontextprotocol/sdk": "0.6.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^20.11.24",
|
|
25
|
+
"typescript": "^5.3.3"
|
|
26
|
+
}
|
|
27
|
+
}
|