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.
Files changed (3) hide show
  1. package/README.md +74 -0
  2. package/build/index.js +158 -0
  3. 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
+ }